diff --git a/amazonclouddrive/amazonclouddrive.go b/amazonclouddrive/amazonclouddrive.go index f6badc1d2..924a5e9a8 100644 --- a/amazonclouddrive/amazonclouddrive.go +++ b/amazonclouddrive/amazonclouddrive.go @@ -215,10 +215,13 @@ func NewFs(name, root string) (fs.Fs, error) { // No root so return old f return f, nil } - obj := newF.newObjectWithInfo(remote, nil) - if obj == nil { - // File doesn't exist so return old f - return f, nil + _, err := newF.newObjectWithInfo(remote, nil) + if err != nil { + if err == fs.ErrorObjectNotFound { + // File doesn't exist so return old f + return f, nil + } + return nil, err } // return an error with an fs which points to the parent return &newF, fs.ErrorIsFile @@ -228,8 +231,8 @@ func NewFs(name, root string) (fs.Fs, error) { // Return an Object from a path // -// May return nil if an error occurred -func (f *Fs) newObjectWithInfo(remote string, info *acd.Node) fs.Object { +// If it can't be found it returns the error fs.ErrorObjectNotFound. +func (f *Fs) newObjectWithInfo(remote string, info *acd.Node) (fs.Object, error) { o := &Object{ fs: f, remote: remote, @@ -240,17 +243,15 @@ func (f *Fs) newObjectWithInfo(remote string, info *acd.Node) fs.Object { } else { err := o.readMetaData() // reads info and meta, returning an error if err != nil { - fs.Log(o, "Failed to read metadata: %s", err) - return nil + return nil, err } } - return o + return o, nil } -// NewObject returns an Object from a path -// -// May return nil if an error occurred -func (f *Fs) NewObject(remote string) fs.Object { +// NewObject finds the Object at remote. If it can't be found +// it returns the error fs.ErrorObjectNotFound. +func (f *Fs) NewObject(remote string) (fs.Object, error) { return f.newObjectWithInfo(remote, nil) } @@ -384,10 +385,13 @@ func (f *Fs) ListDir(out fs.ListOpts, job dircache.ListDirJob) (jobs []dircache. } } case fileKind: - if o := f.newObjectWithInfo(remote, node); o != nil { - if out.Add(o) { - return true - } + o, err := f.newObjectWithInfo(remote, node) + if err != nil { + out.SetError(err) + return true + } + if out.Add(o) { + return true } default: // ignore ASSET etc @@ -430,7 +434,7 @@ func (f *Fs) Put(in io.Reader, src fs.ObjectInfo) (fs.Object, error) { switch err { case nil: return o, o.Update(in, src) - case fs.ErrorDirNotFound, acd.ErrorNodeNotFound: + case fs.ErrorObjectNotFound: // Not found so create it default: return nil, err @@ -608,12 +612,17 @@ func (o *Object) Size() int64 { // readMetaData gets the metadata if it hasn't already been fetched // // it also sets the info +// +// If it can't be found it returns the error fs.ErrorObjectNotFound. func (o *Object) readMetaData() (err error) { if o.info != nil { return nil } leaf, directoryID, err := o.fs.dirCache.FindPath(o.remote, false) if err != nil { + if err == fs.ErrorDirNotFound { + return fs.ErrorObjectNotFound + } return err } folder := acd.FolderFromId(directoryID, o.fs.c.Nodes) @@ -624,6 +633,9 @@ func (o *Object) readMetaData() (err error) { return o.fs.shouldRetry(resp, err) }) if err != nil { + if err == acd.ErrorNodeNotFound { + return fs.ErrorObjectNotFound + } return err } o.info = info.Node diff --git a/b2/b2.go b/b2/b2.go index abe7421c6..191428aa2 100644 --- a/b2/b2.go +++ b/b2/b2.go @@ -237,12 +237,17 @@ func NewFs(name, root string) (fs.Fs, error) { } else { f.root += "/" } - obj := f.NewObject(remote) - if obj != nil { - // return an error with an fs which points to the parent - return f, fs.ErrorIsFile + _, err := f.NewObject(remote) + if err != nil { + if err == fs.ErrorObjectNotFound { + // File doesn't exist so return old f + f.root = oldRoot + return f, nil + } + return nil, err } - f.root = oldRoot + // return an error with an fs which points to the parent + return f, fs.ErrorIsFile } return f, nil } @@ -321,8 +326,8 @@ func (f *Fs) clearUploadURL() { // Return an Object from a path // -// May return nil if an error occurred -func (f *Fs) newObjectWithInfo(remote string, info *api.File) fs.Object { +// If it can't be found it returns the error fs.ErrorObjectNotFound. +func (f *Fs) newObjectWithInfo(remote string, info *api.File) (fs.Object, error) { o := &Object{ fs: f, remote: remote, @@ -330,23 +335,20 @@ func (f *Fs) newObjectWithInfo(remote string, info *api.File) fs.Object { if info != nil { err := o.decodeMetaData(info) if err != nil { - fs.Debug(o, "Failed to decode metadata: %s", err) - return nil + return nil, err } } else { err := o.readMetaData() // reads info and headers, returning an error if err != nil { - fs.Debug(o, "Failed to read metadata: %s", err) - return nil + return nil, err } } - return o + return o, nil } -// NewObject returns an Object from a path -// -// May return nil if an error occurred -func (f *Fs) NewObject(remote string) fs.Object { +// NewObject finds the Object at remote. If it can't be found +// it returns the error fs.ErrorObjectNotFound. +func (f *Fs) NewObject(remote string) (fs.Object, error) { return f.newObjectWithInfo(remote, nil) } @@ -495,10 +497,12 @@ func (f *Fs) listFiles(out fs.ListOpts, dir string) { return fs.ErrorListAborted } } else { - if o := f.newObjectWithInfo(remote, object); o != nil { - if out.Add(o) { - return fs.ErrorListAborted - } + o, err := f.newObjectWithInfo(remote, object) + if err != nil { + return err + } + if out.Add(o) { + return fs.ErrorListAborted } } return nil @@ -855,10 +859,13 @@ func (o *Object) readMetaData() (err error) { return errEndList // read only 1 item }) if err != nil { + if err == fs.ErrorDirNotFound { + return fs.ErrorObjectNotFound + } return err } if info == nil { - return errors.Errorf("object %q not found", o.remote) + return fs.ErrorObjectNotFound } return o.decodeMetaData(info) } diff --git a/drive/drive.go b/drive/drive.go index 841e75d89..a33d23af5 100644 --- a/drive/drive.go +++ b/drive/drive.go @@ -80,7 +80,6 @@ var ( "text/plain": "txt", } extensionToMimeType map[string]string - errorObjectNotFound = errors.New("Object not found") ) // Register with Fs @@ -337,7 +336,7 @@ func NewFs(name, path string) (fs.Fs, error) { // No root so return old f return f, nil } - _, err := newF.newObjectWithInfoErr(remote, nil) + _, err := newF.newObjectWithInfo(remote, nil) if err != nil { // File doesn't exist so return old f return f, nil @@ -350,7 +349,9 @@ func NewFs(name, path string) (fs.Fs, error) { } // Return an Object from a path -func (f *Fs) newObjectWithInfoErr(remote string, info *drive.File) (fs.Object, error) { +// +// If it can't be found it returns the error fs.ErrorObjectNotFound. +func (f *Fs) newObjectWithInfo(remote string, info *drive.File) (fs.Object, error) { o := &Object{ fs: f, remote: remote, @@ -366,21 +367,9 @@ func (f *Fs) newObjectWithInfoErr(remote string, info *drive.File) (fs.Object, e return o, nil } -// Return an Object from a path -// -// May return nil if an error occurred -func (f *Fs) newObjectWithInfo(remote string, info *drive.File) fs.Object { - o, err := f.newObjectWithInfoErr(remote, info) - if err != nil { - fs.Log(o, "Failed to read metadata: %v", err) - } - return o -} - -// NewObject returns an Object from a path -// -// May return nil if an error occurred -func (f *Fs) NewObject(remote string) fs.Object { +// NewObject finds the Object at remote. If it can't be found +// it returns the error fs.ErrorObjectNotFound. +func (f *Fs) NewObject(remote string) (fs.Object, error) { return f.newObjectWithInfo(remote, nil) } @@ -478,10 +467,13 @@ func (f *Fs) ListDir(out fs.ListOpts, job dircache.ListDirJob) (jobs []dircache. } case item.Md5Checksum != "": // If item has MD5 sum it is a file stored on drive - if o := f.newObjectWithInfo(remote, item); o != nil { - if out.Add(o) { - return true - } + o, err := f.newObjectWithInfo(remote, item) + if err != nil { + out.SetError(err) + return true + } + if out.Add(o) { + return true } case len(item.ExportLinks) != 0: // If item has export links then it is a google doc @@ -489,14 +481,17 @@ func (f *Fs) ListDir(out fs.ListOpts, job dircache.ListDirJob) (jobs []dircache. if extension == "" { fs.Debug(remote, "No export formats found") } else { - if o := f.newObjectWithInfo(remote+"."+extension, item); o != nil { - obj := o.(*Object) - obj.isDocument = true - obj.url = link - obj.bytes = -1 - if out.Add(o) { - return true - } + o, err := f.newObjectWithInfo(remote+"."+extension, item) + if err != nil { + out.SetError(err) + return true + } + obj := o.(*Object) + obj.isDocument = true + obj.url = link + obj.bytes = -1 + if out.Add(o) { + return true } } default: @@ -547,11 +542,11 @@ func (f *Fs) createFileInfo(remote string, modTime time.Time, size int64) (*Obje // // The new object may have been created if an error is returned func (f *Fs) Put(in io.Reader, src fs.ObjectInfo) (fs.Object, error) { - exisitingObj, err := f.newObjectWithInfoErr(src.Remote(), nil) + exisitingObj, err := f.newObjectWithInfo(src.Remote(), nil) switch err { case nil: return exisitingObj, exisitingObj.Update(in, src) - case fs.ErrorDirNotFound, errorObjectNotFound: + case fs.ErrorObjectNotFound: // Not found so create it return f.PutUnchecked(in, src) default: @@ -857,6 +852,9 @@ func (o *Object) readMetaData() (err error) { leaf, directoryID, err := o.fs.dirCache.FindPath(o.remote, false) if err != nil { + if err == fs.ErrorDirNotFound { + return fs.ErrorObjectNotFound + } return err } @@ -871,7 +869,7 @@ func (o *Object) readMetaData() (err error) { return err } if !found { - return errorObjectNotFound + return fs.ErrorObjectNotFound } return nil } diff --git a/dropbox/dropbox.go b/dropbox/dropbox.go index 61ea53178..5fb323e98 100644 --- a/dropbox/dropbox.go +++ b/dropbox/dropbox.go @@ -13,6 +13,7 @@ import ( "io" "io/ioutil" "log" + "net/http" "path" "regexp" "strings" @@ -198,8 +199,8 @@ func (f *Fs) setRoot(root string) { // Return an Object from a path // -// May return nil if an error occurred -func (f *Fs) newObjectWithInfo(remote string, info *dropbox.Entry) fs.Object { +// If it can't be found it returns the error fs.ErrorObjectNotFound. +func (f *Fs) newObjectWithInfo(remote string, info *dropbox.Entry) (fs.Object, error) { o := &Object{ fs: f, remote: remote, @@ -209,17 +210,15 @@ func (f *Fs) newObjectWithInfo(remote string, info *dropbox.Entry) fs.Object { } else { err := o.readEntryAndSetMetadata() if err != nil { - // logged already fs.Debug("Failed to read info: %s", err) - return nil + return nil, err } } - return o + return o, nil } -// NewObject returns an Object from a path -// -// May return nil if an error occurred -func (f *Fs) NewObject(remote string) fs.Object { +// NewObject finds the Object at remote. If it can't be found +// it returns the error fs.ErrorObjectNotFound. +func (f *Fs) NewObject(remote string) (fs.Object, error) { return f.newObjectWithInfo(remote, nil) } @@ -322,10 +321,13 @@ func (f *Fs) list(out fs.ListOpts, dir string) { out.SetError(err) return } - if o := f.newObjectWithInfo(path, entry); o != nil { - if out.Add(o) { - return - } + o, err := f.newObjectWithInfo(path, entry) + if err != nil { + out.SetError(err) + return + } + if out.Add(o) { + return } } else { nameTree.PutFile(parentPath, lastComponent, entry) @@ -345,10 +347,12 @@ func (f *Fs) list(out fs.ListOpts, dir string) { if err != nil { return err } - if o := f.newObjectWithInfo(path, entry); o != nil { - if out.Add(o) { - return fs.ErrorListAborted - } + o, err := f.newObjectWithInfo(path, entry) + if err != nil { + return err + } + if out.Add(o) { + return fs.ErrorListAborted } return nil } @@ -387,10 +391,13 @@ func (f *Fs) listOneLevel(out fs.ListOpts, dir string) { return } } else { - if o := f.newObjectWithInfo(remote, entry); o != nil { - if out.Add(o) { - return - } + o, err := f.newObjectWithInfo(remote, entry) + if err != nil { + out.SetError(err) + return + } + if out.Add(o) { + return } } } @@ -622,8 +629,12 @@ func (o *Object) setMetadataFromEntry(info *dropbox.Entry) { func (o *Object) readEntry() (*dropbox.Entry, error) { entry, err := o.fs.db.Metadata(o.remotePath(), false, false, "", "", metadataLimit) if err != nil { - fs.Debug(o, "Error reading file: %s", err) - return nil, errors.Wrap(err, "error reading file") + if dropboxErr, ok := err.(*dropbox.Error); ok { + if dropboxErr.StatusCode == http.StatusNotFound { + return nil, fs.ErrorObjectNotFound + } + } + return nil, err } return entry, nil } diff --git a/fs/fs.go b/fs/fs.go index 903e4c1f3..007c14c9d 100644 --- a/fs/fs.go +++ b/fs/fs.go @@ -39,6 +39,7 @@ var ( ErrorDirExists = errors.New("can't copy directory - destination already exists") ErrorCantSetModTime = errors.New("can't set modified time") ErrorDirNotFound = errors.New("directory not found") + ErrorObjectNotFound = errors.New("object not found") ErrorLevelNotSupported = errors.New("level value not supported") ErrorListAborted = errors.New("list aborted") ErrorListOnlyRoot = errors.New("can only list from root") @@ -117,8 +118,9 @@ type Fs interface { Info ListFser - // NewObject finds the Object at remote. Returns nil if can't be found - NewObject(remote string) Object + // NewObject finds the Object at remote. If it can't be found + // it returns the error ErrorObjectNotFound. + NewObject(remote string) (Object, error) // Put in to the remote path with the modTime given of the given size // diff --git a/fstest/fstests/fstests.go b/fstest/fstests/fstests.go index 46cec1ceb..1a3284ae3 100644 --- a/fstest/fstests/fstests.go +++ b/fstest/fstests/fstests.go @@ -171,23 +171,29 @@ func TestFsListDirEmpty(t *testing.T) { // TestFsNewObjectNotFound tests not finding a object func TestFsNewObjectNotFound(t *testing.T) { skipIfNotOk(t) - if remote.NewObject("potato") != nil { - t.Fatal("Didn't expect to find object") - } + // Object in an existing directory + o, err := remote.NewObject("potato") + assert.Nil(t, o) + assert.Equal(t, fs.ErrorObjectNotFound, err) + // Now try an object in a non existing directory + o, err = remote.NewObject("directory/not/found/potato") + assert.Nil(t, o) + assert.Equal(t, fs.ErrorObjectNotFound, err) } func findObject(t *testing.T, Name string) fs.Object { var obj fs.Object + var err error for i := 1; i <= eventualConsistencyRetries; i++ { - obj = remote.NewObject(Name) - if obj != nil { + obj, err = remote.NewObject(Name) + if err == nil { break } - t.Logf("Sleeping for 1 second for findObject eventual consistency: %d/%d", i, eventualConsistencyRetries) + t.Logf("Sleeping for 1 second for findObject eventual consistency: %d/%d (%v)", i, eventualConsistencyRetries, err) time.Sleep(1 * time.Second) } - if obj == nil { - t.Fatalf("Object not found: %q", Name) + if err != nil { + t.Fatalf("Object %q not found: %v", Name, err) } return obj } @@ -629,10 +635,6 @@ func TestFsIsFileNotFound(t *testing.T) { t.Fatalf("Failed to make remote %q: %v", remoteName, err) } fstest.CheckListing(t, fileRemote, []fstest.Item{}) - _, ok := fileRemote.(*fs.Limited) - if ok { - t.Errorf("%v is is a fs.Limited", fileRemote) - } } // TestObjectRemove tests Remove diff --git a/googlecloudstorage/googlecloudstorage.go b/googlecloudstorage/googlecloudstorage.go index a1fced427..6c8fecd6d 100644 --- a/googlecloudstorage/googlecloudstorage.go +++ b/googlecloudstorage/googlecloudstorage.go @@ -267,8 +267,8 @@ func NewFs(name, root string) (fs.Fs, error) { // Return an Object from a path // -// May return nil if an error occurred -func (f *Fs) newObjectWithInfo(remote string, info *storage.Object) fs.Object { +// If it can't be found it returns the error fs.ErrorObjectNotFound. +func (f *Fs) newObjectWithInfo(remote string, info *storage.Object) (fs.Object, error) { o := &Object{ fs: f, remote: remote, @@ -278,17 +278,15 @@ func (f *Fs) newObjectWithInfo(remote string, info *storage.Object) fs.Object { } else { err := o.readMetaData() // reads info and meta, returning an error if err != nil { - // logged already FsDebug("Failed to read info: %s", err) - return nil + return nil, err } } - return o + return o, nil } -// NewObject returns an Object from a path -// -// May return nil if an error occurred -func (f *Fs) NewObject(remote string) fs.Object { +// NewObject finds the Object at remote. If it can't be found +// it returns the error fs.ErrorObjectNotFound. +func (f *Fs) NewObject(remote string) (fs.Object, error) { return f.newObjectWithInfo(remote, nil) } @@ -369,10 +367,12 @@ func (f *Fs) listFiles(out fs.ListOpts, dir string) { return fs.ErrorListAborted } } else { - if o := f.newObjectWithInfo(remote, object); o != nil { - if out.Add(o) { - return fs.ErrorListAborted - } + o, err := f.newObjectWithInfo(remote, object) + if err != nil { + return err + } + if out.Add(o) { + return fs.ErrorListAborted } } return nil @@ -596,7 +596,11 @@ func (o *Object) readMetaData() (err error) { } object, err := o.fs.svc.Objects.Get(o.fs.bucket, o.fs.root+o.remote).Do() if err != nil { - fs.Debug(o, "Failed to read info: %s", err) + if gErr, ok := err.(*googleapi.Error); ok { + if gErr.Code == http.StatusNotFound { + return fs.ErrorObjectNotFound + } + } return err } o.setMetaData(object) diff --git a/local/local.go b/local/local.go index 76eeba8ad..405cb51ac 100644 --- a/local/local.go +++ b/local/local.go @@ -76,12 +76,7 @@ func NewFs(name, root string) (fs.Fs, error) { fi, err := os.Lstat(f.root) if err == nil && fi.Mode().IsRegular() { // It is a file, so use the parent as the root - var remote string - f.root, remote = getDirFile(f.root) - obj := f.NewObject(remote) - if obj == nil { - return nil, errors.Errorf("failed to make object for %q in %q", remote, f.root) - } + f.root, _ = getDirFile(f.root) // return an error with an fs which points to the parent return f, fs.ErrorIsFile } @@ -118,24 +113,25 @@ func (f *Fs) newObject(remote string) *Object { // Return an Object from a path // // May return nil if an error occurred -func (f *Fs) newObjectWithInfo(remote string, info os.FileInfo) fs.Object { +func (f *Fs) newObjectWithInfo(remote string, info os.FileInfo) (fs.Object, error) { o := f.newObject(remote) if info != nil { o.info = info } else { err := o.lstat() if err != nil { - fs.Debug(o, "Failed to stat %s: %s", o.path, err) - return nil + if os.IsNotExist(err) { + return nil, fs.ErrorObjectNotFound + } + return nil, err } } - return o + return o, nil } -// NewObject returns an Object from a path -// -// May return nil if an error occurred -func (f *Fs) NewObject(remote string) fs.Object { +// NewObject finds the Object at remote. If it can't be found +// it returns the error ErrorObjectNotFound. +func (f *Fs) NewObject(remote string) (fs.Object, error) { return f.newObjectWithInfo(remote, nil) } @@ -192,10 +188,13 @@ func (f *Fs) list(out fs.ListOpts, remote string, dirpath string, level int) (su } } } else { - if fso := f.newObjectWithInfo(newRemote, fi); fso != nil { - if fso.Storable() && out.Add(fso) { - return nil - } + fso, err := f.newObjectWithInfo(newRemote, fi) + if err != nil { + out.SetError(err) + return nil + } + if fso.Storable() && out.Add(fso) { + return nil } } } diff --git a/onedrive/onedrive.go b/onedrive/onedrive.go index f24a49944..1942948ac 100644 --- a/onedrive/onedrive.go +++ b/onedrive/onedrive.go @@ -206,10 +206,13 @@ func NewFs(name, root string) (fs.Fs, error) { // No root so return old f return f, nil } - obj := newF.newObjectWithInfo(remote, nil) - if obj == nil { - // File doesn't exist so return old f - return f, nil + _, err := newF.newObjectWithInfo(remote, nil) + if err != nil { + if err == fs.ErrorObjectNotFound { + // File doesn't exist so return old f + return f, nil + } + return nil, err } // return an error with an fs which points to the parent return &newF, fs.ErrorIsFile @@ -227,8 +230,8 @@ func (f *Fs) rootSlash() string { // Return an Object from a path // -// May return nil if an error occurred -func (f *Fs) newObjectWithInfo(remote string, info *api.Item) fs.Object { +// If it can't be found it returns the error fs.ErrorObjectNotFound. +func (f *Fs) newObjectWithInfo(remote string, info *api.Item) (fs.Object, error) { o := &Object{ fs: f, remote: remote, @@ -239,17 +242,15 @@ func (f *Fs) newObjectWithInfo(remote string, info *api.Item) fs.Object { } else { err := o.readMetaData() // reads info and meta, returning an error if err != nil { - // logged already FsDebug("Failed to read info: %s", err) - return nil + return nil, err } } - return o + return o, nil } -// NewObject returns an Object from a path -// -// May return nil if an error occurred -func (f *Fs) NewObject(remote string) fs.Object { +// NewObject finds the Object at remote. If it can't be found +// it returns the error fs.ErrorObjectNotFound. +func (f *Fs) NewObject(remote string) (fs.Object, error) { return f.newObjectWithInfo(remote, nil) } @@ -391,10 +392,13 @@ func (f *Fs) ListDir(out fs.ListOpts, job dircache.ListDirJob) (jobs []dircache. } } } else { - if o := f.newObjectWithInfo(remote, info); o != nil { - if out.Add(o) { - return true - } + o, err := f.newObjectWithInfo(remote, info) + if err != nil { + out.SetError(err) + return true + } + if out.Add(o) { + return true } } return false @@ -705,7 +709,11 @@ func (o *Object) readMetaData() (err error) { // } info, _, err := o.fs.readMetaDataForPath(o.srvPath()) if err != nil { - fs.Debug(o, "Failed to read info: %s", err) + if apiErr, ok := err.(*api.Error); ok { + if apiErr.ErrorInfo.Code == "itemNotFound" { + return fs.ErrorObjectNotFound + } + } return err } o.setMetaData(info) diff --git a/rclone.go b/rclone.go index a2497740d..5686117a1 100644 --- a/rclone.go +++ b/rclone.go @@ -383,8 +383,9 @@ func NewFsSrc(remote string) fs.Fs { log.Fatalf("Can't limit to single files when using filters: %v", remote) } // Limit transfers to this file - fs.Config.Filter.AddFile(path.Base(fsPath)) - } else if err != nil { + err = fs.Config.Filter.AddFile(path.Base(fsPath)) + } + if err != nil { fs.Stats.Error() log.Fatalf("Failed to create file system for %q: %v", remote, err) } diff --git a/s3/s3.go b/s3/s3.go index eeae5adf4..ede123bae 100644 --- a/s3/s3.go +++ b/s3/s3.go @@ -342,8 +342,8 @@ func NewFs(name, root string) (fs.Fs, error) { // Return an Object from a path // -// May return nil if an error occurred -func (f *Fs) newObjectWithInfo(remote string, info *s3.Object) fs.Object { +//If it can't be found it returns the error ErrorObjectNotFound. +func (f *Fs) newObjectWithInfo(remote string, info *s3.Object) (fs.Object, error) { o := &Object{ fs: f, remote: remote, @@ -361,17 +361,15 @@ func (f *Fs) newObjectWithInfo(remote string, info *s3.Object) fs.Object { } else { err := o.readMetaData() // reads info and meta, returning an error if err != nil { - // logged already FsDebug("Failed to read info: %s", err) - return nil + return nil, err } } - return o + return o, nil } -// NewObject returns an Object from a path -// -// May return nil if an error occurred -func (f *Fs) NewObject(remote string) fs.Object { +// NewObject finds the Object at remote. If it can't be found +// it returns the error fs.ErrorObjectNotFound. +func (f *Fs) NewObject(remote string) (fs.Object, error) { return f.newObjectWithInfo(remote, nil) } @@ -482,10 +480,12 @@ func (f *Fs) listFiles(out fs.ListOpts, dir string) { return fs.ErrorListAborted } } else { - if o := f.newObjectWithInfo(remote, object); o != nil { - if out.Add(o) { - return fs.ErrorListAborted - } + o, err := f.newObjectWithInfo(remote, object) + if err != nil { + return err + } + if out.Add(o) { + return fs.ErrorListAborted } } return nil @@ -634,7 +634,7 @@ func (f *Fs) Copy(src fs.Object, remote string) (fs.Object, error) { if err != nil { return nil, err } - return f.NewObject(remote), err + return f.NewObject(remote) } // Hashes returns the supported hash sets. @@ -697,7 +697,11 @@ func (o *Object) readMetaData() (err error) { } resp, err := o.fs.c.HeadObject(&req) if err != nil { - fs.Debug(o, "Failed to read info: %s", err) + if awsErr, ok := err.(awserr.RequestFailure); ok { + if awsErr.StatusCode() == http.StatusNotFound { + return fs.ErrorObjectNotFound + } + } return err } var size int64 diff --git a/swift/swift.go b/swift/swift.go index d7b03775f..cadbab9b9 100644 --- a/swift/swift.go +++ b/swift/swift.go @@ -223,8 +223,8 @@ func NewFs(name, root string) (fs.Fs, error) { // Return an Object from a path // -// May return nil if an error occurred -func (f *Fs) newObjectWithInfo(remote string, info *swift.Object) fs.Object { +// If it can't be found it returns the error fs.ErrorObjectNotFound. +func (f *Fs) newObjectWithInfo(remote string, info *swift.Object) (fs.Object, error) { o := &Object{ fs: f, remote: remote, @@ -241,17 +241,15 @@ func (f *Fs) newObjectWithInfo(remote string, info *swift.Object) fs.Object { } else { err := o.readMetaData() // reads info and headers, returning an error if err != nil { - fs.Debug(o, "Failed to read metadata: %s", err) - return nil + return nil, err } } - return o + return o, nil } -// NewObject returns an Object from a path -// -// May return nil if an error occurred -func (f *Fs) NewObject(remote string) fs.Object { +// NewObject finds the Object at remote. If it can't be found it +// returns the error fs.ErrorObjectNotFound. +func (f *Fs) NewObject(remote string) (fs.Object, error) { return f.newObjectWithInfo(remote, nil) } @@ -331,12 +329,14 @@ func (f *Fs) listFiles(out fs.ListOpts, dir string) { return fs.ErrorListAborted } } else { - if o := f.newObjectWithInfo(remote, object); o != nil { - // Storable does a full metadata read on 0 size objects which might be dynamic large objects - if o.Storable() { - if out.Add(o) { - return fs.ErrorListAborted - } + o, err := f.newObjectWithInfo(remote, object) + if err != nil { + return err + } + // Storable does a full metadata read on 0 size objects which might be dynamic large objects + if o.Storable() { + if out.Add(o) { + return fs.ErrorListAborted } } } @@ -437,9 +437,11 @@ func (f *Fs) Purge() error { go func() { err = f.list("", fs.MaxLevel, func(remote string, object *swift.Object, isDirectory bool) error { if !isDirectory { - if o := f.newObjectWithInfo(remote, object); o != nil { - toBeDeleted <- o + o, err := f.newObjectWithInfo(remote, object) + if err != nil { + return err } + toBeDeleted <- o } return nil }) @@ -472,7 +474,7 @@ func (f *Fs) Copy(src fs.Object, remote string) (fs.Object, error) { if err != nil { return nil, err } - return f.NewObject(remote), nil + return f.NewObject(remote) } // Hashes returns the supported hash sets. @@ -525,7 +527,7 @@ func (o *Object) Hash(t fs.HashType) (string, error) { func (o *Object) hasHeader(header string) (bool, error) { err := o.readMetaData() if err != nil { - if err == swift.ObjectNotFound { + if err == fs.ErrorObjectNotFound { return false, nil } return false, err @@ -552,12 +554,17 @@ func (o *Object) Size() int64 { // readMetaData gets the metadata if it hasn't already been fetched // // it also sets the info +// +// it returns fs.ErrorObjectNotFound if the object isn't found func (o *Object) readMetaData() (err error) { if o.headers != nil { return nil } info, h, err := o.fs.c.Object(o.fs.container, o.fs.root+o.remote) if err != nil { + if err == swift.ObjectNotFound { + return fs.ErrorObjectNotFound + } return err } o.info = info diff --git a/yandex/yandex.go b/yandex/yandex.go index a9fde823c..762c31ea2 100644 --- a/yandex/yandex.go +++ b/yandex/yandex.go @@ -263,10 +263,12 @@ func (f *Fs) List(out fs.ListOpts, dir string) { return fs.ErrorListAborted } } else { - if o := f.newObjectWithInfo(remote, object); o != nil { - if out.Add(o) { - return fs.ErrorListAborted - } + o, err := f.newObjectWithInfo(remote, object) + if err != nil { + return err + } + if out.Add(o) { + return fs.ErrorListAborted } } return nil @@ -295,17 +297,16 @@ func (f *Fs) List(out fs.ListOpts, dir string) { } } -// NewObject returns an Object from a path -// -// May return nil if an error occurred -func (f *Fs) NewObject(remote string) fs.Object { +// NewObject finds the Object at remote. If it can't be found it +// returns the error fs.ErrorObjectNotFound. +func (f *Fs) NewObject(remote string) (fs.Object, error) { return f.newObjectWithInfo(remote, nil) } // Return an Object from a path // -// May return nil if an error occurred -func (f *Fs) newObjectWithInfo(remote string, info *yandex.ResourceInfoResponse) fs.Object { +// If it can't be found it returns the error fs.ErrorObjectNotFound. +func (f *Fs) newObjectWithInfo(remote string, info *yandex.ResourceInfoResponse) (fs.Object, error) { o := &Object{ fs: f, remote: remote, @@ -315,11 +316,10 @@ func (f *Fs) newObjectWithInfo(remote string, info *yandex.ResourceInfoResponse) } else { err := o.readMetaData() if err != nil { - fs.Debug(f, "Couldn't get object '%s' metadata: %s", o.remotePath(), err) - return nil + return nil, err } } - return o + return o, nil } // setMetaData sets the fs data from a storage.Object @@ -355,6 +355,11 @@ func (o *Object) readMetaData() (err error) { var opt2 yandex.ResourceInfoRequestOptions ResourceInfoResponse, err := o.fs.yd.NewResourceInfoRequest(o.remotePath(), opt2).Exec() if err != nil { + if dcErr, ok := err.(yandex.DiskClientError); ok { + if dcErr.Code == "DiskNotFoundError" { + return fs.ErrorObjectNotFound + } + } return err } o.setMetaData(ResourceInfoResponse)