mirror of
https://github.com/rclone/rclone.git
synced 2024-11-07 09:04:52 +01:00
backends: make NewObject return fs.ErrorIsDir if possible
This changes the interface to NewObject so that if NewObject is called on a directory then it should return fs.ErrorIsDir if possible without doing any extra work, otherwise fs.ErrorObjectNotFound. Tested on integration test server with: go run integration-test.go -tests backend -run TestIntegration/FsMkdir/FsPutFiles/FsNewObjectDir -branch fix-stat -maxtries 1
This commit is contained in:
parent
af732c5431
commit
3fbaa4c0b0
@ -1184,6 +1184,9 @@ func (o *Object) Size() int64 {
|
||||
|
||||
// setMetaData sets the metadata from info
|
||||
func (o *Object) setMetaData(info *api.Item) (err error) {
|
||||
if info.Type == api.ItemTypeFolder {
|
||||
return fs.ErrorIsDir
|
||||
}
|
||||
if info.Type != api.ItemTypeFile {
|
||||
return errors.Wrapf(fs.ErrorNotAFile, "%q is %q", o.remote, info.Type)
|
||||
}
|
||||
|
@ -1374,7 +1374,7 @@ func (f *Fs) newObjectWithExportInfo(
|
||||
}
|
||||
switch {
|
||||
case info.MimeType == driveFolderType:
|
||||
return nil, fs.ErrorNotAFile
|
||||
return nil, fs.ErrorIsDir
|
||||
case info.MimeType == shortcutMimeType:
|
||||
// We can only get here if f.opt.SkipShortcuts is set
|
||||
// and not from a listing. This is unlikely.
|
||||
@ -2922,7 +2922,7 @@ func (f *Fs) makeShortcut(ctx context.Context, srcPath string, dstFs *Fs, dstPat
|
||||
}
|
||||
isDir = true
|
||||
} else if srcObj, err := srcFs.NewObject(ctx, srcPath); err != nil {
|
||||
if err != fs.ErrorNotAFile {
|
||||
if err != fs.ErrorIsDir {
|
||||
return nil, errors.Wrap(err, "can't find source")
|
||||
}
|
||||
// source was a directory
|
||||
@ -2942,7 +2942,7 @@ func (f *Fs) makeShortcut(ctx context.Context, srcPath string, dstFs *Fs, dstPat
|
||||
if err != fs.ErrorObjectNotFound {
|
||||
if err == nil {
|
||||
err = errors.New("existing file")
|
||||
} else if err == fs.ErrorNotAFile {
|
||||
} else if err == fs.ErrorIsDir {
|
||||
err = errors.New("existing directory")
|
||||
}
|
||||
return nil, errors.Wrap(err, "not overwriting shortcut target")
|
||||
|
@ -624,6 +624,9 @@ func (f *Fs) getFileMetadata(ctx context.Context, filePath string) (fileInfo *fi
|
||||
}
|
||||
fileInfo, ok := entry.(*files.FileMetadata)
|
||||
if !ok {
|
||||
if _, ok = entry.(*files.FolderMetadata); ok {
|
||||
return nil, fs.ErrorIsDir
|
||||
}
|
||||
return nil, fs.ErrorNotAFile
|
||||
}
|
||||
return fileInfo, nil
|
||||
|
@ -1089,7 +1089,7 @@ func (o *Object) Size() int64 {
|
||||
// setMetaData sets the metadata from info
|
||||
func (o *Object) setMetaData(info *api.Item) (err error) {
|
||||
if info.Type != api.ItemTypeFile {
|
||||
return errors.Wrapf(fs.ErrorNotAFile, "%q is %q", o.remote, info.Type)
|
||||
return fs.ErrorIsDir
|
||||
}
|
||||
o.hasMetaData = true
|
||||
o.size = info.Size
|
||||
|
@ -599,7 +599,9 @@ func (f *Fs) readMetaDataForPath(ctx context.Context, path string) (info *api.Jo
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "read metadata failed")
|
||||
}
|
||||
if result.XMLName.Local != "file" {
|
||||
if result.XMLName.Local == "folder" {
|
||||
return nil, fs.ErrorIsDir
|
||||
} else if result.XMLName.Local != "file" {
|
||||
return nil, fs.ErrorNotAFile
|
||||
}
|
||||
return &result, nil
|
||||
@ -762,7 +764,7 @@ func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, e
|
||||
// Renew the token in the background
|
||||
f.tokenRenewer = oauthutil.NewRenew(f.String(), ts, func() error {
|
||||
_, err := f.readMetaDataForPath(ctx, "")
|
||||
if err == fs.ErrorNotAFile {
|
||||
if err == fs.ErrorNotAFile || err == fs.ErrorIsDir {
|
||||
err = nil
|
||||
}
|
||||
return err
|
||||
@ -784,7 +786,7 @@ func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, e
|
||||
}
|
||||
_, err := f.NewObject(context.TODO(), remote)
|
||||
if err != nil {
|
||||
if errors.Cause(err) == fs.ErrorObjectNotFound || errors.Cause(err) == fs.ErrorNotAFile {
|
||||
if uErr := errors.Cause(err); uErr == fs.ErrorObjectNotFound || uErr == fs.ErrorNotAFile || uErr == fs.ErrorIsDir {
|
||||
// File doesn't exist so return old f
|
||||
f.root = root
|
||||
return f, nil
|
||||
|
@ -344,7 +344,7 @@ func (f *Fs) NewObject(ctx context.Context, remote string) (obj fs.Object, err e
|
||||
return nil, translateErrorsObject(err)
|
||||
}
|
||||
if info.Type == "dir" {
|
||||
return nil, fs.ErrorNotAFile
|
||||
return nil, fs.ErrorIsDir
|
||||
}
|
||||
return &Object{
|
||||
fs: f,
|
||||
|
@ -401,7 +401,7 @@ func (f *Fs) newObjectWithInfo(remote string, info os.FileInfo) (fs.Object, erro
|
||||
|
||||
}
|
||||
if o.mode.IsDir() {
|
||||
return nil, errors.Wrapf(fs.ErrorNotAFile, "%q", remote)
|
||||
return nil, fs.ErrorIsDir
|
||||
}
|
||||
return o, nil
|
||||
}
|
||||
|
@ -1958,7 +1958,7 @@ func (o *Object) readMetaData(ctx context.Context, force bool) error {
|
||||
}
|
||||
newObj, ok := entry.(*Object)
|
||||
if !ok || dirSize >= 0 {
|
||||
return fs.ErrorNotAFile
|
||||
return fs.ErrorIsDir
|
||||
}
|
||||
if newObj.remote != o.remote {
|
||||
return fmt.Errorf("File %q path has changed to %q", o.remote, newObj.remote)
|
||||
|
@ -303,7 +303,7 @@ func (f *Fs) findObject(rootNode *mega.Node, file string) (node *mega.Node, err
|
||||
if err == mega.ENOENT {
|
||||
return nil, fs.ErrorObjectNotFound
|
||||
} else if err == nil && node.GetType() != mega.FILE {
|
||||
return nil, fs.ErrorNotAFile
|
||||
return nil, fs.ErrorIsDir // all other node types are directories
|
||||
}
|
||||
return node, err
|
||||
}
|
||||
@ -958,7 +958,7 @@ func (o *Object) Size() int64 {
|
||||
// setMetaData sets the metadata from info
|
||||
func (o *Object) setMetaData(info *mega.Node) (err error) {
|
||||
if info.GetType() != mega.FILE {
|
||||
return fs.ErrorNotAFile
|
||||
return fs.ErrorIsDir // all other node types are directories
|
||||
}
|
||||
o.info = info
|
||||
return nil
|
||||
|
@ -1715,7 +1715,7 @@ func (o *Object) Size() int64 {
|
||||
// setMetaData sets the metadata from info
|
||||
func (o *Object) setMetaData(info *api.Item) (err error) {
|
||||
if info.GetFolder() != nil {
|
||||
return errors.Wrapf(fs.ErrorNotAFile, "%q", o.remote)
|
||||
return fs.ErrorIsDir
|
||||
}
|
||||
o.hasMetaData = true
|
||||
o.size = info.GetSize()
|
||||
|
@ -151,7 +151,7 @@ func (o *Object) readEntry(ctx context.Context) (f *putio.File, err error) {
|
||||
return nil, err
|
||||
}
|
||||
if resp.File.IsDir() {
|
||||
return nil, fs.ErrorNotAFile
|
||||
return nil, fs.ErrorIsDir
|
||||
}
|
||||
return &resp.File, err
|
||||
}
|
||||
|
@ -1383,7 +1383,7 @@ func (o *Object) stat(ctx context.Context) error {
|
||||
return errors.Wrap(err, "stat failed")
|
||||
}
|
||||
if info.IsDir() {
|
||||
return errors.Wrapf(fs.ErrorNotAFile, "%q", o.remote)
|
||||
return fs.ErrorIsDir
|
||||
}
|
||||
o.setMetadata(info)
|
||||
return nil
|
||||
|
@ -337,8 +337,12 @@ func (f *Fs) readMetaDataForIDPath(ctx context.Context, id, path string, directo
|
||||
if directoriesOnly && item.Type != api.ItemTypeFolder {
|
||||
return nil, fs.ErrorIsFile
|
||||
}
|
||||
if filesOnly && item.Type != api.ItemTypeFile {
|
||||
return nil, fs.ErrorNotAFile
|
||||
if filesOnly {
|
||||
if item.Type == api.ItemTypeFolder {
|
||||
return nil, fs.ErrorIsDir
|
||||
} else if item.Type != api.ItemTypeFile {
|
||||
return nil, fs.ErrorNotAFile
|
||||
}
|
||||
}
|
||||
return &item, nil
|
||||
}
|
||||
|
@ -317,7 +317,7 @@ func (f *Fs) readMetaDataForPath(ctx context.Context, path string, depth string)
|
||||
return nil, fs.ErrorObjectNotFound
|
||||
}
|
||||
if itemIsDir(&item) {
|
||||
return nil, fs.ErrorNotAFile
|
||||
return nil, fs.ErrorIsDir
|
||||
}
|
||||
return &item.Props, nil
|
||||
}
|
||||
@ -469,7 +469,7 @@ func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, e
|
||||
}
|
||||
_, err := f.NewObject(ctx, remote)
|
||||
if err != nil {
|
||||
if errors.Cause(err) == fs.ErrorObjectNotFound || errors.Cause(err) == fs.ErrorNotAFile {
|
||||
if errors.Cause(err) == fs.ErrorObjectNotFound || errors.Cause(err) == fs.ErrorIsDir {
|
||||
// File doesn't exist so return old f
|
||||
f.root = root
|
||||
return f, nil
|
||||
|
@ -949,7 +949,9 @@ func (o *Object) readMetaData(ctx context.Context) (err error) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.ResourceType != "file" {
|
||||
if info.ResourceType == "dir" {
|
||||
return fs.ErrorIsDir
|
||||
} else if info.ResourceType != "file" {
|
||||
return fs.ErrorNotAFile
|
||||
}
|
||||
return o.setMetaData(info)
|
||||
|
@ -1121,7 +1121,7 @@ func (o *Object) Size() int64 {
|
||||
// setMetaData sets the metadata from info
|
||||
func (o *Object) setMetaData(info *api.Item) (err error) {
|
||||
if info.Attributes.IsFolder {
|
||||
return fs.ErrorNotAFile
|
||||
return fs.ErrorIsDir
|
||||
}
|
||||
o.hasMetaData = true
|
||||
o.size = info.Attributes.StorageInfo.Size
|
||||
|
1
fs/fs.go
1
fs/fs.go
@ -37,6 +37,7 @@ var (
|
||||
ErrorListAborted = errors.New("list aborted")
|
||||
ErrorListBucketRequired = errors.New("bucket or container name is needed in remote")
|
||||
ErrorIsFile = errors.New("is a file not a directory")
|
||||
ErrorIsDir = errors.New("is a directory not a file")
|
||||
ErrorNotAFile = errors.New("is not a regular file")
|
||||
ErrorNotDeleting = errors.New("not deleting files as there were IO errors")
|
||||
ErrorNotDeletingDirs = errors.New("not deleting directories as there were IO errors")
|
||||
|
@ -28,6 +28,10 @@ type Fs interface {
|
||||
|
||||
// NewObject finds the Object at remote. If it can't be found
|
||||
// it returns the error ErrorObjectNotFound.
|
||||
//
|
||||
// If remote points to a directory then it should return
|
||||
// ErrorIsDir if possible without doing any extra work,
|
||||
// otherwise ErrorObjectNotFound.
|
||||
NewObject(ctx context.Context, remote string) (Object, error)
|
||||
|
||||
// Put in to the remote path with the modTime given of the given size
|
||||
|
@ -1044,13 +1044,13 @@ func Run(t *testing.T, opt *Opt) {
|
||||
fstest.CheckListing(t, f, []fstest.Item{file1, file2})
|
||||
})
|
||||
|
||||
// TestFsNewObjectDir tests NewObject on a directory which should produce an error
|
||||
// TestFsNewObjectDir tests NewObject on a directory which should produce fs.ErrorIsDir if possible or fs.ErrorObjectNotFound if not
|
||||
t.Run("FsNewObjectDir", func(t *testing.T) {
|
||||
skipIfNotOk(t)
|
||||
dir := path.Dir(file2.Path)
|
||||
obj, err := f.NewObject(ctx, dir)
|
||||
assert.Nil(t, obj)
|
||||
assert.NotNil(t, err)
|
||||
assert.True(t, err == fs.ErrorIsDir || err == fs.ErrorObjectNotFound, fmt.Sprintf("Wrong error: expecting fs.ErrorIsDir or fs.ErrorObjectNotFound but got: %#v", err))
|
||||
})
|
||||
|
||||
// TestFsPurge tests Purge
|
||||
|
Loading…
Reference in New Issue
Block a user