diff --git a/backend/chunker/chunker.go b/backend/chunker/chunker.go index bb4b49812..baf4656ed 100644 --- a/backend/chunker/chunker.go +++ b/backend/chunker/chunker.go @@ -325,6 +325,14 @@ func NewFs(ctx context.Context, name, rpath string, m configmap.Mapper) (fs.Fs, } } + // Correct root if definitely pointing to a file + if err == fs.ErrorIsFile { + f.root = path.Dir(f.root) + if f.root == "." || f.root == "/" { + f.root = "" + } + } + // Note 1: the features here are ones we could support, and they are // ANDed with the ones from wrappedFs. // Note 2: features.Fill() points features.PutStream to our PutStream, diff --git a/backend/compress/compress.go b/backend/compress/compress.go index f635c5e59..b477512e7 100644 --- a/backend/compress/compress.go +++ b/backend/compress/compress.go @@ -14,6 +14,7 @@ import ( "fmt" "io" "os" + "path" "regexp" "strings" "time" @@ -172,6 +173,13 @@ func NewFs(ctx context.Context, name, rpath string, m configmap.Mapper) (fs.Fs, opt: *opt, mode: compressionModeFromName(opt.CompressionMode), } + // Correct root if definitely pointing to a file + if err == fs.ErrorIsFile { + f.root = path.Dir(f.root) + if f.root == "." || f.root == "/" { + f.root = "" + } + } // the features here are ones we could support, and they are // ANDed with the ones from wrappedFs f.features = (&fs.Features{ diff --git a/backend/crypt/crypt.go b/backend/crypt/crypt.go index 281805fd5..54b1335dc 100644 --- a/backend/crypt/crypt.go +++ b/backend/crypt/crypt.go @@ -253,6 +253,13 @@ func NewFs(ctx context.Context, name, rpath string, m configmap.Mapper) (fs.Fs, cipher: cipher, } cache.PinUntilFinalized(f.Fs, f) + // Correct root if definitely pointing to a file + if err == fs.ErrorIsFile { + f.root = path.Dir(f.root) + if f.root == "." || f.root == "/" { + f.root = "" + } + } // the features here are ones we could support, and they are // ANDed with the ones from wrappedFs f.features = (&fs.Features{ diff --git a/backend/hasher/hasher.go b/backend/hasher/hasher.go index 3428b4dc2..325f7f619 100644 --- a/backend/hasher/hasher.go +++ b/backend/hasher/hasher.go @@ -114,6 +114,13 @@ func NewFs(ctx context.Context, fsname, rpath string, cmap configmap.Mapper) (fs root: rpath, opt: opt, } + // Correct root if definitely pointing to a file + if err == fs.ErrorIsFile { + f.root = path.Dir(f.root) + if f.root == "." || f.root == "/" { + f.root = "" + } + } baseFeatures := baseFs.Features() f.fpTime = baseFs.Precision() != fs.ModTimeNotSupported diff --git a/backend/union/union.go b/backend/union/union.go index eeaed8f31..5854afc11 100644 --- a/backend/union/union.go +++ b/backend/union/union.go @@ -877,6 +877,13 @@ func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, e opt: *opt, upstreams: usedUpstreams, } + // Correct root if definitely pointing to a file + if fserr == fs.ErrorIsFile { + f.root = path.Dir(f.root) + if f.root == "." || f.root == "/" { + f.root = "" + } + } err = upstream.Prepare(f.upstreams) if err != nil { return nil, err diff --git a/fstest/fstests/fstests.go b/fstest/fstests/fstests.go index 7ab03dd60..095a94d23 100644 --- a/fstest/fstests/fstests.go +++ b/fstest/fstests/fstests.go @@ -1675,6 +1675,24 @@ func Run(t *testing.T, opt *Opt) { require.NotNil(t, fileRemote) assert.Equal(t, fs.ErrorIsFile, err) + // Check Fs.Root returns the right thing + t.Run("FsRoot", func(t *testing.T) { + skipIfNotOk(t) + got := fileRemote.Root() + remoteDir := path.Dir(remoteName) + want := remoteDir + colon := strings.LastIndex(want, ":") + if colon >= 0 { + want = want[colon+1:] + } + if isLocalRemote { + // only check last path element on local + require.Equal(t, filepath.Base(remoteDir), filepath.Base(got)) + } else { + require.Equal(t, want, got) + } + }) + if strings.HasPrefix(remoteName, "TestChunker") && strings.Contains(remoteName, "Nometa") { // TODO fix chunker and remove this bypass t.Logf("Skip listing check -- chunker can't yet handle this tricky case")