in lib/backend/s3backend/client.go [233:299]
func (c *Client) List(prefix string, opts ...backend.ListOption) (*backend.ListResult, error) {
// For whatever reason, the S3 list API does not accept an absolute path
// for prefix. Thus, the root is stripped from the input and added manually
// to each output key.
options := backend.DefaultListOptions()
for _, opt := range opts {
opt(options)
}
// If paginiated is enabled use the maximum number of keys requests from thhe options,
// otherwise fall back to the configuration's max keys
maxKeys := int64(c.config.ListMaxKeys)
var continuationToken *string
if options.Paginated {
maxKeys = int64(options.MaxKeys)
// An empty continuationToken should be left as nil when sending paginated list
// requests to s3
if options.ContinuationToken != "" {
continuationToken = aws.String(options.ContinuationToken)
}
}
var names []string
nextContinuationToken := ""
err := c.s3.ListObjectsV2Pages(&s3.ListObjectsV2Input{
Bucket: aws.String(c.config.Bucket),
MaxKeys: aws.Int64(maxKeys),
Prefix: aws.String(path.Join(c.pather.BasePath(), prefix)[1:]),
ContinuationToken: continuationToken,
}, func(page *s3.ListObjectsV2Output, last bool) bool {
for _, object := range page.Contents {
if object.Key == nil {
log.With(
"prefix", prefix,
"object", object).Error("List encountered nil S3 object key")
continue
}
name, err := c.pather.NameFromBlobPath(path.Join("/", *object.Key))
if err != nil {
log.With("key", *object.Key).Errorf("Error converting blob path into name: %s", err)
continue
}
names = append(names, name)
}
if int64(len(names)) < maxKeys {
// Continue iterating pages to get more keys
return true
}
// Attempt to capture the continuation token before we stop iterating pages
if page.IsTruncated != nil && *page.IsTruncated && page.NextContinuationToken != nil {
nextContinuationToken = *page.NextContinuationToken
}
return false
})
if err != nil {
return nil, err
}
return &backend.ListResult{
Names: names,
ContinuationToken: nextContinuationToken,
}, nil
}