Browse Source

sftpd: document chmod/chown on Windows

chmod is partially supported and chown is not supported on Windows.

Skip unsupported test cases on Windows
Nicola Murino 5 years ago
parent
commit
fc442d7862
3 changed files with 66 additions and 11 deletions
  1. 2 2
      README.md
  2. 1 1
      sftpd/handler.go
  3. 63 8
      sftpd/sftpd_test.go

+ 2 - 2
README.md

@@ -365,8 +365,8 @@ For each account the following properties can be configured:
     - `rename` rename files or directories is allowed
     - `create_dirs` create directories is allowed
     - `create_symlinks` create symbolic links is allowed
-    - `chmod` changing file or directory permissions is allowed
-    - `chown` changing file or directory owner and group is allowed
+    - `chmod` changing file or directory permissions is allowed. On Windows, only the 0200 bit (owner writable) of mode is used; it controls whether the file's read-only attribute is set or cleared. The other bits are currently unused. Use mode 0400 for a read-only file and 0600 for a readable+writable file.
+    - `chown` changing file or directory owner and group is allowed. Changing owner and group is not supported on Windows.
 - `upload_bandwidth` maximum upload bandwidth as KB/s, 0 means unlimited.
 - `download_bandwidth` maximum download bandwidth as KB/s, 0 means unlimited.
 

+ 1 - 1
sftpd/handler.go

@@ -229,7 +229,7 @@ func (c Connection) Filelist(request *sftp.Request) (sftp.ListerAt, error) {
 			return nil, sftp.ErrSSHFxPermissionDenied
 		}
 
-		c.Log(logger.LevelDebug, logSender, "requested Stat for file: %#v", p)
+		c.Log(logger.LevelDebug, logSender, "requested stat for file: %#v", p)
 		s, err := os.Stat(p)
 		if err != nil {
 			c.Log(logger.LevelWarn, logSender, "error running Stat on file: %#v", err)

+ 63 - 8
sftpd/sftpd_test.go

@@ -519,6 +519,69 @@ func TestStat(t *testing.T) {
 		if err != nil {
 			t.Errorf("stat error: %v", err)
 		}
+		// mode 0666 and 0444 works on Windows too
+		newPerm := os.FileMode(0666)
+		err = client.Chmod(testFileName, newPerm)
+		if err != nil {
+			t.Errorf("chmod error: %v", err)
+		}
+		newFi, err := client.Lstat(testFileName)
+		if err != nil {
+			t.Errorf("stat error: %v", err)
+		}
+		if newPerm != newFi.Mode().Perm() {
+			t.Errorf("chmod failed expected: %v, actual: %v", newPerm, newFi.Mode().Perm())
+		}
+		newPerm = os.FileMode(0444)
+		err = client.Chmod(testFileName, newPerm)
+		if err != nil {
+			t.Errorf("chmod error: %v", err)
+		}
+		newFi, err = client.Lstat(testFileName)
+		if err != nil {
+			t.Errorf("stat error: %v", err)
+		}
+		if newPerm != newFi.Mode().Perm() {
+			t.Errorf("chmod failed expected: %v, actual: %v", newPerm, newFi.Mode().Perm())
+		}
+		_, err = client.ReadLink(testFileName)
+		if err == nil {
+			t.Errorf("readlink is not supported and must fail")
+		}
+		err = client.Chtimes(testFileName, time.Now(), time.Now())
+		if err != nil {
+			t.Errorf("chtime must be silently ignored: %v", err)
+		}
+	}
+	_, err = httpd.RemoveUser(user, http.StatusOK)
+	if err != nil {
+		t.Errorf("unable to remove user: %v", err)
+	}
+	os.RemoveAll(user.GetHomeDir())
+}
+
+func TestStatChownChmod(t *testing.T) {
+	if runtime.GOOS == "windows" {
+		t.Skip("chown is not supported on Windows, chmod is partially supported")
+	}
+	usePubKey := true
+	user, _, err := httpd.AddUser(getTestUser(usePubKey), http.StatusOK)
+	if err != nil {
+		t.Errorf("unable to add user: %v", err)
+	}
+	client, err := getSftpClient(user, usePubKey)
+	if err != nil {
+		t.Errorf("unable to create sftp client: %v", err)
+	} else {
+		defer client.Close()
+		testFileName := "test_file.dat"
+		testFilePath := filepath.Join(homeBasePath, testFileName)
+		testFileSize := int64(65535)
+		createTestFile(testFilePath, testFileSize)
+		err = sftpUploadFile(testFilePath, testFileName, testFileSize, client)
+		if err != nil {
+			t.Errorf("file upload error: %v", err)
+		}
 		err = client.Chown(testFileName, os.Getuid(), os.Getgid())
 		if err != nil {
 			t.Errorf("chown error: %v", err)
@@ -535,10 +598,6 @@ func TestStat(t *testing.T) {
 		if newPerm != newFi.Mode().Perm() {
 			t.Errorf("chown failed expected: %v, actual: %v", newPerm, newFi.Mode().Perm())
 		}
-		_, err = client.ReadLink(testFileName)
-		if err == nil {
-			t.Errorf("readlink is not supported and must fail")
-		}
 		err = client.Remove(testFileName)
 		if err != nil {
 			t.Errorf("error removing uploaded file: %v", err)
@@ -552,10 +611,6 @@ func TestStat(t *testing.T) {
 		if err != os.ErrNotExist {
 			t.Errorf("unexpected chown error: %v expected: %v", err, os.ErrNotExist)
 		}
-		err = client.Chtimes(testFileName, time.Now(), time.Now())
-		if err != nil {
-			t.Errorf("chtime must be silently ignored: %v", err)
-		}
 	}
 	_, err = httpd.RemoveUser(user, http.StatusOK)
 	if err != nil {