github.com/dennwc/btrfs@v0.0.0-20221026161108-3097362dc072/send/send.go (about) 1 package send 2 3 import ( 4 "errors" 5 "fmt" 6 "github.com/dennwc/btrfs" 7 "io" 8 "io/ioutil" 9 "time" 10 ) 11 12 func NewStreamReader(r io.Reader) (*StreamReader, error) { 13 // read magic and version 14 buf := make([]byte, len(sendStreamMagic)+4) 15 _, err := io.ReadFull(r, buf) 16 if err != nil { 17 return nil, fmt.Errorf("cannot read magic: %v", err) 18 } else if string(buf[:sendStreamMagicSize]) != sendStreamMagic { 19 return nil, errors.New("unexpected stream header") 20 } 21 version := sendEndianess.Uint32(buf[sendStreamMagicSize:]) 22 if version != sendStreamVersion { 23 return nil, fmt.Errorf("stream version %d not supported", version) 24 } 25 return &StreamReader{r: r}, nil 26 } 27 28 type StreamReader struct { 29 r io.Reader 30 buf [cmdHeaderSize]byte 31 } 32 33 func (r *StreamReader) readCmdHeader() (h cmdHeader, err error) { 34 _, err = io.ReadFull(r.r, r.buf[:cmdHeaderSize]) 35 if err == io.EOF { 36 return 37 } else if err != nil { 38 err = fmt.Errorf("cannot read command header: %v", err) 39 return 40 } 41 err = h.Unmarshal(r.buf[:cmdHeaderSize]) 42 // TODO: check CRC 43 return 44 } 45 46 type SendTLV struct { 47 Attr sendCmdAttr 48 Val interface{} 49 } 50 51 func (r *StreamReader) readTLV(rd io.Reader) (*SendTLV, error) { 52 _, err := io.ReadFull(rd, r.buf[:tlvHeaderSize]) 53 if err == io.EOF { 54 return nil, err 55 } else if err != nil { 56 return nil, fmt.Errorf("cannot read tlv header: %v", err) 57 } 58 var h tlvHeader 59 if err = h.Unmarshal(r.buf[:tlvHeaderSize]); err != nil { 60 return nil, err 61 } 62 typ := sendCmdAttr(h.Type) 63 if sendCmdAttr(typ) > sendAttrMax { // || th.Len > _BTRFS_SEND_BUF_SIZE { 64 return nil, fmt.Errorf("invalid tlv in cmd: %q", typ) 65 } 66 buf := make([]byte, h.Len) 67 _, err = io.ReadFull(rd, buf) 68 if err != nil { 69 return nil, fmt.Errorf("cannot read tlv: %v", err) 70 } 71 var v interface{} 72 switch typ { 73 case sendAttrCtransid, sendAttrCloneCtransid, 74 sendAttrUid, sendAttrGid, sendAttrMode, 75 sendAttrIno, sendAttrFileOffset, sendAttrSize, 76 sendAttrCloneOffset, sendAttrCloneLen: 77 if len(buf) != 8 { 78 return nil, fmt.Errorf("unexpected int64 size: %v", h.Len) 79 } 80 v = sendEndianess.Uint64(buf[:8]) 81 case sendAttrPath, sendAttrPathTo, sendAttrClonePath, sendAttrXattrName: 82 v = string(buf) 83 case sendAttrData, sendAttrXattrData: 84 v = buf 85 case sendAttrUuid, sendAttrCloneUuid: 86 if h.Len != btrfs.UUIDSize { 87 return nil, fmt.Errorf("unexpected UUID size: %v", h.Len) 88 } 89 var u btrfs.UUID 90 copy(u[:], buf) 91 v = u 92 case sendAttrAtime, sendAttrMtime, sendAttrCtime, sendAttrOtime: 93 if h.Len != 12 { 94 return nil, fmt.Errorf("unexpected timestamp size: %v", h.Len) 95 } 96 v = time.Unix( // btrfs_timespec 97 int64(sendEndianess.Uint64(buf[:8])), 98 int64(sendEndianess.Uint32(buf[8:])), 99 ) 100 default: 101 return nil, fmt.Errorf("unsupported tlv type: %v (len: %v)", typ, h.Len) 102 } 103 return &SendTLV{Attr: typ, Val: v}, nil 104 } 105 func (r *StreamReader) ReadCommand() (_ Cmd, gerr error) { 106 h, err := r.readCmdHeader() 107 if err != nil { 108 return nil, err 109 } 110 var tlvs []SendTLV 111 rd := io.LimitReader(r.r, int64(h.Len)) 112 defer io.Copy(ioutil.Discard, rd) 113 for { 114 tlv, err := r.readTLV(rd) 115 if err == io.EOF { 116 break 117 } else if err != nil { 118 return nil, fmt.Errorf("command %v: %v", h.Cmd, err) 119 } 120 tlvs = append(tlvs, *tlv) 121 } 122 var c Cmd 123 switch h.Cmd { 124 case sendCmdEnd: 125 c = &StreamEnd{} 126 case sendCmdSubvol: 127 c = &SubvolCmd{} 128 case sendCmdSnapshot: 129 c = &SnapshotCmd{} 130 case sendCmdChown: 131 c = &ChownCmd{} 132 case sendCmdChmod: 133 c = &ChmodCmd{} 134 case sendCmdUtimes: 135 c = &UTimesCmd{} 136 case sendCmdMkdir: 137 c = &MkdirCmd{} 138 case sendCmdRename: 139 c = &RenameCmd{} 140 case sendCmdMkfile: 141 c = &MkfileCmd{} 142 case sendCmdWrite: 143 c = &WriteCmd{} 144 case sendCmdTruncate: 145 c = &TruncateCmd{} 146 } 147 if c == nil { 148 return &UnknownSendCmd{Kind: h.Cmd, Params: tlvs}, nil 149 } 150 if err := c.decode(tlvs); err != nil { 151 return nil, err 152 } 153 return c, nil 154 } 155 156 type errUnexpectedAttrType struct { 157 Cmd CmdType 158 Val SendTLV 159 } 160 161 func (e errUnexpectedAttrType) Error() string { 162 return fmt.Sprintf("unexpected type for %q (in %q): %T", 163 e.Val.Attr, e.Cmd, e.Val.Val) 164 } 165 166 type errUnexpectedAttr struct { 167 Cmd CmdType 168 Val SendTLV 169 } 170 171 func (e errUnexpectedAttr) Error() string { 172 return fmt.Sprintf("unexpected attr %q for %q (%T)", 173 e.Val.Attr, e.Cmd, e.Val.Val) 174 } 175 176 type Cmd interface { 177 Type() CmdType 178 decode(tlvs []SendTLV) error 179 } 180 181 type UnknownSendCmd struct { 182 Kind CmdType 183 Params []SendTLV 184 } 185 186 func (c UnknownSendCmd) Type() CmdType { 187 return c.Kind 188 } 189 func (c *UnknownSendCmd) decode(tlvs []SendTLV) error { 190 c.Params = tlvs 191 return nil 192 } 193 194 type StreamEnd struct{} 195 196 func (c StreamEnd) Type() CmdType { 197 return sendCmdEnd 198 } 199 func (c *StreamEnd) decode(tlvs []SendTLV) error { 200 if len(tlvs) != 0 { 201 return fmt.Errorf("unexpected TLVs for stream end command: %#v", tlvs) 202 } 203 return nil 204 } 205 206 type SubvolCmd struct { 207 Path string 208 UUID btrfs.UUID 209 CTransID uint64 210 } 211 212 func (c SubvolCmd) Type() CmdType { 213 return sendCmdSubvol 214 } 215 func (c *SubvolCmd) decode(tlvs []SendTLV) error { 216 for _, tlv := range tlvs { 217 var ok bool 218 switch tlv.Attr { 219 case sendAttrPath: 220 c.Path, ok = tlv.Val.(string) 221 case sendAttrUuid: 222 c.UUID, ok = tlv.Val.(btrfs.UUID) 223 case sendAttrCtransid: 224 c.CTransID, ok = tlv.Val.(uint64) 225 default: 226 return errUnexpectedAttr{Val: tlv, Cmd: c.Type()} 227 } 228 if !ok { 229 return errUnexpectedAttrType{Val: tlv, Cmd: c.Type()} 230 } 231 } 232 return nil 233 } 234 235 type SnapshotCmd struct { 236 Path string 237 UUID btrfs.UUID 238 CTransID uint64 239 CloneUUID btrfs.UUID 240 CloneTransID uint64 241 } 242 243 func (c SnapshotCmd) Type() CmdType { 244 return sendCmdSnapshot 245 } 246 func (c *SnapshotCmd) decode(tlvs []SendTLV) error { 247 for _, tlv := range tlvs { 248 var ok bool 249 switch tlv.Attr { 250 case sendAttrPath: 251 c.Path, ok = tlv.Val.(string) 252 case sendAttrUuid: 253 c.UUID, ok = tlv.Val.(btrfs.UUID) 254 case sendAttrCtransid: 255 c.CTransID, ok = tlv.Val.(uint64) 256 case sendAttrCloneUuid: 257 c.CloneUUID, ok = tlv.Val.(btrfs.UUID) 258 case sendAttrCloneCtransid: 259 c.CloneTransID, ok = tlv.Val.(uint64) 260 default: 261 return errUnexpectedAttr{Val: tlv, Cmd: c.Type()} 262 } 263 if !ok { 264 return errUnexpectedAttrType{Val: tlv, Cmd: c.Type()} 265 } 266 } 267 return nil 268 } 269 270 type ChownCmd struct { 271 Path string 272 UID, GID uint64 273 } 274 275 func (c ChownCmd) Type() CmdType { 276 return sendCmdChown 277 } 278 func (c *ChownCmd) decode(tlvs []SendTLV) error { 279 for _, tlv := range tlvs { 280 var ok bool 281 switch tlv.Attr { 282 case sendAttrPath: 283 c.Path, ok = tlv.Val.(string) 284 case sendAttrUid: 285 c.UID, ok = tlv.Val.(uint64) 286 case sendAttrGid: 287 c.GID, ok = tlv.Val.(uint64) 288 default: 289 return errUnexpectedAttr{Val: tlv, Cmd: c.Type()} 290 } 291 if !ok { 292 return errUnexpectedAttrType{Val: tlv, Cmd: c.Type()} 293 } 294 } 295 return nil 296 } 297 298 type ChmodCmd struct { 299 Path string 300 Mode uint64 301 } 302 303 func (c ChmodCmd) Type() CmdType { 304 return sendCmdChmod 305 } 306 func (c *ChmodCmd) decode(tlvs []SendTLV) error { 307 for _, tlv := range tlvs { 308 var ok bool 309 switch tlv.Attr { 310 case sendAttrPath: 311 c.Path, ok = tlv.Val.(string) 312 case sendAttrMode: 313 c.Mode, ok = tlv.Val.(uint64) 314 default: 315 return errUnexpectedAttr{Val: tlv, Cmd: c.Type()} 316 } 317 if !ok { 318 return errUnexpectedAttrType{Val: tlv, Cmd: c.Type()} 319 } 320 } 321 return nil 322 } 323 324 type UTimesCmd struct { 325 Path string 326 ATime, MTime, CTime time.Time 327 } 328 329 func (c UTimesCmd) Type() CmdType { 330 return sendCmdUtimes 331 } 332 func (c *UTimesCmd) decode(tlvs []SendTLV) error { 333 for _, tlv := range tlvs { 334 var ok bool 335 switch tlv.Attr { 336 case sendAttrPath: 337 c.Path, ok = tlv.Val.(string) 338 case sendAttrAtime: 339 c.ATime, ok = tlv.Val.(time.Time) 340 case sendAttrMtime: 341 c.MTime, ok = tlv.Val.(time.Time) 342 case sendAttrCtime: 343 c.CTime, ok = tlv.Val.(time.Time) 344 default: 345 return errUnexpectedAttr{Val: tlv, Cmd: c.Type()} 346 } 347 if !ok { 348 return errUnexpectedAttrType{Val: tlv, Cmd: c.Type()} 349 } 350 } 351 return nil 352 } 353 354 type MkdirCmd struct { 355 Path string 356 Ino uint64 357 } 358 359 func (c MkdirCmd) Type() CmdType { 360 return sendCmdMkdir 361 } 362 func (c *MkdirCmd) decode(tlvs []SendTLV) error { 363 for _, tlv := range tlvs { 364 var ok bool 365 switch tlv.Attr { 366 case sendAttrPath: 367 c.Path, ok = tlv.Val.(string) 368 case sendAttrIno: 369 c.Ino, ok = tlv.Val.(uint64) 370 default: 371 return errUnexpectedAttr{Val: tlv, Cmd: c.Type()} 372 } 373 if !ok { 374 return errUnexpectedAttrType{Val: tlv, Cmd: c.Type()} 375 } 376 } 377 return nil 378 } 379 380 type RenameCmd struct { 381 From, To string 382 } 383 384 func (c RenameCmd) Type() CmdType { 385 return sendCmdRename 386 } 387 func (c *RenameCmd) decode(tlvs []SendTLV) error { 388 for _, tlv := range tlvs { 389 var ok bool 390 switch tlv.Attr { 391 case sendAttrPath: 392 c.From, ok = tlv.Val.(string) 393 case sendAttrPathTo: 394 c.To, ok = tlv.Val.(string) 395 default: 396 return errUnexpectedAttr{Val: tlv, Cmd: c.Type()} 397 } 398 if !ok { 399 return errUnexpectedAttrType{Val: tlv, Cmd: c.Type()} 400 } 401 } 402 return nil 403 } 404 405 type MkfileCmd struct { 406 Path string 407 Ino uint64 408 } 409 410 func (c MkfileCmd) Type() CmdType { 411 return sendCmdMkfile 412 } 413 func (c *MkfileCmd) decode(tlvs []SendTLV) error { 414 for _, tlv := range tlvs { 415 var ok bool 416 switch tlv.Attr { 417 case sendAttrPath: 418 c.Path, ok = tlv.Val.(string) 419 case sendAttrIno: 420 c.Ino, ok = tlv.Val.(uint64) 421 default: 422 return errUnexpectedAttr{Val: tlv, Cmd: c.Type()} 423 } 424 if !ok { 425 return errUnexpectedAttrType{Val: tlv, Cmd: c.Type()} 426 } 427 } 428 return nil 429 } 430 431 type WriteCmd struct { 432 Path string 433 Off uint64 434 Data []byte 435 } 436 437 func (c WriteCmd) Type() CmdType { 438 return sendCmdWrite 439 } 440 func (c *WriteCmd) decode(tlvs []SendTLV) error { 441 for _, tlv := range tlvs { 442 var ok bool 443 switch tlv.Attr { 444 case sendAttrPath: 445 c.Path, ok = tlv.Val.(string) 446 case sendAttrFileOffset: 447 c.Off, ok = tlv.Val.(uint64) 448 case sendAttrData: 449 c.Data, ok = tlv.Val.([]byte) 450 default: 451 return errUnexpectedAttr{Val: tlv, Cmd: c.Type()} 452 } 453 if !ok { 454 return errUnexpectedAttrType{Val: tlv, Cmd: c.Type()} 455 } 456 } 457 return nil 458 } 459 460 type TruncateCmd struct { 461 Path string 462 Size uint64 463 } 464 465 func (c TruncateCmd) Type() CmdType { 466 return sendCmdTruncate 467 } 468 func (c *TruncateCmd) decode(tlvs []SendTLV) error { 469 for _, tlv := range tlvs { 470 var ok bool 471 switch tlv.Attr { 472 case sendAttrPath: 473 c.Path, ok = tlv.Val.(string) 474 case sendAttrSize: 475 c.Size, ok = tlv.Val.(uint64) 476 default: 477 return errUnexpectedAttr{Val: tlv, Cmd: c.Type()} 478 } 479 if !ok { 480 return errUnexpectedAttrType{Val: tlv, Cmd: c.Type()} 481 } 482 } 483 return nil 484 }