From 9d2bd163c7e134dc3ec6e93622d9e893823e0e01 Mon Sep 17 00:00:00 2001 From: nielash Date: Sun, 18 Feb 2024 05:03:39 -0500 Subject: [PATCH] opendrive: fix moving file/folder within the same parent dir - #7591 Before this change, moving (renaming) a file or folder to a different name within the same parent directory would fail, due to using the wrong API operation ("/file/move_copy.json" and "/folder/move_copy.json", instead of the separate "/file/rename.json" and "/folder/rename.json" that opendrive has for this purpose.) After this change, Move and DirMove check whether the move is within the same parent dir. If so, "rename" is used. If not, "move_copy" is used, like before. --- backend/opendrive/opendrive.go | 92 ++++++++++++++++++++++++---------- backend/opendrive/types.go | 15 ++++++ 2 files changed, 80 insertions(+), 27 deletions(-) diff --git a/backend/opendrive/opendrive.go b/backend/opendrive/opendrive.go index 0b0ee2e9d..d73933980 100644 --- a/backend/opendrive/opendrive.go +++ b/backend/opendrive/opendrive.go @@ -437,23 +437,41 @@ func (f *Fs) Move(ctx context.Context, src fs.Object, remote string) (fs.Object, return nil, fs.ErrorFileNameTooLong } - // Copy the object + moveCopyFileData := moveCopyFile{ + SessionID: f.session.SessionID, + SrcFileID: srcObj.id, + DstFolderID: directoryID, + Move: "true", + OverwriteIfExists: "true", + NewFileName: leaf, + } + opts := rest.Opts{ + Method: "POST", + Path: "/file/move_copy.json", + } + var request interface{} = moveCopyFileData + + // use /file/rename.json if moving within the same directory + _, srcDirID, err := srcObj.fs.dirCache.FindPath(ctx, srcObj.remote, false) + if err != nil { + return nil, err + } + if srcDirID == directoryID { + fs.Debugf(src, "same parent dir (%v) - using file/rename instead of move_copy for %s", directoryID, remote) + renameFileData := renameFile{ + SessionID: f.session.SessionID, + FileID: srcObj.id, + NewFileName: leaf, + } + opts.Path = "/file/rename.json" + request = renameFileData + } + + // Move the object var resp *http.Response response := moveCopyFileResponse{} err = f.pacer.Call(func() (bool, error) { - copyFileData := moveCopyFile{ - SessionID: f.session.SessionID, - SrcFileID: srcObj.id, - DstFolderID: directoryID, - Move: "true", - OverwriteIfExists: "true", - NewFileName: leaf, - } - opts := rest.Opts{ - Method: "POST", - Path: "/file/move_copy.json", - } - resp, err = f.srv.CallJSON(ctx, &opts, ©FileData, &response) + resp, err = f.srv.CallJSON(ctx, &opts, &request, &response) return f.shouldRetry(ctx, resp, err) }) if err != nil { @@ -482,27 +500,47 @@ func (f *Fs) DirMove(ctx context.Context, src fs.Fs, srcRemote, dstRemote string return fs.ErrorCantDirMove } - srcID, _, _, dstDirectoryID, dstLeaf, err := f.dirCache.DirMove(ctx, srcFs.dirCache, srcFs.root, srcRemote, f.root, dstRemote) + srcID, srcDirectoryID, _, dstDirectoryID, dstLeaf, err := f.dirCache.DirMove(ctx, srcFs.dirCache, srcFs.root, srcRemote, f.root, dstRemote) if err != nil { return err } + // move_copy will silently truncate new filenames + if len(dstLeaf) > 255 { + fs.Debugf(src, "Can't move folder: name (%q) exceeds 255 char", dstLeaf) + return fs.ErrorFileNameTooLong + } + + moveFolderData := moveCopyFolder{ + SessionID: f.session.SessionID, + FolderID: srcID, + DstFolderID: dstDirectoryID, + Move: "true", + NewFolderName: dstLeaf, + } + opts := rest.Opts{ + Method: "POST", + Path: "/folder/move_copy.json", + } + var request interface{} = moveFolderData + + // use /folder/rename.json if moving within the same parent directory + if srcDirectoryID == dstDirectoryID { + fs.Debugf(dstRemote, "same parent dir (%v) - using folder/rename instead of move_copy", srcDirectoryID) + renameFolderData := renameFolder{ + SessionID: f.session.SessionID, + FolderID: srcID, + FolderName: dstLeaf, + } + opts.Path = "/folder/rename.json" + request = renameFolderData + } + // Do the move var resp *http.Response response := moveCopyFolderResponse{} err = f.pacer.Call(func() (bool, error) { - moveFolderData := moveCopyFolder{ - SessionID: f.session.SessionID, - FolderID: srcID, - DstFolderID: dstDirectoryID, - Move: "true", - NewFolderName: dstLeaf, - } - opts := rest.Opts{ - Method: "POST", - Path: "/folder/move_copy.json", - } - resp, err = f.srv.CallJSON(ctx, &opts, &moveFolderData, &response) + resp, err = f.srv.CallJSON(ctx, &opts, &request, &response) return f.shouldRetry(ctx, resp, err) }) if err != nil { diff --git a/backend/opendrive/types.go b/backend/opendrive/types.go index 4b68acbea..d47a35628 100644 --- a/backend/opendrive/types.go +++ b/backend/opendrive/types.go @@ -100,6 +100,13 @@ type moveCopyFolder struct { NewFolderName string `json:"new_folder_name"` // New name for destination folder. } +type renameFolder struct { + SessionID string `json:"session_id"` + FolderID string `json:"folder_id"` + FolderName string `json:"folder_name"` // New name for destination folder (max 255). + SharingID string `json:"sharing_id"` +} + type moveCopyFolderResponse struct { FolderID string `json:"FolderID"` } @@ -146,6 +153,14 @@ type moveCopyFileResponse struct { Size string `json:"Size"` } +type renameFile struct { + SessionID string `json:"session_id"` + NewFileName string `json:"new_file_name"` // New name for destination file. + FileID string `json:"file_id"` + AccessFolderID string `json:"access_folder_id"` + SharingID string `json:"sharing_id"` +} + type createFile struct { SessionID string `json:"session_id"` FolderID string `json:"folder_id"`