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 }