diff --git a/br/pkg/storage/local.go b/br/pkg/storage/local.go index 1fe17c96905bb..bfc0fc9907626 100644 --- a/br/pkg/storage/local.go +++ b/br/pkg/storage/local.go @@ -130,7 +130,11 @@ func (l *LocalStorage) WalkDir(_ context.Context, opt *WalkOption, fn func(strin if !f.Mode().IsRegular() { stat, err := os.Stat(filepath.Join(l.base, path)) if err != nil { - return errors.Trace(err) + // error may happen because of file deleted after walk started, or other errors + // like #49423. We just return 0 size and let the caller handle it in later + // logic. + log.Warn("failed to get file size", zap.String("path", path), zap.Error(err)) + return fn(path, 0) } size = stat.Size() } diff --git a/br/pkg/storage/local_test.go b/br/pkg/storage/local_test.go index fd6f92afb5b6a..02c0b92386166 100644 --- a/br/pkg/storage/local_test.go +++ b/br/pkg/storage/local_test.go @@ -237,3 +237,23 @@ func TestLocalFileReadRange(t *testing.T) { n, _ := r.Read(smallBuf) require.Equal(t, "23", string(smallBuf[:n])) } + +func TestWalkBrokenSymLink(t *testing.T) { + ctx := context.Background() + dir := t.TempDir() + err := os.Symlink(filepath.Join(dir, "non-existing-file"), filepath.Join(dir, "file-that-should-be-ignored")) + require.NoError(t, err) + + sb, err := ParseBackend("file://"+filepath.ToSlash(dir), nil) + require.NoError(t, err) + store, err := New(ctx, sb, nil) + require.NoError(t, err) + + files := map[string]int64{} + err = store.WalkDir(ctx, nil, func(path string, size int64) error { + files[path] = size + return nil + }) + require.NoError(t, err) + require.Equal(t, map[string]int64{"file-that-should-be-ignored": 0}, files) +}