Skip to content

Commit

Permalink
ls: fix incomplete listing for specific prefix
Browse files Browse the repository at this point in the history
Previously it was failing like below.

```
$ mc ls --incomplete myminio/mybucket
[2016-09-16 09:48:57 PDT] 576MiB 1.iso

$ mc ls --incomplete myminio/mybucket/1.iso
mc: <ERROR> Unable to initialize target ‘myminio/mybucket/1.iso’. Object key is missing, object key cannot be empty
```

This patch fixes this issue.
  • Loading branch information
balamurugana committed Oct 4, 2016
1 parent f03aaef commit 1c7aebd
Show file tree
Hide file tree
Showing 8 changed files with 46 additions and 15 deletions.
2 changes: 1 addition & 1 deletion cmd/client-fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -1042,7 +1042,7 @@ func (f *fsClient) SetAccess(access string) *probe.Error {
}

// Stat - get metadata from path.
func (f *fsClient) Stat() (content *clientContent, err *probe.Error) {
func (f *fsClient) Stat(isIncomplete bool) (content *clientContent, err *probe.Error) {
st, err := f.fsStat()
if err != nil {
return nil, err.Trace(f.PathURL.String())
Expand Down
4 changes: 2 additions & 2 deletions cmd/client-fs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ func (s *TestSuite) TestStatBucket(c *C) {
c.Assert(err, IsNil)
err = fsClient.MakeBucket("us-east-1")
c.Assert(err, IsNil)
_, err = fsClient.Stat()
_, err = fsClient.Stat(false)
c.Assert(err, IsNil)
}

Expand Down Expand Up @@ -317,7 +317,7 @@ func (s *TestSuite) TestStatObject(c *C) {
c.Assert(err, IsNil)
c.Assert(n, Equals, int64(len(data)))

content, err := fsClient.Stat()
content, err := fsClient.Stat(false)
c.Assert(err, IsNil)
c.Assert(content.Size, Equals, int64(dataLen))
}
Expand Down
41 changes: 36 additions & 5 deletions cmd/client-s3.go
Original file line number Diff line number Diff line change
Expand Up @@ -667,15 +667,16 @@ func (c *s3Client) listObjectWrapper(bucket, object string, isRecursive bool, do
}

// Stat - send a 'HEAD' on a bucket or object to fetch its metadata.
func (c *s3Client) Stat() (*clientContent, *probe.Error) {
func (c *s3Client) Stat(isIncomplete bool) (*clientContent, *probe.Error) {
c.mutex.Lock()
defer c.mutex.Unlock()
objectMetadata := &clientContent{}
bucket, object := c.url2BucketAndObject()
// Bucket name cannot be empty, stat on URL has no meaning.
if bucket == "" {
return nil, probe.NewError(BucketNameEmpty{})
} else if object == "" {
}

if object == "" {
exists, e := c.api.BucketExists(bucket)
if e != nil {
return nil, probe.NewError(e)
Expand All @@ -686,32 +687,62 @@ func (c *s3Client) Stat() (*clientContent, *probe.Error) {
bucketMetadata := &clientContent{}
bucketMetadata.URL = *c.targetURL
bucketMetadata.Type = os.ModeDir

return bucketMetadata, nil
}
isRecursive := false

// Remove trailing slashes needed for the following ListObjects call.
// In addition, Stat() will be as smart as the client fs version and will
// facilitate the work of the upper layers
object = strings.TrimRight(object, string(c.targetURL.Separator))
nonRecursive := false
objectMetadata := &clientContent{}

// If the request is for incomplete upload stat, handle it here.
if isIncomplete {
for objectMultipartInfo := range c.api.ListIncompleteUploads(bucket, object, nonRecursive, nil) {
if objectMultipartInfo.Err != nil {
return nil, probe.NewError(objectMultipartInfo.Err)
}

if objectMultipartInfo.Key == object {
objectMetadata.URL = *c.targetURL
objectMetadata.Time = objectMultipartInfo.Initiated
objectMetadata.Size = objectMultipartInfo.Size
objectMetadata.Type = os.FileMode(0664)
return objectMetadata, nil
}

for objectStat := range c.listObjectWrapper(bucket, object, isRecursive, nil) {
if strings.HasSuffix(objectMultipartInfo.Key, string(c.targetURL.Separator)) {
objectMetadata.URL = *c.targetURL
objectMetadata.Type = os.ModeDir
return objectMetadata, nil
}
}

return nil, probe.NewError(ObjectMissing{})
}

for objectStat := range c.listObjectWrapper(bucket, object, nonRecursive, nil) {
if objectStat.Err != nil {
return nil, probe.NewError(objectStat.Err)
}

if objectStat.Key == object {
objectMetadata.URL = *c.targetURL
objectMetadata.Time = objectStat.LastModified
objectMetadata.Size = objectStat.Size
objectMetadata.Type = os.FileMode(0664)
return objectMetadata, nil
}

if strings.HasSuffix(objectStat.Key, string(c.targetURL.Separator)) {
objectMetadata.URL = *c.targetURL
objectMetadata.Type = os.ModeDir
return objectMetadata, nil
}
}

return nil, probe.NewError(ObjectMissing{})
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/client-url.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ func url2Stat(urlStr string) (client Client, content *clientContent, err *probe.
if err != nil {
return nil, nil, err.Trace(urlStr)
}
content, err = client.Stat()
content, err = client.Stat(false)
if err != nil {
return nil, nil, err.Trace(urlStr)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import (
// Client - client interface
type Client interface {
// Common operations
Stat() (content *clientContent, err *probe.Error)
Stat(isIncomplete bool) (content *clientContent, err *probe.Error)
List(recursive, incomplete bool) <-chan *clientContent

// Bucket operations
Expand Down
2 changes: 1 addition & 1 deletion cmd/ls-main.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ func mainList(ctx *cli.Context) {
fatalIf(err.Trace(targetURL), "Unable to initialize target ‘"+targetURL+"’.")

var st *clientContent
if st, err = clnt.Stat(); err != nil {
if st, err = clnt.Stat(isIncomplete); err != nil {
switch err.ToGoError().(type) {
case BucketNameEmpty:
// For aliases like ``mc ls s3`` it's acceptable to receive BucketNameEmpty error.
Expand Down
6 changes: 3 additions & 3 deletions cmd/mirror-main.go
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ func (ms *mirrorSession) watch() {
ms.statusCh <- mirrorURL.WithError(err)
continue
}
sourceContent, err := sourceClient.Stat()
sourceContent, err := sourceClient.Stat(false)
if err != nil {
// source doesn't exist anymore
ms.statusCh <- mirrorURL.WithError(err)
Expand All @@ -442,7 +442,7 @@ func (ms *mirrorSession) watch() {
}
shouldQueue := false
if !isForce {
_, err = targetClient.Stat()
_, err = targetClient.Stat(false)
if err == nil {
continue
} // doesn't exist
Expand All @@ -467,7 +467,7 @@ func (ms *mirrorSession) watch() {
ms.statusCh <- mirrorURL.WithError(err)
return
}
_, err = targetClient.Stat()
_, err = targetClient.Stat(false)
if err == nil {
continue
} // doesn't exist
Expand Down
2 changes: 1 addition & 1 deletion cmd/rm-main.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ func rm(targetAlias, targetURL string, isIncomplete, isFake bool, older time.Dur

// Check whether object is created older than given time only if older is >= one hour.
if older >= defaultOlderTime {
info, err := clnt.Stat()
info, err := clnt.Stat(isIncomplete)
if err != nil {
return err.Trace(targetURL)
}
Expand Down

0 comments on commit 1c7aebd

Please sign in to comment.