fix: align WebDAV overwrite authorization

This commit is contained in:
OpenClaw Agent
2026-09-21 22:12:44 +08:00
parent 024c887d96
commit 003244059f
+24 -14
View File
@@ -1061,12 +1061,13 @@ func (f *webdavStorageFS) Copy(ctx context.Context, name, dest string, opts *web
if sameOrDescendantPath(src, dst) { if sameOrDescendantPath(src, dst) {
return false, webdav.NewHTTPError(http.StatusConflict, fmt.Errorf("destination is inside source")) return false, webdav.NewHTTPError(http.StatusConflict, fmt.Errorf("destination is inside source"))
} }
if opts != nil && opts.NoOverwrite { _, dstErr := f.store.Stat(dst)
if _, err := f.store.Stat(dst); err == nil { dstExists := dstErr == nil
return false, webdav.NewHTTPError(http.StatusPreconditionFailed, fmt.Errorf("destination exists")) if dstErr != nil && !os.IsNotExist(dstErr) {
} else if !os.IsNotExist(err) { return false, dstErr
return false, err }
} if opts != nil && opts.NoOverwrite && dstExists {
return false, webdav.NewHTTPError(http.StatusPreconditionFailed, fmt.Errorf("destination exists"))
} }
if m, ok := f.store.(storage.Multi); ok { if m, ok := f.store.(storage.Multi); ok {
srcRoot, _, srcOK := m.FindRoot(src) srcRoot, _, srcOK := m.FindRoot(src)
@@ -1094,7 +1095,7 @@ func (f *webdavStorageFS) Copy(ctx context.Context, name, dest string, opts *web
} }
_ = created _ = created
} }
return true, nil return !dstExists, nil
} }
in, err := f.store.Open(src) in, err := f.store.Open(src)
if err != nil { if err != nil {
@@ -1114,7 +1115,7 @@ func (f *webdavStorageFS) Copy(ctx context.Context, name, dest string, opts *web
if closeErr != nil { if closeErr != nil {
return false, closeErr return false, closeErr
} }
return true, nil return !dstExists, nil
} }
func (f *webdavStorageFS) Move(ctx context.Context, name, dest string, opts *webdav.MoveOptions) (bool, error) { func (f *webdavStorageFS) Move(ctx context.Context, name, dest string, opts *webdav.MoveOptions) (bool, error) {
@@ -1129,12 +1130,12 @@ func (f *webdavStorageFS) Move(ctx context.Context, name, dest string, opts *web
if sameOrDescendantPath(src, dst) { if sameOrDescendantPath(src, dst) {
return false, webdav.NewHTTPError(http.StatusConflict, fmt.Errorf("destination is inside source")) return false, webdav.NewHTTPError(http.StatusConflict, fmt.Errorf("destination is inside source"))
} }
if opts == nil || opts.NoOverwrite { if _, err := f.store.Stat(dst); err == nil {
if _, err := f.store.Stat(dst); err == nil { // CHFS v4 MOVE does not overwrite an existing destination, even when
return false, webdav.NewHTTPError(http.StatusPreconditionFailed, fmt.Errorf("destination exists")) // Overwrite is omitted/T and the caller has delete permission.
} else if !os.IsNotExist(err) { return false, webdav.NewHTTPError(http.StatusPreconditionFailed, fmt.Errorf("destination exists"))
return false, err } else if !os.IsNotExist(err) {
} return false, err
} }
if m, ok := f.store.(storage.Multi); ok { if m, ok := f.store.(storage.Multi); ok {
srcRoot, _, srcOK := m.FindRoot(src) srcRoot, _, srcOK := m.FindRoot(src)
@@ -1370,6 +1371,15 @@ func (f *webdavAuthFS) Create(ctx context.Context, name string, body io.ReadClos
if err := f.allow(parent, auth.Write); err != nil { if err := f.allow(parent, auth.Write); err != nil {
return nil, false, err return nil, false, err
} }
// CHFS permits PUT to overwrite an existing file only when the target
// itself is writable. A writable parent alone is enough for creation.
if _, err := f.inner.Stat(ctx, name); err == nil {
if err := f.allow(name, auth.Write); err != nil {
return nil, false, err
}
} else if !os.IsNotExist(err) {
return nil, false, err
}
return f.inner.Create(ctx, name, body, opts) return f.inner.Create(ctx, name, body, opts)
} }
func (f *webdavAuthFS) RemoveAll(ctx context.Context, name string, opts *webdav.RemoveAllOptions) error { func (f *webdavAuthFS) RemoveAll(ctx context.Context, name string, opts *webdav.RemoveAllOptions) error {