Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[bugfix] FileZilla parses the directory listing in longname #452

Merged
merged 2 commits into from
Jul 9, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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())
}