github.com/pkg/sftp@v1.13.6/internal/encoding/ssh/filexfer/attrs.go (about)

     1  package sshfx
     2  
     3  // Attributes related flags.
     4  const (
     5  	AttrSize        = 1 << iota // SSH_FILEXFER_ATTR_SIZE
     6  	AttrUIDGID                  // SSH_FILEXFER_ATTR_UIDGID
     7  	AttrPermissions             // SSH_FILEXFER_ATTR_PERMISSIONS
     8  	AttrACModTime               // SSH_FILEXFER_ACMODTIME
     9  
    10  	AttrExtended = 1 << 31 // SSH_FILEXFER_ATTR_EXTENDED
    11  )
    12  
    13  // Attributes defines the file attributes type defined in draft-ietf-secsh-filexfer-02
    14  //
    15  // Defined in: https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt#section-5
    16  type Attributes struct {
    17  	Flags uint32
    18  
    19  	// AttrSize
    20  	Size uint64
    21  
    22  	// AttrUIDGID
    23  	UID uint32
    24  	GID uint32
    25  
    26  	// AttrPermissions
    27  	Permissions FileMode
    28  
    29  	// AttrACmodTime
    30  	ATime uint32
    31  	MTime uint32
    32  
    33  	// AttrExtended
    34  	ExtendedAttributes []ExtendedAttribute
    35  }
    36  
    37  // GetSize returns the Size field and a bool that is true if and only if the value is valid/defined.
    38  func (a *Attributes) GetSize() (size uint64, ok bool) {
    39  	return a.Size, a.Flags&AttrSize != 0
    40  }
    41  
    42  // SetSize is a convenience function that sets the Size field,
    43  // and marks the field as valid/defined in Flags.
    44  func (a *Attributes) SetSize(size uint64) {
    45  	a.Flags |= AttrSize
    46  	a.Size = size
    47  }
    48  
    49  // GetUIDGID returns the UID and GID fields and a bool that is true if and only if the values are valid/defined.
    50  func (a *Attributes) GetUIDGID() (uid, gid uint32, ok bool) {
    51  	return a.UID, a.GID, a.Flags&AttrUIDGID != 0
    52  }
    53  
    54  // SetUIDGID is a convenience function that sets the UID and GID fields,
    55  // and marks the fields as valid/defined in Flags.
    56  func (a *Attributes) SetUIDGID(uid, gid uint32) {
    57  	a.Flags |= AttrUIDGID
    58  	a.UID = uid
    59  	a.GID = gid
    60  }
    61  
    62  // GetPermissions returns the Permissions field and a bool that is true if and only if the value is valid/defined.
    63  func (a *Attributes) GetPermissions() (perms FileMode, ok bool) {
    64  	return a.Permissions, a.Flags&AttrPermissions != 0
    65  }
    66  
    67  // SetPermissions is a convenience function that sets the Permissions field,
    68  // and marks the field as valid/defined in Flags.
    69  func (a *Attributes) SetPermissions(perms FileMode) {
    70  	a.Flags |= AttrPermissions
    71  	a.Permissions = perms
    72  }
    73  
    74  // GetACModTime returns the ATime and MTime fields and a bool that is true if and only if the values are valid/defined.
    75  func (a *Attributes) GetACModTime() (atime, mtime uint32, ok bool) {
    76  	return a.ATime, a.MTime, a.Flags&AttrACModTime != 0
    77  }
    78  
    79  // SetACModTime is a convenience function that sets the ATime and MTime fields,
    80  // and marks the fields as valid/defined in Flags.
    81  func (a *Attributes) SetACModTime(atime, mtime uint32) {
    82  	a.Flags |= AttrACModTime
    83  	a.ATime = atime
    84  	a.MTime = mtime
    85  }
    86  
    87  // Len returns the number of bytes a would marshal into.
    88  func (a *Attributes) Len() int {
    89  	length := 4
    90  
    91  	if a.Flags&AttrSize != 0 {
    92  		length += 8
    93  	}
    94  
    95  	if a.Flags&AttrUIDGID != 0 {
    96  		length += 4 + 4
    97  	}
    98  
    99  	if a.Flags&AttrPermissions != 0 {
   100  		length += 4
   101  	}
   102  
   103  	if a.Flags&AttrACModTime != 0 {
   104  		length += 4 + 4
   105  	}
   106  
   107  	if a.Flags&AttrExtended != 0 {
   108  		length += 4
   109  
   110  		for _, ext := range a.ExtendedAttributes {
   111  			length += ext.Len()
   112  		}
   113  	}
   114  
   115  	return length
   116  }
   117  
   118  // MarshalInto marshals e onto the end of the given Buffer.
   119  func (a *Attributes) MarshalInto(buf *Buffer) {
   120  	buf.AppendUint32(a.Flags)
   121  
   122  	if a.Flags&AttrSize != 0 {
   123  		buf.AppendUint64(a.Size)
   124  	}
   125  
   126  	if a.Flags&AttrUIDGID != 0 {
   127  		buf.AppendUint32(a.UID)
   128  		buf.AppendUint32(a.GID)
   129  	}
   130  
   131  	if a.Flags&AttrPermissions != 0 {
   132  		buf.AppendUint32(uint32(a.Permissions))
   133  	}
   134  
   135  	if a.Flags&AttrACModTime != 0 {
   136  		buf.AppendUint32(a.ATime)
   137  		buf.AppendUint32(a.MTime)
   138  	}
   139  
   140  	if a.Flags&AttrExtended != 0 {
   141  		buf.AppendUint32(uint32(len(a.ExtendedAttributes)))
   142  
   143  		for _, ext := range a.ExtendedAttributes {
   144  			ext.MarshalInto(buf)
   145  		}
   146  	}
   147  }
   148  
   149  // MarshalBinary returns a as the binary encoding of a.
   150  func (a *Attributes) MarshalBinary() ([]byte, error) {
   151  	buf := NewBuffer(make([]byte, 0, a.Len()))
   152  	a.MarshalInto(buf)
   153  	return buf.Bytes(), nil
   154  }
   155  
   156  // UnmarshalFrom unmarshals an Attributes from the given Buffer into e.
   157  //
   158  // NOTE: The values of fields not covered in the a.Flags are explicitly undefined.
   159  func (a *Attributes) UnmarshalFrom(buf *Buffer) (err error) {
   160  	flags := buf.ConsumeUint32()
   161  
   162  	return a.XXX_UnmarshalByFlags(flags, buf)
   163  }
   164  
   165  // XXX_UnmarshalByFlags uses the pre-existing a.Flags field to determine which fields to decode.
   166  // DO NOT USE THIS: it is an anti-corruption function to implement existing internal usage in pkg/sftp.
   167  // This function is not a part of any compatibility promise.
   168  func (a *Attributes) XXX_UnmarshalByFlags(flags uint32, buf *Buffer) (err error) {
   169  	a.Flags = flags
   170  
   171  	// Short-circuit dummy attributes.
   172  	if a.Flags == 0 {
   173  		return buf.Err
   174  	}
   175  
   176  	if a.Flags&AttrSize != 0 {
   177  		a.Size = buf.ConsumeUint64()
   178  	}
   179  
   180  	if a.Flags&AttrUIDGID != 0 {
   181  		a.UID = buf.ConsumeUint32()
   182  		a.GID = buf.ConsumeUint32()
   183  	}
   184  
   185  	if a.Flags&AttrPermissions != 0 {
   186  		a.Permissions = FileMode(buf.ConsumeUint32())
   187  	}
   188  
   189  	if a.Flags&AttrACModTime != 0 {
   190  		a.ATime = buf.ConsumeUint32()
   191  		a.MTime = buf.ConsumeUint32()
   192  	}
   193  
   194  	if a.Flags&AttrExtended != 0 {
   195  		count := buf.ConsumeCount()
   196  
   197  		a.ExtendedAttributes = make([]ExtendedAttribute, count)
   198  		for i := range a.ExtendedAttributes {
   199  			a.ExtendedAttributes[i].UnmarshalFrom(buf)
   200  		}
   201  	}
   202  
   203  	return buf.Err
   204  }
   205  
   206  // UnmarshalBinary decodes the binary encoding of Attributes into e.
   207  func (a *Attributes) UnmarshalBinary(data []byte) error {
   208  	return a.UnmarshalFrom(NewBuffer(data))
   209  }
   210  
   211  // ExtendedAttribute defines the extended file attribute type defined in draft-ietf-secsh-filexfer-02
   212  //
   213  // Defined in: https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt#section-5
   214  type ExtendedAttribute struct {
   215  	Type string
   216  	Data string
   217  }
   218  
   219  // Len returns the number of bytes e would marshal into.
   220  func (e *ExtendedAttribute) Len() int {
   221  	return 4 + len(e.Type) + 4 + len(e.Data)
   222  }
   223  
   224  // MarshalInto marshals e onto the end of the given Buffer.
   225  func (e *ExtendedAttribute) MarshalInto(buf *Buffer) {
   226  	buf.AppendString(e.Type)
   227  	buf.AppendString(e.Data)
   228  }
   229  
   230  // MarshalBinary returns e as the binary encoding of e.
   231  func (e *ExtendedAttribute) MarshalBinary() ([]byte, error) {
   232  	buf := NewBuffer(make([]byte, 0, e.Len()))
   233  	e.MarshalInto(buf)
   234  	return buf.Bytes(), nil
   235  }
   236  
   237  // UnmarshalFrom unmarshals an ExtendedAattribute from the given Buffer into e.
   238  func (e *ExtendedAttribute) UnmarshalFrom(buf *Buffer) (err error) {
   239  	*e = ExtendedAttribute{
   240  		Type: buf.ConsumeString(),
   241  		Data: buf.ConsumeString(),
   242  	}
   243  
   244  	return buf.Err
   245  }
   246  
   247  // UnmarshalBinary decodes the binary encoding of ExtendedAttribute into e.
   248  func (e *ExtendedAttribute) UnmarshalBinary(data []byte) error {
   249  	return e.UnmarshalFrom(NewBuffer(data))
   250  }
   251  
   252  // NameEntry implements the SSH_FXP_NAME repeated data type from draft-ietf-secsh-filexfer-02
   253  //
   254  // This type is incompatible with versions 4 or higher.
   255  type NameEntry struct {
   256  	Filename string
   257  	Longname string
   258  	Attrs    Attributes
   259  }
   260  
   261  // Len returns the number of bytes e would marshal into.
   262  func (e *NameEntry) Len() int {
   263  	return 4 + len(e.Filename) + 4 + len(e.Longname) + e.Attrs.Len()
   264  }
   265  
   266  // MarshalInto marshals e onto the end of the given Buffer.
   267  func (e *NameEntry) MarshalInto(buf *Buffer) {
   268  	buf.AppendString(e.Filename)
   269  	buf.AppendString(e.Longname)
   270  
   271  	e.Attrs.MarshalInto(buf)
   272  }
   273  
   274  // MarshalBinary returns e as the binary encoding of e.
   275  func (e *NameEntry) MarshalBinary() ([]byte, error) {
   276  	buf := NewBuffer(make([]byte, 0, e.Len()))
   277  	e.MarshalInto(buf)
   278  	return buf.Bytes(), nil
   279  }
   280  
   281  // UnmarshalFrom unmarshals an NameEntry from the given Buffer into e.
   282  //
   283  // NOTE: The values of fields not covered in the a.Flags are explicitly undefined.
   284  func (e *NameEntry) UnmarshalFrom(buf *Buffer) (err error) {
   285  	*e = NameEntry{
   286  		Filename: buf.ConsumeString(),
   287  		Longname: buf.ConsumeString(),
   288  	}
   289  
   290  	return e.Attrs.UnmarshalFrom(buf)
   291  }
   292  
   293  // UnmarshalBinary decodes the binary encoding of NameEntry into e.
   294  func (e *NameEntry) UnmarshalBinary(data []byte) error {
   295  	return e.UnmarshalFrom(NewBuffer(data))
   296  }