Initial commit: docker compose config
Release Docker multi arch / docker (push) Has been cancelled
Test Install Script / Test Script Syntax (push) Has been cancelled
Test Install Script / Test on almalinux-10 (default) (push) Has been cancelled
Test Install Script / Test on almalinux-10 (root) (push) Has been cancelled
Test Install Script / Test on almalinux-8 (default) (push) Has been cancelled
Test Install Script / Test on almalinux-8 (root) (push) Has been cancelled
Test Install Script / Test on almalinux-9 (default) (push) Has been cancelled
Test Install Script / Test on almalinux-9 (root) (push) Has been cancelled
Test Install Script / Test on amazonlinux-2 (default) (push) Has been cancelled
Test Install Script / Test on amazonlinux-2 (root) (push) Has been cancelled
Test Install Script / Test on debian-11 (default) (push) Has been cancelled
Test Install Script / Test on debian-11 (root) (push) Has been cancelled
Test Install Script / Test on debian-12 (default) (push) Has been cancelled
Test Install Script / Test on debian-12 (root) (push) Has been cancelled
Test Install Script / Test on debian-13 (default) (push) Has been cancelled
Test Install Script / Test on debian-13 (root) (push) Has been cancelled
Test Install Script / Test on fedora-latest (default) (push) Has been cancelled
Test Install Script / Test on fedora-latest (root) (push) Has been cancelled
Test Install Script / Test on rocky-10 (default) (push) Has been cancelled
Test Install Script / Test on rocky-10 (root) (push) Has been cancelled
Test Install Script / Test on rocky-8 (default) (push) Has been cancelled
Test Install Script / Test on rocky-8 (root) (push) Has been cancelled
Test Install Script / Test on rocky-9 (default) (push) Has been cancelled
Test Install Script / Test on rocky-9 (root) (push) Has been cancelled
Test Install Script / Test on ubuntu-22.04 (default) (push) Has been cancelled
Test Install Script / Test on ubuntu-22.04 (root) (push) Has been cancelled
Test Install Script / Test on ubuntu-24.04 (default) (push) Has been cancelled
Test Install Script / Test on ubuntu-24.04 (root) (push) Has been cancelled
Release Docker multi arch / docker (push) Has been cancelled
Test Install Script / Test Script Syntax (push) Has been cancelled
Test Install Script / Test on almalinux-10 (default) (push) Has been cancelled
Test Install Script / Test on almalinux-10 (root) (push) Has been cancelled
Test Install Script / Test on almalinux-8 (default) (push) Has been cancelled
Test Install Script / Test on almalinux-8 (root) (push) Has been cancelled
Test Install Script / Test on almalinux-9 (default) (push) Has been cancelled
Test Install Script / Test on almalinux-9 (root) (push) Has been cancelled
Test Install Script / Test on amazonlinux-2 (default) (push) Has been cancelled
Test Install Script / Test on amazonlinux-2 (root) (push) Has been cancelled
Test Install Script / Test on debian-11 (default) (push) Has been cancelled
Test Install Script / Test on debian-11 (root) (push) Has been cancelled
Test Install Script / Test on debian-12 (default) (push) Has been cancelled
Test Install Script / Test on debian-12 (root) (push) Has been cancelled
Test Install Script / Test on debian-13 (default) (push) Has been cancelled
Test Install Script / Test on debian-13 (root) (push) Has been cancelled
Test Install Script / Test on fedora-latest (default) (push) Has been cancelled
Test Install Script / Test on fedora-latest (root) (push) Has been cancelled
Test Install Script / Test on rocky-10 (default) (push) Has been cancelled
Test Install Script / Test on rocky-10 (root) (push) Has been cancelled
Test Install Script / Test on rocky-8 (default) (push) Has been cancelled
Test Install Script / Test on rocky-8 (root) (push) Has been cancelled
Test Install Script / Test on rocky-9 (default) (push) Has been cancelled
Test Install Script / Test on rocky-9 (root) (push) Has been cancelled
Test Install Script / Test on ubuntu-22.04 (default) (push) Has been cancelled
Test Install Script / Test on ubuntu-22.04 (root) (push) Has been cancelled
Test Install Script / Test on ubuntu-24.04 (default) (push) Has been cancelled
Test Install Script / Test on ubuntu-24.04 (root) (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,232 @@
|
||||
package webdav
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"server/log"
|
||||
|
||||
"server/torrfs"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"golang.org/x/net/webdav"
|
||||
)
|
||||
|
||||
var missingMethods = []string{
|
||||
"PROPFIND", "PROPPATCH", "MKCOL", "COPY", "MOVE", "LOCK", "UNLOCK",
|
||||
}
|
||||
|
||||
func MountWebDAV(r *gin.Engine) {
|
||||
log.TLogln("Starting WebDAV")
|
||||
tfs := torrfs.AsFS(torrfs.New())
|
||||
|
||||
h := &webdav.Handler{
|
||||
Prefix: "/dav",
|
||||
FileSystem: &ReadOnlyFS{FS: tfs},
|
||||
LockSystem: webdav.NewMemLS(),
|
||||
}
|
||||
|
||||
grp := r.Group("/dav")
|
||||
|
||||
handler := func(c *gin.Context) {
|
||||
h.ServeHTTP(c.Writer, c.Request)
|
||||
}
|
||||
|
||||
grp.Any("/*webdav", handler)
|
||||
for _, m := range missingMethods {
|
||||
grp.Handle(m, "/*webdav", handler)
|
||||
}
|
||||
|
||||
grp.Any("", handler)
|
||||
for _, m := range missingMethods {
|
||||
grp.Handle(m, "", handler)
|
||||
}
|
||||
}
|
||||
|
||||
type ReadOnlyFS struct {
|
||||
FS fs.FS
|
||||
}
|
||||
|
||||
var _ webdav.FileSystem = (*ReadOnlyFS)(nil)
|
||||
|
||||
func (ro *ReadOnlyFS) Mkdir(ctx context.Context, name string, perm os.FileMode) error {
|
||||
return os.ErrPermission
|
||||
}
|
||||
|
||||
func (ro *ReadOnlyFS) RemoveAll(ctx context.Context, name string) error {
|
||||
return os.ErrPermission
|
||||
}
|
||||
|
||||
func (ro *ReadOnlyFS) Rename(ctx context.Context, oldName, newName string) error {
|
||||
return os.ErrPermission
|
||||
}
|
||||
|
||||
func (ro *ReadOnlyFS) Stat(ctx context.Context, name string) (os.FileInfo, error) {
|
||||
name = cleanWebDAVPath(name)
|
||||
return fs.Stat(ro.FS, name)
|
||||
}
|
||||
|
||||
func (ro *ReadOnlyFS) OpenFile(ctx context.Context, name string, flag int, perm os.FileMode) (webdav.File, error) {
|
||||
if flag&(os.O_WRONLY|os.O_RDWR|os.O_APPEND|os.O_CREATE|os.O_TRUNC) != 0 {
|
||||
return nil, os.ErrPermission
|
||||
}
|
||||
|
||||
name = cleanWebDAVPath(name)
|
||||
|
||||
f, err := ro.FS.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newROFile(ro.FS, name, f), nil
|
||||
}
|
||||
|
||||
// --- file wrapper ---
|
||||
|
||||
type roFile struct {
|
||||
fsys fs.FS
|
||||
name string
|
||||
|
||||
mu sync.Mutex
|
||||
f fs.File
|
||||
|
||||
dirPos int
|
||||
dirList []fs.DirEntry
|
||||
}
|
||||
|
||||
func newROFile(fsys fs.FS, name string, f fs.File) *roFile {
|
||||
return &roFile{fsys: fsys, name: name, f: f}
|
||||
}
|
||||
|
||||
var _ webdav.File = (*roFile)(nil)
|
||||
|
||||
func (f *roFile) Write(p []byte) (n int, err error) {
|
||||
return 0, fs.ErrPermission
|
||||
}
|
||||
|
||||
func (f *roFile) Close() error {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
if f.f == nil {
|
||||
return nil
|
||||
}
|
||||
err := f.f.Close()
|
||||
f.f = nil
|
||||
f.dirList = nil
|
||||
f.dirPos = 0
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *roFile) Read(p []byte) (int, error) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
|
||||
if f.f == nil {
|
||||
return 0, fs.ErrClosed
|
||||
}
|
||||
r, ok := f.f.(io.Reader)
|
||||
if !ok {
|
||||
return 0, fs.ErrInvalid
|
||||
}
|
||||
return r.Read(p)
|
||||
}
|
||||
|
||||
func (f *roFile) Seek(offset int64, whence int) (int64, error) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
|
||||
if f.f == nil {
|
||||
return 0, fs.ErrClosed
|
||||
}
|
||||
rs, ok := f.f.(io.Seeker)
|
||||
if !ok {
|
||||
return 0, errors.New("seek not supported")
|
||||
}
|
||||
return rs.Seek(offset, whence)
|
||||
}
|
||||
|
||||
func (f *roFile) Stat() (os.FileInfo, error) {
|
||||
return fs.Stat(f.fsys, f.name)
|
||||
}
|
||||
|
||||
func (f *roFile) Readdir(count int) ([]os.FileInfo, error) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
|
||||
if f.f == nil {
|
||||
return nil, fs.ErrClosed
|
||||
}
|
||||
|
||||
fi, err := fs.Stat(f.fsys, f.name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !fi.IsDir() {
|
||||
return nil, fs.ErrInvalid
|
||||
}
|
||||
|
||||
if f.dirList == nil {
|
||||
des, err := fs.ReadDir(f.fsys, f.name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.dirList = des
|
||||
f.dirPos = 0
|
||||
}
|
||||
|
||||
if count <= 0 {
|
||||
out := make([]os.FileInfo, 0, len(f.dirList)-f.dirPos)
|
||||
for f.dirPos < len(f.dirList) {
|
||||
de := f.dirList[f.dirPos]
|
||||
f.dirPos++
|
||||
info, err := de.Info()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
out = append(out, info)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
out := make([]os.FileInfo, 0, count)
|
||||
for f.dirPos < len(f.dirList) && len(out) < count {
|
||||
de := f.dirList[f.dirPos]
|
||||
f.dirPos++
|
||||
info, err := de.Info()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
out = append(out, info)
|
||||
}
|
||||
|
||||
if len(out) == 0 {
|
||||
return nil, io.EOF
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// --- path helpers ---
|
||||
func cleanWebDAVPath(name string) string {
|
||||
if name == "" || name == "/" {
|
||||
return "."
|
||||
}
|
||||
name = path.Clean("/" + name)
|
||||
name = name[1:]
|
||||
if name == "" {
|
||||
return "."
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func nonZeroTime(t time.Time) time.Time {
|
||||
if t.IsZero() {
|
||||
return time.Unix(0, 0)
|
||||
}
|
||||
return t
|
||||
}
|
||||
Reference in New Issue
Block a user