2022-06-30 10:27:26 +00:00
|
|
|
// Copyright 2014 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package webdav
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"net/http"
|
|
|
|
"path"
|
|
|
|
"path/filepath"
|
2022-08-03 06:26:59 +00:00
|
|
|
|
2023-09-13 07:45:57 +00:00
|
|
|
"github.com/alist-org/alist/v3/internal/conf"
|
2022-08-03 06:26:59 +00:00
|
|
|
"github.com/alist-org/alist/v3/internal/fs"
|
|
|
|
"github.com/alist-org/alist/v3/internal/model"
|
2022-12-18 11:51:20 +00:00
|
|
|
"github.com/alist-org/alist/v3/internal/op"
|
2022-06-30 10:27:26 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// slashClean is equivalent to but slightly more efficient than
|
|
|
|
// path.Clean("/" + name).
|
|
|
|
func slashClean(name string) string {
|
|
|
|
if name == "" || name[0] != '/' {
|
|
|
|
name = "/" + name
|
|
|
|
}
|
|
|
|
return path.Clean(name)
|
|
|
|
}
|
|
|
|
|
|
|
|
// moveFiles moves files and/or directories from src to dst.
|
|
|
|
//
|
|
|
|
// See section 9.9.4 for when various HTTP status codes apply.
|
2022-06-30 14:41:55 +00:00
|
|
|
func moveFiles(ctx context.Context, src, dst string, overwrite bool) (status int, err error) {
|
2022-06-30 14:54:45 +00:00
|
|
|
srcDir := path.Dir(src)
|
|
|
|
dstDir := path.Dir(dst)
|
|
|
|
srcName := path.Base(src)
|
|
|
|
dstName := path.Base(dst)
|
|
|
|
if srcDir == dstDir {
|
|
|
|
err = fs.Rename(ctx, src, dstName)
|
|
|
|
} else {
|
|
|
|
err = fs.Move(ctx, src, dstDir)
|
|
|
|
if err != nil {
|
|
|
|
return http.StatusInternalServerError, err
|
|
|
|
}
|
|
|
|
if srcName != dstName {
|
|
|
|
err = fs.Rename(ctx, path.Join(dstDir, srcName), dstName)
|
|
|
|
}
|
|
|
|
}
|
2022-06-30 10:27:26 +00:00
|
|
|
if err != nil {
|
2022-06-30 14:41:55 +00:00
|
|
|
return http.StatusInternalServerError, err
|
2022-06-30 10:27:26 +00:00
|
|
|
}
|
2022-06-30 14:41:55 +00:00
|
|
|
// TODO if there are no files copy, should return 204
|
|
|
|
return http.StatusCreated, nil
|
2022-06-30 10:27:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// copyFiles copies files and/or directories from src to dst.
|
|
|
|
//
|
|
|
|
// See section 9.8.5 for when various HTTP status codes apply.
|
2022-06-30 14:41:55 +00:00
|
|
|
func copyFiles(ctx context.Context, src, dst string, overwrite bool) (status int, err error) {
|
2023-09-13 07:45:57 +00:00
|
|
|
dstDir := path.Dir(dst)
|
|
|
|
_, err = fs.Copy(context.WithValue(ctx, conf.NoTaskKey, struct{}{}), src, dstDir)
|
2022-06-30 10:27:26 +00:00
|
|
|
if err != nil {
|
|
|
|
return http.StatusInternalServerError, err
|
|
|
|
}
|
2022-06-30 14:41:55 +00:00
|
|
|
// TODO if there are no files copy, should return 204
|
|
|
|
return http.StatusCreated, nil
|
2022-06-30 10:27:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// walkFS traverses filesystem fs starting at name up to depth levels.
|
|
|
|
//
|
|
|
|
// Allowed values for depth are 0, 1 or infiniteDepth. For each visited node,
|
|
|
|
// walkFS calls walkFn. If a visited file system node is a directory and
|
2022-06-30 14:41:55 +00:00
|
|
|
// walkFn returns path.SkipDir, walkFS will skip traversal of this node.
|
|
|
|
func walkFS(ctx context.Context, depth int, name string, info model.Obj, walkFn func(reqPath string, info model.Obj, err error) error) error {
|
|
|
|
// This implementation is based on Walk's code in the standard path/path package.
|
2022-06-30 10:27:26 +00:00
|
|
|
err := walkFn(name, info, nil)
|
|
|
|
if err != nil {
|
|
|
|
if info.IsDir() && err == filepath.SkipDir {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !info.IsDir() || depth == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if depth == 1 {
|
|
|
|
depth = 0
|
|
|
|
}
|
2022-12-18 11:51:20 +00:00
|
|
|
meta, _ := op.GetNearestMeta(name)
|
2022-06-30 10:27:26 +00:00
|
|
|
// Read directory names.
|
2023-04-06 16:02:07 +00:00
|
|
|
objs, err := fs.List(context.WithValue(ctx, "meta", meta), name, &fs.ListArgs{})
|
2022-06-30 14:41:55 +00:00
|
|
|
//f, err := fs.OpenFile(ctx, name, os.O_RDONLY, 0)
|
|
|
|
//if err != nil {
|
|
|
|
// return walkFn(name, info, err)
|
|
|
|
//}
|
|
|
|
//fileInfos, err := f.Readdir(0)
|
|
|
|
//f.Close()
|
2022-06-30 10:27:26 +00:00
|
|
|
if err != nil {
|
|
|
|
return walkFn(name, info, err)
|
|
|
|
}
|
|
|
|
|
2022-06-30 14:41:55 +00:00
|
|
|
for _, fileInfo := range objs {
|
2022-11-30 12:46:54 +00:00
|
|
|
filename := path.Join(name, fileInfo.GetName())
|
2022-06-30 10:27:26 +00:00
|
|
|
if err != nil {
|
|
|
|
if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
} else {
|
2022-06-30 14:41:55 +00:00
|
|
|
err = walkFS(ctx, depth, filename, fileInfo, walkFn)
|
2022-06-30 10:27:26 +00:00
|
|
|
if err != nil {
|
|
|
|
if !fileInfo.IsDir() || err != filepath.SkipDir {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|