79 lines
2.1 KiB
Go
79 lines
2.1 KiB
Go
// Copyright (C) 2019 Marius Schellenberger
|
|
|
|
package authdav
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"golang.org/x/net/webdav"
|
|
"os"
|
|
)
|
|
|
|
// ErrWonly indicates forbidden operation
|
|
var ErrWonly = errors.New("authdav: only file write once operations permitted")
|
|
|
|
const writeFlag = os.O_RDWR | os.O_CREATE | os.O_TRUNC
|
|
|
|
// WriteOnlyOnceFileSystem is a file write only wrapper for a webdav.FileSystem
|
|
type WriteOnlyOnceFileSystem struct {
|
|
Filters []Filter
|
|
fs webdav.FileSystem
|
|
}
|
|
|
|
// NewWriteOnlyOnceFileSystem returns a new WriteOnlyOnceFileSystem wrapping a webdav.FileSystem
|
|
func NewWriteOnlyOnceFileSystem(fs webdav.FileSystem) *WriteOnlyOnceFileSystem {
|
|
return &WriteOnlyOnceFileSystem{fs: fs}
|
|
}
|
|
|
|
// Mkdir is not permitted
|
|
func (fs *WriteOnlyOnceFileSystem) Mkdir(ctx context.Context, name string, perm os.FileMode) error {
|
|
return ErrWonly
|
|
}
|
|
|
|
// OpenFile allows write only once operations
|
|
func (fs *WriteOnlyOnceFileSystem) OpenFile(ctx context.Context, name string, flag int, perm os.FileMode) (webdav.File, error) {
|
|
fi, err := fs.Stat(ctx, name)
|
|
if err == nil && fi.Mode().IsRegular() {
|
|
f, ok := fi.(*FileInfo)
|
|
if ok && flag == writeFlag && f.RealSize() > 0 {
|
|
return nil, ErrWonly
|
|
}
|
|
}
|
|
for _, filter := range fs.Filters {
|
|
err = filter.Filter(name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
f, err := fs.fs.OpenFile(ctx, name, flag, perm)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &File{f}, nil
|
|
}
|
|
|
|
// RemoveAll only permits deleting empty files
|
|
func (fs *WriteOnlyOnceFileSystem) RemoveAll(ctx context.Context, name string) error {
|
|
fi, err := fs.fs.Stat(ctx, name)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if fi.Mode().IsRegular() && fi.Size() == 0 {
|
|
return fs.fs.RemoveAll(ctx, name)
|
|
}
|
|
return ErrWonly
|
|
}
|
|
|
|
// Rename is not permitted
|
|
func (fs *WriteOnlyOnceFileSystem) Rename(ctx context.Context, oldName, newName string) error {
|
|
return ErrWonly
|
|
}
|
|
|
|
// Stat returns os.FileInfo wrapped in FileInfo
|
|
func (fs *WriteOnlyOnceFileSystem) Stat(ctx context.Context, name string) (os.FileInfo, error) {
|
|
fi, err := fs.fs.Stat(ctx, name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &FileInfo{fi}, nil
|
|
}
|