forked from TrueCloudLab/restic
152 lines
2.7 KiB
Go
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
|
|
}
|