1package openssh 2 3import ( 4 sshfx "github.com/pkg/sftp/internal/encoding/ssh/filexfer" 5) 6 7const extensionStatVFS = "statvfs@openssh.com" 8 9// RegisterExtensionStatVFS registers the "statvfs@openssh.com" extended packet with the encoding/ssh/filexfer package. 10func RegisterExtensionStatVFS() { 11 sshfx.RegisterExtendedPacketType(extensionStatVFS, func() sshfx.ExtendedData { 12 return new(StatVFSExtendedPacket) 13 }) 14} 15 16// ExtensionStatVFS returns an ExtensionPair suitable to append into an sshfx.InitPacket or sshfx.VersionPacket. 17func ExtensionStatVFS() *sshfx.ExtensionPair { 18 return &sshfx.ExtensionPair{ 19 Name: extensionStatVFS, 20 Data: "2", 21 } 22} 23 24// StatVFSExtendedPacket defines the statvfs@openssh.com extend packet. 25type StatVFSExtendedPacket struct { 26 Path string 27} 28 29// Type returns the SSH_FXP_EXTENDED packet type. 30func (ep *StatVFSExtendedPacket) Type() sshfx.PacketType { 31 return sshfx.PacketTypeExtended 32} 33 34// MarshalPacket returns ep as a two-part binary encoding of the full extended packet. 35func (ep *StatVFSExtendedPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) { 36 p := &sshfx.ExtendedPacket{ 37 ExtendedRequest: extensionStatVFS, 38 39 Data: ep, 40 } 41 return p.MarshalPacket(reqid, b) 42} 43 44// MarshalInto encodes ep into the binary encoding of the statvfs@openssh.com extended packet-specific data. 45func (ep *StatVFSExtendedPacket) MarshalInto(buf *sshfx.Buffer) { 46 buf.AppendString(ep.Path) 47} 48 49// MarshalBinary encodes ep into the binary encoding of the statvfs@openssh.com extended packet-specific data. 50// 51// NOTE: This _only_ encodes the packet-specific data, it does not encode the full extended packet. 52func (ep *StatVFSExtendedPacket) MarshalBinary() ([]byte, error) { 53 size := 4 + len(ep.Path) // string(path) 54 55 buf := sshfx.NewBuffer(make([]byte, 0, size)) 56 57 ep.MarshalInto(buf) 58 59 return buf.Bytes(), nil 60} 61 62// UnmarshalFrom decodes the statvfs@openssh.com extended packet-specific data into ep. 63func (ep *StatVFSExtendedPacket) UnmarshalFrom(buf *sshfx.Buffer) (err error) { 64 if ep.Path, err = buf.ConsumeString(); err != nil { 65 return err 66 } 67 68 return nil 69} 70 71// UnmarshalBinary decodes the statvfs@openssh.com extended packet-specific data into ep. 72func (ep *StatVFSExtendedPacket) UnmarshalBinary(data []byte) (err error) { 73 return ep.UnmarshalFrom(sshfx.NewBuffer(data)) 74} 75 76const extensionFStatVFS = "fstatvfs@openssh.com" 77 78// RegisterExtensionFStatVFS registers the "fstatvfs@openssh.com" extended packet with the encoding/ssh/filexfer package. 79func RegisterExtensionFStatVFS() { 80 sshfx.RegisterExtendedPacketType(extensionFStatVFS, func() sshfx.ExtendedData { 81 return new(FStatVFSExtendedPacket) 82 }) 83} 84 85// ExtensionFStatVFS returns an ExtensionPair suitable to append into an sshfx.InitPacket or sshfx.VersionPacket. 86func ExtensionFStatVFS() *sshfx.ExtensionPair { 87 return &sshfx.ExtensionPair{ 88 Name: extensionFStatVFS, 89 Data: "2", 90 } 91} 92 93// FStatVFSExtendedPacket defines the fstatvfs@openssh.com extend packet. 94type FStatVFSExtendedPacket struct { 95 Path string 96} 97 98// Type returns the SSH_FXP_EXTENDED packet type. 99func (ep *FStatVFSExtendedPacket) Type() sshfx.PacketType { 100 return sshfx.PacketTypeExtended 101} 102 103// MarshalPacket returns ep as a two-part binary encoding of the full extended packet. 104func (ep *FStatVFSExtendedPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) { 105 p := &sshfx.ExtendedPacket{ 106 ExtendedRequest: extensionFStatVFS, 107 108 Data: ep, 109 } 110 return p.MarshalPacket(reqid, b) 111} 112 113// MarshalInto encodes ep into the binary encoding of the statvfs@openssh.com extended packet-specific data. 114func (ep *FStatVFSExtendedPacket) MarshalInto(buf *sshfx.Buffer) { 115 buf.AppendString(ep.Path) 116} 117 118// MarshalBinary encodes ep into the binary encoding of the statvfs@openssh.com extended packet-specific data. 119// 120// NOTE: This _only_ encodes the packet-specific data, it does not encode the full extended packet. 121func (ep *FStatVFSExtendedPacket) MarshalBinary() ([]byte, error) { 122 size := 4 + len(ep.Path) // string(path) 123 124 buf := sshfx.NewBuffer(make([]byte, 0, size)) 125 126 ep.MarshalInto(buf) 127 128 return buf.Bytes(), nil 129} 130 131// UnmarshalFrom decodes the statvfs@openssh.com extended packet-specific data into ep. 132func (ep *FStatVFSExtendedPacket) UnmarshalFrom(buf *sshfx.Buffer) (err error) { 133 if ep.Path, err = buf.ConsumeString(); err != nil { 134 return err 135 } 136 137 return nil 138} 139 140// UnmarshalBinary decodes the statvfs@openssh.com extended packet-specific data into ep. 141func (ep *FStatVFSExtendedPacket) UnmarshalBinary(data []byte) (err error) { 142 return ep.UnmarshalFrom(sshfx.NewBuffer(data)) 143} 144 145// The values for the MountFlags field. 146// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL 147const ( 148 MountFlagsReadOnly = 0x1 // SSH_FXE_STATVFS_ST_RDONLY 149 MountFlagsNoSUID = 0x2 // SSH_FXE_STATVFS_ST_NOSUID 150) 151 152// StatVFSExtendedReplyPacket defines the extended reply packet for statvfs@openssh.com and fstatvfs@openssh.com requests. 153type StatVFSExtendedReplyPacket struct { 154 BlockSize uint64 /* f_bsize: file system block size */ 155 FragmentSize uint64 /* f_frsize: fundamental fs block size / fagment size */ 156 Blocks uint64 /* f_blocks: number of blocks (unit f_frsize) */ 157 BlocksFree uint64 /* f_bfree: free blocks in filesystem */ 158 BlocksAvail uint64 /* f_bavail: free blocks for non-root */ 159 Files uint64 /* f_files: total file inodes */ 160 FilesFree uint64 /* f_ffree: free file inodes */ 161 FilesAvail uint64 /* f_favail: free file inodes for to non-root */ 162 FilesystemID uint64 /* f_fsid: file system id */ 163 MountFlags uint64 /* f_flag: bit mask of mount flag values */ 164 MaxNameLength uint64 /* f_namemax: maximum filename length */ 165} 166 167// Type returns the SSH_FXP_EXTENDED_REPLY packet type. 168func (ep *StatVFSExtendedReplyPacket) Type() sshfx.PacketType { 169 return sshfx.PacketTypeExtendedReply 170} 171 172// MarshalPacket returns ep as a two-part binary encoding of the full extended reply packet. 173func (ep *StatVFSExtendedReplyPacket) MarshalPacket(reqid uint32, b []byte) (header, payload []byte, err error) { 174 p := &sshfx.ExtendedReplyPacket{ 175 Data: ep, 176 } 177 return p.MarshalPacket(reqid, b) 178} 179 180// UnmarshalPacketBody returns ep as a two-part binary encoding of the full extended reply packet. 181func (ep *StatVFSExtendedReplyPacket) UnmarshalPacketBody(buf *sshfx.Buffer) (err error) { 182 p := &sshfx.ExtendedReplyPacket{ 183 Data: ep, 184 } 185 return p.UnmarshalPacketBody(buf) 186} 187 188// MarshalInto encodes ep into the binary encoding of the (f)statvfs@openssh.com extended reply packet-specific data. 189func (ep *StatVFSExtendedReplyPacket) MarshalInto(buf *sshfx.Buffer) { 190 buf.AppendUint64(ep.BlockSize) 191 buf.AppendUint64(ep.FragmentSize) 192 buf.AppendUint64(ep.Blocks) 193 buf.AppendUint64(ep.BlocksFree) 194 buf.AppendUint64(ep.BlocksAvail) 195 buf.AppendUint64(ep.Files) 196 buf.AppendUint64(ep.FilesFree) 197 buf.AppendUint64(ep.FilesAvail) 198 buf.AppendUint64(ep.FilesystemID) 199 buf.AppendUint64(ep.MountFlags) 200 buf.AppendUint64(ep.MaxNameLength) 201} 202 203// MarshalBinary encodes ep into the binary encoding of the (f)statvfs@openssh.com extended reply packet-specific data. 204// 205// NOTE: This _only_ encodes the packet-specific data, it does not encode the full extended reply packet. 206func (ep *StatVFSExtendedReplyPacket) MarshalBinary() ([]byte, error) { 207 size := 11 * 8 // 11 × uint64(various) 208 209 b := sshfx.NewBuffer(make([]byte, 0, size)) 210 ep.MarshalInto(b) 211 return b.Bytes(), nil 212} 213 214// UnmarshalFrom decodes the fstatvfs@openssh.com extended reply packet-specific data into ep. 215func (ep *StatVFSExtendedReplyPacket) UnmarshalFrom(buf *sshfx.Buffer) (err error) { 216 if ep.BlockSize, err = buf.ConsumeUint64(); err != nil { 217 return err 218 } 219 if ep.FragmentSize, err = buf.ConsumeUint64(); err != nil { 220 return err 221 } 222 if ep.Blocks, err = buf.ConsumeUint64(); err != nil { 223 return err 224 } 225 if ep.BlocksFree, err = buf.ConsumeUint64(); err != nil { 226 return err 227 } 228 if ep.BlocksAvail, err = buf.ConsumeUint64(); err != nil { 229 return err 230 } 231 if ep.Files, err = buf.ConsumeUint64(); err != nil { 232 return err 233 } 234 if ep.FilesFree, err = buf.ConsumeUint64(); err != nil { 235 return err 236 } 237 if ep.FilesAvail, err = buf.ConsumeUint64(); err != nil { 238 return err 239 } 240 if ep.FilesystemID, err = buf.ConsumeUint64(); err != nil { 241 return err 242 } 243 if ep.MountFlags, err = buf.ConsumeUint64(); err != nil { 244 return err 245 } 246 if ep.MaxNameLength, err = buf.ConsumeUint64(); err != nil { 247 return err 248 } 249 250 return nil 251} 252 253// UnmarshalBinary decodes the fstatvfs@openssh.com extended reply packet-specific data into ep. 254func (ep *StatVFSExtendedReplyPacket) UnmarshalBinary(data []byte) (err error) { 255 return ep.UnmarshalFrom(sshfx.NewBuffer(data)) 256} 257