From f2ee949eff7ffcc2487ceffee061b6554a9297d1 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Fri, 11 Jun 2021 15:24:05 +0100 Subject: [PATCH] fichier: implement DirMove See: https://forum.rclone.org/t/1fichier-rclone-does-not-allow-to-rename-files-and-folders-when-you-mount-a-1fichier-disk-drive/24726/ --- backend/fichier/api.go | 26 +++++++++++++++++++++ backend/fichier/fichier.go | 46 ++++++++++++++++++++++++++++++++++++++ backend/fichier/structs.go | 16 +++++++++++++ 3 files changed, 88 insertions(+) diff --git a/backend/fichier/api.go b/backend/fichier/api.go index d75869a25..c0e3843dc 100644 --- a/backend/fichier/api.go +++ b/backend/fichier/api.go @@ -408,6 +408,32 @@ func (f *Fs) moveFile(ctx context.Context, url string, folderID int, rename stri return response, nil } +func (f *Fs) moveDir(ctx context.Context, folderID int, newLeaf string, destinationFolderID int) (response *MoveDirResponse, err error) { + request := &MoveDirRequest{ + FolderID: folderID, + DestinationFolderID: destinationFolderID, + Rename: newLeaf, + // DestinationUser: destinationUser, + } + + opts := rest.Opts{ + Method: "POST", + Path: "/folder/mv.cgi", + } + + response = &MoveDirResponse{} + err = f.pacer.Call(func() (bool, error) { + resp, err := f.rest.CallJSON(ctx, &opts, request, response) + return shouldRetry(ctx, resp, err) + }) + + if err != nil { + return nil, fmt.Errorf("couldn't move dir: %w", err) + } + + return response, nil +} + func (f *Fs) copyFile(ctx context.Context, url string, folderID int, rename string) (response *CopyFileResponse, err error) { request := &CopyFileRequest{ URLs: []string{url}, diff --git a/backend/fichier/fichier.go b/backend/fichier/fichier.go index 25df3d971..4a2caf5bf 100644 --- a/backend/fichier/fichier.go +++ b/backend/fichier/fichier.go @@ -488,6 +488,51 @@ func (f *Fs) Move(ctx context.Context, src fs.Object, remote string) (fs.Object, return dstObj, nil } +// DirMove moves src, srcRemote to this remote at dstRemote +// using server-side move operations. +// +// Will only be called if src.Fs().Name() == f.Name() +// +// If it isn't possible then return fs.ErrorCantDirMove. +// +// If destination exists then return fs.ErrorDirExists. +// +// This is complicated by the fact that we can't use moveDir to move +// to a different directory AND rename at the same time as it can +// overwrite files in the source directory. +func (f *Fs) DirMove(ctx context.Context, src fs.Fs, srcRemote, dstRemote string) error { + srcFs, ok := src.(*Fs) + if !ok { + fs.Debugf(srcFs, "Can't move directory - not same remote type") + return fs.ErrorCantDirMove + } + + srcID, _, _, dstDirectoryID, dstLeaf, err := f.dirCache.DirMove(ctx, srcFs.dirCache, srcFs.root, srcRemote, f.root, dstRemote) + if err != nil { + return err + } + srcIDnumeric, err := strconv.Atoi(srcID) + if err != nil { + return err + } + dstDirectoryIDnumeric, err := strconv.Atoi(dstDirectoryID) + if err != nil { + return err + } + + var resp *MoveDirResponse + resp, err = f.moveDir(ctx, srcIDnumeric, dstLeaf, dstDirectoryIDnumeric) + if err != nil { + return fmt.Errorf("couldn't rename leaf: %w", err) + } + if resp.Status != "OK" { + return fmt.Errorf("couldn't rename leaf: %s", resp.Message) + } + + srcFs.dirCache.FlushDir(srcRemote) + return nil +} + // Copy src to this remote using server side move operations. func (f *Fs) Copy(ctx context.Context, src fs.Object, remote string) (fs.Object, error) { srcObj, ok := src.(*Object) @@ -561,6 +606,7 @@ func (f *Fs) PublicLink(ctx context.Context, remote string, expire fs.Duration, var ( _ fs.Fs = (*Fs)(nil) _ fs.Mover = (*Fs)(nil) + _ fs.DirMover = (*Fs)(nil) _ fs.Copier = (*Fs)(nil) _ fs.PublicLinker = (*Fs)(nil) _ fs.PutUncheckeder = (*Fs)(nil) diff --git a/backend/fichier/structs.go b/backend/fichier/structs.go index aed910576..289aa64b7 100644 --- a/backend/fichier/structs.go +++ b/backend/fichier/structs.go @@ -70,6 +70,22 @@ type MoveFileResponse struct { URLs []string `json:"urls"` } +// MoveDirRequest is the request structure of the corresponding request +type MoveDirRequest struct { + FolderID int `json:"folder_id"` + DestinationFolderID int `json:"destination_folder_id,omitempty"` + DestinationUser string `json:"destination_user"` + Rename string `json:"rename,omitempty"` +} + +// MoveDirResponse is the response structure of the corresponding request +type MoveDirResponse struct { + Status string `json:"status"` + Message string `json:"message"` + OldName string `json:"old_name"` + NewName string `json:"new_name"` +} + // CopyFileRequest is the request structure of the corresponding request type CopyFileRequest struct { URLs []string `json:"urls"`