1
0
mirror of https://github.com/rclone/rclone.git synced 2025-12-29 14:43:24 +00:00

vendor: update all dependencies

This commit is contained in:
Nick Craig-Wood
2020-02-25 14:20:57 +00:00
parent 17b4058ee9
commit abb9f89f65
443 changed files with 32118 additions and 18237 deletions

View File

@@ -1,15 +1,10 @@
language: go
go_import_path: github.com/pkg/errors
go:
- 1.4.x
- 1.5.x
- 1.6.x
- 1.7.x
- 1.8.x
- 1.9.x
- 1.10.x
- 1.11.x
- 1.12.x
- 1.13.x
- tip
script:
- go test -v ./...
- make check

44
vendor/github.com/pkg/errors/Makefile generated vendored Normal file
View File

@@ -0,0 +1,44 @@
PKGS := github.com/pkg/errors
SRCDIRS := $(shell go list -f '{{.Dir}}' $(PKGS))
GO := go
check: test vet gofmt misspell unconvert staticcheck ineffassign unparam
test:
$(GO) test $(PKGS)
vet: | test
$(GO) vet $(PKGS)
staticcheck:
$(GO) get honnef.co/go/tools/cmd/staticcheck
staticcheck -checks all $(PKGS)
misspell:
$(GO) get github.com/client9/misspell/cmd/misspell
misspell \
-locale GB \
-error \
*.md *.go
unconvert:
$(GO) get github.com/mdempsky/unconvert
unconvert -v $(PKGS)
ineffassign:
$(GO) get github.com/gordonklaus/ineffassign
find $(SRCDIRS) -name '*.go' | xargs ineffassign
pedantic: check errcheck
unparam:
$(GO) get mvdan.cc/unparam
unparam ./...
errcheck:
$(GO) get github.com/kisielk/errcheck
errcheck $(PKGS)
gofmt:
@echo Checking code is gofmted
@test -z "$(shell gofmt -s -l -d -e $(SRCDIRS) | tee /dev/stderr)"

View File

