mirror of
https://github.com/minio/minio.git
synced 2025-11-09 21:49:46 -05:00
Better support of empty directories (#5890)
Better support of HEAD and listing of zero sized objects with trailing slash (a.k.a empty directory). For that, isLeafDir function is added to indicate if the specified object is an empty directory or not. Each backend (xl, fs) has the responsibility to store that information. Currently, in both of XL & FS, an empty directory is represented by an empty directory in the backend. isLeafDir() checks if the given path is an empty directory or not, since dir listing is costly if the latter contains too many objects, readDirN() is added in this PR to list only N number of entries. In isLeadDir(), we will only list one entry to check if a directory is empty or not.
This commit is contained in:
committed by
Harshavardhana
parent
32700fca52
commit
6d5f2a4391
26
cmd/fs-v1.go
26
cmd/fs-v1.go
@@ -627,6 +627,10 @@ func (fs *FSObjects) getObjectInfoWithLock(ctx context.Context, bucket, object s
|
||||
return oi, toObjectErr(err, bucket)
|
||||
}
|
||||
|
||||
if strings.HasSuffix(object, slashSeparator) && !fs.isObjectDir(bucket, object) {
|
||||
return oi, errFileNotFound
|
||||
}
|
||||
|
||||
return fs.getObjectInfo(ctx, bucket, object)
|
||||
}
|
||||
|
||||
@@ -890,6 +894,17 @@ func (fs *FSObjects) listDirFactory(isLeaf isLeafFunc) listDirFunc {
|
||||
return listDir
|
||||
}
|
||||
|
||||
// isObjectDir returns true if the specified bucket & prefix exists
|
||||
// and the prefix represents an empty directory. An S3 empty directory
|
||||
// is also an empty directory in the FS backend.
|
||||
func (fs *FSObjects) isObjectDir(bucket, prefix string) bool {
|
||||
entries, err := readDirN(pathJoin(fs.fsPath, bucket, prefix), 1)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return len(entries) == 0
|
||||
}
|
||||
|
||||
// getObjectETag is a helper function, which returns only the md5sum
|
||||
// of the file on the disk.
|
||||
func (fs *FSObjects) getObjectETag(ctx context.Context, bucket, entry string, lock bool) (string, error) {
|
||||
@@ -1019,8 +1034,15 @@ func (fs *FSObjects) ListObjects(ctx context.Context, bucket, prefix, marker, de
|
||||
// object string does not end with "/".
|
||||
return !hasSuffix(object, slashSeparator)
|
||||
}
|
||||
// Return true if the specified object is an empty directory
|
||||
isLeafDir := func(bucket, object string) bool {
|
||||
if !hasSuffix(object, slashSeparator) {
|
||||
return false
|
||||
}
|
||||
return fs.isObjectDir(bucket, object)
|
||||
}
|
||||
listDir := fs.listDirFactory(isLeaf)
|
||||
walkResultCh = startTreeWalk(ctx, bucket, prefix, marker, recursive, listDir, isLeaf, endWalkCh)
|
||||
walkResultCh = startTreeWalk(ctx, bucket, prefix, marker, recursive, listDir, isLeaf, isLeafDir, endWalkCh)
|
||||
}
|
||||
|
||||
var objInfos []ObjectInfo
|
||||
@@ -1065,7 +1087,7 @@ func (fs *FSObjects) ListObjects(ctx context.Context, bucket, prefix, marker, de
|
||||
result := ListObjectsInfo{IsTruncated: !eof}
|
||||
for _, objInfo := range objInfos {
|
||||
result.NextMarker = objInfo.Name
|
||||
if objInfo.IsDir {
|
||||
if objInfo.IsDir && delimiter == slashSeparator {
|
||||
result.Prefixes = append(result.Prefixes, objInfo.Name)
|
||||
continue
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user