Skip to content

Commit

Permalink
fixing #321 (#322)
Browse files Browse the repository at this point in the history
File.Readdir appends trailing slash even if there is already one present

by @blockloop
  • Loading branch information
blockloop authored Nov 21, 2021
1 parent 7916fa6 commit fa29bc3
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 16 deletions.
7 changes: 4 additions & 3 deletions s3_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"os"
"path"
"path/filepath"
"strings"
"time"

"github.com/spf13/afero"
Expand Down Expand Up @@ -68,10 +69,10 @@ func (f *File) Readdir(n int) ([]os.FileInfo, error) {
}
// ListObjects treats leading slashes as part of the directory name
// It also needs a trailing slash to list contents of a directory.
name := trimLeadingSlash(f.Name()) // + "/"
name := strings.TrimPrefix(f.Name(), "/") // + "/"

// For the root of the bucket, we need to remove any prefix
if name != "" {
if name != "" && !strings.HasSuffix(name, "/") {
name += "/"
}
output, err := f.fs.s3API.ListObjectsV2(&s3.ListObjectsV2Input{
Expand All @@ -93,7 +94,7 @@ func (f *File) Readdir(n int) ([]os.FileInfo, error) {
fis = append(fis, NewFileInfo(path.Base("/"+*subfolder.Prefix), true, 0, time.Unix(0, 0)))
}
for _, fileObject := range output.Contents {
if hasTrailingSlash(*fileObject.Key) {
if strings.HasSuffix(*fileObject.Key, "/") {
// S3 includes <name>/ in the Contents listing for <name>
continue
}
Expand Down
16 changes: 3 additions & 13 deletions s3_fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"os"
"path"
"path/filepath"
"strings"
"time"

"github.com/aws/aws-sdk-go/aws"
Expand Down Expand Up @@ -223,17 +224,6 @@ func (fs Fs) Rename(oldname, newname string) error {
return err
}

func hasTrailingSlash(s string) bool {
return len(s) > 0 && s[len(s)-1] == '/'
}

func trimLeadingSlash(s string) string {
if len(s) > 0 && s[0] == '/' {
return s[1:]
}
return s
}

// Stat returns a FileInfo describing the named file.
// If there is an error, it will be of type *os.PathError.
func (fs Fs) Stat(name string) (os.FileInfo, error) {
Expand All @@ -254,7 +244,7 @@ func (fs Fs) Stat(name string) (os.FileInfo, error) {
Path: name,
Err: err,
}
} else if hasTrailingSlash(name) {
} else if strings.HasSuffix(name, "/") {
// user asked for a directory, but this is a file
return FileInfo{name: name}, nil
/*
Expand All @@ -272,7 +262,7 @@ func (fs Fs) statDirectory(name string) (os.FileInfo, error) {
nameClean := path.Clean(name)
out, err := fs.s3API.ListObjectsV2(&s3.ListObjectsV2Input{
Bucket: aws.String(fs.bucket),
Prefix: aws.String(trimLeadingSlash(nameClean)),
Prefix: aws.String(strings.TrimPrefix(nameClean, "/")),
MaxKeys: aws.Int64(1),
})
if err != nil {
Expand Down
29 changes: 29 additions & 0 deletions s3_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,35 @@ func TestFileProps(t *testing.T) {

}

func TestFileReaddir(t *testing.T) {
fs := GetFs(t)
req := require.New(t)

err := fs.Mkdir("/dir1", 0750)
req.NoError(err, "Could not create dir1")

_, err = fs.Create("/dir1/readme.txt")
req.NoError(err, "could not create file")

t.Run("WithNoTrailingSlash", func(t *testing.T) {
dir, err := fs.Open("/dir1")
req.NoError(err, "could not open /dir1")

fis, err := dir.Readdir(1)
req.NoError(err, "could not readdir /dir1")
req.Len(fis,1)
})

t.Run("WithNoTrailingSlash", func(t *testing.T) {
dir, err := fs.Open("/dir1/")
req.NoError(err, "could not open /dir1/")

fis, err := dir.Readdir(1)
req.NoError(err, "could not readdir /dir1/")
req.Len(fis,1)
})
}

// Source: rog's code from https://groups.google.com/forum/#!topic/golang-nuts/keG78hYt1I0
func ReadersEqual(r1, r2 io.Reader) (bool, error) {
const chunkSize = 8 * 1024 // 8 KB
Expand Down

0 comments on commit fa29bc3

Please sign in to comment.