2018-07-26 19:04:57 +08:00
|
|
|
// +build darwin dragonfly freebsd !android,linux netbsd openbsd solaris aix
|
2015-09-07 12:37:33 +08:00
|
|
|
// +build cgo
|
|
|
|
|
|
|
|
|
|
package sftp
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"os"
|
2021-04-24 20:28:08 +08:00
|
|
|
"os/user"
|
|
|
|
|
"strconv"
|
2015-09-07 12:37:33 +08:00
|
|
|
"syscall"
|
|
|
|
|
"time"
|
2021-04-24 20:28:08 +08:00
|
|
|
|
|
|
|
|
sshfx "github.com/pkg/sftp/internal/encoding/ssh/filexfer"
|
2015-09-07 12:37:33 +08:00
|
|
|
)
|
|
|
|
|
|
2021-04-24 20:28:08 +08:00
|
|
|
func formatID(id uint32) string {
|
|
|
|
|
return strconv.FormatUint(uint64(id), 10)
|
|
|
|
|
}
|
2015-09-07 12:37:33 +08:00
|
|
|
|
2021-04-24 20:28:08 +08:00
|
|
|
func getUsername(uid uint32) string {
|
|
|
|
|
id := formatID(uid)
|
2018-05-25 02:23:47 +08:00
|
|
|
|
2021-04-24 20:28:08 +08:00
|
|
|
u, err := user.LookupId(id)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return id
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return u.Username
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getGroupName(gid uint32) string {
|
|
|
|
|
id := formatID(gid)
|
|
|
|
|
|
|
|
|
|
g, err := user.LookupGroupId(id)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return id
|
2015-09-07 12:37:33 +08:00
|
|
|
}
|
|
|
|
|
|
2021-04-24 20:28:08 +08:00
|
|
|
return g.Name
|
2015-09-07 12:37:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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 {
|
2021-04-24 20:28:08 +08:00
|
|
|
// 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
|
|
|
|
|
|
|
|
|
|
symPerms := fromFileMode(dirent.Mode()).String()
|
|
|
|
|
|
|
|
|
|
var numLinks uint64 = 1
|
|
|
|
|
uid, gid := "0", "0"
|
|
|
|
|
|
|
|
|
|
switch sys := dirent.Sys().(type) {
|
|
|
|
|
case *syscall.Stat_t:
|
|
|
|
|
uid = getUsername(sys.Uid)
|
|
|
|
|
gid = getGroupName(sys.Gid)
|
|
|
|
|
case *sshfx.Attributes:
|
|
|
|
|
uid = formatID(sys.UID)
|
|
|
|
|
gid = formatID(sys.GID)
|
|
|
|
|
case *FileStat:
|
|
|
|
|
uid = formatID(sys.UID)
|
|
|
|
|
gid = formatID(sys.GID)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mtime := dirent.ModTime()
|
|
|
|
|
date := mtime.Format("Jan 2")
|
|
|
|
|
|
|
|
|
|
var yearOrTime string
|
|
|
|
|
if mtime.Before(time.Now().AddDate(0, -6, 0)) {
|
|
|
|
|
yearOrTime = mtime.Format("2006")
|
2015-09-07 12:37:33 +08:00
|
|
|
} else {
|
2021-04-24 20:28:08 +08:00
|
|
|
yearOrTime = mtime.Format("15:04")
|
2015-09-07 12:37:33 +08:00
|
|
|
}
|
|
|
|
|
|
2021-04-24 20:28:08 +08:00
|
|
|
return fmt.Sprintf("%s %4d %-8s %-8s %8d %s %5s %s", symPerms, numLinks, uid, gid, dirent.Size(), date, yearOrTime, dirent.Name())
|
2015-09-07 12:37:33 +08:00
|
|
|
}
|