github.com/pkg/sftp@v1.13.6/attrs.go (about) 1 package sftp 2 3 // ssh_FXP_ATTRS support 4 // see https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt#section-5 5 6 import ( 7 "os" 8 "time" 9 ) 10 11 const ( 12 sshFileXferAttrSize = 0x00000001 13 sshFileXferAttrUIDGID = 0x00000002 14 sshFileXferAttrPermissions = 0x00000004 15 sshFileXferAttrACmodTime = 0x00000008 16 sshFileXferAttrExtended = 0x80000000 17 18 sshFileXferAttrAll = sshFileXferAttrSize | sshFileXferAttrUIDGID | sshFileXferAttrPermissions | 19 sshFileXferAttrACmodTime | sshFileXferAttrExtended 20 ) 21 22 // fileInfo is an artificial type designed to satisfy os.FileInfo. 23 type fileInfo struct { 24 name string 25 stat *FileStat 26 } 27 28 // Name returns the base name of the file. 29 func (fi *fileInfo) Name() string { return fi.name } 30 31 // Size returns the length in bytes for regular files; system-dependent for others. 32 func (fi *fileInfo) Size() int64 { return int64(fi.stat.Size) } 33 34 // Mode returns file mode bits. 35 func (fi *fileInfo) Mode() os.FileMode { return toFileMode(fi.stat.Mode) } 36 37 // ModTime returns the last modification time of the file. 38 func (fi *fileInfo) ModTime() time.Time { return time.Unix(int64(fi.stat.Mtime), 0) } 39 40 // IsDir returns true if the file is a directory. 41 func (fi *fileInfo) IsDir() bool { return fi.Mode().IsDir() } 42 43 func (fi *fileInfo) Sys() interface{} { return fi.stat } 44 45 // FileStat holds the original unmarshalled values from a call to READDIR or 46 // *STAT. It is exported for the purposes of accessing the raw values via 47 // os.FileInfo.Sys(). It is also used server side to store the unmarshalled 48 // values for SetStat. 49 type FileStat struct { 50 Size uint64 51 Mode uint32 52 Mtime uint32 53 Atime uint32 54 UID uint32 55 GID uint32 56 Extended []StatExtended 57 } 58 59 // StatExtended contains additional, extended information for a FileStat. 60 type StatExtended struct { 61 ExtType string 62 ExtData string 63 } 64 65 func fileInfoFromStat(stat *FileStat, name string) os.FileInfo { 66 return &fileInfo{ 67 name: name, 68 stat: stat, 69 } 70 } 71 72 // FileInfoUidGid extends os.FileInfo and adds callbacks for Uid and Gid retrieval, 73 // as an alternative to *syscall.Stat_t objects on unix systems. 74 type FileInfoUidGid interface { 75 os.FileInfo 76 Uid() uint32 77 Gid() uint32 78 } 79 80 // FileInfoUidGid extends os.FileInfo and adds a callbacks for extended data retrieval. 81 type FileInfoExtendedData interface { 82 os.FileInfo 83 Extended() []StatExtended 84 } 85 86 func fileStatFromInfo(fi os.FileInfo) (uint32, *FileStat) { 87 mtime := fi.ModTime().Unix() 88 atime := mtime 89 var flags uint32 = sshFileXferAttrSize | 90 sshFileXferAttrPermissions | 91 sshFileXferAttrACmodTime 92 93 fileStat := &FileStat{ 94 Size: uint64(fi.Size()), 95 Mode: fromFileMode(fi.Mode()), 96 Mtime: uint32(mtime), 97 Atime: uint32(atime), 98 } 99 100 // os specific file stat decoding 101 fileStatFromInfoOs(fi, &flags, fileStat) 102 103 // The call above will include the sshFileXferAttrUIDGID in case 104 // the os.FileInfo can be casted to *syscall.Stat_t on unix. 105 // If fi implements FileInfoUidGid, retrieve Uid, Gid from it instead. 106 if fiExt, ok := fi.(FileInfoUidGid); ok { 107 flags |= sshFileXferAttrUIDGID 108 fileStat.UID = fiExt.Uid() 109 fileStat.GID = fiExt.Gid() 110 } 111 112 // if fi implements FileInfoExtendedData, retrieve extended data from it 113 if fiExt, ok := fi.(FileInfoExtendedData); ok { 114 fileStat.Extended = fiExt.Extended() 115 if len(fileStat.Extended) > 0 { 116 flags |= sshFileXferAttrExtended 117 } 118 } 119 120 return flags, fileStat 121 }