diff --git a/Makefile b/Makefile index 45ef703a8..8f886efba 100644 --- a/Makefile +++ b/Makefile @@ -35,8 +35,8 @@ lint: cyclo: @echo "Running $@:" - @GO15VENDOREXPERIMENT=1 gocyclo -over 60 *.go - @GO15VENDOREXPERIMENT=1 gocyclo -over 60 pkg + @GO15VENDOREXPERIMENT=1 gocyclo -over 65 *.go + @GO15VENDOREXPERIMENT=1 gocyclo -over 65 pkg build: getdeps verifiers @echo "Installing minio:" #@GO15VENDOREXPERIMENT=1 deadcode diff --git a/pkg/fs/api_suite_windows_test.go b/pkg/fs/api_suite_windows_test.go index 940a4287f..21a3bc541 100644 --- a/pkg/fs/api_suite_windows_test.go +++ b/pkg/fs/api_suite_windows_test.go @@ -228,13 +228,13 @@ func testPaging(c *check.C, create func() Filesystem) { c.Assert(err, check.IsNil) var prefixes []string resources.CommonPrefixes = prefixes // allocate new everytime - resources.Delimiter = "\\" - resources.Prefix = "this\\is\\" + resources.Delimiter = "/" + resources.Prefix = "this/is/" resources.Maxkeys = 10 objects, resources, err = fs.ListObjects("bucket", resources) c.Assert(err, check.IsNil) c.Assert(len(objects), check.Equals, 1) - c.Assert(resources.CommonPrefixes[0], check.Equals, "this\\is\\also\\") + c.Assert(resources.CommonPrefixes[0], check.Equals, "this/is/also/") } time.Sleep(time.Second) @@ -242,7 +242,7 @@ func testPaging(c *check.C, create func() Filesystem) { { var prefixes []string resources.CommonPrefixes = prefixes // allocate new everytime - resources.Delimiter = "\\" + resources.Delimiter = "/" resources.Prefix = "" resources.Maxkeys = 1000 objects, resources, err = fs.ListObjects("bucket", resources) @@ -252,7 +252,7 @@ func testPaging(c *check.C, create func() Filesystem) { c.Assert(objects[2].Object, check.Equals, "obj0") c.Assert(objects[3].Object, check.Equals, "obj1") c.Assert(objects[4].Object, check.Equals, "obj10") - c.Assert(resources.CommonPrefixes[0], check.Equals, "this\\") + c.Assert(resources.CommonPrefixes[0], check.Equals, "this/") } // check results with Marker diff --git a/pkg/fs/fs-bucket.go b/pkg/fs/fs-bucket.go index 2d5828245..064c72019 100644 --- a/pkg/fs/fs-bucket.go +++ b/pkg/fs/fs-bucket.go @@ -219,11 +219,17 @@ func (fs Filesystem) ListObjects(bucket string, resources BucketResourcesMetadat } p.root = rootPrefix - /// automatically treat "/" delimiter as "\\" delimiter on windows due to its path constraints. + /// automatically treat incoming "/" as "\\" on windows due to its path constraints. if runtime.GOOS == "windows" { - resources.Prefix = strings.Replace(resources.Prefix, "/", string(os.PathSeparator), -1) - resources.Delimiter = strings.Replace(resources.Delimiter, "/", string(os.PathSeparator), -1) - resources.Marker = strings.Replace(resources.Marker, "/", string(os.PathSeparator), -1) + if resources.Prefix != "" { + resources.Prefix = strings.Replace(resources.Prefix, "/", string(os.PathSeparator), -1) + } + if resources.Delimiter != "" { + resources.Delimiter = strings.Replace(resources.Delimiter, "/", string(os.PathSeparator), -1) + } + if resources.Marker != "" { + resources.Marker = strings.Replace(resources.Marker, "/", string(os.PathSeparator), -1) + } } // if delimiter is supplied and not prefix then we are the very top level, list everything and move on. @@ -318,7 +324,11 @@ func (fs Filesystem) ListObjects(bucket string, resources BucketResourcesMetadat // has the prefix if it does not skip the directory. if fl.Mode().IsDir() { if resources.Prefix != "" { - if !strings.HasPrefix(fp, filepath.Join(p.root, resources.Prefix)) { + // Skip the directory on following situations + // - when prefix is part of file pointer along with the root path + // - when file pointer is part of the prefix along with root path + if !strings.HasPrefix(fp, filepath.Join(p.root, resources.Prefix)) && + !strings.HasPrefix(filepath.Join(p.root, resources.Prefix), fp) { return ErrSkipDir } } @@ -328,6 +338,7 @@ func (fs Filesystem) ListObjects(bucket string, resources BucketResourcesMetadat if fl.Mode().IsDir() { if resources.Marker != "" { if realFp != "" { + // For windows split with its own os.PathSeparator if runtime.GOOS == "windows" { if realFp < strings.Split(resources.Marker, string(os.PathSeparator))[0] { return ErrSkipDir @@ -427,10 +438,18 @@ func (fs Filesystem) ListObjects(bucket string, resources BucketResourcesMetadat if err != nil { return nil, resources, err.Trace() } + // If windows replace all the incoming paths to API compatible paths + if runtime.GOOS == "windows" { + metadata.Object = sanitizeWindowsPath(metadata.Object) + } if metadata.Bucket != "" { metadataList = append(metadataList, metadata) } } } + // Sanitize common prefixes back into API compatible paths + if runtime.GOOS == "windows" { + resources.CommonPrefixes = sanitizeWindowsPaths(resources.CommonPrefixes...) + } return metadataList, resources, nil } diff --git a/pkg/fs/fs-common.go b/pkg/fs/fs-common.go index 15478151d..63ba3cbf4 100644 --- a/pkg/fs/fs-common.go +++ b/pkg/fs/fs-common.go @@ -31,6 +31,20 @@ type Metadata struct { ContentType string } +// sanitizeWindowsPath - sanitize a path +func sanitizeWindowsPath(path string) string { + return strings.Replace(path, "\\", "/", -1) +} + +// sanitizeWindowsPaths - sanitize some windows paths +func sanitizeWindowsPaths(paths ...string) []string { + var results []string + for _, path := range paths { + results = append(results, sanitizeWindowsPath(path)) + } + return results +} + // sortUnique sort a slice in lexical order, removing duplicate elements func sortUnique(objects []string) []string { results := []string{} diff --git a/pkg/fs/fs-object.go b/pkg/fs/fs-object.go index 57f053fd9..9747db3c2 100644 --- a/pkg/fs/fs-object.go +++ b/pkg/fs/fs-object.go @@ -118,6 +118,7 @@ func getMetadata(rootPath, bucket, object string) (ObjectMetadata, *probe.Error) // Do not use filepath.Join() since filepath.Join strips off any object names with '/', use them as is // in a static manner so that we can send a proper 'ObjectNotFound' reply back upon os.Stat() var objectPath string + // For windows use its special os.PathSeparator == "\\" if runtime.GOOS == "windows" { objectPath = rootPath + string(os.PathSeparator) + bucket + string(os.PathSeparator) + object } else { @@ -131,6 +132,9 @@ func getMetadata(rootPath, bucket, object string) (ObjectMetadata, *probe.Error) return ObjectMetadata{}, probe.NewError(err) } contentType := "application/octet-stream" + if runtime.GOOS == "windows" { + object = sanitizeWindowsPath(object) + } metadata := ObjectMetadata{ Bucket: bucket, Object: object,