139 lines
3.5 KiB
Go
139 lines
3.5 KiB
Go
package fs
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"gosvc/logger"
|
|
"strings"
|
|
"time"
|
|
|
|
"robotfs/utils"
|
|
)
|
|
|
|
func (fs *FileSystem) RenameDirectory(ctx context.Context, oldPath, newPath utils.FullPath, isDir bool) error {
|
|
locker := fs.locker.AcquireOrderedLock(string(oldPath), string(newPath))
|
|
defer fs.locker.ReleaseLocks(locker)
|
|
|
|
if err := fs.canRename(oldPath, newPath, isDir); err != nil {
|
|
return err
|
|
}
|
|
|
|
oldEntry, err := fs.FindEntry(ctx, oldPath)
|
|
if err != nil {
|
|
return fmt.Errorf("%s not found: %v", oldPath, err)
|
|
}
|
|
|
|
moveErr := fs.moveEntry(ctx, oldPath, oldEntry, newPath)
|
|
if moveErr != nil {
|
|
return fmt.Errorf("%s move error: %v", oldPath, moveErr)
|
|
}
|
|
|
|
if err := utils.Move(fs.root, string(oldPath), string(newPath)); err != nil {
|
|
return fmt.Errorf("move file data failed: %v", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (fs *FileSystem) canRename(source, target utils.FullPath, isDir bool) error {
|
|
if string(source) == "/" {
|
|
return fmt.Errorf("mv: cannot move root directory")
|
|
}
|
|
|
|
if isDir && strings.HasPrefix(string(target), string(source)) {
|
|
return fmt.Errorf("mv: can not move directory to a subdirectory if itself")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (fs *FileSystem) moveEntry(ctx context.Context, oldPath utils.FullPath, entry *utils.Entry, newPath utils.FullPath) error {
|
|
if err := fs.moveSelfEntry(ctx, oldPath, entry, newPath, func() error {
|
|
if entry.IsDir {
|
|
if err := fs.moveFolderSubEntries(ctx, oldPath, newPath); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}); err != nil {
|
|
return fmt.Errorf("fail to move %s => %s: %v", oldPath, newPath, err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (fs *FileSystem) moveFolderSubEntries(ctx context.Context, oldPath utils.FullPath, newPath utils.FullPath) error {
|
|
logger.Info("moving folder %s => %s", oldPath, newPath)
|
|
|
|
lastFileName := ""
|
|
includeLastFile := false
|
|
for {
|
|
entries := make([]*utils.Entry, 0, 1000)
|
|
lastFileName, err := fs.doListDirectoryEntries(ctx, oldPath, lastFileName, includeLastFile, 1000, func(entry *utils.Entry) bool {
|
|
entries = append(entries, entry)
|
|
return true
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(entries) == 0 {
|
|
break
|
|
}
|
|
|
|
for _, item := range entries {
|
|
itemOldPath := oldPath.Child(item.FullPath.Name())
|
|
itemNewPath := newPath.Child(item.FullPath.Name())
|
|
err := fs.moveEntry(ctx, itemOldPath, item, itemNewPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if lastFileName == "" || len(entries) < 1000 {
|
|
break
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (fs *FileSystem) moveSelfEntry(ctx context.Context, oldPath utils.FullPath, entry *utils.Entry, newPath utils.FullPath, moveFolderSubEntries func() error) error {
|
|
logger.Info("moving entry %s => %s", oldPath, newPath)
|
|
|
|
if oldPath == newPath {
|
|
logger.Info("skip moving entry %s => %s", oldPath, newPath)
|
|
return nil
|
|
}
|
|
|
|
newEntry := &utils.Entry{
|
|
FullPath: newPath,
|
|
IsDir: entry.IsDir,
|
|
Size: entry.Size,
|
|
CreateTime: time.Now().Unix(),
|
|
S3Key: newPath.ToS3Key(),
|
|
ContentType: entry.ContentType,
|
|
Etag: entry.Etag,
|
|
VersionID: entry.VersionID,
|
|
LastModificationTime: time.Now().Unix(),
|
|
Extended: entry.Extended,
|
|
}
|
|
|
|
if updateErr := fs.meta.UpdateEntry(ctx, newEntry); updateErr != nil {
|
|
return updateErr
|
|
}
|
|
|
|
if moveFolderSubEntries != nil {
|
|
if moveChildrenErr := moveFolderSubEntries(); moveChildrenErr != nil {
|
|
return moveChildrenErr
|
|
}
|
|
}
|
|
|
|
deleteErr := fs.meta.DeleteEntry(ctx, oldPath)
|
|
if deleteErr != nil {
|
|
return deleteErr
|
|
}
|
|
|
|
return nil
|
|
}
|