diff --git a/webdav/memfs.go b/webdav/memfs.go index 837fd9d..c1751ea 100644 --- a/webdav/memfs.go +++ b/webdav/memfs.go @@ -36,13 +36,7 @@ func (fs *MemFS) findNode(path string) (*memNode, error) { current := fs.root parts := strings.Split(path, "/") for _, part := range parts { - if part == "" || part == "." { - continue - } - if part == ".." { - if current.parent != nil { - current = current.parent - } + if part == "" { continue } if current.children == nil { @@ -111,7 +105,6 @@ func (fs *MemFS) OpenFile(ctx context.Context, name string, flag int, perm os.Fi if flag&os.O_TRUNC != 0 { node.data = nil - node.size = 0 } return &memFile{ @@ -241,21 +234,14 @@ func (f *memFile) Write(p []byte) (n int, err error) { func (f *memFile) Seek(offset int64, whence int) (int64, error) { f.fs.mu.Lock() defer f.fs.mu.Unlock() - var newOffset int64 switch whence { - case io.SeekStart: - newOffset = offset - case io.SeekCurrent: - newOffset = f.offset + offset - case io.SeekEnd: - newOffset = f.node.size + offset - default: - return 0, os.ErrInvalid + case 0: + f.offset = offset + case 1: + f.offset += offset + case 2: + f.offset = int64(len(f.node.data)) + offset } - if newOffset < 0 { - return 0, os.ErrInvalid - } - f.offset = newOffset return f.offset, nil } diff --git a/webdav/memlock.go b/webdav/memlock.go index dabdd71..7c1074f 100644 --- a/webdav/memlock.go +++ b/webdav/memlock.go @@ -17,7 +17,6 @@ import ( type MemLock struct { mu sync.RWMutex locks map[string]*lock - stop chan struct{} } type lock struct { @@ -29,35 +28,8 @@ type lock struct { // NewMemLock creates a new in-memory lock system. func NewMemLock() *MemLock { - l := &MemLock{ + return &MemLock{ locks: make(map[string]*lock), - stop: make(chan struct{}), - } - go l.cleanup() - return l -} - -// Close stops the cleanup goroutine. -func (l *MemLock) Close() { - close(l.stop) -} - -func (l *MemLock) cleanup() { - ticker := time.NewTicker(1 * time.Minute) - defer ticker.Stop() - for { - select { - case <-ticker.C: - l.mu.Lock() - for token, lock := range l.locks { - if time.Now().After(lock.expires) { - delete(l.locks, token) - } - } - l.mu.Unlock() - case <-l.stop: - return - } } } @@ -67,9 +39,7 @@ func (l *MemLock) Create(ctx context.Context, path string, info LockInfo) (strin defer l.mu.Unlock() token := make([]byte, 16) - if _, err := rand.Read(token); err != nil { - return "", err - } + rand.Read(token) tokenStr := hex.EncodeToString(token) l.locks[tokenStr] = &lock{ diff --git a/webdav/osfs.go b/webdav/osfs.go index cf4c62e..6a68108 100644 --- a/webdav/osfs.go +++ b/webdav/osfs.go @@ -26,37 +26,10 @@ func NewOSFS(rootDir string) (*OSFS, error) { } func (fs *OSFS) resolve(name string) (string, error) { - if filepath.IsAbs(name) || strings.Contains(name, "..") { - return "", os.ErrPermission - } - path := filepath.Join(fs.RootDir, name) - - // Evaluate symlinks, but only if the path exists. - if _, err := os.Lstat(path); err == nil { - path, err = filepath.EvalSymlinks(path) - if err != nil { - return "", err - } - } else if !os.IsNotExist(err) { - return "", err - // For non-existent paths (like for PUT or MKCOL), we can't EvalSymlinks the full path. - // Instead, we resolve the parent and ensure it's within the root. - } else { - parentDir := filepath.Dir(path) - if _, err := os.Stat(parentDir); err == nil { - parentDir, err = filepath.EvalSymlinks(parentDir) - if err != nil { - return "", err - } - path = filepath.Join(parentDir, filepath.Base(path)) - } - } - if !strings.HasPrefix(path, fs.RootDir) { return "", os.ErrPermission } - return path, nil } diff --git a/webdav/webdav.go b/webdav/webdav.go index 2bad373..07accf7 100644 --- a/webdav/webdav.go +++ b/webdav/webdav.go @@ -284,39 +284,7 @@ func (h *Handler) handleGetHead(c *touka.Context) { func (h *Handler) handleDelete(c *touka.Context) { path, _ := c.Get("webdav_path") - pathStr := path.(string) - - info, err := h.FileSystem.Stat(c.Context(), pathStr) - if err != nil { - if os.IsNotExist(err) { - c.Status(http.StatusNotFound) - } else { - c.Status(http.StatusInternalServerError) - } - return - } - - if info.IsDir() { - file, err := h.FileSystem.OpenFile(c.Context(), pathStr, os.O_RDONLY, 0) - if err != nil { - c.Status(http.StatusInternalServerError) - return - } - defer file.Close() - - // Check if the directory has any children. Readdir(1) is enough. - children, err := file.Readdir(1) - if err != nil && err != io.EOF { - c.Status(http.StatusInternalServerError) - return - } - if len(children) > 0 { - c.Status(http.StatusConflict) // 409 Conflict for non-empty collection - return - } - } - - if err := h.FileSystem.RemoveAll(c.Context(), pathStr); err != nil { + if err := h.FileSystem.RemoveAll(c.Context(), path.(string)); err != nil { if os.IsNotExist(err) { c.Status(http.StatusNotFound) } else { @@ -379,13 +347,11 @@ func (h *Handler) handleCopy(c *touka.Context) { overwrite = "T" // Default is to overwrite } - // Check for existence before the operation to determine status code later. - _, err = h.FileSystem.Stat(c.Context(), destPath) - existed := err == nil - - if overwrite == "F" && existed { - c.Status(http.StatusPreconditionFailed) - return + if overwrite == "F" { + if _, err := h.FileSystem.Stat(c.Context(), destPath); err == nil { + c.Status(http.StatusPreconditionFailed) + return + } } if err := h.copy(c.Context(), srcPath.(string), destPath); err != nil { @@ -393,11 +359,7 @@ func (h *Handler) handleCopy(c *touka.Context) { return } - if existed { - c.Status(http.StatusNoContent) - } else { - c.Status(http.StatusCreated) - } + c.Status(http.StatusCreated) } func (h *Handler) handleMove(c *touka.Context) { @@ -420,13 +382,11 @@ func (h *Handler) handleMove(c *touka.Context) { overwrite = "T" // Default is to overwrite } - // Check for existence before the operation to determine status code later. - _, err = h.FileSystem.Stat(c.Context(), destPath) - existed := err == nil - - if overwrite == "F" && existed { - c.Status(http.StatusPreconditionFailed) - return + if overwrite == "F" { + if _, err := h.FileSystem.Stat(c.Context(), destPath); err == nil { + c.Status(http.StatusPreconditionFailed) + return + } } if err := h.FileSystem.Rename(c.Context(), srcPath.(string), destPath); err != nil { @@ -434,11 +394,7 @@ func (h *Handler) handleMove(c *touka.Context) { return } - if existed { - c.Status(http.StatusNoContent) - } else { - c.Status(http.StatusCreated) - } + c.Status(http.StatusCreated) } func (h *Handler) copy(ctx context.Context, src, dest string) error { @@ -629,11 +585,11 @@ func (h *Handler) handleProppatch(c *touka.Context) { c.Status(http.StatusNotImplemented) } -func (h *Handler) stripPrefix(p string) string { +func (h *Handler) stripPrefix(path string) string { if h.Prefix == "/" { - return p + return path } - return strings.TrimPrefix(p, h.Prefix) + return "/" + strings.TrimPrefix(path, h.Prefix) } func (h *Handler) handleLock(c *touka.Context) { @@ -643,15 +599,7 @@ func (h *Handler) handleLock(c *touka.Context) { } path, _ := c.Get("webdav_path") - tokenHeader := c.GetReqHeader("If") - var token string - if tokenHeader != "" { - // Basic parsing for - if strings.HasPrefix(tokenHeader, "(<") && strings.HasSuffix(tokenHeader, ">)") { - token = strings.TrimPrefix(tokenHeader, "(<") - token = strings.TrimSuffix(token, ">)") - } - } + token := c.GetReqHeader("If") // Refresh lock if token != "" { @@ -718,7 +666,7 @@ func parseTimeout(timeoutStr string) (time.Duration, error) { return seconds, nil } } - return 0, os.ErrInvalid + return 0, nil } func (h *Handler) handleUnlock(c *touka.Context) { @@ -727,16 +675,12 @@ func (h *Handler) handleUnlock(c *touka.Context) { return } - tokenHeader := c.GetReqHeader("Lock-Token") - if tokenHeader == "" { + token := c.GetReqHeader("Lock-Token") + if token == "" { c.Status(http.StatusBadRequest) return } - // Basic parsing for - token := strings.TrimPrefix(tokenHeader, "<") - token = strings.TrimSuffix(token, ">") - if err := h.LockSystem.Unlock(c.Context(), token); err != nil { c.Status(http.StatusConflict) return