diff --git a/weed/server/filer_server_handlers_write.go b/weed/server/filer_server_handlers_write.go index 1ebe66d43..e587f72ba 100644 --- a/weed/server/filer_server_handlers_write.go +++ b/weed/server/filer_server_handlers_write.go @@ -3,6 +3,7 @@ package weed_server import ( "context" "errors" + "fmt" "net/http" "os" "strings" @@ -78,11 +79,78 @@ func (fs *FilerServer) PostHandler(w http.ResponseWriter, r *http.Request, conte return } - fs.autoChunk(ctx, w, r, contentLength, so) + if query.Has("from") { + fs.move(ctx, w, r, so) + } else { + fs.autoChunk(ctx, w, r, contentLength, so) + } + util.CloseRequest(r) } +func (fs *FilerServer) move(ctx context.Context, w http.ResponseWriter, r *http.Request, so *operation.StorageOption) { + src := r.URL.Query().Get("from") + dst := r.URL.Path + + glog.V(2).Infof("FilerServer.move %v to %v", src, dst) + + var err error + if src, err = clearName(src); err != nil { + writeJsonError(w, r, http.StatusBadRequest, err) + return + } + if dst, err = clearName(dst); err != nil { + writeJsonError(w, r, http.StatusBadRequest, err) + return + } + src = strings.TrimRight(src, "/") + if src == "" { + err = fmt.Errorf("invalid source '/'") + writeJsonError(w, r, http.StatusBadRequest, err) + return + } + + srcPath := util.FullPath(src) + dstPath := util.FullPath(dst) + srcEntry, err := fs.filer.FindEntry(ctx, srcPath) + if err != nil { + err = fmt.Errorf("failed to get src entry '%s', err: %s", src, err) + writeJsonError(w, r, http.StatusBadRequest, err) + return + } + + oldDir, oldName := srcPath.DirAndName() + newDir, newName := dstPath.DirAndName() + newName = util.Nvl(newName, oldName) + + dstEntry, err := fs.filer.FindEntry(ctx, util.FullPath(strings.TrimRight(dst, "/"))) + if err != nil && err != filer_pb.ErrNotFound { + err = fmt.Errorf("failed to get dst entry '%s', err: %s", dst, err) + writeJsonError(w, r, http.StatusInternalServerError, err) + return + } + if err == nil && !dstEntry.IsDirectory() && srcEntry.IsDirectory() { + err = fmt.Errorf("move: cannot overwrite non-directory '%s' with directory '%s'", dst, src) + writeJsonError(w, r, http.StatusBadRequest, err) + return + } + + _, err = fs.AtomicRenameEntry(ctx, &filer_pb.AtomicRenameEntryRequest{ + OldDirectory: oldDir, + OldName: oldName, + NewDirectory: newDir, + NewName: newName, + }) + if err != nil { + err = fmt.Errorf("failed to move entry from '%s' to '%s', err: %s", src, dst, err) + writeJsonError(w, r, http.StatusBadRequest, err) + return + } + + w.WriteHeader(http.StatusNoContent) +} + // curl -X DELETE http://localhost:8888/path/to // curl -X DELETE http://localhost:8888/path/to?recursive=true // curl -X DELETE http://localhost:8888/path/to?recursive=true&ignoreRecursiveError=true