1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-11-06 08:49:29 +02:00

Add storageInfoLevelType.

This allows the removal of the callback in the S3/Azure storage drivers that existed only to parse the size/time information.

The extra callback was required because not all callers of storage*ListInternal() want size/time info, so it was wasteful to add it to storage*ListInternal(). Now those callers can request type info only.
This commit is contained in:
David Steele
2021-02-28 18:02:09 -05:00
parent 54c4eb0c10
commit 1d77db3143
4 changed files with 133 additions and 183 deletions

View File

@@ -307,13 +307,13 @@ General function for listing files to be used by other list routines
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
static void static void
storageAzureListInternal( storageAzureListInternal(
StorageAzure *this, const String *path, const String *expression, bool recurse, StorageAzure *this, const String *path, StorageInfoLevel level, const String *expression, bool recurse,
void (*callback)(StorageAzure *this, void *callbackData, const String *name, StorageType type, const XmlNode *xml), StorageInfoListCallback callback, void *callbackData)
void *callbackData)
{ {
FUNCTION_LOG_BEGIN(logLevelDebug); FUNCTION_LOG_BEGIN(logLevelDebug);
FUNCTION_LOG_PARAM(STORAGE_AZURE, this); FUNCTION_LOG_PARAM(STORAGE_AZURE, this);
FUNCTION_LOG_PARAM(STRING, path); FUNCTION_LOG_PARAM(STRING, path);
FUNCTION_LOG_PARAM(ENUM, level);
FUNCTION_LOG_PARAM(STRING, expression); FUNCTION_LOG_PARAM(STRING, expression);
FUNCTION_LOG_PARAM(BOOL, recurse); FUNCTION_LOG_PARAM(BOOL, recurse);
FUNCTION_LOG_PARAM(FUNCTIONP, callback); FUNCTION_LOG_PARAM(FUNCTIONP, callback);
@@ -406,7 +406,7 @@ storageAzureListInternal(
MEM_CONTEXT_PRIOR_END(); MEM_CONTEXT_PRIOR_END();
} }
// Get subpath list // Get prefix list
XmlNode *blobs = xmlNodeChild(xmlRoot, AZURE_XML_TAG_BLOBS_STR, true); XmlNode *blobs = xmlNodeChild(xmlRoot, AZURE_XML_TAG_BLOBS_STR, true);
XmlNodeList *blobPrefixList = xmlNodeChildList(blobs, AZURE_XML_TAG_BLOB_PREFIX_STR); XmlNodeList *blobPrefixList = xmlNodeChildList(blobs, AZURE_XML_TAG_BLOB_PREFIX_STR);
@@ -414,14 +414,23 @@ storageAzureListInternal(
{ {
const XmlNode *subPathNode = xmlNodeLstGet(blobPrefixList, blobPrefixIdx); const XmlNode *subPathNode = xmlNodeLstGet(blobPrefixList, blobPrefixIdx);
// Get subpath name // Get path name
const String *subPath = xmlNodeContent(xmlNodeChild(subPathNode, AZURE_XML_TAG_NAME_STR, true)); StorageInfo info =
{
.level = level,
.name = xmlNodeContent(xmlNodeChild(subPathNode, AZURE_XML_TAG_NAME_STR, true)),
.exists = true,
};
// Strip off base prefix and final / // Strip off base prefix and final /
subPath = strSubN(subPath, strSize(basePrefix), strSize(subPath) - strSize(basePrefix) - 1); info.name = strSubN(info.name, strSize(basePrefix), strSize(info.name) - strSize(basePrefix) - 1);
// Add to list // Add type info if requested
callback(this, callbackData, subPath, storageTypePath, NULL); if (level >= storageInfoLevelType)
info.type = storageTypePath;
// Callback with info
callback(callbackData, &info);
} }
// Get file list // Get file list
@@ -432,14 +441,30 @@ storageAzureListInternal(
const XmlNode *fileNode = xmlNodeLstGet(fileList, fileIdx); const XmlNode *fileNode = xmlNodeLstGet(fileList, fileIdx);
// Get file name // Get file name
const String *file = xmlNodeContent(xmlNodeChild(fileNode, AZURE_XML_TAG_NAME_STR, true)); StorageInfo info =
{
.level = level,
.name = xmlNodeContent(xmlNodeChild(fileNode, AZURE_XML_TAG_NAME_STR, true)),
.exists = true,
};
// Strip off the base prefix when present // Strip off the base prefix when present
file = strEmpty(basePrefix) ? file : strSub(file, strSize(basePrefix)); if (!strEmpty(basePrefix))
info.name = strSub(info.name, strSize(basePrefix));
// Add to list // Add basic info if requested (no need to add type info since file is default type)
callback( if (level >= storageInfoLevelBasic)
this, callbackData, file, storageTypeFile, xmlNodeChild(fileNode, AZURE_XML_TAG_PROPERTIES_STR, true)); {
XmlNode *property = xmlNodeChild(fileNode, AZURE_XML_TAG_PROPERTIES_STR, true);
info.size = cvtZToUInt64(
strZ(xmlNodeContent(xmlNodeChild(property, AZURE_XML_TAG_CONTENT_LENGTH_STR, true))));
info.timeModified = httpDateToTime(
xmlNodeContent(xmlNodeChild(property, AZURE_XML_TAG_LAST_MODIFIED_STR, true)));
}
// Callback with info
callback(callbackData, &info);
} }
} }
MEM_CONTEXT_TEMP_END(); MEM_CONTEXT_TEMP_END();
@@ -473,10 +498,9 @@ storageAzureInfo(THIS_VOID, const String *file, StorageInfoLevel level, StorageI
// Does the file exist? // Does the file exist?
StorageInfo result = {.level = level, .exists = httpResponseCodeOk(httpResponse)}; StorageInfo result = {.level = level, .exists = httpResponseCodeOk(httpResponse)};
// Add basic level info if requested and the file exists // Add basic level info if requested and the file exists (no need to add type info since file is default type)
if (result.level >= storageInfoLevelBasic && result.exists) if (result.level >= storageInfoLevelBasic && result.exists)
{ {
result.type = storageTypeFile;
result.size = cvtZToUInt64(strZ(httpHeaderGet(httpResponseHeader(httpResponse), HTTP_HEADER_CONTENT_LENGTH_STR))); result.size = cvtZToUInt64(strZ(httpHeaderGet(httpResponseHeader(httpResponse), HTTP_HEADER_CONTENT_LENGTH_STR)));
result.timeModified = httpDateToTime(httpHeaderGet(httpResponseHeader(httpResponse), HTTP_HEADER_LAST_MODIFIED_STR)); result.timeModified = httpDateToTime(httpHeaderGet(httpResponseHeader(httpResponse), HTTP_HEADER_LAST_MODIFIED_STR));
} }
@@ -485,56 +509,6 @@ storageAzureInfo(THIS_VOID, const String *file, StorageInfoLevel level, StorageI
} }
/**********************************************************************************************************************************/ /**********************************************************************************************************************************/
typedef struct StorageAzureInfoListData
{
StorageInfoLevel level; // Level of info to set
StorageInfoListCallback callback; // User-supplied callback function
void *callbackData; // User-supplied callback data
} StorageAzureInfoListData;
static void
storageAzureInfoListCallback(StorageAzure *this, void *callbackData, const String *name, StorageType type, const XmlNode *xml)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_AZURE, this);
FUNCTION_TEST_PARAM_P(VOID, callbackData);
FUNCTION_TEST_PARAM(STRING, name);
FUNCTION_TEST_PARAM(ENUM, type);
FUNCTION_TEST_PARAM(XML_NODE, xml);
FUNCTION_TEST_END();
(void)this; // Unused but still logged above for debugging
ASSERT(callbackData != NULL);
ASSERT(name != NULL);
StorageAzureInfoListData *data = (StorageAzureInfoListData *)callbackData;
StorageInfo info =
{
.name = name,
.level = data->level,
.exists = true,
};
if (data->level >= storageInfoLevelBasic)
{
info.type = type;
// Add additional info for files
if (type == storageTypeFile)
{
ASSERT(xml != NULL);
info.size = cvtZToUInt64(strZ(xmlNodeContent(xmlNodeChild(xml, AZURE_XML_TAG_CONTENT_LENGTH_STR, true))));
info.timeModified = httpDateToTime(xmlNodeContent(xmlNodeChild(xml, AZURE_XML_TAG_LAST_MODIFIED_STR, true)));
}
}
data->callback(data->callbackData, &info);
FUNCTION_TEST_RETURN_VOID();
}
static bool static bool
storageAzureInfoList( storageAzureInfoList(
THIS_VOID, const String *path, StorageInfoLevel level, StorageInfoListCallback callback, void *callbackData, THIS_VOID, const String *path, StorageInfoLevel level, StorageInfoListCallback callback, void *callbackData,
@@ -555,12 +529,7 @@ storageAzureInfoList(
ASSERT(path != NULL); ASSERT(path != NULL);
ASSERT(callback != NULL); ASSERT(callback != NULL);
MEM_CONTEXT_TEMP_BEGIN() storageAzureListInternal(this, path, level, param.expression, false, callback, callbackData);
{
StorageAzureInfoListData data = {.level = level, .callback = callback, .callbackData = callbackData};
storageAzureListInternal(this, path, param.expression, false, storageAzureInfoListCallback, &data);
}
MEM_CONTEXT_TEMP_END();
FUNCTION_LOG_RETURN(BOOL, true); FUNCTION_LOG_RETURN(BOOL, true);
} }
@@ -609,27 +578,24 @@ storageAzureNewWrite(THIS_VOID, const String *file, StorageInterfaceNewWritePara
/**********************************************************************************************************************************/ /**********************************************************************************************************************************/
typedef struct StorageAzurePathRemoveData typedef struct StorageAzurePathRemoveData
{ {
StorageAzure *this; // Storage object
MemContext *memContext; // Mem context to create requests in MemContext *memContext; // Mem context to create requests in
HttpRequest *request; // Async remove request HttpRequest *request; // Async remove request
const String *path; // Root path of remove const String *path; // Root path of remove
} StorageAzurePathRemoveData; } StorageAzurePathRemoveData;
static void static void
storageAzurePathRemoveCallback(StorageAzure *this, void *callbackData, const String *name, StorageType type, const XmlNode *xml) storageAzurePathRemoveCallback(void *callbackData, const StorageInfo *info)
{ {
FUNCTION_TEST_BEGIN(); FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_AZURE, this);
FUNCTION_TEST_PARAM_P(VOID, callbackData); FUNCTION_TEST_PARAM_P(VOID, callbackData);
FUNCTION_TEST_PARAM(STRING, name); FUNCTION_TEST_PARAM(STORAGE_INFO, info);
FUNCTION_TEST_PARAM(ENUM, type);
(void)xml; // Unused since no additional data needed for files
FUNCTION_TEST_END(); FUNCTION_TEST_END();
ASSERT(this != NULL);
ASSERT(callbackData != NULL); ASSERT(callbackData != NULL);
ASSERT(name != NULL); ASSERT(info != NULL);
StorageAzurePathRemoveData *data = (StorageAzurePathRemoveData *)callbackData; StorageAzurePathRemoveData *data = callbackData;
// Get response from prior async request // Get response from prior async request
if (data->request != NULL) if (data->request != NULL)
@@ -641,12 +607,12 @@ storageAzurePathRemoveCallback(StorageAzure *this, void *callbackData, const Str
} }
// Only delete files since paths don't really exist // Only delete files since paths don't really exist
if (type == storageTypeFile) if (info->type == storageTypeFile)
{ {
MEM_CONTEXT_BEGIN(data->memContext) MEM_CONTEXT_BEGIN(data->memContext)
{ {
data->request = storageAzureRequestAsyncP( data->request = storageAzureRequestAsyncP(
this, HTTP_VERB_DELETE_STR, strNewFmt("%s/%s", strEq(data->path, FSLASH_STR) ? "" : strZ(data->path), strZ(name))); data->this, HTTP_VERB_DELETE_STR, strNewFmt("%s/%s", strZ(data->path), strZ(info->name)));
} }
MEM_CONTEXT_END(); MEM_CONTEXT_END();
} }
@@ -671,8 +637,14 @@ storageAzurePathRemove(THIS_VOID, const String *path, bool recurse, StorageInter
MEM_CONTEXT_TEMP_BEGIN() MEM_CONTEXT_TEMP_BEGIN()
{ {
StorageAzurePathRemoveData data = {.memContext = memContextCurrent(), .path = path}; StorageAzurePathRemoveData data =
storageAzureListInternal(this, path, NULL, true, storageAzurePathRemoveCallback, &data); {
.this = this,
.memContext = memContextCurrent(),
.path = strEq(path, FSLASH_STR) ? EMPTY_STR : path,
};
storageAzureListInternal(this, path, storageInfoLevelType, NULL, true, storageAzurePathRemoveCallback, &data);
// Check response on last async request // Check response on last async request
if (data.request != NULL) if (data.request != NULL)

View File

@@ -8,17 +8,23 @@ Storage Info
/*********************************************************************************************************************************** /***********************************************************************************************************************************
Specify the level of information required when calling functions that return StorageInfo Specify the level of information required when calling functions that return StorageInfo
Each level includes the level below it, i.e. level storageInfoLevelBasic includes storageInfoLevelType which includes
storageInfoLevelExists.
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
typedef enum typedef enum
{ {
// The info type is determined by driver capabilities. This mimics the prior behavior where drivers would always return as // The info type is determined by driver capabilities. This mimics the prior behavior where drivers would always return as much
// much information as they could. // information as they could.
storageInfoLevelDefault = 0, storageInfoLevelDefault = 0,
// Only test for existence. All drivers support this type. // Only test for existence. All drivers must support this level.
storageInfoLevelExists, storageInfoLevelExists,
// Basic information. All drivers support this type. // Include file type, e.g. storageTypeFile. All drivers must support this level.
storageInfoLevelType,
// Basic information. All drivers support this level.
storageInfoLevelBasic, storageInfoLevelBasic,
// Detailed information that is generally only available from filesystems such as Posix // Detailed information that is generally only available from filesystems such as Posix

View File

@@ -73,17 +73,10 @@ storagePosixInfo(THIS_VOID, const String *file, StorageInfoLevel level, StorageI
{ {
result.exists = true; result.exists = true;
// Add basic level info // Add type info (no need set file type since it is the default)
if (result.level >= storageInfoLevelBasic) if (result.level >= storageInfoLevelType && !S_ISREG(statFile.st_mode))
{ {
result.timeModified = statFile.st_mtime; if (S_ISDIR(statFile.st_mode))
if (S_ISREG(statFile.st_mode))
{
result.type = storageTypeFile;
result.size = (uint64_t)statFile.st_size;
}
else if (S_ISDIR(statFile.st_mode))
result.type = storageTypePath; result.type = storageTypePath;
else if (S_ISLNK(statFile.st_mode)) else if (S_ISLNK(statFile.st_mode))
result.type = storageTypeLink; result.type = storageTypeLink;
@@ -91,6 +84,15 @@ storagePosixInfo(THIS_VOID, const String *file, StorageInfoLevel level, StorageI
result.type = storageTypeSpecial; result.type = storageTypeSpecial;
} }
// Add basic level info
if (result.level >= storageInfoLevelBasic)
{
result.timeModified = statFile.st_mtime;
if (result.type == storageTypeFile)
result.size = (uint64_t)statFile.st_size;
}
// Add detail level info // Add detail level info
if (result.level >= storageInfoLevelDetail) if (result.level >= storageInfoLevelDetail)
{ {

View File

@@ -483,13 +483,13 @@ General function for listing files to be used by other list routines
***********************************************************************************************************************************/ ***********************************************************************************************************************************/
static void static void
storageS3ListInternal( storageS3ListInternal(
StorageS3 *this, const String *path, const String *expression, bool recurse, StorageS3 *this, const String *path, StorageInfoLevel level, const String *expression, bool recurse,
void (*callback)(StorageS3 *this, void *callbackData, const String *name, StorageType type, const XmlNode *xml), StorageInfoListCallback callback, void *callbackData)
void *callbackData)
{ {
FUNCTION_LOG_BEGIN(logLevelDebug); FUNCTION_LOG_BEGIN(logLevelDebug);
FUNCTION_LOG_PARAM(STORAGE_S3, this); FUNCTION_LOG_PARAM(STORAGE_S3, this);
FUNCTION_LOG_PARAM(STRING, path); FUNCTION_LOG_PARAM(STRING, path);
FUNCTION_LOG_PARAM(ENUM, level);
FUNCTION_LOG_PARAM(STRING, expression); FUNCTION_LOG_PARAM(STRING, expression);
FUNCTION_LOG_PARAM(BOOL, recurse); FUNCTION_LOG_PARAM(BOOL, recurse);
FUNCTION_LOG_PARAM(FUNCTIONP, callback); FUNCTION_LOG_PARAM(FUNCTIONP, callback);
@@ -580,21 +580,30 @@ storageS3ListInternal(
MEM_CONTEXT_PRIOR_END(); MEM_CONTEXT_PRIOR_END();
} }
// Get subpath list // Get prefix list
XmlNodeList *subPathList = xmlNodeChildList(xmlRoot, S3_XML_TAG_COMMON_PREFIXES_STR); XmlNodeList *subPathList = xmlNodeChildList(xmlRoot, S3_XML_TAG_COMMON_PREFIXES_STR);
for (unsigned int subPathIdx = 0; subPathIdx < xmlNodeLstSize(subPathList); subPathIdx++) for (unsigned int subPathIdx = 0; subPathIdx < xmlNodeLstSize(subPathList); subPathIdx++)
{ {
const XmlNode *subPathNode = xmlNodeLstGet(subPathList, subPathIdx); const XmlNode *subPathNode = xmlNodeLstGet(subPathList, subPathIdx);
// Get subpath name // Get path name
const String *subPath = xmlNodeContent(xmlNodeChild(subPathNode, S3_XML_TAG_PREFIX_STR, true)); StorageInfo info =
{
.level = level,
.name = xmlNodeContent(xmlNodeChild(subPathNode, S3_XML_TAG_PREFIX_STR, true)),
.exists = true,
};
// Strip off base prefix and final / // Strip off base prefix and final /
subPath = strSubN(subPath, strSize(basePrefix), strSize(subPath) - strSize(basePrefix) - 1); info.name = strSubN(info.name, strSize(basePrefix), strSize(info.name) - strSize(basePrefix) - 1);
// Add to list // Add type info if requested
callback(this, callbackData, subPath, storageTypePath, NULL); if (level >= storageInfoLevelType)
info.type = storageTypePath;
// Callback with info
callback(callbackData, &info);
} }
// Get file list // Get file list
@@ -605,13 +614,27 @@ storageS3ListInternal(
const XmlNode *fileNode = xmlNodeLstGet(fileList, fileIdx); const XmlNode *fileNode = xmlNodeLstGet(fileList, fileIdx);
// Get file name // Get file name
const String *file = xmlNodeContent(xmlNodeChild(fileNode, S3_XML_TAG_KEY_STR, true)); StorageInfo info =
{
.level = level,
.name = xmlNodeContent(xmlNodeChild(fileNode, S3_XML_TAG_KEY_STR, true)),
.exists = true,
};
// Strip off the base prefix when present // Strip off the base prefix when present
file = strEmpty(basePrefix) ? file : strSub(file, strSize(basePrefix)); if (!strEmpty(basePrefix))
info.name = strSub(info.name, strSize(basePrefix));
// Add to list // Add basic info if requested (no need to add type info since file is default type)
callback(this, callbackData, file, storageTypeFile, fileNode); if (level >= storageInfoLevelBasic)
{
info.size = cvtZToUInt64(strZ(xmlNodeContent(xmlNodeChild(fileNode, S3_XML_TAG_SIZE_STR, true))));
info.timeModified = storageS3CvtTime(
xmlNodeContent(xmlNodeChild(fileNode, S3_XML_TAG_LAST_MODIFIED_STR, true)));
}
// Callback with info
callback(callbackData, &info);
} }
} }
MEM_CONTEXT_TEMP_END(); MEM_CONTEXT_TEMP_END();
@@ -645,12 +668,11 @@ storageS3Info(THIS_VOID, const String *file, StorageInfoLevel level, StorageInte
// Does the file exist? // Does the file exist?
StorageInfo result = {.level = level, .exists = httpResponseCodeOk(httpResponse)}; StorageInfo result = {.level = level, .exists = httpResponseCodeOk(httpResponse)};
// Add basic level info if requested and the file exists // Add basic level info if requested and the file exists (no need to add type info since file is default type)
if (result.level >= storageInfoLevelBasic && result.exists) if (result.level >= storageInfoLevelBasic && result.exists)
{ {
const HttpHeader *httpHeader = httpResponseHeader(httpResponse); const HttpHeader *httpHeader = httpResponseHeader(httpResponse);
result.type = storageTypeFile;
result.size = cvtZToUInt64(strZ(httpHeaderGet(httpHeader, HTTP_HEADER_CONTENT_LENGTH_STR))); result.size = cvtZToUInt64(strZ(httpHeaderGet(httpHeader, HTTP_HEADER_CONTENT_LENGTH_STR)));
result.timeModified = httpDateToTime(httpHeaderGet(httpHeader, HTTP_HEADER_LAST_MODIFIED_STR)); result.timeModified = httpDateToTime(httpHeaderGet(httpHeader, HTTP_HEADER_LAST_MODIFIED_STR));
} }
@@ -659,56 +681,6 @@ storageS3Info(THIS_VOID, const String *file, StorageInfoLevel level, StorageInte
} }
/**********************************************************************************************************************************/ /**********************************************************************************************************************************/
typedef struct StorageS3InfoListData
{
StorageInfoLevel level; // Level of info to set
StorageInfoListCallback callback; // User-supplied callback function
void *callbackData; // User-supplied callback data
} StorageS3InfoListData;
static void
storageS3InfoListCallback(StorageS3 *this, void *callbackData, const String *name, StorageType type, const XmlNode *xml)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_S3, this);
FUNCTION_TEST_PARAM_P(VOID, callbackData);
FUNCTION_TEST_PARAM(STRING, name);
FUNCTION_TEST_PARAM(ENUM, type);
FUNCTION_TEST_PARAM(XML_NODE, xml);
FUNCTION_TEST_END();
(void)this; // Unused but still logged above for debugging
ASSERT(callbackData != NULL);
ASSERT(name != NULL);
StorageS3InfoListData *data = (StorageS3InfoListData *)callbackData;
StorageInfo info =
{
.name = name,
.level = data->level,
.exists = true,
};
if (data->level >= storageInfoLevelBasic)
{
info.type = type;
// Add additional info for files
if (type == storageTypeFile)
{
ASSERT(xml != NULL);
info.size = cvtZToUInt64(strZ(xmlNodeContent(xmlNodeChild(xml, S3_XML_TAG_SIZE_STR, true))));
info.timeModified = storageS3CvtTime(xmlNodeContent(xmlNodeChild(xml, S3_XML_TAG_LAST_MODIFIED_STR, true)));
}
}
data->callback(data->callbackData, &info);
FUNCTION_TEST_RETURN_VOID();
}
static bool static bool
storageS3InfoList( storageS3InfoList(
THIS_VOID, const String *path, StorageInfoLevel level, StorageInfoListCallback callback, void *callbackData, THIS_VOID, const String *path, StorageInfoLevel level, StorageInfoListCallback callback, void *callbackData,
@@ -729,12 +701,7 @@ storageS3InfoList(
ASSERT(path != NULL); ASSERT(path != NULL);
ASSERT(callback != NULL); ASSERT(callback != NULL);
MEM_CONTEXT_TEMP_BEGIN() storageS3ListInternal(this, path, level, param.expression, false, callback, callbackData);
{
StorageS3InfoListData data = {.level = level, .callback = callback, .callbackData = callbackData};
storageS3ListInternal(this, path, param.expression, false, storageS3InfoListCallback, &data);
}
MEM_CONTEXT_TEMP_END();
FUNCTION_LOG_RETURN(BOOL, true); FUNCTION_LOG_RETURN(BOOL, true);
} }
@@ -783,10 +750,12 @@ storageS3NewWrite(THIS_VOID, const String *file, StorageInterfaceNewWriteParam p
/**********************************************************************************************************************************/ /**********************************************************************************************************************************/
typedef struct StorageS3PathRemoveData typedef struct StorageS3PathRemoveData
{ {
StorageS3 *this; // Storage object
MemContext *memContext; // Mem context to create xml document in MemContext *memContext; // Mem context to create xml document in
unsigned int size; // Size of delete request unsigned int size; // Size of delete request
HttpRequest *request; // Async delete request HttpRequest *request; // Async delete request
XmlDocument *xml; // Delete xml XmlDocument *xml; // Delete xml
const String *path; // Root path of remove
} StorageS3PathRemoveData; } StorageS3PathRemoveData;
static HttpRequest * static HttpRequest *
@@ -839,24 +808,19 @@ storageS3PathRemoveInternal(StorageS3 *this, HttpRequest *request, XmlDocument *
} }
static void static void
storageS3PathRemoveCallback(StorageS3 *this, void *callbackData, const String *name, StorageType type, const XmlNode *xml) storageS3PathRemoveCallback(void *callbackData, const StorageInfo *info)
{ {
FUNCTION_TEST_BEGIN(); FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STORAGE_S3, this);
FUNCTION_TEST_PARAM_P(VOID, callbackData); FUNCTION_TEST_PARAM_P(VOID, callbackData);
(void)name; // Unused since full path from XML needed FUNCTION_TEST_PARAM(STORAGE_INFO, info);
FUNCTION_TEST_PARAM(ENUM, type);
FUNCTION_TEST_PARAM(XML_NODE, xml);
FUNCTION_TEST_END(); FUNCTION_TEST_END();
ASSERT(this != NULL);
ASSERT(callbackData != NULL); ASSERT(callbackData != NULL);
ASSERT(info != NULL);
// Only delete files since paths don't really exist // Only delete files since paths don't really exist
if (type == storageTypeFile) if (info->type == storageTypeFile)
{ {
ASSERT(xml != NULL);
StorageS3PathRemoveData *data = (StorageS3PathRemoveData *)callbackData; StorageS3PathRemoveData *data = (StorageS3PathRemoveData *)callbackData;
// If there is something to delete then create the request // If there is something to delete then create the request
@@ -873,15 +837,15 @@ storageS3PathRemoveCallback(StorageS3 *this, void *callbackData, const String *n
// Add to delete list // Add to delete list
xmlNodeContentSet( xmlNodeContentSet(
xmlNodeAdd(xmlNodeAdd(xmlDocumentRoot(data->xml), S3_XML_TAG_OBJECT_STR), S3_XML_TAG_KEY_STR), xmlNodeAdd(xmlNodeAdd(xmlDocumentRoot(data->xml), S3_XML_TAG_OBJECT_STR), S3_XML_TAG_KEY_STR),
xmlNodeContent(xmlNodeChild(xml, S3_XML_TAG_KEY_STR, true))); strNewFmt("%s%s", strZ(data->path), strZ(info->name)));
data->size++; data->size++;
// Delete list when it is full // Delete list when it is full
if (data->size == this->deleteMax) if (data->size == data->this->deleteMax)
{ {
MEM_CONTEXT_BEGIN(data->memContext) MEM_CONTEXT_BEGIN(data->memContext)
{ {
data->request = storageS3PathRemoveInternal(this, data->request, data->xml); data->request = storageS3PathRemoveInternal(data->this, data->request, data->xml);
} }
MEM_CONTEXT_END(); MEM_CONTEXT_END();
@@ -911,8 +875,14 @@ storageS3PathRemove(THIS_VOID, const String *path, bool recurse, StorageInterfac
MEM_CONTEXT_TEMP_BEGIN() MEM_CONTEXT_TEMP_BEGIN()
{ {
StorageS3PathRemoveData data = {.memContext = memContextCurrent()}; StorageS3PathRemoveData data =
storageS3ListInternal(this, path, NULL, true, storageS3PathRemoveCallback, &data); {
.this = this,
.memContext = memContextCurrent(),
.path = strEq(path, FSLASH_STR) ? EMPTY_STR : strNewFmt("%s/", strZ(strSub(path, 1))),
};
storageS3ListInternal(this, path, storageInfoLevelType, NULL, true, storageS3PathRemoveCallback, &data);
// Call if there is more to be removed // Call if there is more to be removed
if (data.xml != NULL) if (data.xml != NULL)