Repository: pkg/sftp (go)

Issue:
Creating file on AWS SFTP managed services always get "Cannot open file in mode: WRITE|TRUNCATE|CREATE|READ" (SSH_FX_OP_UNSUPPORTED)
When using AWS SFTP managed services, sftp client always failed to create files. Create function (`client.Create()` ) always returned error with message "Cannot open file in mode: WRITE|TRUNCATE|CREATE|READ" (SSH_FX_OP_UNSUPPORTED).

This error only happened on AWS SFTP managed services. Regular SFTP server has no issue. The same endpoint were tested using sftp command, FileZilla and even .Net sftp library and all working normally. Only go sftp package were returned the error. 



Pull request description:
Issue 305 client write
Fixes #305

Patch:
diff --git a/client.go b/client.go
index fff0cde..50c7dc3 100644
--- a/client.go
+++ b/client.go
@@ -167,6 +167,10 @@ type Client struct {
 // 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))
 }
diff --git a/sftp.go b/sftp.go
index e360d8a..fe3d6bf 100644
--- a/sftp.go
+++ b/sftp.go
@@ -219,4 +219,11 @@ 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)
+}


Test patch:
diff --git a/sftp_test.go b/sftp_test.go
new file mode 100644
index 0000000..42d5ba5
--- /dev/null
+++ b/sftp_test.go
@@ -0,0 +1,28 @@
+package sftp
+
+import (
+	"io"
+	"syscall"
+	"testing"
+
+	"github.com/pkg/errors"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestErrFxCode(t *testing.T) {
+	ider := sshFxpStatusPacket{ID: 1}
+	table := []struct {
+		err error
+		fx  fxerr
+	}{
+		{err: errors.New("random error"), fx: ErrSSHFxFailure},
+		{err: syscall.EBADF, fx: ErrSSHFxFailure},
+		{err: syscall.ENOENT, fx: ErrSSHFxNoSuchFile},
+		{err: syscall.EPERM, fx: ErrSSHFxPermissionDenied},
+		{err: io.EOF, fx: ErrSSHFxEOF},
+	}
+	for _, tt := range table {
+		statusErr := statusFromError(ider, tt.err).StatusError
+		assert.Equal(t, statusErr.FxCode(), tt.fx)
+	}
+}