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

Add support for zos/s390x #582

Merged
merged 4 commits into from Apr 6, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 6 additions & 6 deletions client.go
Expand Up @@ -7,6 +7,7 @@ import (
"errors"
"fmt"
"io"
iofs "io/fs"
"math"
"os"
"path"
Expand Down Expand Up @@ -2113,13 +2114,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) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider that POSIX standard requires the assertion: O_RDONLY | O_WRONLY == O_RDWR[1]

However, due to constant folding, I think we’re still fine here regardless.

1: https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html

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 {
Expand All @@ -2143,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)
dustin-ward marked this conversation as resolved.
Show resolved Hide resolved
perm = uint32(m & mask)

if m&os.ModeSetuid != 0 {
Expand Down
3 changes: 2 additions & 1 deletion client_integration_test.go
Expand Up @@ -9,6 +9,7 @@ import (
"errors"
"fmt"
"io"
iofs "io/fs"
"io/ioutil"
"math/rand"
"net"
Expand Down Expand Up @@ -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)
dustin-ward marked this conversation as resolved.
Show resolved Hide resolved

for _, c := range []struct {
goPerm os.FileMode
Expand Down
7 changes: 7 additions & 0 deletions ls_formatting_test.go
Expand Up @@ -3,6 +3,7 @@ package sftp
import (
"os"
"regexp"
"runtime"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -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]"
Expand Down
9 changes: 7 additions & 2 deletions request-server_test.go
Expand Up @@ -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("/")
Expand Down
9 changes: 7 additions & 2 deletions server_test.go
Expand Up @@ -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()
Expand Down
56 changes: 29 additions & 27 deletions stat_posix.go
Expand Up @@ -6,6 +6,8 @@ package sftp
import (
"os"
"syscall"

sshfx "github.com/pkg/sftp/internal/encoding/ssh/filexfer"
)

const EBADF = syscall.EBADF
Expand Down Expand Up @@ -46,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
}

Expand All @@ -85,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)
)
7 changes: 3 additions & 4 deletions 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)
10 changes: 0 additions & 10 deletions syscall_good.go

This file was deleted.