blob: 8f9dd8a35f829337caa75514955895520b9ad73f [file] [log] [blame]
// +build darwin dragonfly freebsd !android,linux netbsd openbsd solaris
// +build cgo
package sftp
import (
"fmt"
"os"
"os/user"
"path"
"strconv"
"syscall"
"time"
)
func runLsStatt(dirent os.FileInfo, statt *syscall.Stat_t) string {
// example from openssh sftp server:
// crw-rw-rw- 1 root wheel 0 Jul 31 20:52 ttyvd
// format:
// {directory / char device / etc}{rwxrwxrwx} {number of links} owner group size month day [time (this year) | year (otherwise)] name
typeword := runLsTypeWord(dirent)
numLinks := statt.Nlink
uid := statt.Uid
usr, err := user.LookupId(strconv.Itoa(int(uid)))
var username string
if err == nil {
username = usr.Username
} else {
username = fmt.Sprintf("%d", uid)
}
gid := statt.Gid
grp, err := user.LookupGroupId(strconv.Itoa(int(gid)))
var groupname string
if err == nil {
groupname = grp.Name
} else {
groupname = fmt.Sprintf("%d", gid)
}
mtime := dirent.ModTime()
monthStr := mtime.Month().String()[0:3]
day := mtime.Day()
year := mtime.Year()
now := time.Now()
isOld := mtime.Before(now.Add(-time.Hour * 24 * 365 / 2))
yearOrTime := fmt.Sprintf("%02d:%02d", mtime.Hour(), mtime.Minute())
if isOld {
yearOrTime = fmt.Sprintf("%d", year)
}
return fmt.Sprintf("%s %4d %-8s %-8s %8d %s %2d %5s %s", typeword, numLinks, username, groupname, dirent.Size(), monthStr, day, yearOrTime, dirent.Name())
}
// ls -l style output for a file, which is in the 'long output' section of a readdir response packet
// this is a very simple (lazy) implementation, just enough to look almost like openssh in a few basic cases
func runLs(dirname string, dirent os.FileInfo) string {
dsys := dirent.Sys()
if dsys == nil {
} else if statt, ok := dsys.(*syscall.Stat_t); !ok {
} else {
return runLsStatt(dirent, statt)
}
return path.Join(dirname, dirent.Name())
}