@@ -41,11 +41,18 @@ default:
[Read the package documentation for more information](https://godoc.org/github.com/pkg/errors).
## Roadmap
With the upcoming [Go2 error proposals](https://go.googlesource.com/proposal/+/master/design/go2draft.md) this package is moving into maintenance mode. The roadmap for a 1.0 release is as follows:
- 0.9. Remove pre Go 1.9 and Go 1.10 support, address outstanding pull requests (if possible)
- 1.0. Final release.
## Contributing
We welcome pull requests, bug fixes and issue reports. With that said, the bar for adding new symbols to this package is intentionally set high.
Because of the Go2 errors changes, this package is not accepting proposals for new functionality. With that said, we welcome pull requests, bug fixes and issue reports.
Before proposing a change, please discuss your change by raising an issue.
Before sending a PR, please discuss your change by raising an issue.
## License

View File

@@ -82,7 +82,7 @@
//
// if err, ok := err.(stackTracer); ok {
// for _, f := range err.StackTrace() {
// fmt.Printf("%+s:%d", f)
// fmt.Printf("%+s:%d\n", f, f)
// }
// }
//
@@ -159,6 +159,9 @@ type withStack struct {
func (w *withStack) Cause() error { return w.error }
// Unwrap provides compatibility for Go 1.13 error chains.
func (w *withStack) Unwrap() error { return w.error }
func (w *withStack) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
@@ -241,6 +244,9 @@ type withMessage struct {
func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
func (w *withMessage) Cause() error { return w.cause }
// Unwrap provides compatibility for Go 1.13 error chains.
func (w *withMessage) Unwrap() error { return w.cause }
func (w *withMessage) Format(s fmt.State, verb rune) {
switch verb {
case 'v':

38
vendor/github.com/pkg/errors/go113.go generated vendored Normal file
View File

@@ -0,0 +1,38 @@
// +build go1.13
package errors
import (
stderrors "errors"
)
// Is reports whether any error in err's chain matches target.
//
// The chain consists of err itself followed by the sequence of errors obtained by
// repeatedly calling Unwrap.
//
// An error is considered to match a target if it is equal to that target or if
// it implements a method Is(error) bool such that Is(target) returns true.
func Is(err, target error) bool { return stderrors.Is(err, target) }
// As finds the first error in err's chain that matches target, and if so, sets
// target to that error value and returns true.
//
// The chain consists of err itself followed by the sequence of errors obtained by
// repeatedly calling Unwrap.
//
// An error matches target if the error's concrete value is assignable to the value
// pointed to by target, or if the error has a method As(interface{}) bool such that
// As(target) returns true. In the latter case, the As method is responsible for
// setting target.
//
// As will panic if target is not a non-nil pointer to either a type that implements
// error, or to any interface type. As returns false if err is nil.
func As(err error, target interface{}) bool { return stderrors.As(err, target) }
// Unwrap returns the result of calling the Unwrap method on err, if err's
// type contains an Unwrap method returning error.
// Otherwise, Unwrap returns nil.
func Unwrap(err error) error {
return stderrors.Unwrap(err)
}

View File

@@ -5,10 +5,13 @@ import (
"io"
"path"
"runtime"
"strconv"
"strings"
)
// Frame represents a program counter inside a stack frame.
// For historical reasons if Frame is interpreted as a uintptr
// its value represents the program counter + 1.
type Frame uintptr
// pc returns the program counter for this frame;
@@ -37,6 +40,15 @@ func (f Frame) line() int {
return line
}
// name returns the name of this function, if known.
func (f Frame) name() string {
fn := runtime.FuncForPC(f.pc())
if fn == nil {
return "unknown"
}
return fn.Name()
}
// Format formats the frame according to the fmt.Formatter interface.
//
// %s source file
@@ -54,22 +66,16 @@ func (f Frame) Format(s fmt.State, verb rune) {
case 's':
switch {
case s.Flag('+'):
pc := f.pc()
fn := runtime.FuncForPC(pc)
if fn == nil {
io.WriteString(s, "unknown")
} else {
file, _ := fn.FileLine(pc)
fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file)
}
io.WriteString(s, f.name())
io.WriteString(s, "\n\t")
io.WriteString(s, f.file())
default:
io.WriteString(s, path.Base(f.file()))
}
case 'd':
fmt.Fprintf(s, "%d", f.line())
io.WriteString(s, strconv.Itoa(f.line()))
case 'n':
name := runtime.FuncForPC(f.pc()).Name()
io.WriteString(s, funcname(name))
io.WriteString(s, funcname(f.name()))
case 'v':
f.Format(s, 's')
io.WriteString(s, ":")
@@ -77,6 +83,16 @@ func (f Frame) Format(s fmt.State, verb rune) {
}
}
// MarshalText formats a stacktrace Frame as a text string. The output is the
// same as that of fmt.Sprintf("%+v", f), but without newlines or tabs.
func (f Frame) MarshalText() ([]byte, error) {
name := f.name()
if name == "unknown" {
return []byte(name), nil
}
return []byte(fmt.Sprintf("%s %s:%d", name, f.file(), f.line())), nil
}
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
type StackTrace []Frame
@@ -94,18 +110,32 @@ func (st StackTrace) Format(s fmt.State, verb rune) {
switch {
case s.Flag('+'):
for _, f := range st {
fmt.Fprintf(s, "\n%+v", f)
io.WriteString(s, "\n")
f.Format(s, verb)
}
case s.Flag('#'):
fmt.Fprintf(s, "%#v", []Frame(st))
default:
fmt.Fprintf(s, "%v", []Frame(st))
st.formatSlice(s, verb)
}
case 's':
fmt.Fprintf(s, "%s", []Frame(st))
st.formatSlice(s, verb)
}
}
// formatSlice will format this StackTrace into the given buffer as a slice of
// Frame, only valid when called with '%s' or '%v'.
func (st StackTrace) formatSlice(s fmt.State, verb rune) {
io.WriteString(s, "[")
for i, f := range st {
if i > 0 {
io.WriteString(s, " ")
}
f.Format(s, verb)
}
io.WriteString(s, "]")
}
// stack represents a stack of program counters.
type stack []uintptr

View File

@@ -4,25 +4,25 @@ go_import_path: github.com/pkg/sftp
# current and previous stable releases, plus tip
# remember to exclude previous and tip for macs below
go:
- 1.11.x
- 1.12.x
- 1.13.x
- tip
os:
- linux
- osx
env:
global:
- GO111MODULE=on
matrix:
exclude:
- os: osx
go: 1.10.x
go: 1.12.x
- os: osx
go: tip
env:
global:
- GO111MODULE=on
addons:
ssh_known_hosts:
- bitbucket.org

11
vendor/github.com/pkg/sftp/Makefile generated vendored Normal file
View File

@@ -0,0 +1,11 @@
integration:
go test -integration -v
go test -testserver -v
go test -integration -testserver -v
integration_w_race:
go test -race -integration -v
go test -race -testserver -v
go test -race -integration -testserver -v

59
vendor/github.com/pkg/sftp/attrs.go generated vendored
View File

@@ -10,11 +10,14 @@ import (
)
const (
ssh_FILEXFER_ATTR_SIZE = 0x00000001
ssh_FILEXFER_ATTR_UIDGID = 0x00000002
ssh_FILEXFER_ATTR_PERMISSIONS = 0x00000004
ssh_FILEXFER_ATTR_ACMODTIME = 0x00000008
ssh_FILEXFER_ATTR_EXTENDED = 0x80000000
sshFileXferAttrSize = 0x00000001
sshFileXferAttrUIDGID = 0x00000002
sshFileXferAttrPermissions = 0x00000004
sshFileXferAttrACmodTime = 0x00000008
sshFileXferAttrExtented = 0x80000000
sshFileXferAttrAll = sshFileXferAttrSize | sshFileXferAttrUIDGID | sshFileXferAttrPermissions |
sshFileXferAttrACmodTime | sshFileXferAttrExtented
)
// fileInfo is an artificial type designed to satisfy os.FileInfo.
@@ -77,9 +80,9 @@ func fileInfoFromStat(st *FileStat, name string) os.FileInfo {
func fileStatFromInfo(fi os.FileInfo) (uint32, FileStat) {
mtime := fi.ModTime().Unix()
atime := mtime
var flags uint32 = ssh_FILEXFER_ATTR_SIZE |
ssh_FILEXFER_ATTR_PERMISSIONS |
ssh_FILEXFER_ATTR_ACMODTIME
var flags uint32 = sshFileXferAttrSize |
sshFileXferAttrPermissions |
sshFileXferAttrACmodTime
fileStat := FileStat{
Size: uint64(fi.Size()),
@@ -101,31 +104,31 @@ func unmarshalAttrs(b []byte) (*FileStat, []byte) {
func getFileStat(flags uint32, b []byte) (*FileStat, []byte) {
var fs FileStat
if flags&ssh_FILEXFER_ATTR_SIZE == ssh_FILEXFER_ATTR_SIZE {
fs.Size, b = unmarshalUint64(b)
if flags&sshFileXferAttrSize == sshFileXferAttrSize {
fs.Size, b, _ = unmarshalUint64Safe(b)
}
if flags&ssh_FILEXFER_ATTR_UIDGID == ssh_FILEXFER_ATTR_UIDGID {
fs.UID, b = unmarshalUint32(b)
if flags&sshFileXferAttrUIDGID == sshFileXferAttrUIDGID {
fs.UID, b, _ = unmarshalUint32Safe(b)
}
if flags&ssh_FILEXFER_ATTR_UIDGID == ssh_FILEXFER_ATTR_UIDGID {
fs.GID, b = unmarshalUint32(b)
if flags&sshFileXferAttrUIDGID == sshFileXferAttrUIDGID {
fs.GID, b, _ = unmarshalUint32Safe(b)
}
if flags&ssh_FILEXFER_ATTR_PERMISSIONS == ssh_FILEXFER_ATTR_PERMISSIONS {
fs.Mode, b = unmarshalUint32(b)
if flags&sshFileXferAttrPermissions == sshFileXferAttrPermissions {
fs.Mode, b, _ = unmarshalUint32Safe(b)
}
if flags&ssh_FILEXFER_ATTR_ACMODTIME == ssh_FILEXFER_ATTR_ACMODTIME {
fs.Atime, b = unmarshalUint32(b)
fs.Mtime, b = unmarshalUint32(b)
if flags&sshFileXferAttrACmodTime == sshFileXferAttrACmodTime {
fs.Atime, b, _ = unmarshalUint32Safe(b)
fs.Mtime, b, _ = unmarshalUint32Safe(b)
}
if flags&ssh_FILEXFER_ATTR_EXTENDED == ssh_FILEXFER_ATTR_EXTENDED {
if flags&sshFileXferAttrExtented == sshFileXferAttrExtented {
var count uint32
count, b = unmarshalUint32(b)
count, b, _ = unmarshalUint32Safe(b)
ext := make([]StatExtended, count)
for i := uint32(0); i < count; i++ {
var typ string
var data string
typ, b = unmarshalString(b)
data, b = unmarshalString(b)
typ, b, _ = unmarshalStringSafe(b)
data, b, _ = unmarshalStringSafe(b)
ext[i] = StatExtended{typ, data}
}
fs.Extended = ext
@@ -152,17 +155,17 @@ func marshalFileInfo(b []byte, fi os.FileInfo) []byte {
flags, fileStat := fileStatFromInfo(fi)
b = marshalUint32(b, flags)
if flags&ssh_FILEXFER_ATTR_SIZE != 0 {
if flags&sshFileXferAttrSize != 0 {
b = marshalUint64(b, fileStat.Size)
}
if flags&ssh_FILEXFER_ATTR_UIDGID != 0 {
if flags&sshFileXferAttrUIDGID != 0 {
b = marshalUint32(b, fileStat.UID)
b = marshalUint32(b, fileStat.GID)
}
if flags&ssh_FILEXFER_ATTR_PERMISSIONS != 0 {
if flags&sshFileXferAttrPermissions != 0 {
b = marshalUint32(b, fileStat.Mode)
}
if flags&ssh_FILEXFER_ATTR_ACMODTIME != 0 {
if flags&sshFileXferAttrACmodTime != 0 {
b = marshalUint32(b, fileStat.Atime)
b = marshalUint32(b, fileStat.Mtime)
}
@@ -173,7 +176,7 @@ func marshalFileInfo(b []byte, fi os.FileInfo) []byte {
// toFileMode converts sftp filemode bits to the os.FileMode specification
func toFileMode(mode uint32) os.FileMode {
var fm = os.FileMode(mode & 0777)
switch mode & syscall.S_IFMT {
switch mode & S_IFMT {
case syscall.S_IFBLK:
fm |= os.ModeDevice
case syscall.S_IFCHR:

View File

@@ -10,7 +10,7 @@ import (
func fileStatFromInfoOs(fi os.FileInfo, flags *uint32, fileStat *FileStat) {
if statt, ok := fi.Sys().(*syscall.Stat_t); ok {
*flags |= ssh_FILEXFER_ATTR_UIDGID
*flags |= sshFileXferAttrUIDGID
fileStat.UID = statt.Uid
fileStat.GID = statt.Gid
}

187
vendor/github.com/pkg/sftp/client.go generated vendored
View File

@@ -15,12 +15,18 @@ import (
"golang.org/x/crypto/ssh"
)
// InternalInconsistency indicates the packets sent and the data queued to be
// written to the file don't match up. It is an unusual error and usually is
// caused by bad behavior server side or connection issues. The error is
// limited in scope to the call where it happened, the client object is still
// OK to use as long as the connection is still open.
var InternalInconsistency = errors.New("internal inconsistency")
var (
// ErrInternalInconsistency indicates the packets sent and the data queued to be
// written to the file don't match up. It is an unusual error and usually is
// caused by bad behavior server side or connection issues. The error is
// limited in scope to the call where it happened, the client object is still
// OK to use as long as the connection is still open.
ErrInternalInconsistency = errors.New("internal inconsistency")
// InternalInconsistency alias for ErrInternalInconsistency.
//
// Deprecated: please use ErrInternalInconsistency
InternalInconsistency = ErrInternalInconsistency
)
// A ClientOption is a function which applies configuration to a Client.
type ClientOption func(*Client) error
@@ -45,6 +51,30 @@ func MaxPacketChecked(size int) ClientOption {
}
}
// UseFstat sets whether to use Fstat or Stat when File.WriteTo is called
// (usually when copying files).
// Some servers limit the amount of open files and calling Stat after opening
// the file will throw an error From the server. Setting this flag will call
// Fstat instead of Stat which is suppose to be called on an open file handle.
//
// It has been found that that with IBM Sterling SFTP servers which have
// "extractability" level set to 1 which means only 1 file can be opened at
// any given time.
//
// If the server you are working with still has an issue with both Stat and
// Fstat calls you can always open a file and read it until the end.
//
// Another reason to read the file until its end and Fstat doesn't work is
// that in some servers, reading a full file will automatically delete the
// file as some of these mainframes map the file to a message in a queue.
// Once the file has been read it will get deleted.
func UseFstat(value bool) ClientOption {
return func(c *Client) error {
c.useFstat = value
return nil
}
}
// MaxPacketUnchecked sets the maximum size of the payload, measured in bytes.
// It accepts sizes larger than the 32768 bytes all servers should support.
// Only use a setting higher than 32768 if your application always connects to
@@ -155,12 +185,17 @@ type Client struct {
maxPacket int // max packet size read or written.
nextid uint32
maxConcurrentRequests int
useFstat bool
}
// Create creates the named file mode 0666 (before umask), truncating it if it
// already exists. If successful, methods on the returned File can be used for
// I/O; the associated file descriptor has mode O_RDWR. If you need more
// control over the flags/mode used to open the file see client.OpenFile.
//
// Note that some SFTP servers (eg. AWS Transfer) do not support opening files
// read/write at the same time. For those services you will need to use
// `client.OpenFile(os.O_WRONLY|os.O_CREATE|os.O_TRUNC)`.
func (c *Client) Create(path string) (*File, error) {
return c.open(path, flags(os.O_RDWR|os.O_CREATE|os.O_TRUNC))
}
@@ -183,8 +218,8 @@ func (c *Client) recvVersion() error {
if err != nil {
return err
}
if typ != ssh_FXP_VERSION {
return &unexpectedPacketErr{ssh_FXP_VERSION, typ}
if typ != sshFxpVersion {
return &unexpectedPacketErr{sshFxpVersion, typ}
}
version, _ := unmarshalUint32(data)
@@ -222,7 +257,7 @@ func (c *Client) ReadDir(p string) ([]os.FileInfo, error) {
break
}
switch typ {
case ssh_FXP_NAME:
case sshFxpName:
sid, data := unmarshalUint32(data)
if sid != id {
return nil, &unexpectedIDErr{id, sid}
@@ -239,7 +274,7 @@ func (c *Client) ReadDir(p string) ([]os.FileInfo, error) {
}
attrs = append(attrs, fileInfoFromStat(attr, path.Base(filename)))
}
case ssh_FXP_STATUS:
case sshFxpStatus:
// TODO(dfc) scope warning!
err = normaliseError(unmarshalStatus(id, data))
done = true
@@ -263,14 +298,14 @@ func (c *Client) opendir(path string) (string, error) {
return "", err
}
switch typ {
case ssh_FXP_HANDLE:
case sshFxpHandle:
sid, data := unmarshalUint32(data)
if sid != id {
return "", &unexpectedIDErr{id, sid}
}
handle, _ := unmarshalString(data)
return handle, nil
case ssh_FXP_STATUS:
case sshFxpStatus:
return "", normaliseError(unmarshalStatus(id, data))
default:
return "", unimplementedPacketErr(typ)
@@ -289,14 +324,14 @@ func (c *Client) Stat(p string) (os.FileInfo, error) {
return nil, err
}
switch typ {
case ssh_FXP_ATTRS:
case sshFxpAttrs:
sid, data := unmarshalUint32(data)
if sid != id {
return nil, &unexpectedIDErr{id, sid}
}
attr, _ := unmarshalAttrs(data)
return fileInfoFromStat(attr, path.Base(p)), nil
case ssh_FXP_STATUS:
case sshFxpStatus:
return nil, normaliseError(unmarshalStatus(id, data))
default:
return nil, unimplementedPacketErr(typ)
@@ -315,14 +350,14 @@ func (c *Client) Lstat(p string) (os.FileInfo, error) {
return nil, err
}
switch typ {
case ssh_FXP_ATTRS:
case sshFxpAttrs:
sid, data := unmarshalUint32(data)
if sid != id {
return nil, &unexpectedIDErr{id, sid}
}
attr, _ := unmarshalAttrs(data)
return fileInfoFromStat(attr, path.Base(p)), nil
case ssh_FXP_STATUS:
case sshFxpStatus:
return nil, normaliseError(unmarshalStatus(id, data))
default:
return nil, unimplementedPacketErr(typ)
@@ -340,7 +375,7 @@ func (c *Client) ReadLink(p string) (string, error) {
return "", err
}
switch typ {
case ssh_FXP_NAME:
case sshFxpName:
sid, data := unmarshalUint32(data)
if sid != id {
return "", &unexpectedIDErr{id, sid}
@@ -351,13 +386,32 @@ func (c *Client) ReadLink(p string) (string, error) {
}
filename, _ := unmarshalString(data) // ignore dummy attributes
return filename, nil
case ssh_FXP_STATUS:
case sshFxpStatus:
return "", normaliseError(unmarshalStatus(id, data))
default:
return "", unimplementedPacketErr(typ)
}
}
// Link creates a hard link at 'newname', pointing at the same inode as 'oldname'
func (c *Client) Link(oldname, newname string) error {
id := c.nextID()
typ, data, err := c.sendPacket(sshFxpHardlinkPacket{
ID: id,
Oldpath: oldname,
Newpath: newname,
})
if err != nil {
return err
}
switch typ {
case sshFxpStatus:
return normaliseError(unmarshalStatus(id, data))
default:
return unimplementedPacketErr(typ)
}
}
// Symlink creates a symbolic link at 'newname', pointing at target 'oldname'
func (c *Client) Symlink(oldname, newname string) error {
id := c.nextID()
@@ -370,7 +424,7 @@ func (c *Client) Symlink(oldname, newname string) error {
return err
}
switch typ {
case ssh_FXP_STATUS:
case sshFxpStatus:
return normaliseError(unmarshalStatus(id, data))
default:
return unimplementedPacketErr(typ)
@@ -390,7 +444,7 @@ func (c *Client) setstat(path string, flags uint32, attrs interface{}) error {
return err
}
switch typ {
case ssh_FXP_STATUS:
case sshFxpStatus:
return normaliseError(unmarshalStatus(id, data))
default:
return unimplementedPacketErr(typ)
@@ -404,7 +458,7 @@ func (c *Client) Chtimes(path string, atime time.Time, mtime time.Time) error {
Mtime uint32
}
attrs := times{uint32(atime.Unix()), uint32(mtime.Unix())}
return c.setstat(path, ssh_FILEXFER_ATTR_ACMODTIME, attrs)
return c.setstat(path, sshFileXferAttrACmodTime, attrs)
}
// Chown changes the user and group owners of the named file.
@@ -414,12 +468,12 @@ func (c *Client) Chown(path string, uid, gid int) error {
GID uint32
}
attrs := owner{uint32(uid), uint32(gid)}
return c.setstat(path, ssh_FILEXFER_ATTR_UIDGID, attrs)
return c.setstat(path, sshFileXferAttrUIDGID, attrs)
}
// Chmod changes the permissions of the named file.
func (c *Client) Chmod(path string, mode os.FileMode) error {
return c.setstat(path, ssh_FILEXFER_ATTR_PERMISSIONS, uint32(mode))
return c.setstat(path, sshFileXferAttrPermissions, uint32(mode))
}
// Truncate sets the size of the named file. Although it may be safely assumed
@@ -427,7 +481,7 @@ func (c *Client) Chmod(path string, mode os.FileMode) error {
// the SFTP protocol does not specify what behavior the server should do when setting
// size greater than the current size.
func (c *Client) Truncate(path string, size int64) error {
return c.setstat(path, ssh_FILEXFER_ATTR_SIZE, uint64(size))
return c.setstat(path, sshFileXferAttrSize, uint64(size))
}
// Open opens the named file for reading. If successful, methods on the
@@ -455,14 +509,14 @@ func (c *Client) open(path string, pflags uint32) (*File, error) {
return nil, err
}
switch typ {
case ssh_FXP_HANDLE:
case sshFxpHandle:
sid, data := unmarshalUint32(data)
if sid != id {
return nil, &unexpectedIDErr{id, sid}
}
handle, _ := unmarshalString(data)
return &File{c: c, path: path, handle: handle}, nil
case ssh_FXP_STATUS:
case sshFxpStatus:
return nil, normaliseError(unmarshalStatus(id, data))
default:
return nil, unimplementedPacketErr(typ)
@@ -482,7 +536,7 @@ func (c *Client) close(handle string) error {
return err
}
switch typ {
case ssh_FXP_STATUS:
case sshFxpStatus:
return normaliseError(unmarshalStatus(id, data))
default:
return unimplementedPacketErr(typ)
@@ -499,14 +553,14 @@ func (c *Client) fstat(handle string) (*FileStat, error) {
return nil, err
}
switch typ {
case ssh_FXP_ATTRS:
case sshFxpAttrs:
sid, data := unmarshalUint32(data)
if sid != id {
return nil, &unexpectedIDErr{id, sid}
}
attr, _ := unmarshalAttrs(data)
return attr, nil
case ssh_FXP_STATUS:
case sshFxpStatus:
return nil, normaliseError(unmarshalStatus(id, data))
default:
return nil, unimplementedPacketErr(typ)
@@ -530,7 +584,7 @@ func (c *Client) StatVFS(path string) (*StatVFS, error) {
switch typ {
// server responded with valid data
case ssh_FXP_EXTENDED_REPLY:
case sshFxpExtendedReply:
var response StatVFS
err = binary.Read(bytes.NewReader(data), binary.BigEndian, &response)
if err != nil {
@@ -540,8 +594,8 @@ func (c *Client) StatVFS(path string) (*StatVFS, error) {
return &response, nil
// the resquest failed
case ssh_FXP_STATUS:
return nil, errors.New(fxp(ssh_FXP_STATUS).String())
case sshFxpStatus:
return nil, errors.New(fxp(sshFxpStatus).String())
default:
return nil, unimplementedPacketErr(typ)
@@ -562,7 +616,7 @@ func (c *Client) Remove(path string) error {
switch err.Code {
// some servers, *cough* osx *cough*, return EPERM, not ENODIR.
// serv-u returns ssh_FX_FILE_IS_A_DIRECTORY
case ssh_FX_PERMISSION_DENIED, ssh_FX_FAILURE, ssh_FX_FILE_IS_A_DIRECTORY:
case sshFxPermissionDenied, sshFxFailure, sshFxFileIsADirectory:
return c.RemoveDirectory(path)
}
}
@@ -579,7 +633,7 @@ func (c *Client) removeFile(path string) error {
return err
}
switch typ {
case ssh_FXP_STATUS:
case sshFxpStatus:
return normaliseError(unmarshalStatus(id, data))
default:
return unimplementedPacketErr(typ)
@@ -597,7 +651,7 @@ func (c *Client) RemoveDirectory(path string) error {
return err
}
switch typ {
case ssh_FXP_STATUS:
case sshFxpStatus:
return normaliseError(unmarshalStatus(id, data))
default:
return unimplementedPacketErr(typ)
@@ -616,7 +670,7 @@ func (c *Client) Rename(oldname, newname string) error {
return err
}
switch typ {
case ssh_FXP_STATUS:
case sshFxpStatus:
return normaliseError(unmarshalStatus(id, data))
default:
return unimplementedPacketErr(typ)
@@ -636,7 +690,7 @@ func (c *Client) PosixRename(oldname, newname string) error {
return err
}
switch typ {
case ssh_FXP_STATUS:
case sshFxpStatus:
return normaliseError(unmarshalStatus(id, data))
default:
return unimplementedPacketErr(typ)
@@ -653,7 +707,7 @@ func (c *Client) realpath(path string) (string, error) {
return "", err
}
switch typ {
case ssh_FXP_NAME:
case sshFxpName:
sid, data := unmarshalUint32(data)
if sid != id {
return "", &unexpectedIDErr{id, sid}
@@ -664,7 +718,7 @@ func (c *Client) realpath(path string) (string, error) {
}
filename, _ := unmarshalString(data) // ignore attributes
return filename, nil
case ssh_FXP_STATUS:
case sshFxpStatus:
return "", normaliseError(unmarshalStatus(id, data))
default:
return "", unimplementedPacketErr(typ)
@@ -690,7 +744,7 @@ func (c *Client) Mkdir(path string) error {
return err
}
switch typ {
case ssh_FXP_STATUS:
case sshFxpStatus:
return normaliseError(unmarshalStatus(id, data))
default:
return unimplementedPacketErr(typ)
@@ -845,14 +899,14 @@ func (f *File) Read(b []byte) (int, error) {
}
delete(reqs, reqID)
switch res.typ {
case ssh_FXP_STATUS:
case sshFxpStatus:
if firstErr.err == nil || req.offset < firstErr.offset {
firstErr = offsetErr{
offset: req.offset,
err: normaliseError(unmarshalStatus(reqID, res.data)),
}
}
case ssh_FXP_DATA:
case sshFxpData:
l, data := unmarshalUint32(data)
n := copy(req.b, data[:l])
read += n
@@ -884,15 +938,26 @@ func (f *File) Read(b []byte) (int, error) {
// maximise throughput for transferring the entire file (especially
// over high latency links).
func (f *File) WriteTo(w io.Writer) (int64, error) {
fi, err := f.c.Stat(f.path)
if err != nil {
return 0, err
var fileSize uint64
if f.c.useFstat {
fileStat, err := f.c.fstat(f.handle)
if err != nil {
return 0, err
}
fileSize = fileStat.Size
} else {
fi, err := f.c.Stat(f.path)
if err != nil {
return 0, err
}
fileSize = uint64(fi.Size())
}
inFlight := 0
desiredInFlight := 1
offset := f.offset
writeOffset := offset
fileSize := uint64(fi.Size())
// see comment on same line in Read() above
ch := make(chan result, f.c.maxConcurrentRequests+1)
type inflightRead struct {
@@ -934,7 +999,7 @@ func (f *File) WriteTo(w io.Writer) (int64, error) {
if inFlight == 0 {
if firstErr.err == nil && len(pendingWrites) > 0 {
return copied, InternalInconsistency
return copied, ErrInternalInconsistency
}
break
}
@@ -952,11 +1017,11 @@ func (f *File) WriteTo(w io.Writer) (int64, error) {
}
delete(reqs, reqID)
switch res.typ {
case ssh_FXP_STATUS:
case sshFxpStatus:
if firstErr.err == nil || req.offset < firstErr.offset {
firstErr = offsetErr{offset: req.offset, err: normaliseError(unmarshalStatus(reqID, res.data))}
}
case ssh_FXP_DATA:
case sshFxpData:
l, data := unmarshalUint32(data)
if req.offset == writeOffset {
nbytes, err := w.Write(data)
@@ -1071,7 +1136,7 @@ func (f *File) Write(b []byte) (int, error) {
continue
}
switch res.typ {
case ssh_FXP_STATUS:
case sshFxpStatus:
id, _ := unmarshalUint32(res.data)
err := normaliseError(unmarshalStatus(id, res.data))
if err != nil && firstErr == nil {
@@ -1139,7 +1204,7 @@ func (f *File) ReadFrom(r io.Reader) (int64, error) {
continue
}
switch res.typ {
case ssh_FXP_STATUS:
case sshFxpStatus:
id, _ := unmarshalUint32(res.data)
err := normaliseError(unmarshalStatus(id, res.data))
if err != nil && firstErr == nil {
@@ -1218,11 +1283,11 @@ func normaliseError(err error) error {
switch err := err.(type) {
case *StatusError:
switch err.Code {
case ssh_FX_EOF:
case sshFxEOF:
return io.EOF
case ssh_FX_NO_SUCH_FILE:
case sshFxNoSuchFile:
return os.ErrNotExist
case ssh_FX_OK:
case sshFxOk:
return nil
default:
return err
@@ -1260,24 +1325,24 @@ func flags(f int) uint32 {
var out uint32
switch f & os.O_WRONLY {
case os.O_WRONLY:
out |= ssh_FXF_WRITE
out |= sshFxfWrite
case os.O_RDONLY:
out |= ssh_FXF_READ
out |= sshFxfRead
}
if f&os.O_RDWR == os.O_RDWR {
out |= ssh_FXF_READ | ssh_FXF_WRITE
out |= sshFxfRead | sshFxfWrite
}
if f&os.O_APPEND == os.O_APPEND {
out |= ssh_FXF_APPEND
out |= sshFxfAppend
}
if f&os.O_CREATE == os.O_CREATE {
out |= ssh_FXF_CREAT
out |= sshFxfCreat
}
if f&os.O_TRUNC == os.O_TRUNC {
out |= ssh_FXF_TRUNC
out |= sshFxfTrunc
}
if f&os.O_EXCL == os.O_EXCL {
out |= ssh_FXF_EXCL
out |= sshFxfExcl
}
return out
}

View File

@@ -39,7 +39,7 @@ func newPktMgr(sender packetSender) *packetManager {
}
//// packet ordering
func (s *packetManager) newOrderId() uint32 {
func (s *packetManager) newOrderID() uint32 {
s.packetCount++
return s.packetCount
}
@@ -50,10 +50,10 @@ type orderedRequest struct {
}
func (s *packetManager) newOrderedRequest(p requestPacket) orderedRequest {
return orderedRequest{requestPacket: p, orderid: s.newOrderId()}
return orderedRequest{requestPacket: p, orderid: s.newOrderID()}
}
func (p orderedRequest) orderId() uint32 { return p.orderid }
func (p orderedRequest) setOrderId(oid uint32) { p.orderid = oid }
func (p orderedRequest) orderID() uint32 { return p.orderid }
func (p orderedRequest) setOrderID(oid uint32) { p.orderid = oid }
type orderedResponse struct {
responsePacket
@@ -64,18 +64,18 @@ func (s *packetManager) newOrderedResponse(p responsePacket, id uint32,
) orderedResponse {
return orderedResponse{responsePacket: p, orderid: id}
}
func (p orderedResponse) orderId() uint32 { return p.orderid }
func (p orderedResponse) setOrderId(oid uint32) { p.orderid = oid }
func (p orderedResponse) orderID() uint32 { return p.orderid }
func (p orderedResponse) setOrderID(oid uint32) { p.orderid = oid }
type orderedPacket interface {
id() uint32
orderId() uint32
orderID() uint32
}
type orderedPackets []orderedPacket
func (o orderedPackets) Sort() {
sort.Slice(o, func(i, j int) bool {
return o[i].orderId() < o[j].orderId()
return o[i].orderID() < o[j].orderID()
})
}
@@ -145,11 +145,11 @@ func (s *packetManager) controller() {
for {
select {
case pkt := <-s.requests:
debug("incoming id (oid): %v (%v)", pkt.id(), pkt.orderId())
debug("incoming id (oid): %v (%v)", pkt.id(), pkt.orderID())
s.incoming = append(s.incoming, pkt)
s.incoming.Sort()
case pkt := <-s.responses:
debug("outgoing id (oid): %v (%v)", pkt.id(), pkt.orderId())
debug("outgoing id (oid): %v (%v)", pkt.id(), pkt.orderID())
s.outgoing = append(s.outgoing, pkt)
s.outgoing.Sort()
case <-s.fini:
@@ -171,7 +171,7 @@ func (s *packetManager) maybeSendPackets() {
in := s.incoming[0]
// debug("incoming: %v", ids(s.incoming))
// debug("outgoing: %v", ids(s.outgoing))
if in.orderId() == out.orderId() {
if in.orderID() == out.orderID() {
debug("Sending packet: %v", out.id())
s.sender.sendPacket(out.(encoding.BinaryMarshaler))
// pop off heads

View File

@@ -49,8 +49,9 @@ func (p sshFxpOpendirPacket) getPath() string { return p.Path }
func (p sshFxpOpenPacket) getPath() string { return p.Path }
func (p sshFxpExtendedPacketPosixRename) getPath() string { return p.Oldpath }
func (p sshFxpExtendedPacketHardlink) getPath() string { return p.Oldpath }
// hasHandle
// getHandle
func (p sshFxpFstatPacket) getHandle() string { return p.Handle }
func (p sshFxpFsetstatPacket) getHandle() string { return p.Handle }
func (p sshFxpReadPacket) getHandle() string { return p.Handle }
@@ -68,6 +69,7 @@ func (p sshFxpRmdirPacket) notReadOnly() {}
func (p sshFxpRenamePacket) notReadOnly() {}
func (p sshFxpSymlinkPacket) notReadOnly() {}
func (p sshFxpExtendedPacketPosixRename) notReadOnly() {}
func (p sshFxpExtendedPacketHardlink) notReadOnly() {}
// some packets with ID are missing id()
func (p sshFxpDataPacket) id() uint32 { return p.ID }
@@ -82,45 +84,45 @@ func (p sshFxVersionPacket) id() uint32 { return 0 }
func makePacket(p rxPacket) (requestPacket, error) {
var pkt requestPacket
switch p.pktType {
case ssh_FXP_INIT:
case sshFxpInit:
pkt = &sshFxInitPacket{}
case ssh_FXP_LSTAT:
case sshFxpLstat:
pkt = &sshFxpLstatPacket{}
case ssh_FXP_OPEN:
case sshFxpOpen:
pkt = &sshFxpOpenPacket{}
case ssh_FXP_CLOSE:
case sshFxpClose:
pkt = &sshFxpClosePacket{}
case ssh_FXP_READ:
case sshFxpRead:
pkt = &sshFxpReadPacket{}
case ssh_FXP_WRITE:
case sshFxpWrite:
pkt = &sshFxpWritePacket{}
case ssh_FXP_FSTAT:
case sshFxpFstat:
pkt = &sshFxpFstatPacket{}
case ssh_FXP_SETSTAT:
case sshFxpSetstat:
pkt = &sshFxpSetstatPacket{}
case ssh_FXP_FSETSTAT:
case sshFxpFsetstat:
pkt = &sshFxpFsetstatPacket{}
case ssh_FXP_OPENDIR:
case sshFxpOpendir:
pkt = &sshFxpOpendirPacket{}
case ssh_FXP_READDIR:
case sshFxpReaddir:
pkt = &sshFxpReaddirPacket{}
case ssh_FXP_REMOVE:
case sshFxpRemove:
pkt = &sshFxpRemovePacket{}
case ssh_FXP_MKDIR:
case sshFxpMkdir:
pkt = &sshFxpMkdirPacket{}
case ssh_FXP_RMDIR:
case sshFxpRmdir:
pkt = &sshFxpRmdirPacket{}
case ssh_FXP_REALPATH:
case sshFxpRealpath:
pkt = &sshFxpRealpathPacket{}
case ssh_FXP_STAT:
case sshFxpStat:
pkt = &sshFxpStatPacket{}
case ssh_FXP_RENAME:
case sshFxpRename:
pkt = &sshFxpRenamePacket{}
case ssh_FXP_READLINK:
case sshFxpReadlink:
pkt = &sshFxpReadlinkPacket{}
case ssh_FXP_SYMLINK:
case sshFxpSymlink:
pkt = &sshFxpSymlinkPacket{}
case ssh_FXP_EXTENDED:
case sshFxpExtended:
pkt = &sshFxpExtendedPacket{}
default:
return nil, errors.Errorf("unhandled packet type: %s", p.pktType)

125
vendor/github.com/pkg/sftp/packet.go generated vendored
View File

@@ -13,11 +13,13 @@ import (
)
var (
errLongPacket = errors.New("packet too long")
errShortPacket = errors.New("packet too short")
errUnknownExtendedPacket = errors.New("unknown extended packet")
)
const (
maxMsgLength = 256 * 1024
debugDumpTxPacket = false
debugDumpRxPacket = false
debugDumpTxPacketBytes = false
@@ -143,6 +145,10 @@ func recvPacket(r io.Reader) (uint8, []byte, error) {
return 0, nil, err
}
l, _ := unmarshalUint32(b)
if l > maxMsgLength {
debug("recv packet %d bytes too long", l)
return 0, nil, errLongPacket
}
b = make([]byte, l)
if _, err := io.ReadFull(r, b); err != nil {
debug("recv packet %d bytes: err %v", l, err)
@@ -189,7 +195,7 @@ func (p sshFxInitPacket) MarshalBinary() ([]byte, error) {
}
b := make([]byte, 0, l)
b = append(b, ssh_FXP_INIT)
b = append(b, sshFxpInit)
b = marshalUint32(b, p.Version)
for _, e := range p.Extensions {
b = marshalString(b, e.Name)
@@ -216,9 +222,11 @@ func (p *sshFxInitPacket) UnmarshalBinary(b []byte) error {
type sshFxVersionPacket struct {
Version uint32
Extensions []struct {
Name, Data string
}
Extensions []sshExtensionPair
}
type sshExtensionPair struct {
Name, Data string
}
func (p sshFxVersionPacket) MarshalBinary() ([]byte, error) {
@@ -228,7 +236,7 @@ func (p sshFxVersionPacket) MarshalBinary() ([]byte, error) {
}
b := make([]byte, 0, l)
b = append(b, ssh_FXP_VERSION)
b = append(b, sshFxpVersion)
b = marshalUint32(b, p.Version)
for _, e := range p.Extensions {
b = marshalString(b, e.Name)
@@ -266,7 +274,7 @@ type sshFxpReaddirPacket struct {
func (p sshFxpReaddirPacket) id() uint32 { return p.ID }
func (p sshFxpReaddirPacket) MarshalBinary() ([]byte, error) {
return marshalIDString(ssh_FXP_READDIR, p.ID, p.Handle)
return marshalIDString(sshFxpReaddir, p.ID, p.Handle)
}
func (p *sshFxpReaddirPacket) UnmarshalBinary(b []byte) error {
@@ -281,7 +289,7 @@ type sshFxpOpendirPacket struct {
func (p sshFxpOpendirPacket) id() uint32 { return p.ID }
func (p sshFxpOpendirPacket) MarshalBinary() ([]byte, error) {
return marshalIDString(ssh_FXP_OPENDIR, p.ID, p.Path)
return marshalIDString(sshFxpOpendir, p.ID, p.Path)
}
func (p *sshFxpOpendirPacket) UnmarshalBinary(b []byte) error {
@@ -296,7 +304,7 @@ type sshFxpLstatPacket struct {
func (p sshFxpLstatPacket) id() uint32 { return p.ID }
func (p sshFxpLstatPacket) MarshalBinary() ([]byte, error) {
return marshalIDString(ssh_FXP_LSTAT, p.ID, p.Path)
return marshalIDString(sshFxpLstat, p.ID, p.Path)
}
func (p *sshFxpLstatPacket) UnmarshalBinary(b []byte) error {
@@ -311,7 +319,7 @@ type sshFxpStatPacket struct {
func (p sshFxpStatPacket) id() uint32 { return p.ID }
func (p sshFxpStatPacket) MarshalBinary() ([]byte, error) {
return marshalIDString(ssh_FXP_STAT, p.ID, p.Path)
return marshalIDString(sshFxpStat, p.ID, p.Path)
}
func (p *sshFxpStatPacket) UnmarshalBinary(b []byte) error {
@@ -326,7 +334,7 @@ type sshFxpFstatPacket struct {
func (p sshFxpFstatPacket) id() uint32 { return p.ID }
func (p sshFxpFstatPacket) MarshalBinary() ([]byte, error) {
return marshalIDString(ssh_FXP_FSTAT, p.ID, p.Handle)
return marshalIDString(sshFxpFstat, p.ID, p.Handle)
}
func (p *sshFxpFstatPacket) UnmarshalBinary(b []byte) error {
@@ -341,7 +349,7 @@ type sshFxpClosePacket struct {
func (p sshFxpClosePacket) id() uint32 { return p.ID }
func (p sshFxpClosePacket) MarshalBinary() ([]byte, error) {
return marshalIDString(ssh_FXP_CLOSE, p.ID, p.Handle)
return marshalIDString(sshFxpClose, p.ID, p.Handle)
}
func (p *sshFxpClosePacket) UnmarshalBinary(b []byte) error {
@@ -356,7 +364,7 @@ type sshFxpRemovePacket struct {
func (p sshFxpRemovePacket) id() uint32 { return p.ID }
func (p sshFxpRemovePacket) MarshalBinary() ([]byte, error) {
return marshalIDString(ssh_FXP_REMOVE, p.ID, p.Filename)
return marshalIDString(sshFxpRemove, p.ID, p.Filename)
}
func (p *sshFxpRemovePacket) UnmarshalBinary(b []byte) error {
@@ -371,7 +379,7 @@ type sshFxpRmdirPacket struct {
func (p sshFxpRmdirPacket) id() uint32 { return p.ID }
func (p sshFxpRmdirPacket) MarshalBinary() ([]byte, error) {
return marshalIDString(ssh_FXP_RMDIR, p.ID, p.Path)
return marshalIDString(sshFxpRmdir, p.ID, p.Path)
}
func (p *sshFxpRmdirPacket) UnmarshalBinary(b []byte) error {
@@ -392,7 +400,7 @@ func (p sshFxpSymlinkPacket) MarshalBinary() ([]byte, error) {
4 + len(p.Linkpath)
b := make([]byte, 0, l)
b = append(b, ssh_FXP_SYMLINK)
b = append(b, sshFxpSymlink)
b = marshalUint32(b, p.ID)
b = marshalString(b, p.Targetpath)
b = marshalString(b, p.Linkpath)
@@ -411,6 +419,30 @@ func (p *sshFxpSymlinkPacket) UnmarshalBinary(b []byte) error {
return nil
}
type sshFxpHardlinkPacket struct {
ID uint32
Oldpath string
Newpath string
}
func (p sshFxpHardlinkPacket) id() uint32 { return p.ID }
func (p sshFxpHardlinkPacket) MarshalBinary() ([]byte, error) {
const ext = "hardlink@openssh.com"
l := 1 + 4 + // type(byte) + uint32
4 + len(ext) +
4 + len(p.Oldpath) +
4 + len(p.Newpath)
b := make([]byte, 0, l)
b = append(b, sshFxpExtended)
b = marshalUint32(b, p.ID)
b = marshalString(b, ext)
b = marshalString(b, p.Oldpath)
b = marshalString(b, p.Newpath)
return b, nil
}
type sshFxpReadlinkPacket struct {
ID uint32
Path string
@@ -419,7 +451,7 @@ type sshFxpReadlinkPacket struct {
func (p sshFxpReadlinkPacket) id() uint32 { return p.ID }
func (p sshFxpReadlinkPacket) MarshalBinary() ([]byte, error) {
return marshalIDString(ssh_FXP_READLINK, p.ID, p.Path)
return marshalIDString(sshFxpReadlink, p.ID, p.Path)
}
func (p *sshFxpReadlinkPacket) UnmarshalBinary(b []byte) error {
@@ -434,7 +466,7 @@ type sshFxpRealpathPacket struct {
func (p sshFxpRealpathPacket) id() uint32 { return p.ID }
func (p sshFxpRealpathPacket) MarshalBinary() ([]byte, error) {
return marshalIDString(ssh_FXP_REALPATH, p.ID, p.Path)
return marshalIDString(sshFxpRealpath, p.ID, p.Path)
}
func (p *sshFxpRealpathPacket) UnmarshalBinary(b []byte) error {
@@ -464,7 +496,7 @@ type sshFxpNamePacket struct {
func (p sshFxpNamePacket) MarshalBinary() ([]byte, error) {
b := []byte{}
b = append(b, ssh_FXP_NAME)
b = append(b, sshFxpName)
b = marshalUint32(b, p.ID)
b = marshalUint32(b, uint32(len(p.NameAttrs)))
for _, na := range p.NameAttrs {
@@ -493,7 +525,7 @@ func (p sshFxpOpenPacket) MarshalBinary() ([]byte, error) {
4 + 4
b := make([]byte, 0, l)
b = append(b, ssh_FXP_OPEN)
b = append(b, sshFxpOpen)
b = marshalUint32(b, p.ID)
b = marshalString(b, p.Path)
b = marshalUint32(b, p.Pflags)
@@ -530,7 +562,7 @@ func (p sshFxpReadPacket) MarshalBinary() ([]byte, error) {
8 + 4 // uint64 + uint32
b := make([]byte, 0, l)
b = append(b, ssh_FXP_READ)
b = append(b, sshFxpRead)
b = marshalUint32(b, p.ID)
b = marshalString(b, p.Handle)
b = marshalUint64(b, p.Offset)
@@ -566,7 +598,7 @@ func (p sshFxpRenamePacket) MarshalBinary() ([]byte, error) {
4 + len(p.Newpath)
b := make([]byte, 0, l)
b = append(b, ssh_FXP_RENAME)
b = append(b, sshFxpRename)
b = marshalUint32(b, p.ID)
b = marshalString(b, p.Oldpath)
b = marshalString(b, p.Newpath)
@@ -601,7 +633,7 @@ func (p sshFxpPosixRenamePacket) MarshalBinary() ([]byte, error) {
4 + len(p.Newpath)
b := make([]byte, 0, l)
b = append(b, ssh_FXP_EXTENDED)
b = append(b, sshFxpExtended)
b = marshalUint32(b, p.ID)
b = marshalString(b, ext)
b = marshalString(b, p.Oldpath)
@@ -626,7 +658,7 @@ func (p sshFxpWritePacket) MarshalBinary() ([]byte, error) {
len(p.Data)
b := make([]byte, 0, l)
b = append(b, ssh_FXP_WRITE)
b = append(b, sshFxpWrite)
b = marshalUint32(b, p.ID)
b = marshalString(b, p.Handle)
b = marshalUint64(b, p.Offset)
@@ -667,7 +699,7 @@ func (p sshFxpMkdirPacket) MarshalBinary() ([]byte, error) {
4 // uint32
b := make([]byte, 0, l)
b = append(b, ssh_FXP_MKDIR)
b = append(b, sshFxpMkdir)
b = marshalUint32(b, p.ID)
b = marshalString(b, p.Path)
b = marshalUint32(b, p.Flags)
@@ -709,7 +741,7 @@ func (p sshFxpSetstatPacket) MarshalBinary() ([]byte, error) {
4 // uint32 + uint64
b := make([]byte, 0, l)
b = append(b, ssh_FXP_SETSTAT)
b = append(b, sshFxpSetstat)
b = marshalUint32(b, p.ID)
b = marshalString(b, p.Path)
b = marshalUint32(b, p.Flags)
@@ -723,7 +755,7 @@ func (p sshFxpFsetstatPacket) MarshalBinary() ([]byte, error) {
4 // uint32 + uint64
b := make([]byte, 0, l)
b = append(b, ssh_FXP_FSETSTAT)
b = append(b, sshFxpFsetstat)
b = marshalUint32(b, p.ID)
b = marshalString(b, p.Handle)
b = marshalUint32(b, p.Flags)
@@ -763,7 +795,7 @@ type sshFxpHandlePacket struct {
}
func (p sshFxpHandlePacket) MarshalBinary() ([]byte, error) {
b := []byte{ssh_FXP_HANDLE}
b := []byte{sshFxpHandle}
b = marshalUint32(b, p.ID)
b = marshalString(b, p.Handle)
return b, nil
@@ -775,7 +807,7 @@ type sshFxpStatusPacket struct {
}
func (p sshFxpStatusPacket) MarshalBinary() ([]byte, error) {
b := []byte{ssh_FXP_STATUS}
b := []byte{sshFxpStatus}
b = marshalUint32(b, p.ID)
b = marshalStatus(b, p.StatusError)
return b, nil
@@ -788,7 +820,7 @@ type sshFxpDataPacket struct {
}
func (p sshFxpDataPacket) MarshalBinary() ([]byte, error) {
b := []byte{ssh_FXP_DATA}
b := []byte{sshFxpData}
b = marshalUint32(b, p.ID)
b = marshalUint32(b, p.Length)
b = append(b, p.Data[:p.Length]...)
@@ -823,7 +855,7 @@ func (p sshFxpStatvfsPacket) MarshalBinary() ([]byte, error) {
len("statvfs@openssh.com")
b := make([]byte, 0, l)
b = append(b, ssh_FXP_EXTENDED)
b = append(b, sshFxpExtended)
b = marshalUint32(b, p.ID)
b = marshalString(b, "statvfs@openssh.com")
b = marshalString(b, p.Path)
@@ -856,10 +888,10 @@ func (p *StatVFS) FreeSpace() uint64 {
return p.Frsize * p.Bfree
}
// Convert to ssh_FXP_EXTENDED_REPLY packet binary format
// MarshalBinary converts to ssh_FXP_EXTENDED_REPLY packet binary format
func (p *StatVFS) MarshalBinary() ([]byte, error) {
var buf bytes.Buffer
buf.Write([]byte{ssh_FXP_EXTENDED_REPLY})
buf.Write([]byte{sshFxpExtendedReply})
err := binary.Write(&buf, binary.BigEndian, p)
return buf.Bytes(), err
}
@@ -903,6 +935,8 @@ func (p *sshFxpExtendedPacket) UnmarshalBinary(b []byte) error {
p.SpecificPacket = &sshFxpExtendedPacketStatVFS{}
case "posix-rename@openssh.com":
p.SpecificPacket = &sshFxpExtendedPacketPosixRename{}
case "hardlink@openssh.com":
p.SpecificPacket = &sshFxpExtendedPacketHardlink{}
default:
return errors.Wrapf(errUnknownExtendedPacket, "packet type %v", p.SpecificPacket)
}
@@ -957,3 +991,32 @@ func (p sshFxpExtendedPacketPosixRename) respond(s *Server) responsePacket {
err := os.Rename(p.Oldpath, p.Newpath)
return statusFromError(p, err)
}
type sshFxpExtendedPacketHardlink struct {
ID uint32
ExtendedRequest string
Oldpath string
Newpath string
}
// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL
func (p sshFxpExtendedPacketHardlink) id() uint32 { return p.ID }
func (p sshFxpExtendedPacketHardlink) readonly() bool { return true }
func (p *sshFxpExtendedPacketHardlink) UnmarshalBinary(b []byte) error {
var err error
if p.ID, b, err = unmarshalUint32Safe(b); err != nil {
return err
} else if p.ExtendedRequest, b, err = unmarshalStringSafe(b); err != nil {
return err
} else if p.Oldpath, b, err = unmarshalStringSafe(b); err != nil {
return err
} else if p.Newpath, _, err = unmarshalStringSafe(b); err != nil {
return err
}
return nil
}
func (p sshFxpExtendedPacketHardlink) respond(s *Server) responsePacket {
err := os.Link(p.Oldpath, p.Newpath)
return statusFromError(p, err)
}

View File

@@ -5,7 +5,7 @@ package sftp
// request and AttrFlags() and Attributes() when working with SetStat requests.
import "os"
// File Open and Write Flags. Correlate directly with with os.OpenFile flags
// FileOpenFlags defines Open and Write Flags. Correlate directly with with os.OpenFile flags
// (https://golang.org/pkg/os/#pkg-constants).
type FileOpenFlags struct {
Read, Write, Append, Creat, Trunc, Excl bool
@@ -13,12 +13,12 @@ type FileOpenFlags struct {
func newFileOpenFlags(flags uint32) FileOpenFlags {
return FileOpenFlags{
Read: flags&ssh_FXF_READ != 0,
Write: flags&ssh_FXF_WRITE != 0,
Append: flags&ssh_FXF_APPEND != 0,
Creat: flags&ssh_FXF_CREAT != 0,
Trunc: flags&ssh_FXF_TRUNC != 0,
Excl: flags&ssh_FXF_EXCL != 0,
Read: flags&sshFxfRead != 0,
Write: flags&sshFxfWrite != 0,
Append: flags&sshFxfAppend != 0,
Creat: flags&sshFxfCreat != 0,
Trunc: flags&sshFxfTrunc != 0,
Excl: flags&sshFxfExcl != 0,
}
}
@@ -28,7 +28,7 @@ func (r *Request) Pflags() FileOpenFlags {
return newFileOpenFlags(r.Flags)
}
// Flags that indicate whether SFTP file attributes were passed. When a flag is
// FileAttrFlags that indicate whether SFTP file attributes were passed. When a flag is
// true the corresponding attribute should be available from the FileStat
// object returned by Attributes method. Used with SetStat.
type FileAttrFlags struct {
@@ -37,14 +37,14 @@ type FileAttrFlags struct {
func newFileAttrFlags(flags uint32) FileAttrFlags {
return FileAttrFlags{
Size: (flags & ssh_FILEXFER_ATTR_SIZE) != 0,
UidGid: (flags & ssh_FILEXFER_ATTR_UIDGID) != 0,
Permissions: (flags & ssh_FILEXFER_ATTR_PERMISSIONS) != 0,
Acmodtime: (flags & ssh_FILEXFER_ATTR_ACMODTIME) != 0,
Size: (flags & sshFileXferAttrSize) != 0,
UidGid: (flags & sshFileXferAttrUIDGID) != 0,
Permissions: (flags & sshFileXferAttrPermissions) != 0,
Acmodtime: (flags & sshFileXferAttrACmodTime) != 0,
}
}
// FileAttrFlags returns a FileAttrFlags boolean struct based on the
// AttrFlags returns a FileAttrFlags boolean struct based on the
// bitmap/uint32 file attribute flags from the SFTP packaet.
func (r *Request) AttrFlags() FileAttrFlags {
return newFileAttrFlags(r.Flags)
@@ -55,7 +55,7 @@ func (a FileStat) FileMode() os.FileMode {
return os.FileMode(a.Mode)
}
// Attributres parses file attributes byte blob and return them in a
// Attributes parses file attributes byte blob and return them in a
// FileStat object.
func (r *Request) Attributes() *FileStat {
fs, _ := getFileStat(r.Flags, r.Attrs)

View File

@@ -1,40 +1,52 @@
package sftp
type fxerr uint32
// Error types that match the SFTP's SSH_FXP_STATUS codes. Gives you more
// direct control of the errors being sent vs. letting the library work them
// out from the standard os/io errors.
type fxerr uint32
const (
ErrSshFxOk = fxerr(ssh_FX_OK)
ErrSshFxEof = fxerr(ssh_FX_EOF)
ErrSshFxNoSuchFile = fxerr(ssh_FX_NO_SUCH_FILE)
ErrSshFxPermissionDenied = fxerr(ssh_FX_PERMISSION_DENIED)
ErrSshFxFailure = fxerr(ssh_FX_FAILURE)
ErrSshFxBadMessage = fxerr(ssh_FX_BAD_MESSAGE)
ErrSshFxNoConnection = fxerr(ssh_FX_NO_CONNECTION)
ErrSshFxConnectionLost = fxerr(ssh_FX_CONNECTION_LOST)
ErrSshFxOpUnsupported = fxerr(ssh_FX_OP_UNSUPPORTED)
ErrSSHFxOk = fxerr(sshFxOk)
ErrSSHFxEOF = fxerr(sshFxEOF)
ErrSSHFxNoSuchFile = fxerr(sshFxNoSuchFile)
ErrSSHFxPermissionDenied = fxerr(sshFxPermissionDenied)
ErrSSHFxFailure = fxerr(sshFxFailure)
ErrSSHFxBadMessage = fxerr(sshFxBadMessage)
ErrSSHFxNoConnection = fxerr(sshFxNoConnection)
ErrSSHFxConnectionLost = fxerr(sshFxConnectionLost)
ErrSSHFxOpUnsupported = fxerr(sshFxOPUnsupported)
)
// Deprecated error types, these are aliases for the new ones, please use the new ones directly
const (
ErrSshFxOk = ErrSSHFxOk
ErrSshFxEof = ErrSSHFxEOF
ErrSshFxNoSuchFile = ErrSSHFxNoSuchFile
ErrSshFxPermissionDenied = ErrSSHFxPermissionDenied
ErrSshFxFailure = ErrSSHFxFailure
ErrSshFxBadMessage = ErrSSHFxBadMessage
ErrSshFxNoConnection = ErrSSHFxNoConnection
ErrSshFxConnectionLost = ErrSSHFxConnectionLost
ErrSshFxOpUnsupported = ErrSSHFxOpUnsupported
)
func (e fxerr) Error() string {
switch e {
case ErrSshFxOk:
case ErrSSHFxOk:
return "OK"
case ErrSshFxEof:
case ErrSSHFxEOF:
return "EOF"
case ErrSshFxNoSuchFile:
case ErrSSHFxNoSuchFile:
return "No Such File"
case ErrSshFxPermissionDenied:
case ErrSSHFxPermissionDenied:
return "Permission Denied"
case ErrSshFxBadMessage:
case ErrSSHFxBadMessage:
return "Bad Message"
case ErrSshFxNoConnection:
case ErrSSHFxNoConnection:
return "No Connection"
case ErrSshFxConnectionLost:
case ErrSSHFxConnectionLost:
return "Connection Lost"
case ErrSshFxOpUnsupported:
case ErrSSHFxOpUnsupported:
return "Operation Unsupported"
default:
return "Failure"

View File

@@ -11,6 +11,7 @@ import (
"os"
"path/filepath"
"sort"
"strings"
"sync"
"syscall"
"time"
@@ -90,18 +91,51 @@ func (fs *root) Filecmd(r *Request) error {
file.name = r.Target
fs.files[r.Target] = file
delete(fs.files, r.Filepath)
if file.IsDir() {
for path, file := range fs.files {
if strings.HasPrefix(path, r.Filepath+"/") {
file.name = r.Target + path[len(r.Filepath):]
fs.files[r.Target+path[len(r.Filepath):]] = file
delete(fs.files, path)
}
}
}
case "Rmdir", "Remove":
_, err := fs.fetch(filepath.Dir(r.Filepath))
file, err := fs.fetch(filepath.Dir(r.Filepath))
if err != nil {
return err
}
if file.IsDir() {
for path := range fs.files {
if strings.HasPrefix(path, r.Filepath+"/") {
return &os.PathError{
Op: "remove",
Path: r.Filepath + "/",
Err: fmt.Errorf("directory is not empty"),
}
}
}
}
delete(fs.files, r.Filepath)
case "Mkdir":
_, err := fs.fetch(filepath.Dir(r.Filepath))
if err != nil {
return err
}
fs.files[r.Filepath] = newMemFile(r.Filepath, true)
case "Link":
file, err := fs.fetch(r.Filepath)
if err != nil {
return err
}
if file.IsDir() {
return fmt.Errorf("hard link not allowed for directory")
}
fs.files[r.Target] = file
case "Symlink":
_, err := fs.fetch(r.Filepath)
if err != nil {
@@ -147,15 +181,15 @@ func (fs *root) Filelist(r *Request) (ListerAt, error) {
if !file.IsDir() {
return nil, syscall.ENOTDIR
}
ordered_names := []string{}
for fn, _ := range fs.files {
orderedNames := []string{}
for fn := range fs.files {
if filepath.Dir(fn) == r.Filepath {
ordered_names = append(ordered_names, fn)
orderedNames = append(orderedNames, fn)
}
}
sort.Strings(ordered_names)
list := make([]os.FileInfo, len(ordered_names))
for i, fn := range ordered_names {
sort.Strings(orderedNames)
list := make([]os.FileInfo, len(orderedNames))
for i, fn := range orderedNames {
list[i] = fs.files[fn]
}
return listerat(list), nil
@@ -199,13 +233,15 @@ func (fs *root) fetch(path string) (*memFile, error) {
// Implements os.FileInfo, Reader and Writer interfaces.
// These are the 3 interfaces necessary for the Handlers.
// Implements the optional interface TransferError.
type memFile struct {
name string
modtime time.Time
symlink string
isdir bool
content []byte
contentLock sync.RWMutex
name string
modtime time.Time
symlink string
isdir bool
content []byte
transferError error
contentLock sync.RWMutex
}
// factory to make sure modtime is set
@@ -265,3 +301,7 @@ func (f *memFile) WriteAt(p []byte, off int64) (int, error) {
copy(f.content[off:], p)
return len(p), nil
}
func (f *memFile) TransferError(err error) {
f.transferError = err
}

View File

@@ -25,6 +25,8 @@ type FileReader interface {
// The request server code will call Close() on the returned io.WriterAt
// ojbect if an io.Closer type assertion succeeds.
// Note in cases of an error, the error text will be sent to the client.
// Note when receiving an Append flag it is important to not open files using
// O_APPEND if you plan to use WriteAt, as they conflict.
// Called for Methods: Put, Open
type FileWriter interface {
Filewrite(*Request) (io.WriterAt, error)
@@ -32,7 +34,7 @@ type FileWriter interface {
// FileCmder should return an error
// Note in cases of an error, the error text will be sent to the client.
// Called for Methods: Setstat, Rename, Rmdir, Mkdir, Symlink, Remove
// Called for Methods: Setstat, Rename, Rmdir, Mkdir, Link, Symlink, Remove
type FileCmder interface {
Filecmd(*Request) error
}
@@ -53,3 +55,10 @@ type FileLister interface {
type ListerAt interface {
ListAt([]os.FileInfo, int64) (int, error)
}
// TransferError is an optional interface that readerAt and writerAt
// can implement to be notified about the error causing Serve() to exit
// with the request still open
type TransferError interface {
TransferError(err error)
}

View File

@@ -116,11 +116,7 @@ func (rs *RequestServer) Serve() error {
if err != nil {
switch errors.Cause(err) {
case errUnknownExtendedPacket:
if err := rs.serverConn.sendError(pkt, ErrSshFxOpUnsupported); err != nil {
debug("failed to send err packet: %v", err)
rs.conn.Close() // shuts down recvPacket
break
}
// do nothing
default:
debug("makePacket err: %v", err)
rs.conn.Close() // shuts down recvPacket
@@ -137,6 +133,20 @@ func (rs *RequestServer) Serve() error {
// make sure all open requests are properly closed
// (eg. possible on dropped connections, client crashes, etc.)
for handle, req := range rs.openRequests {
if err != nil {
req.state.RLock()
writer := req.state.writerAt
reader := req.state.readerAt
req.state.RUnlock()
if t, ok := writer.(TransferError); ok {
debug("notify error: %v to writer: %v\n", err, writer)
t.TransferError(err)
}
if t, ok := reader.(TransferError); ok {
debug("notify error: %v to reader: %v\n", err, reader)
t.TransferError(err)
}
}
delete(rs.openRequests, handle)
req.close()
}
@@ -148,10 +158,16 @@ func (rs *RequestServer) packetWorker(
ctx context.Context, pktChan chan orderedRequest,
) error {
for pkt := range pktChan {
if epkt, ok := pkt.requestPacket.(*sshFxpExtendedPacket); ok {
if epkt.SpecificPacket != nil {
pkt.requestPacket = epkt.SpecificPacket
}
}
var rpkt responsePacket
switch pkt := pkt.requestPacket.(type) {
case *sshFxInitPacket:
rpkt = sshFxVersionPacket{Version: sftpProtocolVersion}
rpkt = sshFxVersionPacket{Version: sftpProtocolVersion, Extensions: sftpExtensions}
case *sshFxpClosePacket:
handle := pkt.getHandle()
rpkt = statusFromError(pkt, rs.closeRequest(handle))
@@ -174,6 +190,10 @@ func (rs *RequestServer) packetWorker(
request = NewRequest("Stat", request.Filepath)
rpkt = request.call(rs.Handlers, pkt)
}
case *sshFxpExtendedPacketPosixRename:
request := NewRequest("Rename", pkt.Oldpath)
request.Target = pkt.Newpath
rpkt = request.call(rs.Handlers, pkt)
case hasHandle:
handle := pkt.getHandle()
request, ok := rs.getRequest(handle)
@@ -187,11 +207,11 @@ func (rs *RequestServer) packetWorker(
rpkt = request.call(rs.Handlers, pkt)
request.close()
default:
return errors.Errorf("unexpected packet type %T", pkt)
rpkt = statusFromError(pkt, ErrSSHFxOpUnsupported)
}
rs.pktMgr.readyPacket(
rs.pktMgr.newOrderedResponse(rpkt, pkt.orderId()))
rs.pktMgr.newOrderedResponse(rpkt, pkt.orderID()))
}
return nil
}

View File

@@ -14,10 +14,10 @@ func fakeFileInfoSys() interface{} {
func testOsSys(sys interface{}) error {
fstat := sys.(*FileStat)
if fstat.UID != uint32(65534) {
return errors.New("Uid failed to match.")
return errors.New("Uid failed to match")
}
if fstat.GID != uint32(65534) {
return errors.New("Gid failed to match:")
return errors.New("Gid failed to match")
}
return nil
}

View File

@@ -18,7 +18,7 @@ var MaxFilelist int64 = 100
// Request contains the data and state for the incoming service request.
type Request struct {
// Get, Put, Setstat, Stat, Rename, Remove
// Rmdir, Mkdir, List, Readlink, Symlink
// Rmdir, Mkdir, List, Readlink, Link, Symlink
Method string
Filepath string
Flags uint32
@@ -56,6 +56,8 @@ func requestFromPacket(ctx context.Context, pkt hasPath) *Request {
request.Target = cleanPath(p.Newpath)
case *sshFxpSymlinkPacket:
request.Target = cleanPath(p.Linkpath)
case *sshFxpExtendedPacketHardlink:
request.Target = cleanPath(p.Newpath)
}
return request
}
@@ -158,7 +160,7 @@ func (r *Request) call(handlers Handlers, pkt requestPacket) responsePacket {
return fileget(handlers.FileGet, r, pkt)
case "Put":
return fileput(handlers.FilePut, r, pkt)
case "Setstat", "Rename", "Rmdir", "Mkdir", "Symlink", "Remove":
case "Setstat", "Rename", "Rmdir", "Mkdir", "Link", "Symlink", "Remove":
return filecmd(handlers.FileCmd, r, pkt)
case "List":
return filelist(handlers.FileList, r, pkt)
@@ -378,6 +380,8 @@ func requestMethod(p requestPacket) (method string) {
method = "Readlink"
case *sshFxpMkdirPacket:
method = "Mkdir"
case *sshFxpExtendedPacketHardlink:
method = "Link"
}
return method
}

100
vendor/github.com/pkg/sftp/server.go generated vendored
View File

@@ -18,6 +18,7 @@ import (
)
const (
// SftpServerWorkerCount defines the number of workers for the SFTP server
SftpServerWorkerCount = 8
)
@@ -141,7 +142,7 @@ func (svr *Server) sftpServerWorker(pktChan chan orderedRequest) error {
if !readonly && svr.readOnly {
svr.sendPacket(orderedResponse{
responsePacket: statusFromError(pkt, syscall.EPERM),
orderid: pkt.orderId()})
orderid: pkt.orderID()})
continue
}
@@ -156,7 +157,10 @@ func handlePacket(s *Server, p orderedRequest) error {
var rpkt responsePacket
switch p := p.requestPacket.(type) {
case *sshFxInitPacket:
rpkt = sshFxVersionPacket{Version: sftpProtocolVersion}
rpkt = sshFxVersionPacket{
Version: sftpProtocolVersion,
Extensions: sftpExtensions,
}
case *sshFxpStatPacket:
// stat the requested file
info, err := os.Stat(p.Path)
@@ -246,7 +250,7 @@ func handlePacket(s *Server, p orderedRequest) error {
rpkt = sshFxpOpenPacket{
ID: p.ID,
Path: p.Path,
Pflags: ssh_FXF_READ,
Pflags: sshFxfRead,
}.respond(s)
}
case *sshFxpReadPacket:
@@ -276,13 +280,19 @@ func handlePacket(s *Server, p orderedRequest) error {
_, err = f.WriteAt(p.Data, int64(p.Offset))
}
rpkt = statusFromError(p, err)
case *sshFxpExtendedPacket:
if p.SpecificPacket == nil {
rpkt = statusFromError(p, ErrSSHFxOpUnsupported)
} else {
rpkt = p.respond(s)
}
case serverRespondablePacket:
rpkt = p.respond(s)
default:
return errors.Errorf("unexpected packet type %T", p)
}
s.pktMgr.readyPacket(s.pktMgr.newOrderedResponse(rpkt, p.orderId()))
s.pktMgr.readyPacket(s.pktMgr.newOrderedResponse(rpkt, p.orderID()))
return nil
}
@@ -315,11 +325,11 @@ func (svr *Server) Serve() error {
if err != nil {
switch errors.Cause(err) {
case errUnknownExtendedPacket:
if err := svr.serverConn.sendError(pkt, ErrSshFxOpUnsupported); err != nil {
debug("failed to send err packet: %v", err)
svr.conn.Close() // shuts down recvPacket
break
}
//if err := svr.serverConn.sendError(pkt, ErrSshFxOpUnsupported); err != nil {
// debug("failed to send err packet: %v", err)
// svr.conn.Close() // shuts down recvPacket
// break
//}
default:
debug("makePacket err: %v", err)
svr.conn.Close() // shuts down recvPacket
@@ -354,7 +364,7 @@ type sshFxpStatResponse struct {
}
func (p sshFxpStatResponse) MarshalBinary() ([]byte, error) {
b := []byte{ssh_FXP_ATTRS}
b := []byte{sshFxpAttrs}
b = marshalUint32(b, p.ID)
b = marshalFileInfo(b, p.info)
return b, nil
@@ -363,7 +373,7 @@ func (p sshFxpStatResponse) MarshalBinary() ([]byte, error) {
var emptyFileStat = []interface{}{uint32(0)}
func (p sshFxpOpenPacket) readonly() bool {
return !p.hasPflags(ssh_FXF_WRITE)
return !p.hasPflags(sshFxfWrite)
}
func (p sshFxpOpenPacket) hasPflags(flags ...uint32) bool {
@@ -377,27 +387,27 @@ func (p sshFxpOpenPacket) hasPflags(flags ...uint32) bool {
func (p sshFxpOpenPacket) respond(svr *Server) responsePacket {
var osFlags int
if p.hasPflags(ssh_FXF_READ, ssh_FXF_WRITE) {
if p.hasPflags(sshFxfRead, sshFxfWrite) {
osFlags |= os.O_RDWR
} else if p.hasPflags(ssh_FXF_WRITE) {
} else if p.hasPflags(sshFxfWrite) {
osFlags |= os.O_WRONLY
} else if p.hasPflags(ssh_FXF_READ) {
} else if p.hasPflags(sshFxfRead) {
osFlags |= os.O_RDONLY
} else {
// how are they opening?
return statusFromError(p, syscall.EINVAL)
}
if p.hasPflags(ssh_FXF_APPEND) {
osFlags |= os.O_APPEND
}
if p.hasPflags(ssh_FXF_CREAT) {
// Don't use O_APPEND flag as it conflicts with WriteAt.
// The sshFxfAppend flag is a no-op here as the client sends the offsets.
if p.hasPflags(sshFxfCreat) {
osFlags |= os.O_CREATE
}
if p.hasPflags(ssh_FXF_TRUNC) {
if p.hasPflags(sshFxfTrunc) {
osFlags |= os.O_TRUNC
}
if p.hasPflags(ssh_FXF_EXCL) {
if p.hasPflags(sshFxfExcl) {
osFlags |= os.O_EXCL
}
@@ -439,19 +449,19 @@ func (p sshFxpSetstatPacket) respond(svr *Server) responsePacket {
var err error
debug("setstat name \"%s\"", p.Path)
if (p.Flags & ssh_FILEXFER_ATTR_SIZE) != 0 {
if (p.Flags & sshFileXferAttrSize) != 0 {
var size uint64
if size, b, err = unmarshalUint64Safe(b); err == nil {
err = os.Truncate(p.Path, int64(size))
}
}
if (p.Flags & ssh_FILEXFER_ATTR_PERMISSIONS) != 0 {
if (p.Flags & sshFileXferAttrPermissions) != 0 {
var mode uint32
if mode, b, err = unmarshalUint32Safe(b); err == nil {
err = os.Chmod(p.Path, os.FileMode(mode))
}
}
if (p.Flags & ssh_FILEXFER_ATTR_ACMODTIME) != 0 {
if (p.Flags & sshFileXferAttrACmodTime) != 0 {
var atime uint32
var mtime uint32
if atime, b, err = unmarshalUint32Safe(b); err != nil {
@@ -462,7 +472,7 @@ func (p sshFxpSetstatPacket) respond(svr *Server) responsePacket {
err = os.Chtimes(p.Path, atimeT, mtimeT)
}
}
if (p.Flags & ssh_FILEXFER_ATTR_UIDGID) != 0 {
if (p.Flags & sshFileXferAttrUIDGID) != 0 {
var uid uint32
var gid uint32
if uid, b, err = unmarshalUint32Safe(b); err != nil {
@@ -486,19 +496,19 @@ func (p sshFxpFsetstatPacket) respond(svr *Server) responsePacket {
var err error
debug("fsetstat name \"%s\"", f.Name())
if (p.Flags & ssh_FILEXFER_ATTR_SIZE) != 0 {
if (p.Flags & sshFileXferAttrSize) != 0 {
var size uint64
if size, b, err = unmarshalUint64Safe(b); err == nil {
err = f.Truncate(int64(size))
}
}
if (p.Flags & ssh_FILEXFER_ATTR_PERMISSIONS) != 0 {
if (p.Flags & sshFileXferAttrPermissions) != 0 {
var mode uint32
if mode, b, err = unmarshalUint32Safe(b); err == nil {
err = f.Chmod(os.FileMode(mode))
}
}
if (p.Flags & ssh_FILEXFER_ATTR_ACMODTIME) != 0 {
if (p.Flags & sshFileXferAttrACmodTime) != 0 {
var atime uint32
var mtime uint32
if atime, b, err = unmarshalUint32Safe(b); err != nil {
@@ -509,7 +519,7 @@ func (p sshFxpFsetstatPacket) respond(svr *Server) responsePacket {
err = os.Chtimes(f.Name(), atimeT, mtimeT)
}
}
if (p.Flags & ssh_FILEXFER_ATTR_UIDGID) != 0 {
if (p.Flags & sshFileXferAttrUIDGID) != 0 {
var uid uint32
var gid uint32
if uid, b, err = unmarshalUint32Safe(b); err != nil {
@@ -526,30 +536,30 @@ func (p sshFxpFsetstatPacket) respond(svr *Server) responsePacket {
func translateErrno(errno syscall.Errno) uint32 {
switch errno {
case 0:
return ssh_FX_OK
return sshFxOk
case syscall.ENOENT:
return ssh_FX_NO_SUCH_FILE
return sshFxNoSuchFile
case syscall.EPERM:
return ssh_FX_PERMISSION_DENIED
return sshFxPermissionDenied
}
return ssh_FX_FAILURE
return sshFxFailure
}
func statusFromError(p ider, err error) sshFxpStatusPacket {
ret := sshFxpStatusPacket{
ID: p.id(),
StatusError: StatusError{
// ssh_FX_OK = 0
// ssh_FX_EOF = 1
// ssh_FX_NO_SUCH_FILE = 2 ENOENT
// ssh_FX_PERMISSION_DENIED = 3
// ssh_FX_FAILURE = 4
// ssh_FX_BAD_MESSAGE = 5
// ssh_FX_NO_CONNECTION = 6
// ssh_FX_CONNECTION_LOST = 7
// ssh_FX_OP_UNSUPPORTED = 8
Code: ssh_FX_OK,
// sshFXOk = 0
// sshFXEOF = 1
// sshFXNoSuchFile = 2 ENOENT
// sshFXPermissionDenied = 3
// sshFXFailure = 4
// sshFXBadMessage = 5
// sshFXNoConnection = 6
// sshFXConnectionLost = 7
// sshFXOPUnsupported = 8
Code: sshFxOk,
},
}
if err == nil {
@@ -557,7 +567,7 @@ func statusFromError(p ider, err error) sshFxpStatusPacket {
}
debug("statusFromError: error is %T %#v", err, err)
ret.StatusError.Code = ssh_FX_FAILURE
ret.StatusError.Code = sshFxFailure
ret.StatusError.msg = err.Error()
switch e := err.(type) {
@@ -573,9 +583,9 @@ func statusFromError(p ider, err error) sshFxpStatusPacket {
default:
switch e {
case io.EOF:
ret.StatusError.Code = ssh_FX_EOF
ret.StatusError.Code = sshFxEOF
case os.ErrNotExist:
ret.StatusError.Code = ssh_FX_NO_SUCH_FILE
ret.StatusError.Code = sshFxNoSuchFile
}
}

246
vendor/github.com/pkg/sftp/sftp.go generated vendored
View File

@@ -9,139 +9,148 @@ import (
)
const (
ssh_FXP_INIT = 1
ssh_FXP_VERSION = 2
ssh_FXP_OPEN = 3
ssh_FXP_CLOSE = 4
ssh_FXP_READ = 5
ssh_FXP_WRITE = 6
ssh_FXP_LSTAT = 7
ssh_FXP_FSTAT = 8
ssh_FXP_SETSTAT = 9
ssh_FXP_FSETSTAT = 10
ssh_FXP_OPENDIR = 11
ssh_FXP_READDIR = 12
ssh_FXP_REMOVE = 13
ssh_FXP_MKDIR = 14
ssh_FXP_RMDIR = 15
ssh_FXP_REALPATH = 16
ssh_FXP_STAT = 17
ssh_FXP_RENAME = 18
ssh_FXP_READLINK = 19
ssh_FXP_SYMLINK = 20
ssh_FXP_STATUS = 101
ssh_FXP_HANDLE = 102
ssh_FXP_DATA = 103
ssh_FXP_NAME = 104
ssh_FXP_ATTRS = 105
ssh_FXP_EXTENDED = 200
ssh_FXP_EXTENDED_REPLY = 201
sshFxpInit = 1
sshFxpVersion = 2
sshFxpOpen = 3
sshFxpClose = 4
sshFxpRead = 5
sshFxpWrite = 6
sshFxpLstat = 7
sshFxpFstat = 8
sshFxpSetstat = 9
sshFxpFsetstat = 10
sshFxpOpendir = 11
sshFxpReaddir = 12
sshFxpRemove = 13
sshFxpMkdir = 14
sshFxpRmdir = 15
sshFxpRealpath = 16
sshFxpStat = 17
sshFxpRename = 18
sshFxpReadlink = 19
sshFxpSymlink = 20
sshFxpStatus = 101
sshFxpHandle = 102
sshFxpData = 103
sshFxpName = 104
sshFxpAttrs = 105
sshFxpExtended = 200
sshFxpExtendedReply = 201
)
const (
ssh_FX_OK = 0
ssh_FX_EOF = 1
ssh_FX_NO_SUCH_FILE = 2
ssh_FX_PERMISSION_DENIED = 3
ssh_FX_FAILURE = 4
ssh_FX_BAD_MESSAGE = 5
ssh_FX_NO_CONNECTION = 6
ssh_FX_CONNECTION_LOST = 7
ssh_FX_OP_UNSUPPORTED = 8
sshFxOk = 0
sshFxEOF = 1
sshFxNoSuchFile = 2
sshFxPermissionDenied = 3
sshFxFailure = 4
sshFxBadMessage = 5
sshFxNoConnection = 6
sshFxConnectionLost = 7
sshFxOPUnsupported = 8
// see draft-ietf-secsh-filexfer-13
// https://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.1
ssh_FX_INVALID_HANDLE = 9
ssh_FX_NO_SUCH_PATH = 10
ssh_FX_FILE_ALREADY_EXISTS = 11
ssh_FX_WRITE_PROTECT = 12
ssh_FX_NO_MEDIA = 13
ssh_FX_NO_SPACE_ON_FILESYSTEM = 14
ssh_FX_QUOTA_EXCEEDED = 15
ssh_FX_UNKNOWN_PRINCIPAL = 16
ssh_FX_LOCK_CONFLICT = 17
ssh_FX_DIR_NOT_EMPTY = 18
ssh_FX_NOT_A_DIRECTORY = 19
ssh_FX_INVALID_FILENAME = 20
ssh_FX_LINK_LOOP = 21
ssh_FX_CANNOT_DELETE = 22
ssh_FX_INVALID_PARAMETER = 23
ssh_FX_FILE_IS_A_DIRECTORY = 24
ssh_FX_BYTE_RANGE_LOCK_CONFLICT = 25
ssh_FX_BYTE_RANGE_LOCK_REFUSED = 26
ssh_FX_DELETE_PENDING = 27
ssh_FX_FILE_CORRUPT = 28
ssh_FX_OWNER_INVALID = 29
ssh_FX_GROUP_INVALID = 30
ssh_FX_NO_MATCHING_BYTE_RANGE_LOCK = 31
sshFxInvalidHandle = 9
sshFxNoSuchPath = 10
sshFxFileAlreadyExists = 11
sshFxWriteProtect = 12
sshFxNoMedia = 13
sshFxNoSpaceOnFilesystem = 14
sshFxQuotaExceeded = 15
sshFxUnlnownPrincipal = 16
sshFxLockConflict = 17
sshFxDitNotEmpty = 18
sshFxNotADirectory = 19
sshFxInvalidFilename = 20
sshFxLinkLoop = 21
sshFxCannotDelete = 22
sshFxInvalidParameter = 23
sshFxFileIsADirectory = 24
sshFxByteRangeLockConflict = 25
sshFxByteRangeLockRefused = 26
sshFxDeletePending = 27
sshFxFileCorrupt = 28
sshFxOwnerInvalid = 29
sshFxGroupInvalid = 30
sshFxNoMatchingByteRangeLock = 31
)
const (
ssh_FXF_READ = 0x00000001
ssh_FXF_WRITE = 0x00000002
ssh_FXF_APPEND = 0x00000004
ssh_FXF_CREAT = 0x00000008
ssh_FXF_TRUNC = 0x00000010
ssh_FXF_EXCL = 0x00000020
sshFxfRead = 0x00000001
sshFxfWrite = 0x00000002
sshFxfAppend = 0x00000004
sshFxfCreat = 0x00000008
sshFxfTrunc = 0x00000010
sshFxfExcl = 0x00000020
)
var (
// supportedSFTPExtensions defines the supported extensions
supportedSFTPExtensions = []sshExtensionPair{
{"hardlink@openssh.com", "1"},
{"posix-rename@openssh.com", "1"},
}
sftpExtensions = supportedSFTPExtensions
)
type fxp uint8
func (f fxp) String() string {
switch f {
case ssh_FXP_INIT:
case sshFxpInit:
return "SSH_FXP_INIT"
case ssh_FXP_VERSION:
case sshFxpVersion:
return "SSH_FXP_VERSION"
case ssh_FXP_OPEN:
case sshFxpOpen:
return "SSH_FXP_OPEN"
case ssh_FXP_CLOSE:
case sshFxpClose:
return "SSH_FXP_CLOSE"
case ssh_FXP_READ:
case sshFxpRead:
return "SSH_FXP_READ"
case ssh_FXP_WRITE:
case sshFxpWrite:
return "SSH_FXP_WRITE"
case ssh_FXP_LSTAT:
case sshFxpLstat:
return "SSH_FXP_LSTAT"
case ssh_FXP_FSTAT:
case sshFxpFstat:
return "SSH_FXP_FSTAT"
case ssh_FXP_SETSTAT:
case sshFxpSetstat:
return "SSH_FXP_SETSTAT"
case ssh_FXP_FSETSTAT:
case sshFxpFsetstat:
return "SSH_FXP_FSETSTAT"
case ssh_FXP_OPENDIR:
case sshFxpOpendir:
return "SSH_FXP_OPENDIR"
case ssh_FXP_READDIR:
case sshFxpReaddir:
return "SSH_FXP_READDIR"
case ssh_FXP_REMOVE:
case sshFxpRemove:
return "SSH_FXP_REMOVE"
case ssh_FXP_MKDIR:
case sshFxpMkdir:
return "SSH_FXP_MKDIR"
case ssh_FXP_RMDIR:
case sshFxpRmdir:
return "SSH_FXP_RMDIR"
case ssh_FXP_REALPATH:
case sshFxpRealpath:
return "SSH_FXP_REALPATH"
case ssh_FXP_STAT:
case sshFxpStat:
return "SSH_FXP_STAT"
case ssh_FXP_RENAME:
case sshFxpRename:
return "SSH_FXP_RENAME"
case ssh_FXP_READLINK:
case sshFxpReadlink:
return "SSH_FXP_READLINK"
case ssh_FXP_SYMLINK:
case sshFxpSymlink:
return "SSH_FXP_SYMLINK"
case ssh_FXP_STATUS:
case sshFxpStatus:
return "SSH_FXP_STATUS"
case ssh_FXP_HANDLE:
case sshFxpHandle:
return "SSH_FXP_HANDLE"
case ssh_FXP_DATA:
case sshFxpData:
return "SSH_FXP_DATA"
case ssh_FXP_NAME:
case sshFxpName:
return "SSH_FXP_NAME"
case ssh_FXP_ATTRS:
case sshFxpAttrs:
return "SSH_FXP_ATTRS"
case ssh_FXP_EXTENDED:
case sshFxpExtended:
return "SSH_FXP_EXTENDED"
case ssh_FXP_EXTENDED_REPLY:
case sshFxpExtendedReply:
return "SSH_FXP_EXTENDED_REPLY"
default:
return "unknown"
@@ -152,23 +161,23 @@ type fx uint8
func (f fx) String() string {
switch f {
case ssh_FX_OK:
case sshFxOk:
return "SSH_FX_OK"
case ssh_FX_EOF:
case sshFxEOF:
return "SSH_FX_EOF"
case ssh_FX_NO_SUCH_FILE:
case sshFxNoSuchFile:
return "SSH_FX_NO_SUCH_FILE"
case ssh_FX_PERMISSION_DENIED:
case sshFxPermissionDenied:
return "SSH_FX_PERMISSION_DENIED"
case ssh_FX_FAILURE:
case sshFxFailure:
return "SSH_FX_FAILURE"
case ssh_FX_BAD_MESSAGE:
case sshFxBadMessage:
return "SSH_FX_BAD_MESSAGE"
case ssh_FX_NO_CONNECTION:
case sshFxNoConnection:
return "SSH_FX_NO_CONNECTION"
case ssh_FX_CONNECTION_LOST:
case sshFxConnectionLost:
return "SSH_FX_CONNECTION_LOST"
case ssh_FX_OP_UNSUPPORTED:
case sshFxOPUnsupported:
return "SSH_FX_OP_UNSUPPORTED"
default:
return "unknown"
@@ -214,4 +223,37 @@ type StatusError struct {
msg, lang string
}
func (s *StatusError) Error() string { return fmt.Sprintf("sftp: %q (%v)", s.msg, fx(s.Code)) }
func (s *StatusError) Error() string {
return fmt.Sprintf("sftp: %q (%v)", s.msg, fx(s.Code))
}
// FxCode returns the error code typed to match against the exported codes
func (s *StatusError) FxCode() fxerr {
return fxerr(s.Code)
}
func getSupportedExtensionByName(extensionName string) (sshExtensionPair, error) {
for _, supportedExtension := range supportedSFTPExtensions {
if supportedExtension.Name == extensionName {
return supportedExtension, nil
}
}
return sshExtensionPair{}, fmt.Errorf("Unsupported extension: %v", extensionName)
}
// SetSFTPExtensions allows to customize the supported server extensions.
// See the variable supportedSFTPExtensions for supported extensions.
// This method accepts a slice of sshExtensionPair names for example 'hardlink@openssh.com'.
// If an invalid extension is given an error will be returned and nothing will be changed
func SetSFTPExtensions(extensions ...string) error {
tempExtensions := []sshExtensionPair{}
for _, extension := range extensions {
sftpExtension, err := getSupportedExtensionByName(extension)
if err != nil {
return err
}
tempExtensions = append(tempExtensions, sftpExtension)
}
sftpExtensions = tempExtensions
return nil
}

9
vendor/github.com/pkg/sftp/syscall_fixed.go generated vendored Normal file
View File

@@ -0,0 +1,9 @@
// +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

8
vendor/github.com/pkg/sftp/syscall_good.go generated vendored Normal file
View File

@@ -0,0 +1,8 @@
// +build !plan9,!windows
// +build !js !wasm
package sftp
import "syscall"
const S_IFMT = syscall.S_IFMT