diff --git a/cmd/fs-v1-helpers.go b/cmd/fs-v1-helpers.go index 598fb8c02..a3cd1f95f 100644 --- a/cmd/fs-v1-helpers.go +++ b/cmd/fs-v1-helpers.go @@ -225,6 +225,15 @@ func fsStatDir(ctx context.Context, statDir string) (os.FileInfo, error) { return fi, nil } +// Returns if the dirPath is a directory. +func fsIsDir(ctx context.Context, dirPath string) bool { + fi, err := fsStat(ctx, dirPath) + if err != nil { + return false + } + return fi.IsDir() +} + // Lookup if file exists, returns file attributes upon success. func fsStatFile(ctx context.Context, statFile string) (os.FileInfo, error) { fi, err := fsStat(ctx, statFile) @@ -242,6 +251,15 @@ func fsStatFile(ctx context.Context, statFile string) (os.FileInfo, error) { return fi, nil } +// Returns if the filePath is a regular file. +func fsIsFile(ctx context.Context, filePath string) bool { + fi, err := fsStat(ctx, filePath) + if err != nil { + return false + } + return fi.Mode().IsRegular() +} + // Opens the file at given path, optionally from an offset. Upon success returns // a readable stream and the size of the readable stream. func fsOpenFile(ctx context.Context, readPath string, offset int64) (io.ReadCloser, int64, error) { @@ -402,7 +420,9 @@ func fsDeleteFile(ctx context.Context, basePath, deletePath string) error { } if err := deleteFile(basePath, deletePath); err != nil { - logger.LogIf(ctx, err) + if err != errFileNotFound { + logger.LogIf(ctx, err) + } return err } return nil diff --git a/cmd/fs-v1-helpers_test.go b/cmd/fs-v1-helpers_test.go index 6bbd41eb7..0df862a3c 100644 --- a/cmd/fs-v1-helpers_test.go +++ b/cmd/fs-v1-helpers_test.go @@ -547,3 +547,33 @@ func TestFSRemoveMeta(t *testing.T) { t.Fatalf("`%s` parent directory found though it should have been deleted.", filePath) } } + +func TestFSIsDir(t *testing.T) { + dirPath, err := ioutil.TempDir(globalTestTmpDir, "minio-") + if err != nil { + t.Fatalf("Unable to create tmp directory %s", err) + } + defer os.RemoveAll(dirPath) + + if !fsIsDir(context.Background(), dirPath) { + t.Fatalf("Expected %s to be a directory", dirPath) + } +} + +func TestFSIsFile(t *testing.T) { + dirPath, err := ioutil.TempDir(globalTestTmpDir, "minio-") + if err != nil { + t.Fatalf("Unable to create tmp directory %s", err) + } + defer os.RemoveAll(dirPath) + + filePath := pathJoin(dirPath, "tmpfile") + + if err = ioutil.WriteFile(filePath, nil, 0777); err != nil { + t.Fatalf("Unable to create file %s", filePath) + } + + if !fsIsFile(context.Background(), filePath) { + t.Fatalf("Expected %s to be a file", filePath) + } +} diff --git a/cmd/fs-v1.go b/cmd/fs-v1.go index 79ea9ce75..f3f299799 100644 --- a/cmd/fs-v1.go +++ b/cmd/fs-v1.go @@ -563,17 +563,16 @@ func (fs *FSObjects) defaultFsJSON(object string) fsMetaV1 { // getObjectInfo - wrapper for reading object metadata and constructs ObjectInfo. func (fs *FSObjects) getObjectInfo(ctx context.Context, bucket, object string) (oi ObjectInfo, e error) { fsMeta := fsMetaV1{} - fi, err := fsStatDir(ctx, pathJoin(fs.fsPath, bucket, object)) - if err != nil && err != errFileAccessDenied { - return oi, err - } - if fi != nil { - // If file found and request was with object ending with "/", consider it - // as directory and return object info - if hasSuffix(object, slashSeparator) { - return fsMeta.ToObjectInfo(bucket, object, fi), nil + if hasSuffix(object, slashSeparator) { + // Since we support PUT of a "directory" object, we allow HEAD. + if !fsIsDir(ctx, pathJoin(fs.fsPath, bucket, object)) { + return oi, errFileNotFound } - return oi, errFileNotFound + fi, err := fsStatDir(ctx, pathJoin(fs.fsPath, bucket, object)) + if err != nil { + return oi, err + } + return fsMeta.ToObjectInfo(bucket, object, fi), nil } fsMetaPath := pathJoin(fs.fsPath, minioMetaBucket, bucketMetaPrefix, bucket, object, fs.metaJSONFile) @@ -602,7 +601,7 @@ func (fs *FSObjects) getObjectInfo(ctx context.Context, bucket, object string) ( } // Stat the file to get file size. - fi, err = fsStatFile(ctx, pathJoin(fs.fsPath, bucket, object)) + fi, err := fsStatFile(ctx, pathJoin(fs.fsPath, bucket, object)) if err != nil { return oi, err } @@ -664,7 +663,7 @@ func (fs *FSObjects) parentDirIsObject(ctx context.Context, bucket, parent strin if p == "." || p == "/" { return false } - if _, err := fsStatFile(ctx, pathJoin(fs.fsPath, bucket, p)); err == nil { + if fsIsFile(ctx, pathJoin(fs.fsPath, bucket, p)) { // If there is already a file at prefix "p", return true. return true } diff --git a/cmd/xl-v1-bucket.go b/cmd/xl-v1-bucket.go index e447d9e94..a3eca5d6d 100644 --- a/cmd/xl-v1-bucket.go +++ b/cmd/xl-v1-bucket.go @@ -137,7 +137,6 @@ func (xl xlObjects) getBucketInfo(ctx context.Context, bucketName string) (bucke } return bucketInfo, nil } - logger.LogIf(ctx, serr) err = serr // For any reason disk went offline continue and pick the next one. if IsErrIgnored(err, bucketMetadataOpIgnoredErrs...) { diff --git a/cmd/xl-v1-object.go b/cmd/xl-v1-object.go index a3f7e9ff1..606903430 100644 --- a/cmd/xl-v1-object.go +++ b/cmd/xl-v1-object.go @@ -832,7 +832,6 @@ func (xl xlObjects) DeleteObject(ctx context.Context, bucket, object string) (er // Validate object exists. if !xl.isObject(bucket, object) { - logger.LogIf(ctx, ObjectNotFound{bucket, object}) return ObjectNotFound{bucket, object} } // else proceed to delete the object. diff --git a/cmd/xl-v1-utils.go b/cmd/xl-v1-utils.go index 4e16c3958..cd7102917 100644 --- a/cmd/xl-v1-utils.go +++ b/cmd/xl-v1-utils.go @@ -66,7 +66,7 @@ func reduceErrs(errs []error, ignoredErrs []error) (maxCount int, maxErr error) func reduceQuorumErrs(ctx context.Context, errs []error, ignoredErrs []error, quorum int, quorumErr error) error { maxCount, maxErr := reduceErrs(errs, ignoredErrs) if maxCount >= quorum { - if maxErr != errFileNotFound { + if maxErr != errFileNotFound && maxErr != errVolumeNotFound { logger.LogIf(ctx, maxErr) } return maxErr