From 66bdd057c62504eeb03af71a850cb45fdfcd9415 Mon Sep 17 00:00:00 2001 From: zhijian Date: Tue, 1 Aug 2023 10:28:04 +0800 Subject: [PATCH] cmd/sync: listall interface add to `followlink` parameters (#3942) close #3934 --------- Co-authored-by: Davies Liu --- cmd/destroy.go | 2 +- cmd/format.go | 2 +- cmd/fsck.go | 2 +- cmd/gc.go | 2 +- cmd/objbench.go | 6 +++--- cmd/object.go | 13 ++++++------- pkg/object/azure.go | 2 +- pkg/object/b2.go | 2 +- pkg/object/bos.go | 2 +- pkg/object/ceph.go | 2 +- pkg/object/cos.go | 4 ++-- pkg/object/etcd.go | 2 +- pkg/object/file.go | 13 ++++++------- pkg/object/filesystem_test.go | 19 ++++++++++++++----- pkg/object/gluster.go | 13 ++++++------- pkg/object/gs.go | 4 ++-- pkg/object/hdfs.go | 2 +- pkg/object/ibmcos.go | 4 ++-- pkg/object/interface.go | 4 ++-- pkg/object/ks3.go | 4 ++-- pkg/object/mem.go | 2 +- pkg/object/object_storage.go | 10 +++++----- pkg/object/object_storage_test.go | 22 +++++++++++----------- pkg/object/obs.go | 4 ++-- pkg/object/oos.go | 6 +++--- pkg/object/oss.go | 4 ++-- pkg/object/prefix.go | 8 ++++---- pkg/object/qingstor.go | 4 ++-- pkg/object/qiniu.go | 2 +- pkg/object/redis.go | 2 +- pkg/object/restful.go | 2 +- pkg/object/s3.go | 6 +++--- pkg/object/scs.go | 2 +- pkg/object/sftp.go | 15 ++++++++------- pkg/object/sharding.go | 16 ++++++++-------- pkg/object/speedy.go | 2 +- pkg/object/sql.go | 2 +- pkg/object/swift.go | 2 +- pkg/object/tikv.go | 2 +- pkg/object/tos.go | 4 ++-- pkg/object/ufile.go | 2 +- pkg/object/upyun.go | 2 +- pkg/object/webdav.go | 2 +- pkg/sync/sync.go | 24 ++++++++++++------------ pkg/sync/sync_test.go | 14 +++++++------- pkg/vfs/backup.go | 2 +- pkg/vfs/backup_test.go | 2 +- 47 files changed, 138 insertions(+), 131 deletions(-) diff --git a/cmd/destroy.go b/cmd/destroy.go index 10b95b9a301c..bd797c0390af 100644 --- a/cmd/destroy.go +++ b/cmd/destroy.go @@ -158,7 +158,7 @@ func destroy(ctx *cli.Context) error { } } - objs, err := osync.ListAll(blob, "", "", "") + objs, err := osync.ListAll(blob, "", "", "", true) if err != nil { logger.Fatalf("list all objects: %s", err) } diff --git a/cmd/format.go b/cmd/format.go index 52acf3f26e50..a4dd5150a08c 100644 --- a/cmd/format.go +++ b/cmd/format.go @@ -474,7 +474,7 @@ func format(c *cli.Context) error { logger.Fatalf("Storage %s is not configured correctly: %s", blob, err) } if create { - if objs, err := osync.ListAll(blob, "", "", ""); err == nil { + if objs, err := osync.ListAll(blob, "", "", "", true); err == nil { for o := range objs { if o == nil { logger.Warnf("List storage %s failed", blob) diff --git a/cmd/fsck.go b/cmd/fsck.go index e5d7e3e0df23..53eb5a97d198 100644 --- a/cmd/fsck.go +++ b/cmd/fsck.go @@ -107,7 +107,7 @@ func fsck(ctx *cli.Context) error { } logger.Infof("Data use %s", blob) blob = object.WithPrefix(blob, "chunks/") - objs, err := osync.ListAll(blob, "", "", "") + objs, err := osync.ListAll(blob, "", "", "", true) if err != nil { logger.Fatalf("list all blocks: %s", err) } diff --git a/cmd/gc.go b/cmd/gc.go index ce96e6414a19..06f66de70f08 100644 --- a/cmd/gc.go +++ b/cmd/gc.go @@ -232,7 +232,7 @@ func gc(ctx *cli.Context) error { // Scan all objects to find leaked ones blob = object.WithPrefix(blob, "chunks/") - objs, err := osync.ListAll(blob, "", "", "") + objs, err := osync.ListAll(blob, "", "", "", true) if err != nil { logger.Fatalf("list all blocks: %s", err) } diff --git a/cmd/objbench.go b/cmd/objbench.go index 705321557a3c..88bf4a4ffe9d 100644 --- a/cmd/objbench.go +++ b/cmd/objbench.go @@ -569,7 +569,7 @@ func (bm *benchMarkObj) head(key string, startKey int) error { } func (bm *benchMarkObj) list(key string, startKey int) error { - result, err := osync.ListAll(bm.blob, "", "", "") + result, err := osync.ListAll(bm.blob, "", "", "", true) for range result { } return err @@ -588,7 +588,7 @@ func (bm *benchMarkObj) chtimes(key string, startKey int) error { } func listAll(s object.ObjectStorage, prefix, marker string, limit int64) ([]object.Object, error) { - ch, err := object.ListAll(s, prefix, marker) + ch, err := object.ListAll(s, prefix, marker, true) if err == nil { objs := make([]object.Object, 0) for obj := range ch { @@ -896,7 +896,7 @@ func functionalTesting(blob object.ObjectStorage, result *[][]string, colorful b if err := blob.Put(key, bytes.NewReader([]byte("1"))); err != nil { return fmt.Errorf("put encode file failed: %s", err) } else { - if resp, err := blob.List("", "测试编码文件", "", 1); err != nil && err != utils.ENOTSUP { + if resp, err := blob.List("", "测试编码文件", "", 1, true); err != nil && err != utils.ENOTSUP { return fmt.Errorf("list encode file failed %s", err) } else if len(resp) == 1 && resp[0].Key() != key { return fmt.Errorf("list encode file failed: expect key %s, but got %s", key, resp[0].Key()) diff --git a/cmd/object.go b/cmd/object.go index f19b6d855d9b..39b646c1681e 100644 --- a/cmd/object.go +++ b/cmd/object.go @@ -200,7 +200,7 @@ func (j *juiceFS) Head(key string) (object.Object, error) { return &jObj{key, fi}, nil } -func (j *juiceFS) List(prefix, marker, delimiter string, limit int64) ([]object.Object, error) { +func (j *juiceFS) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]object.Object, error) { if delimiter != "/" { return nil, utils.ENOTSUP } @@ -221,7 +221,7 @@ func (j *juiceFS) List(prefix, marker, delimiter string, limit int64) ([]object. } objs = append(objs, obj) } - entries, err := j.readDirSorted(dir) + entries, err := j.readDirSorted(dir, followLink) if err != 0 { if err == syscall.ENOENT { return nil, nil @@ -250,7 +250,7 @@ type mEntry struct { // readDirSorted reads the directory named by dirname and returns // a sorted list of directory entries. -func (j *juiceFS) readDirSorted(dirname string) ([]*mEntry, syscall.Errno) { +func (j *juiceFS) readDirSorted(dirname string, followLink bool) ([]*mEntry, syscall.Errno) { f, err := j.jfs.Open(ctx, dirname, 0) if err != 0 { return nil, err @@ -265,8 +265,7 @@ func (j *juiceFS) readDirSorted(dirname string) ([]*mEntry, syscall.Errno) { fi := fs.AttrToFileInfo(e.Inode, e.Attr) if fi.IsDir() { mEntries[i] = &mEntry{fi, string(e.Name) + dirSuffix, false} - } else if fi.IsSymlink() { - // follow symlink + } else if fi.IsSymlink() && followLink { fi2, err := j.jfs.Stat(ctx, filepath.Join(dirname, string(e.Name))) if err != 0 { mEntries[i] = &mEntry{fi, string(e.Name), true} @@ -276,9 +275,9 @@ func (j *juiceFS) readDirSorted(dirname string) ([]*mEntry, syscall.Errno) { if fi2.IsDir() { name += dirSuffix } - mEntries[i] = &mEntry{fi2, name, true} + mEntries[i] = &mEntry{fi2, name, false} } else { - mEntries[i] = &mEntry{fi, string(e.Name), false} + mEntries[i] = &mEntry{fi, string(e.Name), fi.IsSymlink()} } } sort.Slice(mEntries, func(i, j int) bool { return mEntries[i].name < mEntries[j].name }) diff --git a/pkg/object/azure.go b/pkg/object/azure.go index 2c860315ccb4..a4f885c9441f 100644 --- a/pkg/object/azure.go +++ b/pkg/object/azure.go @@ -132,7 +132,7 @@ func (b *wasb) Delete(key string) error { return err } -func (b *wasb) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (b *wasb) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { if delimiter != "" { return nil, notSupported } diff --git a/pkg/object/b2.go b/pkg/object/b2.go index 1755ed7688aa..0e8e8dd20626 100644 --- a/pkg/object/b2.go +++ b/pkg/object/b2.go @@ -122,7 +122,7 @@ func (c *b2client) Delete(key string) error { return err } -func (c *b2client) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (c *b2client) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { if limit > 1000 { limit = 1000 } diff --git a/pkg/object/bos.go b/pkg/object/bos.go index a936736f0288..2c1a0b4bce87 100644 --- a/pkg/object/bos.go +++ b/pkg/object/bos.go @@ -138,7 +138,7 @@ func (q *bosclient) Delete(key string) error { return err } -func (q *bosclient) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (q *bosclient) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { if limit > 1000 { limit = 1000 } diff --git a/pkg/object/ceph.go b/pkg/object/ceph.go index b89bca376d82..02731b04dce2 100644 --- a/pkg/object/ceph.go +++ b/pkg/object/ceph.go @@ -203,7 +203,7 @@ func (c *ceph) Head(key string) (Object, error) { return o, err } -func (c *ceph) ListAll(prefix, marker string) (<-chan Object, error) { +func (c *ceph) ListAll(prefix, marker string, followLink bool) (<-chan Object, error) { var objs = make(chan Object, 1000) err := c.do(func(ctx *rados.IOContext) error { iter, err := ctx.Iter() diff --git a/pkg/object/cos.go b/pkg/object/cos.go index 60f816f812ee..4103c5125894 100644 --- a/pkg/object/cos.go +++ b/pkg/object/cos.go @@ -155,7 +155,7 @@ func (c *COS) Delete(key string) error { return err } -func (c *COS) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (c *COS) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { param := cos.BucketGetOptions{ Prefix: prefix, Marker: marker, @@ -197,7 +197,7 @@ func (c *COS) List(prefix, marker, delimiter string, limit int64) ([]Object, err return objs, nil } -func (c *COS) ListAll(prefix, marker string) (<-chan Object, error) { +func (c *COS) ListAll(prefix, marker string, followLink bool) (<-chan Object, error) { return nil, notSupported } diff --git a/pkg/object/etcd.go b/pkg/object/etcd.go index 31ca83bae2b7..58d82ed400c7 100644 --- a/pkg/object/etcd.go +++ b/pkg/object/etcd.go @@ -111,7 +111,7 @@ func genNextKey(key string) string { return string(next) } -func (c *etcdClient) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (c *etcdClient) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { if delimiter != "" { return nil, notSupported } diff --git a/pkg/object/file.go b/pkg/object/file.go index 908b3b20cb28..26373a7b3148 100644 --- a/pkg/object/file.go +++ b/pkg/object/file.go @@ -224,7 +224,7 @@ func (m *mEntry) IsDir() bool { // readDirSorted reads the directory named by dirname and returns // a sorted list of directory entries. -func readDirSorted(dirname string) ([]*mEntry, error) { +func readDirSorted(dirname string, followLink bool) ([]*mEntry, error) { f, err := os.Open(dirname) if err != nil { return nil, err @@ -239,8 +239,7 @@ func readDirSorted(dirname string) ([]*mEntry, error) { for i, e := range entries { if e.IsDir() { mEntries[i] = &mEntry{e, e.Name() + dirSuffix, nil, false} - } else if !e.Type().IsRegular() { - // follow symlink + } else if !e.Type().IsRegular() && followLink { fi, err := os.Stat(filepath.Join(dirname, e.Name())) if err != nil { mEntries[i] = &mEntry{e, e.Name(), nil, true} @@ -250,16 +249,16 @@ func readDirSorted(dirname string) ([]*mEntry, error) { if fi.IsDir() { name = e.Name() + dirSuffix } - mEntries[i] = &mEntry{e, name, fi, true} + mEntries[i] = &mEntry{e, name, fi, false} } else { - mEntries[i] = &mEntry{e, e.Name(), nil, false} + mEntries[i] = &mEntry{e, e.Name(), nil, !e.Type().IsRegular()} } } sort.Slice(mEntries, func(i, j int) bool { return mEntries[i].Name() < mEntries[j].Name() }) return mEntries, err } -func (d *filestore) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (d *filestore) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { if delimiter != "/" { return nil, notSupported } @@ -280,7 +279,7 @@ func (d *filestore) List(prefix, marker, delimiter string, limit int64) ([]Objec } objs = append(objs, obj) } - entries, err := readDirSorted(dir) + entries, err := readDirSorted(dir, followLink) if err != nil { if os.IsNotExist(err) { return nil, nil diff --git a/pkg/object/filesystem_test.go b/pkg/object/filesystem_test.go index 6a275270e2ae..642fc7c3cd2c 100644 --- a/pkg/object/filesystem_test.go +++ b/pkg/object/filesystem_test.go @@ -92,7 +92,7 @@ func testFileSystem(t *testing.T, s ObjectStorage) { // cleanup defer func() { // delete reversely, directory only can be deleted when it's empty - objs, err := listAll(s, "", "", 100) + objs, err := listAll(s, "", "", 100, true) if err != nil { t.Fatalf("listall failed: %s", err) } @@ -107,7 +107,7 @@ func testFileSystem(t *testing.T, s ObjectStorage) { } } }() - objs, err := listAll(s, "x/", "", 100) + objs, err := listAll(s, "x/", "", 100, true) if err != nil { t.Fatalf("list failed: %s", err) } @@ -116,7 +116,7 @@ func testFileSystem(t *testing.T, s ObjectStorage) { t.Fatalf("testKeysEqual fail: %s", err) } - objs, err = listAll(s, "x", "", 100) + objs, err = listAll(s, "x", "", 100, true) if err != nil { t.Fatalf("list failed: %s", err) } @@ -125,7 +125,7 @@ func testFileSystem(t *testing.T, s ObjectStorage) { t.Fatalf("testKeysEqual fail: %s", err) } - objs, err = listAll(s, "xy", "", 100) + objs, err = listAll(s, "xy", "", 100, true) if err != nil { t.Fatalf("list failed: %s", err) } @@ -159,7 +159,7 @@ func testFileSystem(t *testing.T, s ObjectStorage) { } _ = ss.Symlink("xyz/notExist/", "b") - objs, err = listAll(s, "", "", 100) + objs, err = listAll(s, "", "", 100, true) if err != nil { t.Fatalf("listall failed: %s", err) } @@ -173,5 +173,14 @@ func testFileSystem(t *testing.T, s ObjectStorage) { if objs[9].Size() != 10 { t.Fatalf("size of target(file) should be 10") } + + // test don't follow symlink + if _, ok := s.(*hdfsclient); !ok { + objs, err = listAll(s, "", "", 100, false) + expectedKeys = []string{"", "a", "a-", "a0", "b", "b-", "b0", "bb/", "bb/b1", "x/", "x/x.txt", "xy.txt", "xyz/", "xyz/ol1/", "xyz/ol1/p.txt", "xyz/xyz.txt"} + if err = testKeysEqual(objs, expectedKeys); err != nil { + t.Fatalf("testKeysEqual fail: %s", err) + } + } } } diff --git a/pkg/object/gluster.go b/pkg/object/gluster.go index ed780617b7b6..39556ed50874 100644 --- a/pkg/object/gluster.go +++ b/pkg/object/gluster.go @@ -147,7 +147,7 @@ func (c *gluster) Delete(key string) error { // readDirSorted reads the directory named by dirname and returns // a sorted list of directory entries. -func (d *gluster) readDirSorted(dirname string) ([]*mEntry, error) { +func (d *gluster) readDirSorted(dirname string, followLink bool) ([]*mEntry, error) { f, err := d.vol.Open(dirname) if err != nil { return nil, err @@ -166,8 +166,7 @@ func (d *gluster) readDirSorted(dirname string) ([]*mEntry, error) { } if e.IsDir() { mEntries = append(mEntries, &mEntry{nil, name + dirSuffix, e, false}) - } else if !e.Mode().IsRegular() { - // follow symlink + } else if !e.Mode().IsRegular() && followLink { fi, err := d.vol.Stat(filepath.Join(dirname, name)) if err != nil { mEntries = append(mEntries, &mEntry{nil, name, e, true}) @@ -176,16 +175,16 @@ func (d *gluster) readDirSorted(dirname string) ([]*mEntry, error) { if fi.IsDir() { name += dirSuffix } - mEntries = append(mEntries, &mEntry{nil, name, fi, true}) + mEntries = append(mEntries, &mEntry{nil, name, fi, false}) } else { - mEntries = append(mEntries, &mEntry{nil, name, e, false}) + mEntries = append(mEntries, &mEntry{nil, name, e, !e.Mode().IsRegular()}) } } sort.Slice(mEntries, func(i, j int) bool { return mEntries[i].Name() < mEntries[j].Name() }) return mEntries, err } -func (d *gluster) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (d *gluster) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { if delimiter != "/" { return nil, notSupported } @@ -206,7 +205,7 @@ func (d *gluster) List(prefix, marker, delimiter string, limit int64) ([]Object, } objs = append(objs, obj) } - entries, err := d.readDirSorted(dir) + entries, err := d.readDirSorted(dir, followLink) if err != nil { if os.IsNotExist(err) { return nil, nil diff --git a/pkg/object/gs.go b/pkg/object/gs.go index cf94da8e80bd..d5098034ade3 100644 --- a/pkg/object/gs.go +++ b/pkg/object/gs.go @@ -51,7 +51,7 @@ func (g *gs) String() string { func (g *gs) Create() error { // check if the bucket is already exists - if objs, err := g.List("", "", "", 1); err == nil && len(objs) > 0 { + if objs, err := g.List("", "", "", 1, true); err == nil && len(objs) > 0 { return nil } @@ -141,7 +141,7 @@ func (g *gs) Delete(key string) error { return nil } -func (g *gs) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (g *gs) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { if marker != "" && g.pageToken == "" { // last page return nil, nil diff --git a/pkg/object/hdfs.go b/pkg/object/hdfs.go index bb977ca1ca9f..7026121cee1b 100644 --- a/pkg/object/hdfs.go +++ b/pkg/object/hdfs.go @@ -176,7 +176,7 @@ func (h *hdfsclient) Delete(key string) error { return err } -func (h *hdfsclient) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (h *hdfsclient) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { if delimiter != "/" { return nil, notSupported } diff --git a/pkg/object/ibmcos.go b/pkg/object/ibmcos.go index 67abeee2961b..2b184677fad5 100644 --- a/pkg/object/ibmcos.go +++ b/pkg/object/ibmcos.go @@ -165,7 +165,7 @@ func (s *ibmcos) Delete(key string) error { return err } -func (s *ibmcos) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (s *ibmcos) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { param := s3.ListObjectsInput{ Bucket: &s.bucket, Prefix: &prefix, @@ -203,7 +203,7 @@ func (s *ibmcos) List(prefix, marker, delimiter string, limit int64) ([]Object, return objs, nil } -func (s *ibmcos) ListAll(prefix, marker string) (<-chan Object, error) { +func (s *ibmcos) ListAll(prefix, marker string, followLink bool) (<-chan Object, error) { return nil, notSupported } diff --git a/pkg/object/interface.go b/pkg/object/interface.go index e96d592e2943..4e6b2f0393ee 100644 --- a/pkg/object/interface.go +++ b/pkg/object/interface.go @@ -92,9 +92,9 @@ type ObjectStorage interface { // Head returns some information about the object or an error if not found. Head(key string) (Object, error) // List returns a list of objects. - List(prefix, marker, delimiter string, limit int64) ([]Object, error) + List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) // ListAll returns all the objects as an channel. - ListAll(prefix, marker string) (<-chan Object, error) + ListAll(prefix, marker string, followLink bool) (<-chan Object, error) // CreateMultipartUpload starts to upload a large object part by part. CreateMultipartUpload(key string) (*MultipartUpload, error) diff --git a/pkg/object/ks3.go b/pkg/object/ks3.go index 1ab462bb33bc..75c8e1c28c0a 100644 --- a/pkg/object/ks3.go +++ b/pkg/object/ks3.go @@ -174,7 +174,7 @@ func (s *ks3) Delete(key string) error { return err } -func (s *ks3) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (s *ks3) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { param := s3.ListObjectsInput{ Bucket: &s.bucket, Prefix: &prefix, @@ -212,7 +212,7 @@ func (s *ks3) List(prefix, marker, delimiter string, limit int64) ([]Object, err return objs, nil } -func (s *ks3) ListAll(prefix, marker string) (<-chan Object, error) { +func (s *ks3) ListAll(prefix, marker string, followLink bool) (<-chan Object, error) { return nil, notSupported } diff --git a/pkg/object/mem.go b/pkg/object/mem.go index df357bf6f344..4ca9f52e273e 100644 --- a/pkg/object/mem.go +++ b/pkg/object/mem.go @@ -129,7 +129,7 @@ func (m *memStore) Delete(key string) error { return nil } -func (m *memStore) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (m *memStore) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { m.Lock() defer m.Unlock() diff --git a/pkg/object/object_storage.go b/pkg/object/object_storage.go index df70ef2b503d..a45f58693d84 100644 --- a/pkg/object/object_storage.go +++ b/pkg/object/object_storage.go @@ -149,11 +149,11 @@ func (s DefaultObjectStorage) ListUploads(marker string) ([]*PendingPart, string return nil, "", nil } -func (s DefaultObjectStorage) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (s DefaultObjectStorage) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { return nil, notSupported } -func (s DefaultObjectStorage) ListAll(prefix, marker string) (<-chan Object, error) { +func (s DefaultObjectStorage) ListAll(prefix, marker string, followLink bool) (<-chan Object, error) { return nil, notSupported } @@ -189,8 +189,8 @@ type listThread struct { entries []Object } -func ListAllWithDelimiter(store ObjectStorage, prefix, start, end string) (<-chan Object, error) { - entries, err := store.List(prefix, "", "/", 1e9) +func ListAllWithDelimiter(store ObjectStorage, prefix, start, end string, followLink bool) (<-chan Object, error) { + entries, err := store.List(prefix, "", "/", 1e9, followLink) if err != nil { logger.Errorf("list %s: %s", prefix, err) return nil, err @@ -218,7 +218,7 @@ func ListAllWithDelimiter(store ObjectStorage, prefix, start, end string) (<-cha continue } - t.entries, t.err = store.List(key, "\x00", "/", 1e9) // exclude itself + t.entries, t.err = store.List(key, "\x00", "/", 1e9, followLink) // exclude itself t.Lock() t.ready = true t.cond.Signal() diff --git a/pkg/object/object_storage_test.go b/pkg/object/object_storage_test.go index 39047c376db1..4c273d60dfc6 100644 --- a/pkg/object/object_storage_test.go +++ b/pkg/object/object_storage_test.go @@ -58,8 +58,8 @@ func get(s ObjectStorage, k string, off, limit int64) (string, error) { return string(data), nil } -func listAll(s ObjectStorage, prefix, marker string, limit int64) ([]Object, error) { - ch, err := ListAll(s, prefix, marker) +func listAll(s ObjectStorage, prefix, marker string, limit int64, followLink bool) ([]Object, error) { + ch, err := ListAll(s, prefix, marker, followLink) if err == nil { objs := make([]Object, 0) for obj := range ch { @@ -130,7 +130,7 @@ func testStorage(t *testing.T, s ObjectStorage) { if err := s.Put(key, bytes.NewReader(nil)); err != nil { t.Logf("PUT testEncodeFile failed: %s", err.Error()) } else { - if resp, err := s.List("", "测试编码文件", "", 1); err != nil && err != notSupported { + if resp, err := s.List("", "测试编码文件", "", 1, true); err != nil && err != notSupported { t.Logf("List testEncodeFile Failed: %s", err) } else if len(resp) == 1 && resp[0].Key() != key { t.Logf("List testEncodeFile Failed: expect key %s, but got %s", key, resp[0].Key()) @@ -181,7 +181,7 @@ func testStorage(t *testing.T, s ObjectStorage) { } switch s.(*withPrefix).os.(type) { case FileSystem: - objs, err2 := listAll(s, "", "", 2) + objs, err2 := listAll(s, "", "", 2, true) if err2 == nil { if len(objs) != 2 { t.Fatalf("List should return 2 keys, but got %d", len(objs)) @@ -206,14 +206,14 @@ func testStorage(t *testing.T, s ObjectStorage) { t.Fatalf("list failed: %s", err2.Error()) } - objs, err2 = listAll(s, "", "test2", 1) + objs, err2 = listAll(s, "", "test2", 1, true) if err2 != nil { t.Fatalf("list3 failed: %s", err2.Error()) } else if len(objs) != 0 { t.Fatalf("list3 should not return anything, but got %d", len(objs)) } default: - objs, err2 := listAll(s, "", "", 1) + objs, err2 := listAll(s, "", "", 1, true) if err2 == nil { if len(objs) != 1 { t.Fatalf("List should return 1 keys, but got %d", len(objs)) @@ -232,7 +232,7 @@ func testStorage(t *testing.T, s ObjectStorage) { t.Fatalf("list failed: %s", err2.Error()) } - objs, err2 = listAll(s, "", "test2", 1) + objs, err2 = listAll(s, "", "test2", 1, true) if err2 != nil { t.Fatalf("list3 failed: %s", err2.Error()) } else if len(objs) != 0 { @@ -277,7 +277,7 @@ func testStorage(t *testing.T, s ObjectStorage) { if err := s.Put("a1", bytes.NewReader(br)); err != nil { t.Fatalf("PUT failed: %s", err.Error()) } - if obs, err := s.List("", "", "/", 10); err != nil { + if obs, err := s.List("", "", "/", 10, true); err != nil { if !errors.Is(err, notSupported) { t.Fatalf("list with delimiter: %s", err) } else { @@ -303,7 +303,7 @@ func testStorage(t *testing.T, s ObjectStorage) { } } - if obs, err := s.List("a", "", "/", 10); err != nil { + if obs, err := s.List("a", "", "/", 10, true); err != nil { if !errors.Is(err, notSupported) { t.Fatalf("list with delimiter: %s", err) } @@ -319,7 +319,7 @@ func testStorage(t *testing.T, s ObjectStorage) { } } - if obs, err := s.List("a/", "", "/", 10); err != nil { + if obs, err := s.List("a/", "", "/", 10, true); err != nil { if !errors.Is(err, notSupported) { t.Fatalf("list with delimiter: %s", err) } else { @@ -361,7 +361,7 @@ func testStorage(t *testing.T, s ObjectStorage) { _ = s.Delete(fmt.Sprintf("hashKey%d", i)) } }() - objs, err := listAll(s, "hashKey", "", int64(keyTotal)) + objs, err := listAll(s, "hashKey", "", int64(keyTotal), true) if err != nil { t.Fatalf("list4 failed: %s", err.Error()) } else { diff --git a/pkg/object/obs.go b/pkg/object/obs.go index 0f963c3958ad..4a56746e8769 100644 --- a/pkg/object/obs.go +++ b/pkg/object/obs.go @@ -201,7 +201,7 @@ func (s *obsClient) Delete(key string) error { return err } -func (s *obsClient) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (s *obsClient) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { input := &obs.ListObjectsInput{ Bucket: s.bucket, Marker: marker, @@ -237,7 +237,7 @@ func (s *obsClient) List(prefix, marker, delimiter string, limit int64) ([]Objec return objs, nil } -func (s *obsClient) ListAll(prefix, marker string) (<-chan Object, error) { +func (s *obsClient) ListAll(prefix, marker string, followLink bool) (<-chan Object, error) { return nil, notSupported } diff --git a/pkg/object/oos.go b/pkg/object/oos.go index 2cc269c2fd00..533fa46b464c 100644 --- a/pkg/object/oos.go +++ b/pkg/object/oos.go @@ -46,18 +46,18 @@ func (s *oos) Limits() Limits { } func (s *oos) Create() error { - _, err := s.List("", "", "", 1) + _, err := s.List("", "", "", 1, true) if err != nil { return fmt.Errorf("please create bucket %s manually", s.s3client.bucket) } return err } -func (s *oos) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (s *oos) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { if limit > 1000 { limit = 1000 } - objs, err := s.s3client.List(prefix, marker, delimiter, limit) + objs, err := s.s3client.List(prefix, marker, delimiter, limit, followLink) if marker != "" && len(objs) > 0 && objs[0].Key() == marker { objs = objs[1:] } diff --git a/pkg/object/oss.go b/pkg/object/oss.go index 68dadc3f4ab5..59ec96996727 100644 --- a/pkg/object/oss.go +++ b/pkg/object/oss.go @@ -166,7 +166,7 @@ func (o *ossClient) Delete(key string) error { return o.checkError(err) } -func (o *ossClient) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (o *ossClient) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { if limit > 1000 { limit = 1000 } @@ -190,7 +190,7 @@ func (o *ossClient) List(prefix, marker, delimiter string, limit int64) ([]Objec return objs, nil } -func (o *ossClient) ListAll(prefix, marker string) (<-chan Object, error) { +func (o *ossClient) ListAll(prefix, marker string, followLink bool) (<-chan Object, error) { return nil, notSupported } diff --git a/pkg/object/prefix.go b/pkg/object/prefix.go index bb68b27284a5..36b62f766de4 100644 --- a/pkg/object/prefix.go +++ b/pkg/object/prefix.go @@ -125,22 +125,22 @@ func (p *withPrefix) Delete(key string) error { return p.os.Delete(p.prefix + key) } -func (p *withPrefix) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (p *withPrefix) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { if marker != "" { marker = p.prefix + marker } - objs, err := p.os.List(p.prefix+prefix, marker, delimiter, limit) + objs, err := p.os.List(p.prefix+prefix, marker, delimiter, limit, followLink) for i, o := range objs { objs[i] = p.updateKey(o) } return objs, err } -func (p *withPrefix) ListAll(prefix, marker string) (<-chan Object, error) { +func (p *withPrefix) ListAll(prefix, marker string, followLink bool) (<-chan Object, error) { if marker != "" { marker = p.prefix + marker } - r, err := p.os.ListAll(p.prefix+prefix, marker) + r, err := p.os.ListAll(p.prefix+prefix, marker, followLink) if err != nil { return r, err } diff --git a/pkg/object/qingstor.go b/pkg/object/qingstor.go index 2117d167cb6b..248f90ca1921 100644 --- a/pkg/object/qingstor.go +++ b/pkg/object/qingstor.go @@ -189,7 +189,7 @@ func (q *qingstor) Delete(key string) error { return err } -func (q *qingstor) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (q *qingstor) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { if limit > 1000 { limit = 1000 } @@ -227,7 +227,7 @@ func (q *qingstor) List(prefix, marker, delimiter string, limit int64) ([]Object return objs, nil } -func (q *qingstor) ListAll(prefix, marker string) (<-chan Object, error) { +func (q *qingstor) ListAll(prefix, marker string, followLink bool) (<-chan Object, error) { return nil, notSupported } diff --git a/pkg/object/qiniu.go b/pkg/object/qiniu.go index a55afcd02894..2a7fcc0f9230 100644 --- a/pkg/object/qiniu.go +++ b/pkg/object/qiniu.go @@ -145,7 +145,7 @@ func (q *qiniu) Delete(key string) error { return err } -func (q *qiniu) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (q *qiniu) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { if limit > 1000 { limit = 1000 } diff --git a/pkg/object/redis.go b/pkg/object/redis.go index 2c8eaa941066..ad936829da2f 100644 --- a/pkg/object/redis.go +++ b/pkg/object/redis.go @@ -77,7 +77,7 @@ func (r *redisStore) Delete(key string) error { return r.rdb.Del(ctx, key).Err() } -func (t *redisStore) ListAll(prefix, marker string) (<-chan Object, error) { +func (t *redisStore) ListAll(prefix, marker string, followLink bool) (<-chan Object, error) { var scanCli []redis.UniversalClient var m sync.Mutex if c, ok := t.rdb.(*redis.ClusterClient); ok { diff --git a/pkg/object/restful.go b/pkg/object/restful.go index d0eeb777835c..c8ef92477cb5 100644 --- a/pkg/object/restful.go +++ b/pkg/object/restful.go @@ -261,7 +261,7 @@ func (s *RestfulStorage) Delete(key string) error { return nil } -func (s *RestfulStorage) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (s *RestfulStorage) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { return nil, notSupported } diff --git a/pkg/object/s3.go b/pkg/object/s3.go index a5ce111d4050..962167ed5000 100644 --- a/pkg/object/s3.go +++ b/pkg/object/s3.go @@ -82,7 +82,7 @@ func isExists(err error) bool { } func (s *s3client) Create() error { - if _, err := s.List("", "", "", 1); err == nil { + if _, err := s.List("", "", "", 1, true); err == nil { return nil } _, err := s.s3.CreateBucket(&s3.CreateBucketInput{Bucket: &s.bucket}) @@ -202,7 +202,7 @@ func (s *s3client) Delete(key string) error { return err } -func (s *s3client) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (s *s3client) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { param := s3.ListObjectsInput{ Bucket: &s.bucket, Prefix: &prefix, @@ -249,7 +249,7 @@ func (s *s3client) List(prefix, marker, delimiter string, limit int64) ([]Object return objs, nil } -func (s *s3client) ListAll(prefix, marker string) (<-chan Object, error) { +func (s *s3client) ListAll(prefix, marker string, followLink bool) (<-chan Object, error) { return nil, notSupported } diff --git a/pkg/object/scs.go b/pkg/object/scs.go index c259ab1462b0..39e4fd704285 100644 --- a/pkg/object/scs.go +++ b/pkg/object/scs.go @@ -97,7 +97,7 @@ func (s *scsClient) Delete(key string) error { return s.b.Delete(key) } -func (s *scsClient) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (s *scsClient) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { if marker != "" { if s.marker == "" { // last page diff --git a/pkg/object/sftp.go b/pkg/object/sftp.go index d99fcb12606e..5a0ba8489763 100644 --- a/pkg/object/sftp.go +++ b/pkg/object/sftp.go @@ -170,7 +170,7 @@ func (f *sftpStore) Head(key string) (Object, error) { if err != nil { return nil, err } - return f.fileInfo(nil, key, info), nil + return f.fileInfo(nil, key, info, true), nil } func (f *sftpStore) Get(key string, off, limit int64) (io.ReadCloser, error) { @@ -307,25 +307,26 @@ func (f *sftpStore) Delete(key string) error { return err } -func (f *sftpStore) sortByName(c *sftp.Client, path string, fis []os.FileInfo) []Object { +func (f *sftpStore) sortByName(c *sftp.Client, path string, fis []os.FileInfo, followLink bool) []Object { var obs = make([]Object, 0, len(fis)) for _, fi := range fis { p := path + fi.Name() if strings.HasPrefix(p, f.root) { key := p[len(f.root):] - obs = append(obs, f.fileInfo(c, key, fi)) + obs = append(obs, f.fileInfo(c, key, fi, followLink)) } } sort.Slice(obs, func(i, j int) bool { return obs[i].Key() < obs[j].Key() }) return obs } -func (f *sftpStore) fileInfo(c *sftp.Client, key string, fi os.FileInfo) Object { +func (f *sftpStore) fileInfo(c *sftp.Client, key string, fi os.FileInfo, followLink bool) Object { owner, group := getOwnerGroup(fi) isSymlink := !fi.Mode().IsDir() && !fi.Mode().IsRegular() - if isSymlink && c != nil { + if isSymlink && c != nil && followLink { if fi2, err := c.Stat(f.root + key); err == nil { fi = fi2 + isSymlink = false } } ff := &file{ @@ -344,7 +345,7 @@ func (f *sftpStore) fileInfo(c *sftp.Client, key string, fi os.FileInfo) Object return ff } -func (f *sftpStore) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (f *sftpStore) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { if delimiter != "/" { return nil, notSupported } @@ -380,7 +381,7 @@ func (f *sftpStore) List(prefix, marker, delimiter string, limit int64) ([]Objec return nil, err } - entries := f.sortByName(c.sftpClient, dir, infos) + entries := f.sortByName(c.sftpClient, dir, infos, followLink) for _, o := range entries { key := o.Key() if !strings.HasPrefix(key, prefix) || (marker != "" && key <= marker) { diff --git a/pkg/object/sharding.go b/pkg/object/sharding.go index 61cebac54512..d8b42e6c8ca9 100644 --- a/pkg/object/sharding.go +++ b/pkg/object/sharding.go @@ -88,8 +88,8 @@ func (s *sharded) SetStorageClass(sc string) { const maxResults = 10000 // ListAll on all the keys that starts at marker from object storage. -func ListAll(store ObjectStorage, prefix, marker string) (<-chan Object, error) { - if ch, err := store.ListAll(prefix, marker); err == nil { +func ListAll(store ObjectStorage, prefix, marker string, followLink bool) (<-chan Object, error) { + if ch, err := store.ListAll(prefix, marker, followLink); err == nil { return ch, nil } else if !errors.Is(err, notSupported) { return nil, err @@ -98,9 +98,9 @@ func ListAll(store ObjectStorage, prefix, marker string) (<-chan Object, error) startTime := time.Now() out := make(chan Object, maxResults) logger.Debugf("Listing objects from %s marker %q", store, marker) - objs, err := store.List(prefix, marker, "", maxResults) + objs, err := store.List(prefix, marker, "", maxResults, followLink) if err == notSupported { - return ListAllWithDelimiter(store, prefix, marker, "") + return ListAllWithDelimiter(store, prefix, marker, "", followLink) } if err != nil { logger.Errorf("Can't list %s: %s", store, err.Error()) @@ -134,12 +134,12 @@ func ListAll(store ObjectStorage, prefix, marker string) (<-chan Object, error) marker = lastkey startTime = time.Now() logger.Debugf("Continue listing objects from %s marker %q", store, marker) - objs, err = store.List(prefix, marker, "", maxResults) + objs, err = store.List(prefix, marker, "", maxResults, followLink) for err != nil { logger.Warnf("Fail to list: %s, retry again", err.Error()) // slow down time.Sleep(time.Millisecond * 100) - objs, err = store.List(prefix, marker, "", maxResults) + objs, err = store.List(prefix, marker, "", maxResults, followLink) } logger.Debugf("Found %d object from %s in %s", len(objs), store, time.Since(startTime)) } @@ -166,10 +166,10 @@ func (s *nextObjects) Pop() interface{} { return o } -func (s *sharded) ListAll(prefix, marker string) (<-chan Object, error) { +func (s *sharded) ListAll(prefix, marker string, followLink bool) (<-chan Object, error) { heads := &nextObjects{make([]nextKey, 0)} for i := range s.stores { - ch, err := ListAll(s.stores[i], prefix, marker) + ch, err := ListAll(s.stores[i], prefix, marker, followLink) if err != nil { return nil, fmt.Errorf("list %s: %s", s.stores[i], err) } diff --git a/pkg/object/speedy.go b/pkg/object/speedy.go index 9ec77c619f62..abeed2ac4444 100644 --- a/pkg/object/speedy.go +++ b/pkg/object/speedy.go @@ -53,7 +53,7 @@ func (s *speedy) String() string { return fmt.Sprintf("speedy://%s/", uri.Host) } -func (s *speedy) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (s *speedy) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { if delimiter != "" { return nil, notSupported } diff --git a/pkg/object/sql.go b/pkg/object/sql.go index a06a3a20524a..21b7b1df1a3d 100644 --- a/pkg/object/sql.go +++ b/pkg/object/sql.go @@ -128,7 +128,7 @@ func (s *sqlStore) Delete(key string) error { return err } -func (s *sqlStore) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (s *sqlStore) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { if marker == "" { marker = prefix } diff --git a/pkg/object/swift.go b/pkg/object/swift.go index c27d54aca8e7..15000e34b8ec 100644 --- a/pkg/object/swift.go +++ b/pkg/object/swift.go @@ -78,7 +78,7 @@ func (s *swiftOSS) Delete(key string) error { return err } -func (s *swiftOSS) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (s *swiftOSS) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { if limit > 10000 { limit = 10000 } diff --git a/pkg/object/tikv.go b/pkg/object/tikv.go index 77457394aa5e..463327ff0c54 100644 --- a/pkg/object/tikv.go +++ b/pkg/object/tikv.go @@ -89,7 +89,7 @@ func (t *tikv) Delete(key string) error { return t.c.Delete(context.TODO(), []byte(key)) } -func (t *tikv) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (t *tikv) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { if delimiter != "" { return nil, notSupported } diff --git a/pkg/object/tos.go b/pkg/object/tos.go index bb13394b3278..0f588a1ee934 100644 --- a/pkg/object/tos.go +++ b/pkg/object/tos.go @@ -131,7 +131,7 @@ func (t *tosClient) Head(key string) (Object, error) { }, err } -func (t *tosClient) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (t *tosClient) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { resp, err := t.client.ListObjectsV2(context.Background(), &tos.ListObjectsV2Input{ Bucket: t.bucket, ListObjectsInput: tos.ListObjectsInput{ @@ -168,7 +168,7 @@ func (t *tosClient) List(prefix, marker, delimiter string, limit int64) ([]Objec return objs, nil } -func (t *tosClient) ListAll(prefix, marker string) (<-chan Object, error) { +func (t *tosClient) ListAll(prefix, marker string, followLink bool) (<-chan Object, error) { return nil, notSupported } diff --git a/pkg/object/ufile.go b/pkg/object/ufile.go index 7c0a3f5ed58d..e857a6949604 100644 --- a/pkg/object/ufile.go +++ b/pkg/object/ufile.go @@ -199,7 +199,7 @@ type uFileListObjectsOutput struct { DataSet []*DataItem `json:"DataSet,omitempty"` } -func (u *ufile) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (u *ufile) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { if delimiter != "" { // TODO: or US3? return nil, notSupported diff --git a/pkg/object/upyun.go b/pkg/object/upyun.go index caef53fc36ac..0e43d87e6562 100644 --- a/pkg/object/upyun.go +++ b/pkg/object/upyun.go @@ -98,7 +98,7 @@ func (u *up) Copy(dst, src string) error { }) } -func (u *up) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (u *up) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { if delimiter != "" { return nil, notSupported } diff --git a/pkg/object/webdav.go b/pkg/object/webdav.go index 7316a3be2a16..b6898afe0e50 100644 --- a/pkg/object/webdav.go +++ b/pkg/object/webdav.go @@ -175,7 +175,7 @@ func (w webDAVFile) Name() string { return w.name } -func (w *webdav) List(prefix, marker, delimiter string, limit int64) ([]Object, error) { +func (w *webdav) List(prefix, marker, delimiter string, limit int64, followLink bool) ([]Object, error) { if delimiter != "/" { return nil, notSupported } diff --git a/pkg/sync/sync.go b/pkg/sync/sync.go index ca7b73fd0724..768f6b377e75 100644 --- a/pkg/sync/sync.go +++ b/pkg/sync/sync.go @@ -73,7 +73,7 @@ func formatSize(bytes int64) string { } // ListAll on all the keys that starts at marker from object storage. -func ListAll(store object.ObjectStorage, prefix, start, end string) (<-chan object.Object, error) { +func ListAll(store object.ObjectStorage, prefix, start, end string, followLink bool) (<-chan object.Object, error) { startTime := time.Now() logger.Debugf("Iterating objects from %s with prefix %s start %q", store, prefix, start) @@ -88,7 +88,7 @@ func ListAll(store object.ObjectStorage, prefix, start, end string) (<-chan obje } } - if ch, err := store.ListAll(prefix, start); err == nil { + if ch, err := store.ListAll(prefix, start, followLink); err == nil { go func() { for obj := range ch { if obj != nil && end != "" && obj.Key() > end { @@ -105,9 +105,9 @@ func ListAll(store object.ObjectStorage, prefix, start, end string) (<-chan obje marker := start logger.Debugf("Listing objects from %s marker %q", store, marker) - objs, err := store.List(prefix, marker, "", maxResults) + objs, err := store.List(prefix, marker, "", maxResults, followLink) if err == utils.ENOTSUP { - return object.ListAllWithDelimiter(store, prefix, start, end) + return object.ListAllWithDelimiter(store, prefix, start, end, followLink) } if err != nil { logger.Errorf("Can't list %s: %s", store, err.Error()) @@ -143,13 +143,13 @@ func ListAll(store object.ObjectStorage, prefix, start, end string) (<-chan obje marker = lastkey startTime = time.Now() logger.Debugf("Continue listing objects from %s marker %q", store, marker) - objs, err = store.List(prefix, marker, "", maxResults) + objs, err = store.List(prefix, marker, "", maxResults, followLink) count := 0 for err != nil && count < 3 { logger.Warnf("Fail to list: %s, retry again", err.Error()) // slow down time.Sleep(time.Millisecond * 100) - objs, err = store.List(prefix, marker, "", maxResults) + objs, err = store.List(prefix, marker, "", maxResults, followLink) count++ } logger.Debugf("Found %d object from %s in %s", len(objs), store, time.Since(startTime)) @@ -641,12 +641,12 @@ func startSingleProducer(tasks chan<- object.Object, src, dst object.ObjectStora start, end := config.Start, config.End logger.Debugf("maxResults: %d, defaultPartSize: %d, maxBlock: %d", maxResults, defaultPartSize, maxBlock) - srckeys, err := ListAll(src, prefix, start, end) + srckeys, err := ListAll(src, prefix, start, end, !config.Links) if err != nil { return fmt.Errorf("list %s: %s", src, err) } - dstkeys, err := ListAll(dst, prefix, start, end) + dstkeys, err := ListAll(dst, prefix, start, end, !config.Links) if err != nil { return fmt.Errorf("list %s: %s", dst, err) } @@ -848,11 +848,11 @@ func matchKey(rules []rule, key string) bool { return true } -func listCommonPrefix(store object.ObjectStorage, prefix string, cp chan object.Object) (chan object.Object, error) { +func listCommonPrefix(store object.ObjectStorage, prefix string, cp chan object.Object, followLink bool) (chan object.Object, error) { var total []object.Object var marker string for { - objs, err := store.List(prefix, marker, "/", maxResults) + objs, err := store.List(prefix, marker, "/", maxResults, followLink) if err != nil { return nil, err } @@ -936,7 +936,7 @@ func startProducer(tasks chan<- object.Object, src, dst object.ObjectStorage, pr } }() - srckeys, err := listCommonPrefix(src, prefix, commonPrefix) + srckeys, err := listCommonPrefix(src, prefix, commonPrefix, !config.Links) if err == utils.ENOTSUP { return startSingleProducer(tasks, src, dst, prefix, config) } else if err != nil { @@ -946,7 +946,7 @@ func startProducer(tasks chan<- object.Object, src, dst object.ObjectStorage, pr if config.DeleteDst { dcp = commonPrefix // search common prefix in dst } - dstkeys, err := listCommonPrefix(dst, prefix, dcp) + dstkeys, err := listCommonPrefix(dst, prefix, dcp, !config.Links) if err == utils.ENOTSUP { return startSingleProducer(tasks, src, dst, prefix, config) } else if err != nil { diff --git a/pkg/sync/sync_test.go b/pkg/sync/sync_test.go index fd7f7e83d5d8..a9a25d3f86d3 100644 --- a/pkg/sync/sync_test.go +++ b/pkg/sync/sync_test.go @@ -44,7 +44,7 @@ func TestIterator(t *testing.T) { m.Put("aa", bytes.NewReader([]byte("a"))) m.Put("c", bytes.NewReader([]byte("a"))) - ch, _ := ListAll(m, "", "a", "b") + ch, _ := ListAll(m, "", "a", "b", true) keys := collectAll(ch) if len(keys) != 3 { t.Fatalf("length should be 3, but got %d", len(keys)) @@ -56,7 +56,7 @@ func TestIterator(t *testing.T) { // Single object s, _ := object.CreateStorage("mem", "", "", "", "") s.Put("a", bytes.NewReader([]byte("a"))) - ch, _ = ListAll(s, "", "", "") + ch, _ = ListAll(s, "", "", "", true) keys = collectAll(ch) if !reflect.DeepEqual(keys, []string{"a"}) { t.Fatalf("result wrong: %s", keys) @@ -75,7 +75,7 @@ func TestIeratorSingleEmptyKey(t *testing.T) { // Simulate command line prefix in SRC or DST s = object.WithPrefix(s, "abc") - ch, _ := ListAll(s, "", "", "") + ch, _ := ListAll(s, "", "", "", true) keys := collectAll(ch) if !reflect.DeepEqual(keys, []string{""}) { t.Fatalf("result wrong: %s", keys) @@ -148,8 +148,8 @@ func TestSync(t *testing.T) { t.Fatalf("should copy 1 keys, but got %d", c) } // Now a: {"a1", "a2", "abc", "ba", "c1", "c2"}, b: {"a1", "a2", "ba"} - aRes, _ := ListAll(a, "", "", "") - bRes, _ := ListAll(b, "", "", "") + aRes, _ := ListAll(a, "", "", "", true) + bRes, _ := ListAll(b, "", "", "", true) var aObjs, bObjs []object.Object for obj := range aRes { @@ -249,7 +249,7 @@ func TestSyncIncludeAndExclude(t *testing.T) { t.Fatalf("sync: %s", err) } - bRes, _ := ListAll(b, "", "", "") + bRes, _ := ListAll(b, "", "", "", true) var bKeys []string for obj := range bRes { bKeys = append(bKeys, obj.Key()) @@ -481,7 +481,7 @@ func TestLimits(t *testing.T) { t.Fatalf("sync: %s", err) } - all, err := ListAll(tcase.dst, "", "", "") + all, err := ListAll(tcase.dst, "", "", "", true) if err != nil { t.Fatalf("list all b: %s", err) } diff --git a/pkg/vfs/backup.go b/pkg/vfs/backup.go index 69c11ed746fd..fd7a01e19ced 100644 --- a/pkg/vfs/backup.go +++ b/pkg/vfs/backup.go @@ -96,7 +96,7 @@ func backup(m meta.Meta, blob object.ObjectStorage, now time.Time) error { func cleanupBackups(blob object.ObjectStorage, now time.Time) { blob = object.WithPrefix(blob, "meta/") - ch, err := osync.ListAll(blob, "", "", "") + ch, err := osync.ListAll(blob, "", "", "", true) if err != nil { logger.Warnf("listAll prefix meta/: %s", err) return diff --git a/pkg/vfs/backup_test.go b/pkg/vfs/backup_test.go index 6c28bc9c0597..ad72290e5ce5 100644 --- a/pkg/vfs/backup_test.go +++ b/pkg/vfs/backup_test.go @@ -73,7 +73,7 @@ func TestBackup(t *testing.T) { time.Sleep(time.Millisecond * 100) blob = object.WithPrefix(blob, "meta/") - kc, _ := osync.ListAll(blob, "", "", "") + kc, _ := osync.ListAll(blob, "", "", "", true) var keys []string for obj := range kc { keys = append(keys, obj.Key())