فهرست منبع

check rename source and target

Nicola Murino 3 سال پیش
والد
کامیت
4d7a4aa99a
8فایلهای تغییر یافته به همراه44 افزوده شده و 9 حذف شده
  1. 3 0
      common/connection.go
  2. 8 0
      common/protocol_test.go
  3. 1 3
      ftpd/internal_test.go
  4. 1 1
      go.mod
  5. 2 2
      go.sum
  6. 2 0
      httpd/api_utils.go
  7. 22 2
      httpd/httpd_test.go
  8. 5 1
      templates/webclient/files.html

+ 3 - 0
common/connection.go

@@ -408,6 +408,9 @@ func (c *BaseConnection) RemoveDir(virtualPath string) error {
 
 // Rename renames (moves) virtualSourcePath to virtualTargetPath
 func (c *BaseConnection) Rename(virtualSourcePath, virtualTargetPath string) error {
+	if virtualSourcePath == virtualTargetPath {
+		return fmt.Errorf("the rename source and target cannot be the same: %w", c.GetOpUnsupportedError())
+	}
 	fsSrc, fsSourcePath, err := c.GetFsAndResolvedPath(virtualSourcePath)
 	if err != nil {
 		return err

+ 8 - 0
common/protocol_test.go

@@ -209,6 +209,10 @@ func TestBaseConnection(t *testing.T) {
 		if assert.NoError(t, err) {
 			assert.True(t, info.IsDir())
 		}
+		err = client.Rename(testDir, testDir)
+		if assert.Error(t, err) {
+			assert.Contains(t, err.Error(), "the rename source and target cannot be the same")
+		}
 		err = client.RemoveDirectory(testDir)
 		assert.NoError(t, err)
 		err = client.Remove(testFileName)
@@ -220,6 +224,10 @@ func TestBaseConnection(t *testing.T) {
 		err = f.Close()
 		assert.NoError(t, err)
 		linkName := testFileName + ".link"
+		err = client.Rename(testFileName, testFileName)
+		if assert.Error(t, err) {
+			assert.Contains(t, err.Error(), "the rename source and target cannot be the same")
+		}
 		err = client.Symlink(testFileName, linkName)
 		assert.NoError(t, err)
 		err = client.Symlink(testFileName, testFileName)

+ 1 - 3
ftpd/internal_test.go

@@ -648,9 +648,7 @@ func TestResolvePathErrors(t *testing.T) {
 		assert.EqualError(t, err, common.ErrGenericFailure.Error())
 	}
 	err = connection.Rename("", "")
-	if assert.Error(t, err) {
-		assert.EqualError(t, err, common.ErrGenericFailure.Error())
-	}
+	assert.ErrorIs(t, err, common.ErrOpUnsupported)
 	err = connection.Symlink("", "")
 	if assert.Error(t, err) {
 		assert.EqualError(t, err, common.ErrGenericFailure.Error())

+ 1 - 1
go.mod

@@ -140,7 +140,7 @@ require (
 
 replace (
 	github.com/eikenb/pipeat => github.com/drakkan/pipeat v0.0.0-20210805162858-70e57fa8a639
-	github.com/fclairamb/ftpserverlib => github.com/drakkan/ftpserverlib v0.0.0-20211107071448-34ff70e85dfb
+	github.com/fclairamb/ftpserverlib => github.com/drakkan/ftpserverlib v0.0.0-20211227100741-2a2e613fb19d
 	github.com/jlaffaye/ftp => github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9
 	golang.org/x/crypto => github.com/drakkan/crypto v0.0.0-20211216170250-0a05a5747f0f
 	golang.org/x/net => github.com/drakkan/net v0.0.0-20211210172952-3f0f9446f73f

+ 2 - 2
go.sum

@@ -227,8 +227,8 @@ github.com/drakkan/crypto v0.0.0-20211216170250-0a05a5747f0f h1:12WWFMrTzDfKo/7s
 github.com/drakkan/crypto v0.0.0-20211216170250-0a05a5747f0f/go.mod h1:SiM6ypd8Xu1xldObYtbDztuUU7xUzMnUULfphXFZmro=
 github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9 h1:LPH1dEblAOO/LoG7yHPMtBLXhQmjaga91/DDjWk9jWA=
 github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9/go.mod h1:2lmrmq866uF2tnje75wQHzmPXhmSWUt7Gyx2vgK1RCU=
-github.com/drakkan/ftpserverlib v0.0.0-20211107071448-34ff70e85dfb h1:cT/w4XStm7m022JgVqmrXZLcZ4UjoUER1VW5/5gd6ec=
-github.com/drakkan/ftpserverlib v0.0.0-20211107071448-34ff70e85dfb/go.mod h1:fBiQ19WDhtvKArMu0Pifg71k+0xqRYn+F0d9AsjkZw8=
+github.com/drakkan/ftpserverlib v0.0.0-20211227100741-2a2e613fb19d h1:md7VSy/KrGNBEy376AhmJJ7YzZ+f35Y7mZFMcM2qGmg=
+github.com/drakkan/ftpserverlib v0.0.0-20211227100741-2a2e613fb19d/go.mod h1:fBiQ19WDhtvKArMu0Pifg71k+0xqRYn+F0d9AsjkZw8=
 github.com/drakkan/net v0.0.0-20211210172952-3f0f9446f73f h1:8XuTk84FMb6DGc5MxmPkswjO5m4XFqGoZomO/Q8CUwQ=
 github.com/drakkan/net v0.0.0-20211210172952-3f0f9446f73f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 github.com/drakkan/pipeat v0.0.0-20210805162858-70e57fa8a639 h1:8tfGdb4kg/YCvAbIrsMazgoNtnqdOqQVDKW12uUCuuU=

+ 2 - 0
httpd/api_utils.go

@@ -101,6 +101,8 @@ func getMappedStatusCode(err error) int {
 		statusCode = http.StatusNotFound
 	case errors.Is(err, common.ErrQuotaExceeded):
 		statusCode = http.StatusRequestEntityTooLarge
+	case errors.Is(err, common.ErrOpUnsupported):
+		statusCode = http.StatusBadRequest
 	default:
 		statusCode = http.StatusInternalServerError
 	}

+ 22 - 2
httpd/httpd_test.go

@@ -9219,7 +9219,7 @@ func TestShareUploadSingle(t *testing.T) {
 	assert.NoError(t, err)
 	req.SetBasicAuth(defaultUsername, defaultPassword)
 	rr = executeRequest(req)
-	checkResponseCode(t, http.StatusInternalServerError, rr)
+	checkResponseCode(t, http.StatusBadRequest, rr)
 	assert.Contains(t, rr.Body.String(), "operation unsupported")
 
 	share, err = dataprovider.ShareExists(objectID, user.Username)
@@ -10240,6 +10240,19 @@ func TestWebDirsAPI(t *testing.T) {
 	if assert.Len(t, contents, 1) {
 		assert.Equal(t, testDir, contents[0]["name"])
 	}
+	// rename a dir with the same source and target name
+	req, err = http.NewRequest(http.MethodPatch, userDirsPath+"?path="+testDir+"&target="+testDir, nil)
+	assert.NoError(t, err)
+	setBearerForReq(req, webAPIToken)
+	rr = executeRequest(req)
+	checkResponseCode(t, http.StatusBadRequest, rr)
+	assert.Contains(t, rr.Body.String(), "operation unsupported")
+	req, err = http.NewRequest(http.MethodPatch, userDirsPath+"?path="+testDir+"&target=%2F"+testDir+"%2F", nil)
+	assert.NoError(t, err)
+	setBearerForReq(req, webAPIToken)
+	rr = executeRequest(req)
+	checkResponseCode(t, http.StatusBadRequest, rr)
+	assert.Contains(t, rr.Body.String(), "operation unsupported")
 	// create a dir with missing parents
 	req, err = http.NewRequest(http.MethodPost, userDirsPath+"?path="+url.QueryEscape(path.Join("/sub/dir", testDir)), nil)
 	assert.NoError(t, err)
@@ -10556,6 +10569,13 @@ func TestWebFilesAPI(t *testing.T) {
 	setBearerForReq(req, webAPIToken)
 	rr = executeRequest(req)
 	checkResponseCode(t, http.StatusNotFound, rr)
+	// rename a file with target name equal to source name
+	req, err = http.NewRequest(http.MethodPatch, userFilesPath+"?path=file1.txt&target=file1.txt", nil)
+	assert.NoError(t, err)
+	setBearerForReq(req, webAPIToken)
+	rr = executeRequest(req)
+	checkResponseCode(t, http.StatusBadRequest, rr)
+	assert.Contains(t, rr.Body.String(), "operation unsupported")
 	// delete a file
 	req, err = http.NewRequest(http.MethodDelete, userFilesPath+"?path=file2.txt", nil)
 	assert.NoError(t, err)
@@ -10717,7 +10737,7 @@ func TestWebUploadErrors(t *testing.T) {
 	req.Header.Add("Content-Type", writer.FormDataContentType())
 	setBearerForReq(req, webAPIToken)
 	rr = executeRequest(req)
-	checkResponseCode(t, http.StatusInternalServerError, rr)
+	checkResponseCode(t, http.StatusBadRequest, rr)
 	assert.Contains(t, rr.Body.String(), "operation unsupported")
 	// try to upload to a missing parent directory
 	_, err = reader.Seek(0, io.SeekStart)

+ 5 - 1
templates/webclient/files.html

@@ -541,6 +541,8 @@
                 spinnerDone = true;
                 if (!has_errors){
                     location.reload();
+                } else {
+                    table.button('delete:name').enable(true);
                 }
                 return;
             }
@@ -786,7 +788,9 @@
                     $('#errorMsg').show();
                     setTimeout(function () {
                         $('#errorMsg').hide();
-                    }, 5000);
+                    }, 8000);
+                    var selectedItems = table.column(0).checkboxes.selected().length;
+                    table.button('rename:name').enable(selectedItems == 1);
                 }
             });
         });