From 3834ad5c486906f183a5ab8f71083682f2e14677 Mon Sep 17 00:00:00 2001 From: Nico D'Cotta <45274424+Cottand@users.noreply.github.com> Date: Wed, 1 Nov 2023 19:12:49 -0100 Subject: [PATCH] refactor webdav subdirectory, fixes #4967 (#4969) * refactor webdav subdirectory, fixes #4967 * fix bug where Name() was not called on delegate wrappedFileInfo --- weed/server/webdav_server.go | 8 +-- weed/server/wrapped_webdav_fs.go | 97 ++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 weed/server/wrapped_webdav_fs.go diff --git a/weed/server/webdav_server.go b/weed/server/webdav_server.go index 189378dcd..945c68279 100644 --- a/weed/server/webdav_server.go +++ b/weed/server/webdav_server.go @@ -63,6 +63,10 @@ func NewWebDavServer(option *WebDavOption) (ws *WebDavServer, err error) { if option.FilerRootPath == "/" { option.FilerRootPath = "" } + // filer.path non "/" option means we are accessing filer's sub-folders + if option.FilerRootPath != "" { + fs = NewWrappedFs(fs, path.Clean(option.FilerRootPath)) + } ws = &WebDavServer{ option: option, @@ -204,8 +208,6 @@ func (fs *WebDavFileSystem) Mkdir(ctx context.Context, fullDirPath string, perm } func (fs *WebDavFileSystem) OpenFile(ctx context.Context, fullFilePath string, flag int, perm os.FileMode) (webdav.File, error) { - // Add filer.path - fullFilePath = fs.option.FilerRootPath + fullFilePath glog.V(2).Infof("WebDavFileSystem.OpenFile %v %x", fullFilePath, flag) var err error @@ -377,8 +379,6 @@ func (fs *WebDavFileSystem) stat(ctx context.Context, fullFilePath string) (os.F } func (fs *WebDavFileSystem) Stat(ctx context.Context, name string) (os.FileInfo, error) { - // Add filer.path - name = fs.option.FilerRootPath + name glog.V(2).Infof("WebDavFileSystem.Stat %v", name) return fs.stat(ctx, name) diff --git a/weed/server/wrapped_webdav_fs.go b/weed/server/wrapped_webdav_fs.go new file mode 100644 index 000000000..93e2b3122 --- /dev/null +++ b/weed/server/wrapped_webdav_fs.go @@ -0,0 +1,97 @@ +package weed_server + +import ( + "context" + "golang.org/x/net/webdav" + "io/fs" + "os" + "strings" +) + +type wrappedFs struct { + subFolder string + webdav.FileSystem +} + +// NewWrappedFs returns a webdav.FileSystem identical to fs, except it +// provides access to a sub-folder of fs that is denominated by subFolder. +// It transparently handles renaming paths and filenames so that the outer part of the wrapped filesystem +// does not leak out. +func NewWrappedFs(fs webdav.FileSystem, subFolder string) webdav.FileSystem { + return wrappedFs{ + subFolder: subFolder, + FileSystem: fs, + } +} + +func (w wrappedFs) Mkdir(ctx context.Context, name string, perm os.FileMode) error { + name = w.subFolder + name + return w.FileSystem.Mkdir(ctx, name, perm) +} + +func (w wrappedFs) OpenFile(ctx context.Context, name string, flag int, perm os.FileMode) (webdav.File, error) { + name = w.subFolder + name + file, err := w.FileSystem.OpenFile(ctx, name, flag, perm) + file = wrappedFile{ + File: file, + subFolder: &w.subFolder, + } + + return file, err +} + +func (w wrappedFs) RemoveAll(ctx context.Context, name string) error { + name = w.subFolder + name + return w.FileSystem.RemoveAll(ctx, name) +} + +func (w wrappedFs) Rename(ctx context.Context, oldName, newName string) error { + oldName = w.subFolder + oldName + newName = w.subFolder + newName + return w.FileSystem.Rename(ctx, oldName, newName) +} + +func (w wrappedFs) Stat(ctx context.Context, name string) (os.FileInfo, error) { + name = w.subFolder + name + info, err := w.FileSystem.Stat(ctx, name) + info = wrappedFileInfo{ + subFolder: &w.subFolder, + FileInfo: info, + } + return info, err +} + +type wrappedFile struct { + webdav.File + subFolder *string +} + +func (w wrappedFile) Readdir(count int) ([]fs.FileInfo, error) { + infos, err := w.File.Readdir(count) + for i, info := range infos { + infos[i] = wrappedFileInfo{ + subFolder: w.subFolder, + FileInfo: info, + } + } + return infos, err +} + +func (w wrappedFile) Stat() (fs.FileInfo, error) { + info, err := w.File.Stat() + info = wrappedFileInfo{ + subFolder: w.subFolder, + FileInfo: info, + } + return info, err +} + +type wrappedFileInfo struct { + subFolder *string + fs.FileInfo +} + +func (w wrappedFileInfo) Name() string { + name := w.FileInfo.Name() + return strings.TrimPrefix(name, *w.subFolder) +}