diff --git a/backend/crypt/crypt.go b/backend/crypt/crypt.go index 13f5f0246..8f0272453 100644 --- a/backend/crypt/crypt.go +++ b/backend/crypt/crypt.go @@ -1197,7 +1197,7 @@ func (o *ObjectInfo) Hash(ctx context.Context, hash hash.Type) (string, error) { return "", nil } // if this is wrapping a local object then we work out the hash - if srcObj.Fs().Features().IsLocal { + if srcObj != nil && srcObj.Fs().Features().IsLocal { // Read the data and encrypt it to calculate the hash fs.Debugf(o, "Computing %v hash of encrypted source", hash) return o.f.computeHashWithNonce(ctx, o.nonce, srcObj, hash) diff --git a/backend/crypt/crypt_internal_test.go b/backend/crypt/crypt_internal_test.go index 8cf49a396..83dec91db 100644 --- a/backend/crypt/crypt_internal_test.go +++ b/backend/crypt/crypt_internal_test.go @@ -93,6 +93,16 @@ func testObjectInfo(t *testing.T, f *Fs, wrap bool) { assert.Equal(t, fmt.Sprintf("%x", wantHash), gotHash) } +// Test ObjectInfo.Hash doesn't panic when the source is an +// fs.OverrideRemote which wraps an fs.ObjectInfo that isn't an fs.Object +func TestObjectInfoHashOverrideRemoteNotObject(t *testing.T) { + src := object.NewStaticObjectInfo("file", time.Now(), 3, true, nil, nil) + oi := (&Fs{}).newObjectInfo(fs.NewOverrideRemote(src, "new_remote"), nonce{}) + gotHash, err := oi.Hash(context.Background(), hash.MD5) + require.NoError(t, err) + assert.Equal(t, "", gotHash) +} + func testComputeHash(t *testing.T, f *Fs) { var ( contents = random.String(100)