Skip to content

Commit

Permalink
Merge pull request #452 from pkg/patch/fix-filezilla
Browse files Browse the repository at this point in the history
[bugfix] FileZilla parses the directory listing in longname
  • Loading branch information
drakkan authored Jul 9, 2021
2 parents eaa697c + 66e738e commit 7bfa5f2
Showing 1 changed file with 19 additions and 18 deletions.
37 changes: 19 additions & 18 deletions server_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,35 @@ package sftp
import (
"fmt"
"os"
"path"
"syscall"
"time"
)

func runLsStatt(dirent os.FileInfo, statt *syscall.Stat_t) string {
// 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 {
// 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
gid := statt.Gid

var numLinks uint64 = 1
if dirent.IsDir() {
numLinks = 0
}

var uid, gid uint32

if statt, ok := dirent.Sys().(*syscall.Stat_t); ok {
// The type of Nlink varies form int16 (aix-ppc64) to uint64 (linux-amd64),
// we cast up to uint64 to make all OS/ARCH combos source compatible.
numLinks = uint64(statt.Nlink)
uid = statt.Uid
gid = statt.Gid
}

username := fmt.Sprintf("%d", uid)
groupname := fmt.Sprintf("%d", gid)
// TODO FIXME: uid -> username, gid -> groupname lookup for ls -l format output
Expand All @@ -39,16 +53,3 @@ func runLsStatt(dirent os.FileInfo, statt *syscall.Stat_t) string {

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())
}

0 comments on commit 7bfa5f2

Please sign in to comment.