in src/s3fs.cpp [2905:3016]
static int list_bucket(const char* path, S3ObjList& head, const char* delimiter, bool check_content_only)
{
std::string s3_realpath;
std::string query_delimiter;
std::string query_prefix;
std::string query_maxkey;
std::string next_continuation_token;
std::string next_marker;
bool truncated = true;
S3fsCurl s3fscurl;
xmlDocPtr doc;
S3FS_PRN_INFO1("[path=%s]", path);
if(delimiter && 0 < strlen(delimiter)){
query_delimiter += "delimiter=";
query_delimiter += delimiter;
query_delimiter += "&";
}
query_prefix += "&prefix=";
s3_realpath = get_realpath(path);
if(s3_realpath.empty() || '/' != *s3_realpath.rbegin()){
// last word must be "/"
query_prefix += urlEncode(s3_realpath.substr(1) + "/");
}else{
query_prefix += urlEncode(s3_realpath.substr(1));
}
if (check_content_only){
// Just need to know if there are child objects in dir
// For dir with children, expect "dir/" and "dir/child"
query_maxkey += "max-keys=2";
}else{
query_maxkey += "max-keys=" + str(max_keys_list_object);
}
while(truncated){
// append parameters to query in alphabetical order
std::string each_query;
if(!next_continuation_token.empty()){
each_query += "continuation-token=" + urlEncode(next_continuation_token) + "&";
next_continuation_token = "";
}
each_query += query_delimiter;
if(S3fsCurl::IsListObjectsV2()){
each_query += "list-type=2&";
}
if(!next_marker.empty()){
each_query += "marker=" + urlEncode(next_marker) + "&";
next_marker = "";
}
each_query += query_maxkey;
each_query += query_prefix;
// request
int result;
if(0 != (result = s3fscurl.ListBucketRequest(path, each_query.c_str()))){
S3FS_PRN_ERR("ListBucketRequest returns with error.");
return result;
}
const std::string* body = s3fscurl.GetBodyData();
// xmlDocPtr
if(NULL == (doc = xmlReadMemory(body->c_str(), static_cast<int>(body->size()), "", NULL, 0))){
S3FS_PRN_ERR("xmlReadMemory returns with error.");
return -EIO;
}
if(0 != append_objects_from_xml(path, doc, head)){
S3FS_PRN_ERR("append_objects_from_xml returns with error.");
xmlFreeDoc(doc);
return -EIO;
}
if(true == (truncated = is_truncated(doc))){
xmlChar* tmpch;
if(NULL != (tmpch = get_next_continuation_token(doc))){
next_continuation_token = (char*)tmpch;
xmlFree(tmpch);
}else if(NULL != (tmpch = get_next_marker(doc))){
next_marker = (char*)tmpch;
xmlFree(tmpch);
}
if(next_continuation_token.empty() && next_marker.empty()){
// If did not specify "delimiter", s3 did not return "NextMarker".
// On this case, can use last name for next marker.
//
std::string lastname;
if(!head.GetLastName(lastname)){
S3FS_PRN_WARN("Could not find next marker, thus break loop.");
truncated = false;
}else{
next_marker = s3_realpath.substr(1);
if(s3_realpath.empty() || '/' != *s3_realpath.rbegin()){
next_marker += "/";
}
next_marker += lastname;
}
}
}
S3FS_XMLFREEDOC(doc);
// reset(initialize) curl object
s3fscurl.DestroyCurlHandle();
if(check_content_only){
break;
}
}
S3FS_MALLOCTRIM(0);
return 0;
}