diff --git a/models/folder.go b/models/folder.go index ebc1069..80f712c 100644 --- a/models/folder.go +++ b/models/folder.go @@ -18,7 +18,8 @@ type Folder struct { OwnerID uint `gorm:"index:owner_id"` // 数据库忽略字段 - Position string `gorm:"-"` + Position string `gorm:"-"` + WebdavDstName string `gorm:"-"` } // Create 创建目录 @@ -169,6 +170,11 @@ func (folder *Folder) MoveOrCopyFileTo(files []uint, dstFolder *Folder, isCopy b oldFile.FolderID = dstFolder.ID oldFile.UserID = dstFolder.OwnerID + // webdav目标名重置 + if dstFolder.WebdavDstName != "" { + oldFile.Name = dstFolder.WebdavDstName + } + if err := DB.Create(&oldFile).Error; err != nil { return copiedSize, err } @@ -177,6 +183,14 @@ func (folder *Folder) MoveOrCopyFileTo(files []uint, dstFolder *Folder, isCopy b } } else { + var updates = map[string]interface{}{ + "folder_id": dstFolder.ID, + } + // webdav目标名重置 + if dstFolder.WebdavDstName != "" { + updates["name"] = dstFolder.WebdavDstName + } + // 更改顶级要移动文件的父目录指向 err := DB.Model(File{}).Where( "id in (?) and user_id = ? and folder_id = ?", @@ -184,9 +198,7 @@ func (folder *Folder) MoveOrCopyFileTo(files []uint, dstFolder *Folder, isCopy b folder.OwnerID, folder.ID, ). - Update(map[string]interface{}{ - "folder_id": dstFolder.ID, - }). + Update(updates). Error if err != nil { return 0, err @@ -221,6 +233,10 @@ func (folder *Folder) CopyFolderTo(folderID uint, dstFolder *Folder) (size uint6 // 顶级目录直接指向新的目的目录 if folder.ID == folderID { newID = dstFolder.ID + // webdav目标名重置 + if dstFolder.WebdavDstName != "" { + folder.Name = dstFolder.WebdavDstName + } } else if IDCache, ok := newIDCache[*folder.ParentID]; ok { newID = IDCache } else { @@ -282,15 +298,21 @@ func (folder *Folder) MoveFolderTo(dirs []uint, dstFolder *Folder) error { return errors.New("cannot move a folder into itself") } + var updates = map[string]interface{}{ + "parent_id": dstFolder.ID, + } + // webdav目标名重置 + if dstFolder.WebdavDstName != "" { + updates["name"] = dstFolder.WebdavDstName + } + // 更改顶级要移动目录的父目录指向 err := DB.Model(Folder{}).Where( "id in (?) and owner_id = ? and parent_id = ?", dirs, folder.OwnerID, folder.ID, - ).Update(map[string]interface{}{ - "parent_id": dstFolder.ID, - }).Error + ).Update(updates).Error return err diff --git a/pkg/filesystem/fsctx/context.go b/pkg/filesystem/fsctx/context.go index 942551c..3c6445d 100644 --- a/pkg/filesystem/fsctx/context.go +++ b/pkg/filesystem/fsctx/context.go @@ -35,4 +35,6 @@ const ( CancelFuncCtx // 文件在从机节点中的路径 SlaveSrcPath + // Webdav目标名称 + WebdavDstName ) diff --git a/pkg/filesystem/manage.go b/pkg/filesystem/manage.go index acf739c..c77c9d9 100644 --- a/pkg/filesystem/manage.go +++ b/pkg/filesystem/manage.go @@ -69,6 +69,11 @@ func (fs *FileSystem) Copy(ctx context.Context, dirs, files []uint, src, dst str // 记录复制的文件的总容量 var newUsedStorage uint64 + // 设置webdav目标名 + if dstName, ok := ctx.Value(fsctx.WebdavDstName).(string); ok { + dstFolder.WebdavDstName = dstName + } + // 复制目录 if len(dirs) > 0 { subFileSizes, err := srcFolder.CopyFolderTo(dirs[0], dstFolder) @@ -103,6 +108,11 @@ func (fs *FileSystem) Move(ctx context.Context, dirs, files []uint, src, dst str return ErrPathNotExist } + // 设置webdav目标名 + if dstName, ok := ctx.Value(fsctx.WebdavDstName).(string); ok { + dstFolder.WebdavDstName = dstName + } + // 处理目录及子文件移动 err := srcFolder.MoveFolderTo(dirs, dstFolder) if err != nil { diff --git a/pkg/webdav/file.go b/pkg/webdav/file.go index 5076a63..a0e589b 100644 --- a/pkg/webdav/file.go +++ b/pkg/webdav/file.go @@ -9,9 +9,12 @@ import ( "net/http" "path" "path/filepath" + "strconv" + "time" model "github.com/cloudreve/Cloudreve/v3/models" "github.com/cloudreve/Cloudreve/v3/pkg/filesystem" + "github.com/cloudreve/Cloudreve/v3/pkg/filesystem/fsctx" ) // slashClean is equivalent to but slightly more efficient than @@ -23,6 +26,31 @@ func slashClean(name string) string { return path.Clean(name) } +// 更新Copy或Move后的修改时间 +func updateCopyMoveModtime(req *http.Request, fs *filesystem.FileSystem, dst string) error { + var modtime time.Time + if timeVal := req.Header.Get("X-OC-Mtime"); timeVal != "" { + timeUnix, err := strconv.ParseInt(timeVal, 10, 64) + if err == nil { + modtime = time.Unix(timeUnix, 0) + } + } + + if modtime.IsZero() { + return nil + } + + ok, fi := isPathExist(req.Context(), fs, dst) + if !ok { + return nil + } + + if fi.IsDir() { + return model.DB.Model(fi.(*model.Folder)).UpdateColumn("updated_at", modtime).Error + } + return model.DB.Model(fi.(*model.File)).UpdateColumn("updated_at", modtime).Error +} + // moveFiles moves files and/or directories from src to dst. // // See section 9.9.4 for when various HTTP status codes apply. @@ -44,20 +72,17 @@ func moveFiles(ctx context.Context, fs *filesystem.FileSystem, src FileInfo, dst } } - // 判断是否需要移动 if src.GetPosition() != path.Dir(dst) { err = fs.Move( - ctx, + context.WithValue(ctx, fsctx.WebdavDstName, path.Base(dst)), folderIDs, fileIDs, src.GetPosition(), path.Dir(dst), ) - } - - // 判断是否需要重命名 - if err == nil && src.GetName() != path.Base(dst) { + } else if src.GetName() != path.Base(dst) { + // 判断是否需要重命名 err = fs.Rename( ctx, folderIDs, @@ -81,7 +106,6 @@ func copyFiles(ctx context.Context, fs *filesystem.FileSystem, src FileInfo, dst } recursion++ - var ( fileIDs []uint folderIDs []uint @@ -100,7 +124,7 @@ func copyFiles(ctx context.Context, fs *filesystem.FileSystem, src FileInfo, dst } err = fs.Copy( - ctx, + context.WithValue(ctx, fsctx.WebdavDstName, path.Base(dst)), folderIDs, fileIDs, src.GetPosition(), diff --git a/pkg/webdav/webdav.go b/pkg/webdav/webdav.go index 9b2ff1b..3c72f11 100644 --- a/pkg/webdav/webdav.go +++ b/pkg/webdav/webdav.go @@ -496,7 +496,16 @@ func (h *Handler) handleCopyMove(w http.ResponseWriter, r *http.Request, fs *fil return http.StatusBadRequest, errInvalidDepth } } - return copyFiles(ctx, fs, target, dst, r.Header.Get("Overwrite") != "F", depth, 0) + status, err = copyFiles(ctx, fs, target, dst, r.Header.Get("Overwrite") != "F", depth, 0) + if err != nil { + return status, err + } + + err = updateCopyMoveModtime(r, fs, dst) + if err != nil { + return http.StatusInternalServerError, err + } + return status, nil } // windows下,某些情况下(网盘根目录下)Office保存文件时附带的锁token只包含源文件, @@ -515,7 +524,16 @@ func (h *Handler) handleCopyMove(w http.ResponseWriter, r *http.Request, fs *fil return http.StatusBadRequest, errInvalidDepth } } - return moveFiles(ctx, fs, target, dst, r.Header.Get("Overwrite") == "T") + status, err = moveFiles(ctx, fs, target, dst, r.Header.Get("Overwrite") == "T") + if err != nil { + return status, err + } + + err = updateCopyMoveModtime(r, fs, dst) + if err != nil { + return http.StatusInternalServerError, err + } + return status, nil } // OK