diff --git a/cmd/admin-bucket-handlers.go b/cmd/admin-bucket-handlers.go index 4793e1ae5..fff3d0a57 100644 --- a/cmd/admin-bucket-handlers.go +++ b/cmd/admin-bucket-handlers.go @@ -21,7 +21,6 @@ import ( "io" "io/ioutil" "net/http" - "path" "github.com/gorilla/mux" "github.com/minio/minio/cmd/logger" @@ -51,7 +50,7 @@ func (a adminAPIHandlers) PutBucketQuotaConfigHandler(w http.ResponseWriter, r * } vars := mux.Vars(r) - bucket := path.Clean(vars["bucket"]) + bucket := pathClean(vars["bucket"]) if _, err := objectAPI.GetBucketInfo(ctx, bucket); err != nil { writeErrorResponseJSON(ctx, w, toAPIError(ctx, err), r.URL) @@ -91,7 +90,7 @@ func (a adminAPIHandlers) GetBucketQuotaConfigHandler(w http.ResponseWriter, r * } vars := mux.Vars(r) - bucket := path.Clean(vars["bucket"]) + bucket := pathClean(vars["bucket"]) if _, err := objectAPI.GetBucketInfo(ctx, bucket); err != nil { writeErrorResponseJSON(ctx, w, toAPIError(ctx, err), r.URL) @@ -120,7 +119,7 @@ func (a adminAPIHandlers) SetRemoteTargetHandler(w http.ResponseWriter, r *http. defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r)) vars := mux.Vars(r) - bucket := path.Clean(vars["bucket"]) + bucket := pathClean(vars["bucket"]) update := r.URL.Query().Get("update") == "true" if !globalIsErasure { @@ -213,7 +212,7 @@ func (a adminAPIHandlers) ListRemoteTargetsHandler(w http.ResponseWriter, r *htt defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r)) vars := mux.Vars(r) - bucket := path.Clean(vars["bucket"]) + bucket := pathClean(vars["bucket"]) arnType := vars["type"] if !globalIsErasure { writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrNotImplemented), r.URL) @@ -252,7 +251,7 @@ func (a adminAPIHandlers) RemoveRemoteTargetHandler(w http.ResponseWriter, r *ht defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r)) vars := mux.Vars(r) - bucket := path.Clean(vars["bucket"]) + bucket := pathClean(vars["bucket"]) arn := vars["arn"] if !globalIsErasure { diff --git a/cmd/admin-handlers-users.go b/cmd/admin-handlers-users.go index 44757b922..9d571de38 100644 --- a/cmd/admin-handlers-users.go +++ b/cmd/admin-handlers-users.go @@ -23,7 +23,6 @@ import ( "io" "io/ioutil" "net/http" - "path" "sort" "github.com/gorilla/mux" @@ -363,7 +362,7 @@ func (a adminAPIHandlers) AddUser(w http.ResponseWriter, r *http.Request) { defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r)) vars := mux.Vars(r) - accessKey := path.Clean(vars["accessKey"]) + accessKey := vars["accessKey"] // Get current object layer instance. objectAPI := newObjectLayerFn() diff --git a/cmd/bucket-handlers.go b/cmd/bucket-handlers.go index a070d3a40..ed02ae39f 100644 --- a/cmd/bucket-handlers.go +++ b/cmd/bucket-handlers.go @@ -760,7 +760,9 @@ func (api objectAPIHandlers) PutBucketHandler(w http.ResponseWriter, r *http.Req globalNotificationSys.LoadBucketMetadata(GlobalContext, bucket) // Make sure to add Location information here only for bucket - w.Header().Set(xhttp.Location, path.Clean(r.URL.Path)) // Clean any trailing slashes. + if cp := pathClean(r.URL.Path); cp != "" { + w.Header().Set(xhttp.Location, cp) // Clean any trailing slashes. + } writeSuccessResponseHeadersOnly(w) diff --git a/cmd/data-scanner.go b/cmd/data-scanner.go index 51fa5771c..a476aa6d0 100644 --- a/cmd/data-scanner.go +++ b/cmd/data-scanner.go @@ -419,7 +419,13 @@ func (f *folderScanner) scanQueuedLevels(ctx context.Context, folders []cachedFo err := readDirFn(path.Join(f.root, folder.name), func(entName string, typ os.FileMode) error { // Parse - entName = path.Clean(path.Join(folder.name, entName)) + entName = pathClean(path.Join(folder.name, entName)) + if entName == "" { + if f.dataUsageScannerDebug { + console.Debugf(scannerLogPrefix+" no bucket (%s,%s)\n", f.root, entName) + } + return errDoneForNow + } bucket, prefix := path2BucketObjectWithBasePath(f.root, entName) if bucket == "" { if f.dataUsageScannerDebug { diff --git a/cmd/data-update-tracker.go b/cmd/data-update-tracker.go index efd563ed5..e1fd06af3 100644 --- a/cmd/data-update-tracker.go +++ b/cmd/data-update-tracker.go @@ -638,7 +638,7 @@ func (d *dataUpdateTracker) cycleFilter(ctx context.Context, req bloomFilterRequ // splitPathDeterministic will split the provided relative path // deterministically and return up to the first 3 elements of the path. -// Slash and dot prefixes are removed. +// slash and dot prefixes are removed. // Trailing slashes are removed. // Returns 0 length if no parts are found after trimming. func splitPathDeterministic(in string) []string { diff --git a/cmd/iam-etcd-store.go b/cmd/iam-etcd-store.go index 0d08e0380..ebd8b81ea 100644 --- a/cmd/iam-etcd-store.go +++ b/cmd/iam-etcd-store.go @@ -55,7 +55,7 @@ func etcdKvsToSet(prefix string, kvs []*mvccpb.KeyValue) set.StringSet { // suffix := "config.json" // result is foo func extractPathPrefixAndSuffix(s string, prefix string, suffix string) string { - return path.Clean(strings.TrimSuffix(strings.TrimPrefix(string(s), prefix), suffix)) + return pathClean(strings.TrimSuffix(strings.TrimPrefix(string(s), prefix), suffix)) } // IAMEtcdStore implements IAMStorageAPI diff --git a/cmd/utils.go b/cmd/utils.go index 0d1322369..92723e62a 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -687,6 +687,16 @@ func ceilFrac(numerator, denominator int64) (ceil int64) { return } +// pathClean is like path.Clean but does not return "." for +// empty inputs, instead returns "empty" as is. +func pathClean(p string) string { + cp := path.Clean(p) + if cp == "." { + return "" + } + return cp +} + func trimLeadingSlash(ep string) string { if len(ep) > 0 && ep[0] == '/' { // Path ends with '/' preserve it diff --git a/pkg/iam/policy/resource.go b/pkg/iam/policy/resource.go index efccfd8b0..d8d66001e 100644 --- a/pkg/iam/policy/resource.go +++ b/pkg/iam/policy/resource.go @@ -56,7 +56,7 @@ func (r Resource) Match(resource string, conditionValues map[string][]string) bo pattern = strings.Replace(pattern, key.VarName(), rvalues[0], -1) } } - if path.Clean(resource) == pattern { + if cp := path.Clean(resource); cp != "." && cp == pattern { return true } return wildcard.Match(pattern, resource)