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  }