From 9b553ccfda368b7daa512e82fef766c8d9f5efcf Mon Sep 17 00:00:00 2001 From: dustin-ward Date: Thu, 4 Apr 2024 16:19:37 -0400 Subject: [PATCH 1/4] Add support for zos/s390x --- client.go | 9 ++- ls_formatting_test.go | 7 +++ request-server_test.go | 9 ++- server_test.go | 9 ++- stat_posix.go | 3 +- stat_zos.go | 137 +++++++++++++++++++++++++++++++++++++++++ syscall_good.go | 3 +- 7 files changed, 166 insertions(+), 11 deletions(-) create mode 100644 stat_zos.go diff --git a/client.go b/client.go index 5f457221..9423b4dd 100644 --- a/client.go +++ b/client.go @@ -2113,13 +2113,12 @@ func normaliseError(err error) error { // Unsupported flags are ignored. func toPflags(f int) uint32 { var out uint32 - switch f & os.O_WRONLY { - case os.O_WRONLY: - out |= sshFxfWrite + switch f & (os.O_RDONLY | os.O_WRONLY | os.O_RDWR) { case os.O_RDONLY: out |= sshFxfRead - } - if f&os.O_RDWR == os.O_RDWR { + case os.O_WRONLY: + out |= sshFxfWrite + case os.O_RDWR: out |= sshFxfRead | sshFxfWrite } if f&os.O_APPEND == os.O_APPEND { diff --git a/ls_formatting_test.go b/ls_formatting_test.go index 8d0fefbc..d6e5e036 100644 --- a/ls_formatting_test.go +++ b/ls_formatting_test.go @@ -3,6 +3,7 @@ package sftp import ( "os" "regexp" + "runtime" "strings" "testing" "time" @@ -101,6 +102,12 @@ func runLsTestHelper(t *testing.T, result, expectedType, path string) { dateTime := strings.Join(fields[5:8], " ") filename := fields[8] + if runtime.GOOS == "zos" { + // User and Group are always only uppercase characters on z/OS + user = strings.ToLower(user) + group = strings.ToLower(group) + } + // permissions (len 10, "drwxr-xr-x") const ( rwxs = "[-r][-w][-xsS]" diff --git a/request-server_test.go b/request-server_test.go index 6825bf43..668d803a 100644 --- a/request-server_test.go +++ b/request-server_test.go @@ -780,8 +780,13 @@ func TestRequestReaddir(t *testing.T) { } } _, err := p.cli.ReadDir("/foo_01") - assert.Equal(t, &StatusError{Code: sshFxFailure, - msg: " /foo_01: not a directory"}, err) + if runtime.GOOS == "zos" { + assert.Equal(t, &StatusError{Code: sshFxFailure, + msg: " /foo_01: EDC5135I Not a directory."}, err) + } else { + assert.Equal(t, &StatusError{Code: sshFxFailure, + msg: " /foo_01: not a directory"}, err) + } _, err = p.cli.ReadDir("/does_not_exist") assert.Equal(t, os.ErrNotExist, err) di, err := p.cli.ReadDir("/") diff --git a/server_test.go b/server_test.go index 4cec3123..5bac81eb 100644 --- a/server_test.go +++ b/server_test.go @@ -99,9 +99,14 @@ func TestInvalidExtendedPacket(t *testing.T) { // test that server handles concurrent requests correctly func TestConcurrentRequests(t *testing.T) { skipIfWindows(t) - filename := "/etc/passwd" - if runtime.GOOS == "plan9" { + var filename string + switch runtime.GOOS { + case "plan9": filename = "/lib/ndb/local" + case "zos": + filename = "/etc/.shrc" + default: + filename = "/etc/passwd" } client, server := clientServerPair(t) defer client.Close() diff --git a/stat_posix.go b/stat_posix.go index 5b870e23..a15b9c3b 100644 --- a/stat_posix.go +++ b/stat_posix.go @@ -1,5 +1,6 @@ -//go:build !plan9 +//go:build !plan9 && !zos // +build !plan9 +// +build !zos package sftp diff --git a/stat_zos.go b/stat_zos.go new file mode 100644 index 00000000..3643e5ea --- /dev/null +++ b/stat_zos.go @@ -0,0 +1,137 @@ +//go:build zos +// +build zos + +package sftp + +import ( + "os" + "syscall" +) + +const EBADF = syscall.EBADF + +// z/OS syscall constants are not compatible with the stat structure returned +// from the server. Define the OpenBSD ones here instead. +const ( + S_IFMT = 0xF000 + S_IFIFO = 0x1000 + S_IFCHR = 0x2000 + S_IFDIR = 0x4000 + S_IFBLK = 0x6000 + S_IFREG = 0x8000 + S_IFLNK = 0xA000 + S_IFSOCK = 0xC000 +) + +func wrapPathError(filepath string, err error) error { + if errno, ok := err.(syscall.Errno); ok { + return &os.PathError{Path: filepath, Err: errno} + } + return err +} + +// translateErrno translates a syscall error number to a SFTP error code. +func translateErrno(errno syscall.Errno) uint32 { + switch errno { + case 0: + return sshFxOk + case syscall.ENOENT: + return sshFxNoSuchFile + case syscall.EACCES, syscall.EPERM: + return sshFxPermissionDenied + } + + return sshFxFailure +} + +func translateSyscallError(err error) (uint32, bool) { + switch e := err.(type) { + case syscall.Errno: + return translateErrno(e), true + case *os.PathError: + debug("statusFromError,pathError: error is %T %#v", e.Err, e.Err) + if errno, ok := e.Err.(syscall.Errno); ok { + return translateErrno(errno), true + } + } + return 0, false +} + +// isRegular returns true if the mode describes a regular file. +func isRegular(mode uint32) bool { + return mode&S_IFMT == S_IFREG +} + +// toFileMode converts sftp filemode bits to the os.FileMode specification +func toFileMode(mode uint32) os.FileMode { + var fm = os.FileMode(mode & 0777) + + switch mode & S_IFMT { + case S_IFBLK: + fm |= os.ModeDevice + case S_IFCHR: + fm |= os.ModeDevice | os.ModeCharDevice + case S_IFDIR: + fm |= os.ModeDir + case S_IFIFO: + fm |= os.ModeNamedPipe + case S_IFLNK: + fm |= os.ModeSymlink + case S_IFREG: + // nothing to do + case S_IFSOCK: + fm |= os.ModeSocket + } + + if mode&syscall.S_ISUID != 0 { + fm |= os.ModeSetuid + } + if mode&syscall.S_ISGID != 0 { + fm |= os.ModeSetgid + } + if mode&syscall.S_ISVTX != 0 { + fm |= os.ModeSticky + } + + return fm +} + +// fromFileMode converts from the os.FileMode specification to sftp filemode bits +func fromFileMode(mode os.FileMode) uint32 { + ret := uint32(mode & os.ModePerm) + + switch mode & os.ModeType { + case os.ModeDevice | os.ModeCharDevice: + ret |= S_IFCHR + case os.ModeDevice: + ret |= S_IFBLK + case os.ModeDir: + ret |= S_IFDIR + case os.ModeNamedPipe: + ret |= S_IFIFO + case os.ModeSymlink: + ret |= S_IFLNK + case 0: + ret |= S_IFREG + case os.ModeSocket: + ret |= S_IFSOCK + } + + if mode&os.ModeSetuid != 0 { + ret |= syscall.S_ISUID + } + if mode&os.ModeSetgid != 0 { + ret |= syscall.S_ISGID + } + if mode&os.ModeSticky != 0 { + ret |= syscall.S_ISVTX + } + + return ret +} + +const ( + s_ISUID = syscall.S_ISUID + s_ISGID = syscall.S_ISGID + s_ISVTX = syscall.S_ISVTX +) diff --git a/syscall_good.go b/syscall_good.go index 50052189..235d6039 100644 --- a/syscall_good.go +++ b/syscall_good.go @@ -1,6 +1,7 @@ -//go:build !plan9 && !windows && (!js || !wasm) +//go:build !plan9 && !windows && !zos && (!js || !wasm) // +build !plan9 // +build !windows +// +build !zos // +build !js !wasm package sftp From 96b29c55dd0f3428a198bae04f9c99935166414a Mon Sep 17 00:00:00 2001 From: dustin-ward Date: Fri, 5 Apr 2024 12:37:27 -0400 Subject: [PATCH 2/4] address review set 1 --- client.go | 3 +- client_integration_test.go | 3 +- stat_posix.go | 59 ++++++++-------- stat_zos.go | 137 ------------------------------------- syscall_fixed.go | 7 +- syscall_good.go | 11 --- 6 files changed, 37 insertions(+), 183 deletions(-) delete mode 100644 stat_zos.go delete mode 100644 syscall_good.go diff --git a/client.go b/client.go index 9423b4dd..3894d39f 100644 --- a/client.go +++ b/client.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "io" + iofs "io/fs" "math" "os" "path" @@ -2142,7 +2143,7 @@ func toPflags(f int) uint32 { // setuid, setgid and sticky in m, because we've historically supported those // bits, and we mask off any non-permission bits. func toChmodPerm(m os.FileMode) (perm uint32) { - const mask = os.ModePerm | s_ISUID | s_ISGID | s_ISVTX + const mask = os.ModePerm | iofs.FileMode(s_ISUID|s_ISGID|s_ISVTX) perm = uint32(m & mask) if m&os.ModeSetuid != 0 { diff --git a/client_integration_test.go b/client_integration_test.go index 35ccbea5..c9039a52 100644 --- a/client_integration_test.go +++ b/client_integration_test.go @@ -9,6 +9,7 @@ import ( "errors" "fmt" "io" + iofs "io/fs" "io/ioutil" "math/rand" "net" @@ -974,7 +975,7 @@ func TestClientSetuid(t *testing.T) { f.Close() const allPerm = os.ModePerm | os.ModeSetuid | os.ModeSetgid | os.ModeSticky | - s_ISUID | s_ISGID | s_ISVTX + iofs.FileMode(s_ISUID|s_ISGID|s_ISVTX) for _, c := range []struct { goPerm os.FileMode diff --git a/stat_posix.go b/stat_posix.go index a15b9c3b..891b2400 100644 --- a/stat_posix.go +++ b/stat_posix.go @@ -1,12 +1,13 @@ -//go:build !plan9 && !zos +//go:build !plan9 // +build !plan9 -// +build !zos package sftp import ( "os" "syscall" + + sshfx "github.com/pkg/sftp/internal/encoding/ssh/filexfer" ) const EBADF = syscall.EBADF @@ -47,37 +48,37 @@ func translateSyscallError(err error) (uint32, bool) { // isRegular returns true if the mode describes a regular file. func isRegular(mode uint32) bool { - return mode&S_IFMT == syscall.S_IFREG + return sshfx.FileMode(mode)&sshfx.ModeType == sshfx.ModeRegular } // toFileMode converts sftp filemode bits to the os.FileMode specification func toFileMode(mode uint32) os.FileMode { var fm = os.FileMode(mode & 0777) - switch mode & S_IFMT { - case syscall.S_IFBLK: + switch sshfx.FileMode(mode) & sshfx.ModeType { + case sshfx.ModeDevice: fm |= os.ModeDevice - case syscall.S_IFCHR: + case sshfx.ModeCharDevice: fm |= os.ModeDevice | os.ModeCharDevice - case syscall.S_IFDIR: + case sshfx.ModeDir: fm |= os.ModeDir - case syscall.S_IFIFO: + case sshfx.ModeNamedPipe: fm |= os.ModeNamedPipe - case syscall.S_IFLNK: + case sshfx.ModeSymlink: fm |= os.ModeSymlink - case syscall.S_IFREG: + case sshfx.ModeRegular: // nothing to do - case syscall.S_IFSOCK: + case sshfx.ModeSocket: fm |= os.ModeSocket } - if mode&syscall.S_ISUID != 0 { + if sshfx.FileMode(mode)&sshfx.ModeSetUID != 0 { fm |= os.ModeSetuid } - if mode&syscall.S_ISGID != 0 { + if sshfx.FileMode(mode)&sshfx.ModeSetGID != 0 { fm |= os.ModeSetgid } - if mode&syscall.S_ISVTX != 0 { + if sshfx.FileMode(mode)&sshfx.ModeSticky != 0 { fm |= os.ModeSticky } @@ -86,40 +87,40 @@ func toFileMode(mode uint32) os.FileMode { // fromFileMode converts from the os.FileMode specification to sftp filemode bits func fromFileMode(mode os.FileMode) uint32 { - ret := uint32(mode & os.ModePerm) + ret := sshfx.FileMode(mode & os.ModePerm) switch mode & os.ModeType { case os.ModeDevice | os.ModeCharDevice: - ret |= syscall.S_IFCHR + ret |= sshfx.ModeCharDevice case os.ModeDevice: - ret |= syscall.S_IFBLK + ret |= sshfx.ModeDevice case os.ModeDir: - ret |= syscall.S_IFDIR + ret |= sshfx.ModeDir case os.ModeNamedPipe: - ret |= syscall.S_IFIFO + ret |= sshfx.ModeNamedPipe case os.ModeSymlink: - ret |= syscall.S_IFLNK + ret |= sshfx.ModeSymlink case 0: - ret |= syscall.S_IFREG + ret |= sshfx.ModeRegular case os.ModeSocket: - ret |= syscall.S_IFSOCK + ret |= sshfx.ModeSocket } if mode&os.ModeSetuid != 0 { - ret |= syscall.S_ISUID + ret |= sshfx.ModeSetUID } if mode&os.ModeSetgid != 0 { - ret |= syscall.S_ISGID + ret |= sshfx.ModeSetGID } if mode&os.ModeSticky != 0 { - ret |= syscall.S_ISVTX + ret |= sshfx.ModeSticky } - return ret + return uint32(ret) } const ( - s_ISUID = syscall.S_ISUID - s_ISGID = syscall.S_ISGID - s_ISVTX = syscall.S_ISVTX + s_ISUID = uint32(sshfx.ModeSetUID) + s_ISGID = uint32(sshfx.ModeSetGID) + s_ISVTX = uint32(sshfx.ModeSticky) ) diff --git a/stat_zos.go b/stat_zos.go deleted file mode 100644 index 3643e5ea..00000000 --- a/stat_zos.go +++ /dev/null @@ -1,137 +0,0 @@ -//go:build zos -// +build zos - -package sftp - -import ( - "os" - "syscall" -) - -const EBADF = syscall.EBADF - -// z/OS syscall constants are not compatible with the stat structure returned -// from the server. Define the OpenBSD ones here instead. -const ( - S_IFMT = 0xF000 - S_IFIFO = 0x1000 - S_IFCHR = 0x2000 - S_IFDIR = 0x4000 - S_IFBLK = 0x6000 - S_IFREG = 0x8000 - S_IFLNK = 0xA000 - S_IFSOCK = 0xC000 -) - -func wrapPathError(filepath string, err error) error { - if errno, ok := err.(syscall.Errno); ok { - return &os.PathError{Path: filepath, Err: errno} - } - return err -} - -// translateErrno translates a syscall error number to a SFTP error code. -func translateErrno(errno syscall.Errno) uint32 { - switch errno { - case 0: - return sshFxOk - case syscall.ENOENT: - return sshFxNoSuchFile - case syscall.EACCES, syscall.EPERM: - return sshFxPermissionDenied - } - - return sshFxFailure -} - -func translateSyscallError(err error) (uint32, bool) { - switch e := err.(type) { - case syscall.Errno: - return translateErrno(e), true - case *os.PathError: - debug("statusFromError,pathError: error is %T %#v", e.Err, e.Err) - if errno, ok := e.Err.(syscall.Errno); ok { - return translateErrno(errno), true - } - } - return 0, false -} - -// isRegular returns true if the mode describes a regular file. -func isRegular(mode uint32) bool { - return mode&S_IFMT == S_IFREG -} - -// toFileMode converts sftp filemode bits to the os.FileMode specification -func toFileMode(mode uint32) os.FileMode { - var fm = os.FileMode(mode & 0777) - - switch mode & S_IFMT { - case S_IFBLK: - fm |= os.ModeDevice - case S_IFCHR: - fm |= os.ModeDevice | os.ModeCharDevice - case S_IFDIR: - fm |= os.ModeDir - case S_IFIFO: - fm |= os.ModeNamedPipe - case S_IFLNK: - fm |= os.ModeSymlink - case S_IFREG: - // nothing to do - case S_IFSOCK: - fm |= os.ModeSocket - } - - if mode&syscall.S_ISUID != 0 { - fm |= os.ModeSetuid - } - if mode&syscall.S_ISGID != 0 { - fm |= os.ModeSetgid - } - if mode&syscall.S_ISVTX != 0 { - fm |= os.ModeSticky - } - - return fm -} - -// fromFileMode converts from the os.FileMode specification to sftp filemode bits -func fromFileMode(mode os.FileMode) uint32 { - ret := uint32(mode & os.ModePerm) - - switch mode & os.ModeType { - case os.ModeDevice | os.ModeCharDevice: - ret |= S_IFCHR - case os.ModeDevice: - ret |= S_IFBLK - case os.ModeDir: - ret |= S_IFDIR - case os.ModeNamedPipe: - ret |= S_IFIFO - case os.ModeSymlink: - ret |= S_IFLNK - case 0: - ret |= S_IFREG - case os.ModeSocket: - ret |= S_IFSOCK - } - - if mode&os.ModeSetuid != 0 { - ret |= syscall.S_ISUID - } - if mode&os.ModeSetgid != 0 { - ret |= syscall.S_ISGID - } - if mode&os.ModeSticky != 0 { - ret |= syscall.S_ISVTX - } - - return ret -} - -const ( - s_ISUID = syscall.S_ISUID - s_ISGID = syscall.S_ISGID - s_ISVTX = syscall.S_ISVTX -) diff --git a/syscall_fixed.go b/syscall_fixed.go index e8443083..0f80dd5c 100644 --- a/syscall_fixed.go +++ b/syscall_fixed.go @@ -1,10 +1,9 @@ -//go:build plan9 || windows || (js && wasm) -// +build plan9 windows js,wasm - // Go defines S_IFMT on windows, plan9 and js/wasm as 0x1f000 instead of // 0xf000. None of the the other S_IFxyz values include the "1" (in 0x1f000) // which prevents them from matching the bitmask. package sftp -const S_IFMT = 0xf000 +import sshfx "github.com/pkg/sftp/internal/encoding/ssh/filexfer" + +const S_IFMT = uint32(sshfx.ModeType) diff --git a/syscall_good.go b/syscall_good.go deleted file mode 100644 index 235d6039..00000000 --- a/syscall_good.go +++ /dev/null @@ -1,11 +0,0 @@ -//go:build !plan9 && !windows && !zos && (!js || !wasm) -// +build !plan9 -// +build !windows -// +build !zos -// +build !js !wasm - -package sftp - -import "syscall" - -const S_IFMT = syscall.S_IFMT From 8411183d33fd098275176b677108d5012ba232bb Mon Sep 17 00:00:00 2001 From: dustin-ward Date: Fri, 5 Apr 2024 16:07:40 -0400 Subject: [PATCH 3/4] address review set 2 --- client.go | 3 +- client_integration_test.go | 3 +- errno_plan9.go | 42 +++++++++++++++ errno_posix.go | 45 ++++++++++++++++ stat_posix.go => stat.go | 47 +++-------------- stat_plan9.go | 103 ------------------------------------- syscall_fixed.go | 9 ---- 7 files changed, 96 insertions(+), 156 deletions(-) create mode 100644 errno_plan9.go create mode 100644 errno_posix.go rename stat_posix.go => stat.go (68%) delete mode 100644 stat_plan9.go delete mode 100644 syscall_fixed.go diff --git a/client.go b/client.go index 3894d39f..3a9a8bf1 100644 --- a/client.go +++ b/client.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "io" - iofs "io/fs" "math" "os" "path" @@ -2143,7 +2142,7 @@ func toPflags(f int) uint32 { // setuid, setgid and sticky in m, because we've historically supported those // bits, and we mask off any non-permission bits. func toChmodPerm(m os.FileMode) (perm uint32) { - const mask = os.ModePerm | iofs.FileMode(s_ISUID|s_ISGID|s_ISVTX) + const mask = os.ModePerm | os.FileMode(s_ISUID|s_ISGID|s_ISVTX) perm = uint32(m & mask) if m&os.ModeSetuid != 0 { diff --git a/client_integration_test.go b/client_integration_test.go index c9039a52..546ba211 100644 --- a/client_integration_test.go +++ b/client_integration_test.go @@ -9,7 +9,6 @@ import ( "errors" "fmt" "io" - iofs "io/fs" "io/ioutil" "math/rand" "net" @@ -975,7 +974,7 @@ func TestClientSetuid(t *testing.T) { f.Close() const allPerm = os.ModePerm | os.ModeSetuid | os.ModeSetgid | os.ModeSticky | - iofs.FileMode(s_ISUID|s_ISGID|s_ISVTX) + os.FileMode(s_ISUID|s_ISGID|s_ISVTX) for _, c := range []struct { goPerm os.FileMode diff --git a/errno_plan9.go b/errno_plan9.go new file mode 100644 index 00000000..cf9d3902 --- /dev/null +++ b/errno_plan9.go @@ -0,0 +1,42 @@ +package sftp + +import ( + "os" + "syscall" +) + +var EBADF = syscall.NewError("fd out of range or not open") + +func wrapPathError(filepath string, err error) error { + if errno, ok := err.(syscall.ErrorString); ok { + return &os.PathError{Path: filepath, Err: errno} + } + return err +} + +// translateErrno translates a syscall error number to a SFTP error code. +func translateErrno(errno syscall.ErrorString) uint32 { + switch errno { + case "": + return sshFxOk + case syscall.ENOENT: + return sshFxNoSuchFile + case syscall.EPERM: + return sshFxPermissionDenied + } + + return sshFxFailure +} + +func translateSyscallError(err error) (uint32, bool) { + switch e := err.(type) { + case syscall.ErrorString: + return translateErrno(e), true + case *os.PathError: + debug("statusFromError,pathError: error is %T %#v", e.Err, e.Err) + if errno, ok := e.Err.(syscall.ErrorString); ok { + return translateErrno(errno), true + } + } + return 0, false +} diff --git a/errno_posix.go b/errno_posix.go new file mode 100644 index 00000000..cd87e1b5 --- /dev/null +++ b/errno_posix.go @@ -0,0 +1,45 @@ +//go:build !plan9 +// +build !plan9 + +package sftp + +import ( + "os" + "syscall" +) + +const EBADF = syscall.EBADF + +func wrapPathError(filepath string, err error) error { + if errno, ok := err.(syscall.Errno); ok { + return &os.PathError{Path: filepath, Err: errno} + } + return err +} + +// translateErrno translates a syscall error number to a SFTP error code. +func translateErrno(errno syscall.Errno) uint32 { + switch errno { + case 0: + return sshFxOk + case syscall.ENOENT: + return sshFxNoSuchFile + case syscall.EACCES, syscall.EPERM: + return sshFxPermissionDenied + } + + return sshFxFailure +} + +func translateSyscallError(err error) (uint32, bool) { + switch e := err.(type) { + case syscall.Errno: + return translateErrno(e), true + case *os.PathError: + debug("statusFromError,pathError: error is %T %#v", e.Err, e.Err) + if errno, ok := e.Err.(syscall.Errno); ok { + return translateErrno(errno), true + } + } + return 0, false +} diff --git a/stat_posix.go b/stat.go similarity index 68% rename from stat_posix.go rename to stat.go index 891b2400..f0e68b90 100644 --- a/stat_posix.go +++ b/stat.go @@ -1,51 +1,11 @@ -//go:build !plan9 -// +build !plan9 - package sftp import ( "os" - "syscall" sshfx "github.com/pkg/sftp/internal/encoding/ssh/filexfer" ) -const EBADF = syscall.EBADF - -func wrapPathError(filepath string, err error) error { - if errno, ok := err.(syscall.Errno); ok { - return &os.PathError{Path: filepath, Err: errno} - } - return err -} - -// translateErrno translates a syscall error number to a SFTP error code. -func translateErrno(errno syscall.Errno) uint32 { - switch errno { - case 0: - return sshFxOk - case syscall.ENOENT: - return sshFxNoSuchFile - case syscall.EACCES, syscall.EPERM: - return sshFxPermissionDenied - } - - return sshFxFailure -} - -func translateSyscallError(err error) (uint32, bool) { - switch e := err.(type) { - case syscall.Errno: - return translateErrno(e), true - case *os.PathError: - debug("statusFromError,pathError: error is %T %#v", e.Err, e.Err) - if errno, ok := e.Err.(syscall.Errno); ok { - return translateErrno(errno), true - } - } - return 0, false -} - // isRegular returns true if the mode describes a regular file. func isRegular(mode uint32) bool { return sshfx.FileMode(mode)&sshfx.ModeType == sshfx.ModeRegular @@ -124,3 +84,10 @@ const ( s_ISGID = uint32(sshfx.ModeSetGID) s_ISVTX = uint32(sshfx.ModeSticky) ) + +// Legacy export: +// +// Go defines S_IFMT on windows, plan9 and js/wasm as 0x1f000 instead of +// 0xf000. None of the the other S_IFxyz values include the "1" (in 0x1f000) +// which prevents them from matching the bitmask. +const S_IFMT = uint32(sshfx.ModeType) diff --git a/stat_plan9.go b/stat_plan9.go deleted file mode 100644 index 761abdf5..00000000 --- a/stat_plan9.go +++ /dev/null @@ -1,103 +0,0 @@ -package sftp - -import ( - "os" - "syscall" -) - -var EBADF = syscall.NewError("fd out of range or not open") - -func wrapPathError(filepath string, err error) error { - if errno, ok := err.(syscall.ErrorString); ok { - return &os.PathError{Path: filepath, Err: errno} - } - return err -} - -// translateErrno translates a syscall error number to a SFTP error code. -func translateErrno(errno syscall.ErrorString) uint32 { - switch errno { - case "": - return sshFxOk - case syscall.ENOENT: - return sshFxNoSuchFile - case syscall.EPERM: - return sshFxPermissionDenied - } - - return sshFxFailure -} - -func translateSyscallError(err error) (uint32, bool) { - switch e := err.(type) { - case syscall.ErrorString: - return translateErrno(e), true - case *os.PathError: - debug("statusFromError,pathError: error is %T %#v", e.Err, e.Err) - if errno, ok := e.Err.(syscall.ErrorString); ok { - return translateErrno(errno), true - } - } - return 0, false -} - -// isRegular returns true if the mode describes a regular file. -func isRegular(mode uint32) bool { - return mode&S_IFMT == syscall.S_IFREG -} - -// toFileMode converts sftp filemode bits to the os.FileMode specification -func toFileMode(mode uint32) os.FileMode { - var fm = os.FileMode(mode & 0777) - - switch mode & S_IFMT { - case syscall.S_IFBLK: - fm |= os.ModeDevice - case syscall.S_IFCHR: - fm |= os.ModeDevice | os.ModeCharDevice - case syscall.S_IFDIR: - fm |= os.ModeDir - case syscall.S_IFIFO: - fm |= os.ModeNamedPipe - case syscall.S_IFLNK: - fm |= os.ModeSymlink - case syscall.S_IFREG: - // nothing to do - case syscall.S_IFSOCK: - fm |= os.ModeSocket - } - - return fm -} - -// fromFileMode converts from the os.FileMode specification to sftp filemode bits -func fromFileMode(mode os.FileMode) uint32 { - ret := uint32(mode & os.ModePerm) - - switch mode & os.ModeType { - case os.ModeDevice | os.ModeCharDevice: - ret |= syscall.S_IFCHR - case os.ModeDevice: - ret |= syscall.S_IFBLK - case os.ModeDir: - ret |= syscall.S_IFDIR - case os.ModeNamedPipe: - ret |= syscall.S_IFIFO - case os.ModeSymlink: - ret |= syscall.S_IFLNK - case 0: - ret |= syscall.S_IFREG - case os.ModeSocket: - ret |= syscall.S_IFSOCK - } - - return ret -} - -// Plan 9 doesn't have setuid, setgid or sticky, but a Plan 9 client should -// be able to send these bits to a POSIX server. -const ( - s_ISUID = 04000 - s_ISGID = 02000 - s_ISVTX = 01000 -) diff --git a/syscall_fixed.go b/syscall_fixed.go deleted file mode 100644 index 0f80dd5c..00000000 --- a/syscall_fixed.go +++ /dev/null @@ -1,9 +0,0 @@ -// Go defines S_IFMT on windows, plan9 and js/wasm as 0x1f000 instead of -// 0xf000. None of the the other S_IFxyz values include the "1" (in 0x1f000) -// which prevents them from matching the bitmask. - -package sftp - -import sshfx "github.com/pkg/sftp/internal/encoding/ssh/filexfer" - -const S_IFMT = uint32(sshfx.ModeType) From 3588ee80db20622709895556868ed7c0d2613abc Mon Sep 17 00:00:00 2001 From: dustin-ward Date: Fri, 5 Apr 2024 22:11:36 -0400 Subject: [PATCH 4/4] fix godoc comment --- stat.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/stat.go b/stat.go index f0e68b90..a34a98f5 100644 --- a/stat.go +++ b/stat.go @@ -85,9 +85,5 @@ const ( s_ISVTX = uint32(sshfx.ModeSticky) ) -// Legacy export: -// -// Go defines S_IFMT on windows, plan9 and js/wasm as 0x1f000 instead of -// 0xf000. None of the the other S_IFxyz values include the "1" (in 0x1f000) -// which prevents them from matching the bitmask. +// S_IFMT is a legacy export. `sshfx.ModeType` should be used instead const S_IFMT = uint32(sshfx.ModeType)