webdav: stop using os errors in FileSystem interface

Use NewHTTPError instead.

Closes: https://github.com/emersion/go-webdav/issues/20
This commit is contained in:
Simon Ser 2024-02-06 15:23:30 +01:00
parent eaac65215b
commit 80d77a977a
2 changed files with 39 additions and 33 deletions

View File

@ -63,6 +63,18 @@ func fileInfoFromOS(p string, fi os.FileInfo) *FileInfo {
}
}
func errFromOS(err error) error {
if os.IsNotExist(err) {
return NewHTTPError(http.StatusNotFound, err)
} else if os.IsPermission(err) {
return NewHTTPError(http.StatusForbidden, err)
} else if os.IsTimeout(err) {
return NewHTTPError(http.StatusServiceUnavailable, err)
} else {
return err
}
}
func (fs LocalFileSystem) Stat(ctx context.Context, name string) (*FileInfo, error) {
p, err := fs.localPath(name)
if err != nil {
@ -70,7 +82,7 @@ func (fs LocalFileSystem) Stat(ctx context.Context, name string) (*FileInfo, err
}
fi, err := os.Stat(p)
if err != nil {
return nil, err
return nil, errFromOS(err)
}
return fileInfoFromOS(name, fi), nil
}
@ -99,7 +111,7 @@ func (fs LocalFileSystem) ReadDir(ctx context.Context, name string, recursive bo
}
return nil
})
return l, err
return l, errFromOS(err)
}
func (fs LocalFileSystem) Create(ctx context.Context, name string) (io.WriteCloser, error) {
@ -107,7 +119,8 @@ func (fs LocalFileSystem) Create(ctx context.Context, name string) (io.WriteClos
if err != nil {
return nil, err
}
return os.Create(p)
wc, err := os.Create(p)
return wc, errFromOS(err)
}
func (fs LocalFileSystem) RemoveAll(ctx context.Context, name string) error {
@ -119,10 +132,10 @@ func (fs LocalFileSystem) RemoveAll(ctx context.Context, name string) error {
// WebDAV semantics are that it should return a "404 Not Found" error in
// case the resource doesn't exist. We need to Stat before RemoveAll.
if _, err = os.Stat(p); err != nil {
return err
return errFromOS(err)
}
return os.RemoveAll(p)
return errFromOS(os.RemoveAll(p))
}
func (fs LocalFileSystem) Mkdir(ctx context.Context, name string) error {
@ -130,20 +143,21 @@ func (fs LocalFileSystem) Mkdir(ctx context.Context, name string) error {
if err != nil {
return err
}
return os.Mkdir(p, 0755)
return errFromOS(os.Mkdir(p, 0755))
}
func copyRegularFile(src, dst string, perm os.FileMode) error {
srcFile, err := os.Open(src)
if err != nil {
return err
return errFromOS(err)
}
defer srcFile.Close()
dstFile, err := os.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, perm)
if err != nil {
// TODO: send http.StatusConflict on os.IsNotExist
return err
if os.IsNotExist(err) {
return NewHTTPError(http.StatusConflict, err)
} else if err != nil {
return errFromOS(err)
}
defer dstFile.Close()
@ -169,21 +183,21 @@ func (fs LocalFileSystem) Copy(ctx context.Context, src, dst string, options *Co
srcInfo, err := os.Stat(srcPath)
if err != nil {
return false, err
return false, errFromOS(err)
}
srcPerm := srcInfo.Mode() & os.ModePerm
if _, err := os.Stat(dstPath); err != nil {
if !os.IsNotExist(err) {
return false, err
return false, errFromOS(err)
}
created = true
} else {
if options.NoOverwrite {
return false, os.ErrExist
return false, NewHTTPError(http.StatusPreconditionFailed, os.ErrExist)
}
if err := os.RemoveAll(dstPath); err != nil {
return false, err
return false, errFromOS(err)
}
}
@ -194,7 +208,7 @@ func (fs LocalFileSystem) Copy(ctx context.Context, src, dst string, options *Co
if fi.IsDir() {
if err := os.Mkdir(dstPath, srcPerm); err != nil {
return err
return errFromOS(err)
}
} else {
if err := copyRegularFile(srcPath, dstPath, srcPerm); err != nil {
@ -208,7 +222,7 @@ func (fs LocalFileSystem) Copy(ctx context.Context, src, dst string, options *Co
return nil
})
if err != nil {
return false, err
return false, errFromOS(err)
}
return created, nil
@ -226,20 +240,20 @@ func (fs LocalFileSystem) Move(ctx context.Context, src, dst string, options *Mo
if _, err := os.Stat(dstPath); err != nil {
if !os.IsNotExist(err) {
return false, err
return false, errFromOS(err)
}
created = true
} else {
if options.NoOverwrite {
return false, os.ErrExist
return false, NewHTTPError(http.StatusPreconditionFailed, os.ErrExist)
}
if err := os.RemoveAll(dstPath); err != nil {
return false, err
return false, errFromOS(err)
}
}
if err := os.Rename(srcPath, dstPath); err != nil {
return false, err
return false, errFromOS(err)
}
return created, nil

View File

@ -57,7 +57,7 @@ type backend struct {
func (b *backend) Options(r *http.Request) (caps []string, allow []string, err error) {
fi, err := b.FileSystem.Stat(r.Context(), r.URL.Path)
if os.IsNotExist(err) {
if internal.IsNotFound(err) {
return nil, []string{http.MethodOptions, http.MethodPut, "MKCOL"}, nil
} else if err != nil {
return nil, nil, err
@ -80,9 +80,7 @@ func (b *backend) Options(r *http.Request) (caps []string, allow []string, err e
func (b *backend) HeadGet(w http.ResponseWriter, r *http.Request) error {
fi, err := b.FileSystem.Stat(r.Context(), r.URL.Path)
if os.IsNotExist(err) {
return &internal.HTTPError{Code: http.StatusNotFound, Err: err}
} else if err != nil {
if err != nil {
return err
}
if fi.IsDir {
@ -121,9 +119,7 @@ func (b *backend) PropFind(r *http.Request, propfind *internal.PropFind, depth i
// TODO: use partial error Response on error
fi, err := b.FileSystem.Stat(r.Context(), r.URL.Path)
if os.IsNotExist(err) {
return nil, &internal.HTTPError{Code: http.StatusNotFound, Err: err}
} else if err != nil {
if err != nil {
return nil, err
}
@ -212,11 +208,7 @@ func (b *backend) Put(r *http.Request) (*internal.Href, error) {
}
func (b *backend) Delete(r *http.Request) error {
err := b.FileSystem.RemoveAll(r.Context(), r.URL.Path)
if os.IsNotExist(err) {
return &internal.HTTPError{Code: http.StatusNotFound, Err: err}
}
return err
return b.FileSystem.RemoveAll(r.Context(), r.URL.Path)
}
func (b *backend) Mkcol(r *http.Request) error {
@ -224,7 +216,7 @@ func (b *backend) Mkcol(r *http.Request) error {
return internal.HTTPErrorf(http.StatusUnsupportedMediaType, "webdav: request body not supported in MKCOL request")
}
err := b.FileSystem.Mkdir(r.Context(), r.URL.Path)
if os.IsNotExist(err) {
if internal.IsNotFound(err) {
return &internal.HTTPError{Code: http.StatusConflict, Err: err}
}
return err