github.com/pkg/sftp@v1.13.6/ls_formatting.go (about) 1 package sftp 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "os/user" 8 "strconv" 9 "time" 10 11 sshfx "github.com/pkg/sftp/internal/encoding/ssh/filexfer" 12 ) 13 14 func lsFormatID(id uint32) string { 15 return strconv.FormatUint(uint64(id), 10) 16 } 17 18 type osIDLookup struct{} 19 20 func (osIDLookup) Filelist(*Request) (ListerAt, error) { 21 return nil, errors.New("unimplemented stub") 22 } 23 24 func (osIDLookup) LookupUserName(uid string) string { 25 u, err := user.LookupId(uid) 26 if err != nil { 27 return uid 28 } 29 30 return u.Username 31 } 32 33 func (osIDLookup) LookupGroupName(gid string) string { 34 g, err := user.LookupGroupId(gid) 35 if err != nil { 36 return gid 37 } 38 39 return g.Name 40 } 41 42 // runLs formats the FileInfo as per `ls -l` style, which is in the 'longname' field of a SSH_FXP_NAME entry. 43 // This is a fairly simple implementation, just enough to look close to openssh in simple cases. 44 func runLs(idLookup NameLookupFileLister, dirent os.FileInfo) string { 45 // example from openssh sftp server: 46 // crw-rw-rw- 1 root wheel 0 Jul 31 20:52 ttyvd 47 // format: 48 // {directory / char device / etc}{rwxrwxrwx} {number of links} owner group size month day [time (this year) | year (otherwise)] name 49 50 symPerms := sshfx.FileMode(fromFileMode(dirent.Mode())).String() 51 52 var numLinks uint64 = 1 53 uid, gid := "0", "0" 54 55 switch sys := dirent.Sys().(type) { 56 case *sshfx.Attributes: 57 uid = lsFormatID(sys.UID) 58 gid = lsFormatID(sys.GID) 59 case *FileStat: 60 uid = lsFormatID(sys.UID) 61 gid = lsFormatID(sys.GID) 62 default: 63 if fiExt, ok := dirent.(FileInfoUidGid); ok { 64 uid = lsFormatID(fiExt.Uid()) 65 gid = lsFormatID(fiExt.Gid()) 66 67 break 68 } 69 70 numLinks, uid, gid = lsLinksUIDGID(dirent) 71 } 72 73 if idLookup != nil { 74 uid, gid = idLookup.LookupUserName(uid), idLookup.LookupGroupName(gid) 75 } 76 77 mtime := dirent.ModTime() 78 date := mtime.Format("Jan 2") 79 80 var yearOrTime string 81 if mtime.Before(time.Now().AddDate(0, -6, 0)) { 82 yearOrTime = mtime.Format("2006") 83 } else { 84 yearOrTime = mtime.Format("15:04") 85 } 86 87 return fmt.Sprintf("%s %4d %-8s %-8s %8d %s %5s %s", symPerms, numLinks, uid, gid, dirent.Size(), date, yearOrTime, dirent.Name()) 88 }