package engine import ( "context" "fmt" "gosvc/logger" "strings" "time" "robotfs/utils" ) func (f *FileSystemManager) RenameDirectory(ctx context.Context, oldPath, newPath utils.FullPath, isDir bool) error { f.Lock() defer f.Unlock() if err := f.canRename(oldPath, newPath, isDir); err != nil { return err } oldEntry, err := f.FindEntry(ctx, oldPath) if err != nil { return fmt.Errorf("%s not found: %v", oldPath, err) } moveErr := f.moveEntry(ctx, oldPath, oldEntry, newPath) if moveErr != nil { return fmt.Errorf("%s move error: %v", oldPath, moveErr) } if err := utils.Move(f.root, string(oldPath), string(newPath)); err != nil { return fmt.Errorf("move file data failed: %v", err) } return nil } func (f *FileSystemManager) 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 (f *FileSystemManager) moveEntry(ctx context.Context, oldPath utils.FullPath, entry *utils.Entry, newPath utils.FullPath) error { if err := f.moveSelfEntry(ctx, oldPath, entry, newPath, func() error { if entry.IsDir { if err := f.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 (f *FileSystemManager) 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 := f.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 := f.moveEntry(ctx, itemOldPath, item, itemNewPath) if err != nil { return err } } if lastFileName == "" || len(entries) < 1000 { break } } return nil } func (f *FileSystemManager) 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: entry.S3Key, ContentType: entry.ContentType, Etag: entry.Etag, VersionID: entry.VersionID, LastModificationTime: time.Now().Unix(), Extended: entry.Extended, } if createErr := f.meta.InsertEntry(ctx, newEntry); createErr != nil { return createErr } if moveFolderSubEntries != nil { if moveChildrenErr := moveFolderSubEntries(); moveChildrenErr != nil { return moveChildrenErr } } deleteErr := f.meta.DeleteEntry(ctx, oldPath) if deleteErr != nil { return deleteErr } return nil }