restic/internal/server/rofs/webdav_fs.go
Alexander Neumann b3f38686ee wip
2024-03-03 14:19:22 +01:00

152 lines
2.7 KiB
Go

package rofs
import (
"context"
"fmt"
"io"
"io/fs"
"os"
"path"
"golang.org/x/net/webdav"
)
// WebDAVFS returns a file system suitable for use with the WebDAV server.
func WebDAVFS(fs *ROFS) webdav.FileSystem {
return &webDAVFS{FS: fs}
}
// webDAVFS wraps an fs.FS and returns a (read-only) filesystem suitable for use with WebDAV.
type webDAVFS struct {
fs.FS
}
// ensure that WebDAVFS can be used for webdav.
var _ webdav.FileSystem = &webDAVFS{}
func (*webDAVFS) Mkdir(_ context.Context, name string, _ fs.FileMode) error {
return &fs.PathError{
Op: "Mkdir",
Path: name,
Err: fs.ErrPermission,
}
}
func (*webDAVFS) RemoveAll(_ context.Context, name string) error {
return &fs.PathError{
Op: "RemoveAll",
Path: name,
Err: fs.ErrPermission,
}
}
func (*webDAVFS) Rename(_ context.Context, from string, to string) error {
return &fs.PathError{
Op: "Rename",
Path: from,
Err: fs.ErrPermission,
}
}
func (w *webDAVFS) Open(name string) (fs.File, error) {
// use relative paths for FS
name = path.Join(".", name)
return w.FS.Open(name)
}
func (w *webDAVFS) OpenFile(ctx context.Context, name string, flag int, perm fs.FileMode) (webdav.File, error) {
// use relative paths for FS
name = path.Join(".", name)
if flag != os.O_RDONLY {
return nil, &fs.PathError{
Op: "OpenFile",
Path: name,
Err: fs.ErrPermission,
}
}
f, err := w.FS.Open(name)
if err != nil {
return nil, err
}
readdirFile, ok := f.(fs.ReadDirFile)
if !ok {
readdirFile = nil
}
seeker, ok := f.(io.Seeker)
if !ok {
seeker = nil
}
return &readOnlyFile{File: f, readDirFile: readdirFile, Seeker: seeker}, nil
}
func (w *webDAVFS) Stat(ctx context.Context, name string) (fs.FileInfo, error) {
// use relative paths for FS
name = path.Join(".", name)
f, err := w.FS.Open(name)
if err != nil {
return nil, err
}
fi, err := f.Stat()
if err != nil {
_ = f.Close()
return nil, err
}
err = f.Close()
if err != nil {
return nil, err
}
return fi, nil
}
type readOnlyFile struct {
fs.File
readDirFile fs.ReadDirFile
io.Seeker
}
func (f readOnlyFile) Write([]byte) (int, error) {
return 0, fs.ErrPermission
}
func (f readOnlyFile) Seek(offset int64, whence int) (int64, error) {
if f.Seeker == nil {
return 0, fs.ErrInvalid
}
return f.Seeker.Seek(offset, whence)
}
func (f readOnlyFile) Readdir(n int) ([]fs.FileInfo, error) {
if f.readDirFile == nil {
return nil, fs.ErrInvalid
}
entries, err := f.readDirFile.ReadDir(n)
if err != nil {
return nil, err
}
result := make([]fs.FileInfo, 0, len(entries))
for _, entry := range entries {
fi, err := entry.Info()
if err != nil {
return nil, fmt.Errorf("get fileinfo: %w", err)
}
result = append(result, fi)
}
return result, nil
}