|
|
@ -49,6 +49,9 @@ type WalkDirOptions struct { |
|
|
|
// FilterPrefix will only return results with given prefix within folder.
|
|
|
|
// FilterPrefix will only return results with given prefix within folder.
|
|
|
|
// Should never contain a slash.
|
|
|
|
// Should never contain a slash.
|
|
|
|
FilterPrefix string |
|
|
|
FilterPrefix string |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ForwardTo will forward to the given object path.
|
|
|
|
|
|
|
|
ForwardTo string |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// WalkDir will traverse a directory and return all entries found.
|
|
|
|
// WalkDir will traverse a directory and return all entries found.
|
|
|
@ -107,6 +110,7 @@ func (s *xlStorage) WalkDir(ctx context.Context, opts WalkDirOptions, wr io.Writ |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
prefix := opts.FilterPrefix |
|
|
|
prefix := opts.FilterPrefix |
|
|
|
|
|
|
|
forward := opts.ForwardTo |
|
|
|
var scanDir func(path string) error |
|
|
|
var scanDir func(path string) error |
|
|
|
scanDir = func(current string) error { |
|
|
|
scanDir = func(current string) error { |
|
|
|
entries, err := s.ListDir(ctx, opts.Bucket, current, -1) |
|
|
|
entries, err := s.ListDir(ctx, opts.Bucket, current, -1) |
|
|
@ -126,6 +130,9 @@ func (s *xlStorage) WalkDir(ctx context.Context, opts WalkDirOptions, wr io.Writ |
|
|
|
if len(prefix) > 0 && !strings.HasPrefix(entry, prefix) { |
|
|
|
if len(prefix) > 0 && !strings.HasPrefix(entry, prefix) { |
|
|
|
continue |
|
|
|
continue |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if len(forward) > 0 && entry < forward { |
|
|
|
|
|
|
|
continue |
|
|
|
|
|
|
|
} |
|
|
|
if strings.HasSuffix(entry, slashSeparator) { |
|
|
|
if strings.HasSuffix(entry, slashSeparator) { |
|
|
|
if strings.HasSuffix(entry, globalDirSuffixWithSlash) { |
|
|
|
if strings.HasSuffix(entry, globalDirSuffixWithSlash) { |
|
|
|
// Add without extension so it is sorted correctly.
|
|
|
|
// Add without extension so it is sorted correctly.
|
|
|
@ -177,6 +184,7 @@ func (s *xlStorage) WalkDir(ctx context.Context, opts WalkDirOptions, wr io.Writ |
|
|
|
sort.Strings(entries) |
|
|
|
sort.Strings(entries) |
|
|
|
dirStack := make([]string, 0, 5) |
|
|
|
dirStack := make([]string, 0, 5) |
|
|
|
prefix = "" // Remove prefix after first level.
|
|
|
|
prefix = "" // Remove prefix after first level.
|
|
|
|
|
|
|
|
|
|
|
|
for _, entry := range entries { |
|
|
|
for _, entry := range entries { |
|
|
|
if entry == "" { |
|
|
|
if entry == "" { |
|
|
|
continue |
|
|
|
continue |
|
|
@ -189,8 +197,11 @@ func (s *xlStorage) WalkDir(ctx context.Context, opts WalkDirOptions, wr io.Writ |
|
|
|
out <- metaCacheEntry{name: pop} |
|
|
|
out <- metaCacheEntry{name: pop} |
|
|
|
if opts.Recursive { |
|
|
|
if opts.Recursive { |
|
|
|
// Scan folder we found. Should be in correct sort order where we are.
|
|
|
|
// Scan folder we found. Should be in correct sort order where we are.
|
|
|
|
err := scanDir(pop) |
|
|
|
forward = "" |
|
|
|
logger.LogIf(ctx, err) |
|
|
|
if len(opts.ForwardTo) > 0 && strings.HasPrefix(opts.ForwardTo, pop) { |
|
|
|
|
|
|
|
forward = strings.TrimPrefix(opts.ForwardTo, pop) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
logger.LogIf(ctx, scanDir(pop)) |
|
|
|
} |
|
|
|
} |
|
|
|
dirStack = dirStack[:len(dirStack)-1] |
|
|
|
dirStack = dirStack[:len(dirStack)-1] |
|
|
|
} |
|
|
|
} |
|
|
@ -239,8 +250,11 @@ func (s *xlStorage) WalkDir(ctx context.Context, opts WalkDirOptions, wr io.Writ |
|
|
|
out <- metaCacheEntry{name: pop} |
|
|
|
out <- metaCacheEntry{name: pop} |
|
|
|
if opts.Recursive { |
|
|
|
if opts.Recursive { |
|
|
|
// Scan folder we found. Should be in correct sort order where we are.
|
|
|
|
// Scan folder we found. Should be in correct sort order where we are.
|
|
|
|
err := scanDir(pop) |
|
|
|
forward = "" |
|
|
|
logger.LogIf(ctx, err) |
|
|
|
if len(opts.ForwardTo) > 0 && strings.HasPrefix(opts.ForwardTo, pop) { |
|
|
|
|
|
|
|
forward = strings.TrimPrefix(opts.ForwardTo, pop) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
logger.LogIf(ctx, scanDir(pop)) |
|
|
|
} |
|
|
|
} |
|
|
|
dirStack = dirStack[:len(dirStack)-1] |
|
|
|
dirStack = dirStack[:len(dirStack)-1] |
|
|
|
} |
|
|
|
} |
|
|
@ -267,6 +281,7 @@ func (client *storageRESTClient) WalkDir(ctx context.Context, opts WalkDirOption |
|
|
|
values.Set(storageRESTRecursive, strconv.FormatBool(opts.Recursive)) |
|
|
|
values.Set(storageRESTRecursive, strconv.FormatBool(opts.Recursive)) |
|
|
|
values.Set(storageRESTReportNotFound, strconv.FormatBool(opts.ReportNotFound)) |
|
|
|
values.Set(storageRESTReportNotFound, strconv.FormatBool(opts.ReportNotFound)) |
|
|
|
values.Set(storageRESTPrefixFilter, opts.FilterPrefix) |
|
|
|
values.Set(storageRESTPrefixFilter, opts.FilterPrefix) |
|
|
|
|
|
|
|
values.Set(storageRESTForwardFilter, opts.ForwardTo) |
|
|
|
respBody, err := client.call(ctx, storageRESTMethodWalkDir, values, nil, -1) |
|
|
|
respBody, err := client.call(ctx, storageRESTMethodWalkDir, values, nil, -1) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
logger.LogIf(ctx, err) |
|
|
|
logger.LogIf(ctx, err) |
|
|
@ -299,6 +314,7 @@ func (s *storageRESTServer) WalkDirHandler(w http.ResponseWriter, r *http.Reques |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
prefix := r.URL.Query().Get(storageRESTPrefixFilter) |
|
|
|
prefix := r.URL.Query().Get(storageRESTPrefixFilter) |
|
|
|
|
|
|
|
forward := r.URL.Query().Get(storageRESTForwardFilter) |
|
|
|
writer := streamHTTPResponse(w) |
|
|
|
writer := streamHTTPResponse(w) |
|
|
|
writer.CloseWithError(s.storage.WalkDir(r.Context(), WalkDirOptions{ |
|
|
|
writer.CloseWithError(s.storage.WalkDir(r.Context(), WalkDirOptions{ |
|
|
|
Bucket: volume, |
|
|
|
Bucket: volume, |
|
|
@ -306,5 +322,6 @@ func (s *storageRESTServer) WalkDirHandler(w http.ResponseWriter, r *http.Reques |
|
|
|
Recursive: recursive, |
|
|
|
Recursive: recursive, |
|
|
|
ReportNotFound: reportNotFound, |
|
|
|
ReportNotFound: reportNotFound, |
|
|
|
FilterPrefix: prefix, |
|
|
|
FilterPrefix: prefix, |
|
|
|
|
|
|
|
ForwardTo: forward, |
|
|
|
}, writer)) |
|
|
|
}, writer)) |
|
|
|
} |
|
|
|
} |
|
|
|