Skip to content

Commit 19bfb49

Browse files
authored
Merge pull request #618 from pkg/v1-backport-client-remove-and-fsync
Backport v2/Client.Remove and File.Sync
2 parents 5b63029 + eea14d0 commit 19bfb49

File tree

2 files changed

+58
-14
lines changed

2 files changed

+58
-14
lines changed

client.go

+57-13
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import (
1717

1818
"github.com/kr/fs"
1919
"golang.org/x/crypto/ssh"
20+
21+
"github.com/pkg/sftp/internal/encoding/ssh/filexfer/openssh"
2022
)
2123

2224
var (
@@ -758,20 +760,39 @@ func (c *Client) Join(elem ...string) string { return path.Join(elem...) }
758760
// file or directory with the specified path exists, or if the specified directory
759761
// is not empty.
760762
func (c *Client) Remove(path string) error {
761-
err := c.removeFile(path)
762-
// some servers, *cough* osx *cough*, return EPERM, not ENODIR.
763-
// serv-u returns ssh_FX_FILE_IS_A_DIRECTORY
764-
// EPERM is converted to os.ErrPermission so it is not a StatusError
765-
if err, ok := err.(*StatusError); ok {
766-
switch err.Code {
767-
case sshFxFailure, sshFxFileIsADirectory:
768-
return c.RemoveDirectory(path)
763+
errF := c.removeFile(path)
764+
if errF == nil {
765+
return nil
766+
}
767+
768+
errD := c.RemoveDirectory(path)
769+
if errD == nil {
770+
return nil
771+
}
772+
773+
// Both failed: figure out which error to return.
774+
775+
if errF, ok := errF.(*os.PathError); ok {
776+
// The only time it makes sense to compare errors, is when both are `*os.PathError`.
777+
// We cannot test these directly with errF == errD, as that would be a pointer comparison.
778+
779+
if errD, ok := errD.(*os.PathError); ok && errors.Is(errF.Err, errD.Err) {
780+
// If they are both pointers to PathError,
781+
// and the same underlying error, then return that.
782+
return errF
769783
}
770784
}
771-
if os.IsPermission(err) {
772-
return c.RemoveDirectory(path)
785+
786+
fi, err := c.Stat(path)
787+
if err != nil {
788+
return err
773789
}
774-
return err
790+
791+
if fi.IsDir() {
792+
return errD
793+
}
794+
795+
return errF
775796
}
776797

777798
func (c *Client) removeFile(path string) error {
@@ -785,7 +806,15 @@ func (c *Client) removeFile(path string) error {
785806
}
786807
switch typ {
787808
case sshFxpStatus:
788-
return normaliseError(unmarshalStatus(id, data))
809+
err = normaliseError(unmarshalStatus(id, data))
810+
if err == nil {
811+
return nil
812+
}
813+
return &os.PathError{
814+
Op: "remove",
815+
Path: path,
816+
Err: err,
817+
}
789818
default:
790819
return unimplementedPacketErr(typ)
791820
}
@@ -803,7 +832,15 @@ func (c *Client) RemoveDirectory(path string) error {
803832
}
804833
switch typ {
805834
case sshFxpStatus:
806-
return normaliseError(unmarshalStatus(id, data))
835+
err = normaliseError(unmarshalStatus(id, data))
836+
if err == nil {
837+
return nil
838+
}
839+
return &os.PathError{
840+
Op: "remove",
841+
Path: path,
842+
Err: err,
843+
}
807844
default:
808845
return unimplementedPacketErr(typ)
809846
}
@@ -2122,6 +2159,13 @@ func (f *File) Sync() error {
21222159
return os.ErrClosed
21232160
}
21242161

2162+
if data, ok := f.c.HasExtension(openssh.ExtensionFSync().Name); !ok || data != "1" {
2163+
return &StatusError{
2164+
Code: sshFxOPUnsupported,
2165+
msg: "fsync not supported",
2166+
}
2167+
}
2168+
21252169
id := f.c.nextID()
21262170
typ, data, err := f.c.sendPacket(context.Background(), nil, &sshFxpFsyncPacket{
21272171
ID: id,

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ require (
66
github.com/kr/fs v0.1.0
77
github.com/stretchr/testify v1.8.0
88
golang.org/x/crypto v0.31.0
9-
golang.org/x/sys v0.28.0 // indirect
9+
golang.org/x/sys v0.28.0
1010
)

0 commit comments

Comments
 (0)