Small bug fixes and my own implementation of webdav.Dir
parent
dd3ccec696
commit
a753247333
|
@ -12,9 +12,8 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"golang.org/x/net/webdav"
|
|
||||||
|
|
||||||
. "github.com/hacdias/filemanager"
|
. "github.com/hacdias/filemanager"
|
||||||
|
"github.com/hacdias/filemanager/dir"
|
||||||
"github.com/mholt/caddy"
|
"github.com/mholt/caddy"
|
||||||
"github.com/mholt/caddy/caddyhttp/httpserver"
|
"github.com/mholt/caddy/caddyhttp/httpserver"
|
||||||
)
|
)
|
||||||
|
@ -137,7 +136,7 @@ func parse(c *caddy.Controller) ([]*config, error) {
|
||||||
Regexp: &Regexp{Raw: "\\/\\..+"},
|
Regexp: &Regexp{Raw: "\\/\\..+"},
|
||||||
}},
|
}},
|
||||||
CSS: "",
|
CSS: "",
|
||||||
FileSystem: webdav.Dir(baseScope),
|
FileSystem: dir.Dir(baseScope),
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -12,9 +12,9 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hacdias/filemanager"
|
"github.com/hacdias/filemanager"
|
||||||
|
"github.com/hacdias/filemanager/dir"
|
||||||
"github.com/mholt/caddy"
|
"github.com/mholt/caddy"
|
||||||
"github.com/mholt/caddy/caddyhttp/httpserver"
|
"github.com/mholt/caddy/caddyhttp/httpserver"
|
||||||
"golang.org/x/net/webdav"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -112,7 +112,7 @@ func parse(c *caddy.Controller) ([]*filemanager.FileManager, error) {
|
||||||
Regexp: &filemanager.Regexp{Raw: "\\/\\..+"},
|
Regexp: &filemanager.Regexp{Raw: "\\/\\..+"},
|
||||||
}},
|
}},
|
||||||
CSS: "",
|
CSS: "",
|
||||||
FileSystem: webdav.Dir(directory),
|
FileSystem: dir.Dir(directory),
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -11,8 +11,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hacdias/filemanager"
|
"github.com/hacdias/filemanager"
|
||||||
|
"github.com/hacdias/filemanager/dir"
|
||||||
"golang.org/x/net/webdav"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// confFile contains the configuration file for this File Manager instance.
|
// confFile contains the configuration file for this File Manager instance.
|
||||||
|
@ -65,7 +64,7 @@ func main() {
|
||||||
Commands: strings.Split(strings.TrimSpace(commands), " "),
|
Commands: strings.Split(strings.TrimSpace(commands), " "),
|
||||||
Rules: []*filemanager.Rule{},
|
Rules: []*filemanager.Rule{},
|
||||||
CSS: "",
|
CSS: "",
|
||||||
FileSystem: webdav.Dir(scope),
|
FileSystem: dir.Dir(scope),
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -0,0 +1,226 @@
|
||||||
|
// Package dir implements a FileSystem interface using the native
|
||||||
|
// file system restricted to a specific directory tree. Originally from
|
||||||
|
// https://github.com/golang/net/blob/master/webdav/file.go#L68
|
||||||
|
package dir
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Dir uses the native file system restricted to a specific directory tree.
|
||||||
|
//
|
||||||
|
// While the FileSystem.OpenFile method takes '/'-separated paths, a Dir's
|
||||||
|
// string value is a filename on the native file system, not a URL, so it is
|
||||||
|
// separated by filepath.Separator, which isn't necessarily '/'.
|
||||||
|
//
|
||||||
|
// An empty Dir is treated as ".".
|
||||||
|
type Dir string
|
||||||
|
|
||||||
|
func (d Dir) resolve(name string) string {
|
||||||
|
// This implementation is based on Dir.Open's code in the standard net/http package.
|
||||||
|
if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 ||
|
||||||
|
strings.Contains(name, "\x00") {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
dir := string(d)
|
||||||
|
if dir == "" {
|
||||||
|
dir = "."
|
||||||
|
}
|
||||||
|
|
||||||
|
return filepath.Join(dir, filepath.FromSlash(SlashClean(name)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mkdir implements os.Mkdir in this directory context.
|
||||||
|
func (d Dir) Mkdir(name string, perm os.FileMode) error {
|
||||||
|
if name = d.resolve(name); name == "" {
|
||||||
|
return os.ErrNotExist
|
||||||
|
}
|
||||||
|
return os.Mkdir(name, perm)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenFile implements os.OpenFile in this directory context.
|
||||||
|
func (d Dir) OpenFile(name string, flag int, perm os.FileMode) (*os.File, error) {
|
||||||
|
if name = d.resolve(name); name == "" {
|
||||||
|
return nil, os.ErrNotExist
|
||||||
|
}
|
||||||
|
f, err := os.OpenFile(name, flag, perm)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveAll implements os.RemoveAll in this directory context.
|
||||||
|
func (d Dir) RemoveAll(name string) error {
|
||||||
|
if name = d.resolve(name); name == "" {
|
||||||
|
return os.ErrNotExist
|
||||||
|
}
|
||||||
|
|
||||||
|
if name == filepath.Clean(string(d)) {
|
||||||
|
// Prohibit removing the virtual root directory.
|
||||||
|
return os.ErrInvalid
|
||||||
|
}
|
||||||
|
return os.RemoveAll(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rename implements os.Rename in this directory context.
|
||||||
|
func (d Dir) Rename(oldName, newName string) error {
|
||||||
|
if oldName = d.resolve(oldName); oldName == "" {
|
||||||
|
return os.ErrNotExist
|
||||||
|
}
|
||||||
|
if newName = d.resolve(newName); newName == "" {
|
||||||
|
return os.ErrNotExist
|
||||||
|
}
|
||||||
|
if root := filepath.Clean(string(d)); root == oldName || root == newName {
|
||||||
|
// Prohibit renaming from or to the virtual root directory.
|
||||||
|
return os.ErrInvalid
|
||||||
|
}
|
||||||
|
return os.Rename(oldName, newName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stat implements os.Stat in this directory context.
|
||||||
|
func (d Dir) Stat(name string) (os.FileInfo, error) {
|
||||||
|
if name = d.resolve(name); name == "" {
|
||||||
|
return nil, os.ErrNotExist
|
||||||
|
}
|
||||||
|
|
||||||
|
return os.Stat(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy copies a file or directory from src to dst. If it is
|
||||||
|
// a directory, all of the files and sub-directories will be copied.
|
||||||
|
func (d Dir) Copy(src, dst string) error {
|
||||||
|
if src = d.resolve(src); src == "" {
|
||||||
|
return os.ErrNotExist
|
||||||
|
}
|
||||||
|
|
||||||
|
if dst = d.resolve(dst); dst == "" {
|
||||||
|
return os.ErrNotExist
|
||||||
|
}
|
||||||
|
|
||||||
|
if root := filepath.Clean(string(d)); root == src || root == dst {
|
||||||
|
// Prohibit copying from or to the virtual root directory.
|
||||||
|
return os.ErrInvalid
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := d.Stat(src)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.IsDir() {
|
||||||
|
return CopyDir(src, dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
return CopyFile(src, dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyFile copies a file from source to dest and returns
|
||||||
|
// an error if any.
|
||||||
|
func CopyFile(source string, dest string) error {
|
||||||
|
// Open the source file.
|
||||||
|
src, err := os.Open(source)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer src.Close()
|
||||||
|
|
||||||
|
// Makes the directory needed to create the dst
|
||||||
|
// file.
|
||||||
|
err = os.MkdirAll(filepath.Dir(dest), 0666)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the destination file.
|
||||||
|
dst, err := os.Create(dest)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer dst.Close()
|
||||||
|
|
||||||
|
// Copy the contents of the file.
|
||||||
|
_, err = io.Copy(dst, src)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the mode if the user can't
|
||||||
|
// open the file.
|
||||||
|
info, err := os.Stat(source)
|
||||||
|
if err != nil {
|
||||||
|
err = os.Chmod(dest, info.Mode())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyDir copies a directory from source to dest and all
|
||||||
|
// of its sub-directories. It doesn't stop if it finds an error
|
||||||
|
// during the copy. Returns an error if any.
|
||||||
|
func CopyDir(source string, dest string) error {
|
||||||
|
// Get properties of source.
|
||||||
|
srcinfo, err := os.Stat(source)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the destination directory.
|
||||||
|
err = os.MkdirAll(dest, srcinfo.Mode())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
dir, _ := os.Open(source)
|
||||||
|
obs, err := dir.Readdir(-1)
|
||||||
|
|
||||||
|
var errs []error
|
||||||
|
|
||||||
|
for _, obj := range obs {
|
||||||
|
fsource := source + "/" + obj.Name()
|
||||||
|
fdest := dest + "/" + obj.Name()
|
||||||
|
|
||||||
|
if obj.IsDir() {
|
||||||
|
// Create sub-directories, recursively.
|
||||||
|
err = CopyDir(fsource, fdest)
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Perform the file copy.
|
||||||
|
err = CopyFile(fsource, fdest)
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var errString string
|
||||||
|
for _, err := range errs {
|
||||||
|
errString += err.Error() + "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
if errString != "" {
|
||||||
|
return errors.New(errString)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
74
file.go
74
file.go
|
@ -2,14 +2,12 @@ package filemanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"hash"
|
"hash"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -89,7 +87,7 @@ func getInfo(url *url.URL, c *FileManager, u *User) (*file, error) {
|
||||||
Path: filepath.Join(string(u.FileSystem), url.Path),
|
Path: filepath.Join(string(u.FileSystem), url.Path),
|
||||||
}
|
}
|
||||||
|
|
||||||
info, err := u.FileSystem.Stat(context.TODO(), url.Path)
|
info, err := u.FileSystem.Stat(url.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
@ -112,7 +110,7 @@ func getInfo(url *url.URL, c *FileManager, u *User) (*file, error) {
|
||||||
func (i *file) getListing(c *RequestContext, r *http.Request) error {
|
func (i *file) getListing(c *RequestContext, r *http.Request) error {
|
||||||
// Gets the directory information using the Virtual File System of
|
// Gets the directory information using the Virtual File System of
|
||||||
// the user configuration.
|
// the user configuration.
|
||||||
f, err := c.User.FileSystem.OpenFile(context.TODO(), c.FI.VirtualPath, os.O_RDONLY, 0)
|
f, err := c.User.FileSystem.OpenFile(c.FI.VirtualPath, os.O_RDONLY, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -446,71 +444,3 @@ func editorLanguage(mode string) string {
|
||||||
|
|
||||||
return mode
|
return mode
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyFile(source string, dest string) (err error) {
|
|
||||||
sourcefile, err := os.Open(source)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer sourcefile.Close()
|
|
||||||
|
|
||||||
destfile, err := os.Create(dest)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer destfile.Close()
|
|
||||||
|
|
||||||
_, err = io.Copy(destfile, sourcefile)
|
|
||||||
if err == nil {
|
|
||||||
sourceinfo, err := os.Stat(source)
|
|
||||||
if err != nil {
|
|
||||||
err = os.Chmod(dest, sourceinfo.Mode())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func copyDir(source string, dest string) (err error) {
|
|
||||||
// get properties of source dir
|
|
||||||
sourceinfo, err := os.Stat(source)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// create dest dir
|
|
||||||
err = os.MkdirAll(dest, sourceinfo.Mode())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
directory, _ := os.Open(source)
|
|
||||||
objects, err := directory.Readdir(-1)
|
|
||||||
|
|
||||||
for _, obj := range objects {
|
|
||||||
sourcefilepointer := source + "/" + obj.Name()
|
|
||||||
destinationfilepointer := dest + "/" + obj.Name()
|
|
||||||
|
|
||||||
if obj.IsDir() {
|
|
||||||
// create sub-directories - recursively
|
|
||||||
err = copyDir(sourcefilepointer, destinationfilepointer)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// perform copy
|
|
||||||
err = copyFile(sourcefilepointer, destinationfilepointer)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
|
@ -11,8 +11,8 @@ import (
|
||||||
|
|
||||||
rice "github.com/GeertJohan/go.rice"
|
rice "github.com/GeertJohan/go.rice"
|
||||||
"github.com/asdine/storm"
|
"github.com/asdine/storm"
|
||||||
|
"github.com/hacdias/filemanager/dir"
|
||||||
"github.com/mholt/caddy"
|
"github.com/mholt/caddy"
|
||||||
"golang.org/x/net/webdav"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -74,7 +74,7 @@ type User struct {
|
||||||
Admin bool `json:"admin"`
|
Admin bool `json:"admin"`
|
||||||
|
|
||||||
// FileSystem is the virtual file system the user has access.
|
// FileSystem is the virtual file system the user has access.
|
||||||
FileSystem webdav.Dir `json:"filesystem"`
|
FileSystem dir.Dir `json:"filesystem"`
|
||||||
|
|
||||||
// Rules is an array of access and deny rules.
|
// Rules is an array of access and deny rules.
|
||||||
Rules []*Rule `json:"rules"`
|
Rules []*Rule `json:"rules"`
|
||||||
|
@ -134,7 +134,7 @@ var DefaultUser = User{
|
||||||
Rules: []*Rule{},
|
Rules: []*Rule{},
|
||||||
CSS: "",
|
CSS: "",
|
||||||
Admin: true,
|
Admin: true,
|
||||||
FileSystem: webdav.Dir("."),
|
FileSystem: dir.Dir("."),
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new File Manager instance. If 'database' file already
|
// New creates a new File Manager instance. If 'database' file already
|
||||||
|
|
2
http.go
2
http.go
|
@ -142,6 +142,8 @@ func apiHandler(c *RequestContext, w http.ResponseWriter, r *http.Request) (int,
|
||||||
code, err = commandsHandler(c, w, r)
|
code, err = commandsHandler(c, w, r)
|
||||||
case "plugins":
|
case "plugins":
|
||||||
code, err = pluginsHandler(c, w, r)
|
code, err = pluginsHandler(c, w, r)
|
||||||
|
default:
|
||||||
|
code = http.StatusNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
if code >= 300 || err != nil {
|
if code >= 300 || err != nil {
|
||||||
|
|
30
resource.go
30
resource.go
|
@ -1,7 +1,6 @@
|
||||||
package filemanager
|
package filemanager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
@ -10,15 +9,16 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/hacdias/filemanager/dir"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DISCLAIMER: this doesn't sanitize the target path so some may think
|
|
||||||
// that path trasversal would be possible and the user could change files
|
|
||||||
// outside of their scope. The User.FileSystem variable is of type webdav.Dir
|
|
||||||
// which does those checks so this package doesn't need to do them.
|
|
||||||
// https://github.com/golang/net/blob/master/webdav/file.go#L68
|
|
||||||
|
|
||||||
func resourceHandler(c *RequestContext, w http.ResponseWriter, r *http.Request) (int, error) {
|
func resourceHandler(c *RequestContext, w http.ResponseWriter, r *http.Request) (int, error) {
|
||||||
|
r.URL.Path = dir.SlashClean(r.URL.Path)
|
||||||
|
if !c.User.Allowed(r.URL.Path) {
|
||||||
|
return http.StatusForbidden, nil
|
||||||
|
}
|
||||||
|
|
||||||
switch r.Method {
|
switch r.Method {
|
||||||
case http.MethodGet:
|
case http.MethodGet:
|
||||||
return resourceGetHandler(c, w, r)
|
return resourceGetHandler(c, w, r)
|
||||||
|
@ -131,7 +131,7 @@ func resourceDeleteHandler(c *RequestContext, w http.ResponseWriter, r *http.Req
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the file or folder.
|
// Remove the file or folder.
|
||||||
err := c.User.FileSystem.RemoveAll(context.TODO(), r.URL.Path)
|
err := c.User.FileSystem.RemoveAll(r.URL.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errorToHTTP(err, true), err
|
return errorToHTTP(err, true), err
|
||||||
}
|
}
|
||||||
|
@ -157,7 +157,7 @@ func resourcePostPutHandler(c *RequestContext, w http.ResponseWriter, r *http.Re
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise we try to create the directory.
|
// Otherwise we try to create the directory.
|
||||||
err := c.User.FileSystem.Mkdir(context.TODO(), r.URL.Path, 0666)
|
err := c.User.FileSystem.Mkdir(r.URL.Path, 0666)
|
||||||
return errorToHTTP(err, false), err
|
return errorToHTTP(err, false), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,13 +165,13 @@ func resourcePostPutHandler(c *RequestContext, w http.ResponseWriter, r *http.Re
|
||||||
// desirable to override an already existent file. Thus, we check
|
// desirable to override an already existent file. Thus, we check
|
||||||
// if the file already exists. If so, we just return a 409 Conflict.
|
// if the file already exists. If so, we just return a 409 Conflict.
|
||||||
if r.Method == http.MethodPost {
|
if r.Method == http.MethodPost {
|
||||||
if _, err := c.User.FileSystem.Stat(context.TODO(), r.URL.Path); err == nil {
|
if _, err := c.User.FileSystem.Stat(r.URL.Path); err == nil {
|
||||||
return http.StatusConflict, errors.New("There is already a file on that path")
|
return http.StatusConflict, errors.New("There is already a file on that path")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create/Open the file.
|
// Create/Open the file.
|
||||||
f, err := c.User.FileSystem.OpenFile(context.TODO(), r.URL.Path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
|
f, err := c.User.FileSystem.OpenFile(r.URL.Path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errorToHTTP(err, false), err
|
return errorToHTTP(err, false), err
|
||||||
}
|
}
|
||||||
|
@ -202,6 +202,7 @@ func resourcePatchHandler(c *RequestContext, w http.ResponseWriter, r *http.Requ
|
||||||
}
|
}
|
||||||
|
|
||||||
dst := r.Header.Get("Destination")
|
dst := r.Header.Get("Destination")
|
||||||
|
action := r.Header.Get("Action")
|
||||||
dst, err := url.QueryUnescape(dst)
|
dst, err := url.QueryUnescape(dst)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errorToHTTP(err, true), err
|
return errorToHTTP(err, true), err
|
||||||
|
@ -213,7 +214,12 @@ func resourcePatchHandler(c *RequestContext, w http.ResponseWriter, r *http.Requ
|
||||||
return http.StatusForbidden, nil
|
return http.StatusForbidden, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.User.FileSystem.Rename(context.TODO(), src, dst)
|
if action == "copy" {
|
||||||
|
err = c.User.FileSystem.Copy(src, dst)
|
||||||
|
} else {
|
||||||
|
err = c.User.FileSystem.Rename(src, dst)
|
||||||
|
}
|
||||||
|
|
||||||
return errorToHTTP(err, true), err
|
return errorToHTTP(err, true), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue