Skip to content

Commit 7b784d2

Browse files
Merge pull request #1113 from versity/fix/listobjects-dir-objs
fix: Fixes ListObjects direcotry objects listing issue. Fixes DeleteO…
2 parents 19e296c + d59ee87 commit 7b784d2

File tree

4 files changed

+74
-8
lines changed

4 files changed

+74
-8
lines changed

backend/posix/posix.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -3212,7 +3212,10 @@ func (p *Posix) removeParents(bucket, object string) {
32123212
// this with a special attribute to indicate these. stop
32133213
// at either the bucket or the first parent we encounter
32143214
// with the attribute, whichever comes first.
3215-
objPath := object
3215+
3216+
// Remove the last path separator for the directory objects
3217+
// to correctly detect the parent in the loop
3218+
objPath := strings.TrimSuffix(object, "/")
32163219
for {
32173220
parent := filepath.Dir(objPath)
32183221
if parent == string(filepath.Separator) || parent == "." {

backend/walk.go

+9-7
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ func Walk(ctx context.Context, fileSystem fs.FS, prefix, delimiter, marker strin
8888
// so we can skip a directory without an early return
8989
var skipflag error
9090
if d.IsDir() {
91+
fmt.Println("path: ", path)
9192
// If prefix is defined and the directory does not match prefix,
9293
// do not descend into the directory because nothing will
9394
// match this prefix. Make sure to append the / at the end of
@@ -108,13 +109,7 @@ func Walk(ctx context.Context, fileSystem fs.FS, prefix, delimiter, marker strin
108109
strings.Contains(strings.TrimPrefix(path+"/", prefix), delimiter) {
109110
skipflag = fs.SkipDir
110111
} else {
111-
// TODO: can we do better here rather than a second readdir
112-
// per directory?
113-
ents, err := fs.ReadDir(fileSystem, path)
114-
if err != nil {
115-
return fmt.Errorf("readdir %q: %w", path, err)
116-
}
117-
if len(ents) == 0 && delimiter == "" {
112+
if delimiter == "" {
118113
dirobj, err := getObj(path+"/", d)
119114
if err == ErrSkipObj {
120115
return skipflag
@@ -127,6 +122,13 @@ func Walk(ctx context.Context, fileSystem fs.FS, prefix, delimiter, marker strin
127122
return skipflag
128123
}
129124

125+
// TODO: can we do better here rather than a second readdir
126+
// per directory?
127+
ents, err := fs.ReadDir(fileSystem, path)
128+
if err != nil {
129+
return fmt.Errorf("readdir %q: %w", path, err)
130+
}
131+
130132
if len(ents) != 0 {
131133
return skipflag
132134
}

tests/integration/group-tests.go

+4
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ func TestListObjects(s *S3Conf) {
213213
ListObjects_max_keys_none(s)
214214
ListObjects_marker_not_from_obj_list(s)
215215
ListObjects_list_all_objs(s)
216+
ListObjects_nested_dir_file_objs(s)
216217
//TODO: remove the condition after implementing checksums in azure
217218
if !s.azureTests {
218219
ListObjects_with_checksum(s)
@@ -246,6 +247,7 @@ func TestDeleteObject(s *S3Conf) {
246247
DeleteObject_non_existing_object(s)
247248
DeleteObject_directory_object_noslash(s)
248249
DeleteObject_non_existing_dir_object(s)
250+
DeleteObject_directory_object(s)
249251
DeleteObject_success(s)
250252
DeleteObject_success_status_code(s)
251253
}
@@ -876,6 +878,7 @@ func GetIntTests() IntTests {
876878
"ListObjects_max_keys_none": ListObjects_max_keys_none,
877879
"ListObjects_marker_not_from_obj_list": ListObjects_marker_not_from_obj_list,
878880
"ListObjects_list_all_objs": ListObjects_list_all_objs,
881+
"ListObjects_nested_dir_file_objs": ListObjects_nested_dir_file_objs,
879882
"ListObjects_with_checksum": ListObjects_with_checksum,
880883
"ListObjectsV2_start_after": ListObjectsV2_start_after,
881884
"ListObjectsV2_both_start_after_and_continuation_token": ListObjectsV2_both_start_after_and_continuation_token,
@@ -892,6 +895,7 @@ func GetIntTests() IntTests {
892895
"DeleteObject_directory_object_noslash": DeleteObject_directory_object_noslash,
893896
"DeleteObject_name_too_long": DeleteObject_name_too_long,
894897
"DeleteObject_non_existing_dir_object": DeleteObject_non_existing_dir_object,
898+
"DeleteObject_directory_object": DeleteObject_directory_object,
895899
"DeleteObject_success": DeleteObject_success,
896900
"DeleteObject_success_status_code": DeleteObject_success_status_code,
897901
"DeleteObjects_empty_input": DeleteObjects_empty_input,

tests/integration/tests.go

+57
Original file line numberDiff line numberDiff line change
@@ -4771,6 +4771,44 @@ func ListObjects_list_all_objs(s *S3Conf) error {
47714771
})
47724772
}
47734773

4774+
func ListObjects_nested_dir_file_objs(s *S3Conf) error {
4775+
testName := "ListObjects_nested_dir_file_objs"
4776+
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
4777+
contents, err := putObjects(s3client, []string{"foo/bar/", "foo/bar/baz", "foo/bar/quxx"}, bucket)
4778+
if err != nil {
4779+
return err
4780+
}
4781+
4782+
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
4783+
res, err := s3client.ListObjects(ctx, &s3.ListObjectsInput{
4784+
Bucket: &bucket,
4785+
})
4786+
cancel()
4787+
if err != nil {
4788+
return err
4789+
}
4790+
4791+
if !compareObjects(contents, res.Contents) {
4792+
return fmt.Errorf("expected the objects list to be %+v, instead got %+v", contents, res.Contents)
4793+
}
4794+
4795+
// Clean up the nested objects to avoid `ErrDirectoryNotEmpty` error on teardown
4796+
for _, obj := range []string{"foo/bar/baz", "foo/bar/quxx"} {
4797+
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
4798+
_, err := s3client.DeleteObject(ctx, &s3.DeleteObjectInput{
4799+
Bucket: &bucket,
4800+
Key: &obj,
4801+
})
4802+
cancel()
4803+
if err != nil {
4804+
return err
4805+
}
4806+
}
4807+
4808+
return nil
4809+
})
4810+
}
4811+
47744812
func ListObjectsV2_start_after(s *S3Conf) error {
47754813
testName := "ListObjectsV2_start_after"
47764814
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
@@ -5391,6 +5429,25 @@ func DeleteObject_non_existing_dir_object(s *S3Conf) error {
53915429
})
53925430
}
53935431

5432+
func DeleteObject_directory_object(s *S3Conf) error {
5433+
testName := "DeleteObject_directory_object"
5434+
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
5435+
obj := "foo/bar/"
5436+
_, err := putObjects(s3client, []string{obj}, bucket)
5437+
if err != nil {
5438+
return err
5439+
}
5440+
5441+
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
5442+
_, err = s3client.DeleteObject(ctx, &s3.DeleteObjectInput{
5443+
Bucket: &bucket,
5444+
Key: &obj,
5445+
})
5446+
cancel()
5447+
return err
5448+
})
5449+
}
5450+
53945451
func DeleteObject_success(s *S3Conf) error {
53955452
testName := "DeleteObject_success"
53965453
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {

0 commit comments

Comments
 (0)