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.
This commit is contained in:
nielash 2024-02-18 05:03:39 -05:00 committed by Nick Craig-Wood
parent db8fb5ceda
commit 9d2bd163c7
2 changed files with 80 additions and 27 deletions

View File

@ -437,23 +437,41 @@ func (f *Fs) Move(ctx context.Context, src fs.Object, remote string) (fs.Object,
return nil, fs.ErrorFileNameTooLong 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 var resp *http.Response
response := moveCopyFileResponse{} response := moveCopyFileResponse{}
err = f.pacer.Call(func() (bool, error) { err = f.pacer.Call(func() (bool, error) {
copyFileData := moveCopyFile{ resp, err = f.srv.CallJSON(ctx, &opts, &request, &response)
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, &copyFileData, &response)
return f.shouldRetry(ctx, resp, err) return f.shouldRetry(ctx, resp, err)
}) })
if err != nil { if err != nil {
@ -482,27 +500,47 @@ func (f *Fs) DirMove(ctx context.Context, src fs.Fs, srcRemote, dstRemote string
return fs.ErrorCantDirMove 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 { if err != nil {
return err 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 // Do the move
var resp *http.Response var resp *http.Response
response := moveCopyFolderResponse{} response := moveCopyFolderResponse{}
err = f.pacer.Call(func() (bool, error) { err = f.pacer.Call(func() (bool, error) {
moveFolderData := moveCopyFolder{ resp, err = f.srv.CallJSON(ctx, &opts, &request, &response)
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)
return f.shouldRetry(ctx, resp, err) return f.shouldRetry(ctx, resp, err)
}) })
if err != nil { if err != nil {

View File

@ -100,6 +100,13 @@ type moveCopyFolder struct {
NewFolderName string `json:"new_folder_name"` // New name for destination folder. 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 { type moveCopyFolderResponse struct {
FolderID string `json:"FolderID"` FolderID string `json:"FolderID"`
} }
@ -146,6 +153,14 @@ type moveCopyFileResponse struct {
Size string `json:"Size"` 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 { type createFile struct {
SessionID string `json:"session_id"` SessionID string `json:"session_id"`
FolderID string `json:"folder_id"` FolderID string `json:"folder_id"`