multipart.c 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117
  1. /** **************************************************************************
  2. * multipart.c
  3. *
  4. * Copyright 2008 Bryan Ischo <[email protected]>
  5. *
  6. * This file is part of libs3.
  7. *
  8. * libs3 is free software: you can redistribute it and/or modify it under the
  9. * terms of the GNU Lesser General Public License as published by the Free
  10. * Software Foundation, version 3 or above of the License. You can also
  11. * redistribute and/or modify it under the terms of the GNU General Public
  12. * License, version 2 or above of the License.
  13. *
  14. * In addition, as a special exception, the copyright holders give
  15. * permission to link the code of this library and its programs with the
  16. * OpenSSL library, and distribute linked combinations including the two.
  17. *
  18. * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY
  19. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  20. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  21. * details.
  22. *
  23. * You should have received a copy of the GNU Lesser General Public License
  24. * version 3 along with libs3, in a file named COPYING. If not, see
  25. * <https://www.gnu.org/licenses/>.
  26. *
  27. * You should also have received a copy of the GNU General Public License
  28. * version 2 along with libs3, in a file named COPYING-GPLv2. If not, see
  29. * <https://www.gnu.org/licenses/>.
  30. *
  31. ************************************************************************** **/
  32. #include <string.h>
  33. #include <stdlib.h>
  34. #include "libs3.h"
  35. #include "request.h"
  36. #include "simplexml.h"
  37. typedef struct InitialMultipartData
  38. {
  39. SimpleXml simpleXml;
  40. int len;
  41. S3MultipartInitialHandler *handler;
  42. string_buffer(upload_id, 256);
  43. void *userdata;
  44. } InitialMultipartData;
  45. static S3Status InitialMultipartCallback(int bufferSize, const char *buffer,
  46. void *callbackData)
  47. {
  48. InitialMultipartData *mdata = (InitialMultipartData *) callbackData;
  49. return simplexml_add(&(mdata->simpleXml), buffer, bufferSize);
  50. }
  51. static void InitialMultipartCompleteCallback
  52. (S3Status requestStatus, const S3ErrorDetails *s3ErrorDetails,
  53. void *callbackData)
  54. {
  55. InitialMultipartData *mdata = (InitialMultipartData *) callbackData;
  56. if (mdata->handler->responseHandler.completeCallback) {
  57. (*mdata->handler->responseHandler.completeCallback)
  58. (requestStatus, s3ErrorDetails, mdata->userdata);
  59. }
  60. if (mdata->handler->responseXmlCallback) {
  61. (*mdata->handler->responseXmlCallback)
  62. (mdata->upload_id, mdata->userdata);
  63. }
  64. simplexml_deinitialize(&(mdata->simpleXml));
  65. free(mdata);
  66. }
  67. #ifndef WINSCP
  68. static void AbortMultipartUploadCompleteCallback
  69. (S3Status requestStatus, const S3ErrorDetails *s3ErrorDetails,
  70. void *callbackData)
  71. {
  72. (void) callbackData;
  73. (void) s3ErrorDetails;
  74. fprintf(stderr, "\nERROR: %s\n", S3_get_status_name(requestStatus));
  75. }
  76. #endif
  77. static S3Status initialMultipartXmlCallback(const char *elementPath,
  78. const char *data,
  79. int dataLen,
  80. void *callbackData)
  81. {
  82. InitialMultipartData *mdata = (InitialMultipartData *) callbackData;
  83. int fit;
  84. if (data) {
  85. if (!strcmp(elementPath, "InitiateMultipartUploadResult/UploadId")) {
  86. string_buffer_append(mdata->upload_id,data, dataLen, fit);
  87. }
  88. }
  89. (void) fit;
  90. return S3StatusOK;
  91. }
  92. static S3Status InitialMultipartPropertiesCallback(const S3ResponseProperties *properties,
  93. void *callbackData)
  94. {
  95. InitialMultipartData *mdata = (InitialMultipartData *)callbackData;
  96. return mdata->handler->responseHandler.propertiesCallback(properties, mdata->userdata);
  97. }
  98. void S3_initiate_multipart(S3BucketContext *bucketContext, const char *key,
  99. S3PutProperties *putProperties,
  100. S3MultipartInitialHandler *handler,
  101. S3RequestContext *requestContext,
  102. int timeoutMs,
  103. void *callbackData)
  104. {
  105. InitialMultipartData *mdata =
  106. (InitialMultipartData *) malloc(sizeof(InitialMultipartData));
  107. simplexml_initialize(&(mdata->simpleXml), &initialMultipartXmlCallback,
  108. mdata);
  109. string_buffer_initialize(mdata->upload_id);
  110. mdata->handler= handler;
  111. mdata->userdata = callbackData;
  112. RequestParams params =
  113. {
  114. HttpRequestTypePOST, // httpRequestType
  115. { bucketContext->hostName, // hostName
  116. bucketContext->bucketName, // bucketName
  117. bucketContext->protocol, // protocol
  118. bucketContext->uriStyle, // uriStyle
  119. bucketContext->accessKeyId, // accessKeyId
  120. bucketContext->secretAccessKey, // secretAccessKey
  121. bucketContext->securityToken, // securityToken
  122. bucketContext->authRegion }, // authRegion
  123. key, // key
  124. 0, // queryParams
  125. "uploads", // subResource
  126. 0, // copySourceBucketName
  127. 0, // copySourceKey
  128. 0, // getConditions
  129. 0, // startByte
  130. 0, // byteCount
  131. putProperties, // putProperties
  132. InitialMultipartPropertiesCallback, // propertiesCallback
  133. 0, // toS3Callback
  134. 0, // toS3CallbackTotalSize
  135. InitialMultipartCallback, // fromS3Callback
  136. InitialMultipartCompleteCallback, // completeCallback
  137. mdata, // callbackData
  138. timeoutMs // timeoutMs
  139. };
  140. // Perform the request
  141. request_perform(&params, requestContext);
  142. }
  143. void S3_abort_multipart_upload(S3BucketContext *bucketContext, const char *key,
  144. const char *uploadId,
  145. int timeoutMs,
  146. S3AbortMultipartUploadHandler *handler,
  147. S3RequestContext *requestContext, // WINSCP
  148. void *callbackData) // WINSCP
  149. {
  150. char subResource[512];
  151. snprintf(subResource, 512, "uploadId=%s", uploadId);
  152. RequestParams params =
  153. {
  154. HttpRequestTypeDELETE, // httpRequestType
  155. { bucketContext->hostName, // hostName
  156. bucketContext->bucketName, // bucketName
  157. bucketContext->protocol, // protocol
  158. bucketContext->uriStyle, // uriStyle
  159. bucketContext->accessKeyId, // accessKeyId
  160. bucketContext->secretAccessKey, // secretAccessKey
  161. bucketContext->securityToken, // securityToken
  162. bucketContext->authRegion }, // authRegion
  163. key, // key
  164. 0, // queryParams
  165. subResource, // subResource
  166. 0, // copySourceBucketName
  167. 0, // copySourceKey
  168. 0, // getConditions
  169. 0, // startByte
  170. 0, // byteCount
  171. 0, // putProperties
  172. handler->responseHandler.propertiesCallback, // propertiesCallback
  173. 0, // toS3Callback
  174. 0, // toS3CallbackTotalSize
  175. 0, // fromS3Callback
  176. handler->responseHandler.completeCallback, // completeCallback WINSCP
  177. callbackData, // callbackData WINSCP
  178. timeoutMs // timeoutMs
  179. };
  180. // Perform the request
  181. request_perform(&params, requestContext); // WINSCP
  182. }
  183. /*
  184. * S3 Upload Part
  185. */
  186. void S3_upload_part(S3BucketContext *bucketContext, const char *key,
  187. S3PutProperties *putProperties,
  188. S3PutObjectHandler *handler, int seq,
  189. const char *upload_id, int partContentLength,
  190. S3RequestContext *requestContext,
  191. int timeoutMs,
  192. void *callbackData)
  193. {
  194. char queryParams[512];
  195. snprintf(queryParams, 512, "partNumber=%d&uploadId=%s", seq, upload_id);
  196. RequestParams params =
  197. {
  198. HttpRequestTypePUT, // httpRequestType
  199. { bucketContext->hostName, // hostName
  200. bucketContext->bucketName, // bucketName
  201. bucketContext->protocol, // protocol
  202. bucketContext->uriStyle, // uriStyle
  203. bucketContext->accessKeyId, // accessKeyId
  204. bucketContext->secretAccessKey, // secretAccessKey
  205. bucketContext->securityToken, // securityToken
  206. bucketContext->authRegion }, // authRegion
  207. key, // key
  208. queryParams, // queryParams
  209. 0, // subResource
  210. 0, // copySourceBucketName
  211. 0, // copySourceKey
  212. 0, // getConditions
  213. 0, // startByte
  214. 0, // byteCount
  215. putProperties, // putProperties
  216. handler->responseHandler.propertiesCallback, // propertiesCallback
  217. handler->putObjectDataCallback, // toS3Callback
  218. partContentLength, // toS3CallbackTotalSize
  219. 0, // fromS3Callback
  220. handler->responseHandler.completeCallback, // completeCallback
  221. callbackData, // callbackData
  222. timeoutMs // timeoutMs
  223. };
  224. request_perform(&params, requestContext);
  225. }
  226. /*
  227. * S3 commit multipart
  228. *
  229. */
  230. typedef struct CommitMultiPartData {
  231. SimpleXml simplexml;
  232. void *userdata;
  233. S3MultipartCommitHandler *handler;
  234. //response parsed from
  235. string_buffer(location,128);
  236. string_buffer(etag,128);
  237. } CommitMultiPartData;
  238. static S3Status commitMultipartResponseXMLcallback(const char *elementPath,
  239. const char *data,
  240. int dataLen,
  241. void *callbackData)
  242. {
  243. int fit;
  244. CommitMultiPartData *commit_data = (CommitMultiPartData *) callbackData;
  245. if (data) {
  246. if (!strcmp(elementPath, "CompleteMultipartUploadResult/Location")) {
  247. string_buffer_append(commit_data->location, data, dataLen, fit);
  248. }
  249. else if (!strcmp(elementPath, "CompleteMultipartUploadResult/ETag")) {
  250. string_buffer_append(commit_data->etag, data, dataLen, fit);
  251. }
  252. }
  253. (void) fit;
  254. return S3StatusOK;
  255. }
  256. static S3Status commitMultipartCallback(int bufferSize, const char *buffer,
  257. void *callbackData)
  258. {
  259. CommitMultiPartData *data = (CommitMultiPartData *) callbackData;
  260. return simplexml_add(&(data->simplexml), buffer, bufferSize);
  261. }
  262. static S3Status commitMultipartPropertiesCallback
  263. (const S3ResponseProperties *responseProperties, void *callbackData)
  264. {
  265. CommitMultiPartData *data = (CommitMultiPartData *) callbackData;
  266. if (data->handler->responseHandler.propertiesCallback) {
  267. (*(data->handler->responseHandler.propertiesCallback))
  268. (responseProperties, data->userdata);
  269. }
  270. return S3StatusOK;
  271. }
  272. static void commitMultipartCompleteCallback
  273. (S3Status requestStatus, const S3ErrorDetails *s3ErrorDetails,
  274. void *callbackData)
  275. {
  276. CommitMultiPartData *data = (CommitMultiPartData*) callbackData;
  277. if (data->handler->responseHandler.completeCallback) {
  278. (*(data->handler->responseHandler.completeCallback))
  279. (requestStatus, s3ErrorDetails, data->userdata);
  280. }
  281. if (data->handler->responseXmlCallback) {
  282. (*data->handler->responseXmlCallback)(data->location, data->etag,
  283. data->userdata);
  284. }
  285. simplexml_deinitialize(&(data->simplexml));
  286. free(data);
  287. }
  288. static int commitMultipartPutObject(int bufferSize, char *buffer,
  289. void *callbackData)
  290. {
  291. CommitMultiPartData *data = (CommitMultiPartData*) callbackData;
  292. if (data->handler->putObjectDataCallback) {
  293. return data->handler->putObjectDataCallback(bufferSize, buffer,
  294. data->userdata);
  295. }
  296. else {
  297. return -1;
  298. }
  299. }
  300. void S3_complete_multipart_upload(S3BucketContext *bucketContext,
  301. const char *key,
  302. S3MultipartCommitHandler *handler,
  303. const char *upload_id, int contentLength,
  304. S3RequestContext *requestContext,
  305. int timeoutMs,
  306. void *callbackData)
  307. {
  308. char queryParams[512];
  309. snprintf(queryParams, 512, "uploadId=%s", upload_id);
  310. CommitMultiPartData *data =
  311. (CommitMultiPartData *) malloc(sizeof(CommitMultiPartData));
  312. data->userdata = callbackData;
  313. data->handler = handler;
  314. string_buffer_initialize(data->location);
  315. string_buffer_initialize(data->etag);
  316. simplexml_initialize(&(data->simplexml),
  317. commitMultipartResponseXMLcallback, data);
  318. RequestParams params =
  319. {
  320. HttpRequestTypePOST, // httpRequestType
  321. { bucketContext->hostName, // hostName
  322. bucketContext->bucketName, // bucketName
  323. bucketContext->protocol, // protocol
  324. bucketContext->uriStyle, // uriStyle
  325. bucketContext->accessKeyId, // accessKeyId
  326. bucketContext->secretAccessKey, // secretAccessKey
  327. bucketContext->securityToken, // securityToken
  328. bucketContext->authRegion }, // authRegion
  329. key, // key
  330. queryParams, // queryParams
  331. 0, // subResource
  332. 0, // copySourceBucketName
  333. 0, // copySourceKey
  334. 0, // getConditions
  335. 0, // startByte
  336. 0, // byteCount
  337. 0, // putProperties
  338. commitMultipartPropertiesCallback, // propertiesCallback
  339. commitMultipartPutObject, // toS3Callback
  340. contentLength, // toS3CallbackTotalSize
  341. commitMultipartCallback, // fromS3Callback
  342. commitMultipartCompleteCallback, // completeCallback
  343. data, // callbackData
  344. timeoutMs // timeoutMs
  345. };
  346. request_perform(&params, requestContext);
  347. }
  348. // We read up to 32 Uploads at a time
  349. #define MAX_UPLOADS 32
  350. // We read up to 8 CommonPrefixes at a time
  351. #define MAX_COMMON_PREFIXES 8
  352. #define MAX_PARTS 32
  353. typedef struct ListMultipartUpload
  354. {
  355. string_buffer(key, 1024);
  356. string_buffer(uploadId, 256);
  357. string_buffer(initiatorId, 256);
  358. string_buffer(initiatorDisplayName, 256);
  359. string_buffer(ownerId, 256);
  360. string_buffer(ownerDisplayName, 256);
  361. string_buffer(storageClass, 256);
  362. string_buffer(initiated, 256);
  363. } ListMultipartUpload;
  364. typedef struct ListPart
  365. {
  366. string_buffer(eTag, 1024);
  367. string_buffer(partNumber, 24);
  368. string_buffer(size, 256);
  369. string_buffer(lastModified, 256);
  370. } ListPart;
  371. typedef struct ListMultipartData
  372. {
  373. SimpleXml simpleXml;
  374. S3ResponsePropertiesCallback *responsePropertiesCallback;
  375. S3ListMultipartUploadsResponseCallback *listMultipartCallback;
  376. S3ResponseCompleteCallback *responseCompleteCallback;
  377. void *callbackData;
  378. string_buffer(isTruncated, 64);
  379. string_buffer(nextKeyMarker, 1024);
  380. string_buffer(nextUploadIdMarker, 1024);
  381. int uploadsCount;
  382. ListMultipartUpload uploads[MAX_UPLOADS];
  383. int commonPrefixesCount;
  384. char commonPrefixes[MAX_COMMON_PREFIXES][1024];
  385. int commonPrefixLens[MAX_COMMON_PREFIXES];
  386. } ListMultipartData;
  387. typedef struct ListPartsData
  388. {
  389. SimpleXml simpleXml;
  390. S3ResponsePropertiesCallback *responsePropertiesCallback;
  391. S3ListPartsResponseCallback *listPartsCallback;
  392. S3ResponseCompleteCallback *responseCompleteCallback;
  393. void *callbackData;
  394. string_buffer(isTruncated, 64);
  395. string_buffer(nextPartNumberMarker, 1024);
  396. string_buffer(initiatorId, 256);
  397. string_buffer(initiatorDisplayName, 256);
  398. string_buffer(ownerId, 256);
  399. string_buffer(ownerDisplayName, 256);
  400. string_buffer(storageClass, 256);
  401. int handlePartsStart;
  402. int partsCount;
  403. ListPart parts[MAX_PARTS];
  404. } ListPartsData;
  405. static void initialize_list_multipart_upload(ListMultipartUpload *upload)
  406. {
  407. string_buffer_initialize(upload->key);
  408. string_buffer_initialize(upload->uploadId);
  409. string_buffer_initialize(upload->initiatorId);
  410. string_buffer_initialize(upload->initiatorDisplayName);
  411. string_buffer_initialize(upload->ownerId);
  412. string_buffer_initialize(upload->ownerDisplayName);
  413. string_buffer_initialize(upload->storageClass);
  414. string_buffer_initialize(upload->initiated);
  415. }
  416. static void initialize_list_part(ListPart *part)
  417. {
  418. string_buffer_initialize(part->eTag);
  419. string_buffer_initialize(part->partNumber);
  420. string_buffer_initialize(part->size);
  421. string_buffer_initialize(part->lastModified);
  422. }
  423. static void initialize_list_multipart_data(ListMultipartData *lmData)
  424. {
  425. lmData->uploadsCount = 0;
  426. initialize_list_multipart_upload(lmData->uploads);
  427. lmData->commonPrefixesCount = 0;
  428. lmData->commonPrefixes[0][0] = 0;
  429. lmData->commonPrefixLens[0] = 0;
  430. }
  431. static void initialize_list_parts_data(ListPartsData *lpData)
  432. {
  433. lpData->partsCount = 0;
  434. initialize_list_part(lpData->parts);
  435. }
  436. static S3Status listMultipartPropertiesCallback
  437. (const S3ResponseProperties *responseProperties, void *callbackData)
  438. {
  439. ListMultipartData *lmData = (ListMultipartData *) callbackData;
  440. return (*(lmData->responsePropertiesCallback))
  441. (responseProperties, lmData->callbackData);
  442. }
  443. static S3Status listPartsPropertiesCallback
  444. (const S3ResponseProperties *responseProperties, void *callbackData)
  445. {
  446. ListPartsData *lpData = (ListPartsData *) callbackData;
  447. return (*(lpData->responsePropertiesCallback))
  448. (responseProperties, lpData->callbackData);
  449. }
  450. static S3Status listMultipartDataCallback(int bufferSize, const char *buffer,
  451. void *callbackData)
  452. {
  453. ListMultipartData *lmData = (ListMultipartData *) callbackData;
  454. return simplexml_add(&(lmData->simpleXml), buffer, bufferSize);
  455. }
  456. static S3Status listPartsDataCallback(int bufferSize, const char *buffer,
  457. void *callbackData)
  458. {
  459. ListPartsData *lpData = (ListPartsData *) callbackData;
  460. return simplexml_add(&(lpData->simpleXml), buffer, bufferSize);
  461. }
  462. static S3Status make_list_multipart_callback(ListMultipartData *lmData)
  463. {
  464. int i;
  465. // Convert IsTruncated
  466. int isTruncated = (!strcmp(lmData->isTruncated, "true") ||
  467. !strcmp(lmData->isTruncated, "1")) ? 1 : 0;
  468. // Convert the contents
  469. S3ListMultipartUpload * uploads = new S3ListMultipartUpload[lmData->uploadsCount]; // WINSCP (heap allocation)
  470. int uploadsCount = lmData->uploadsCount;
  471. for (i = 0; i < uploadsCount; i++) {
  472. S3ListMultipartUpload *uploadDest = &(uploads[i]);
  473. ListMultipartUpload *uploadSrc = &(lmData->uploads[i]);
  474. uploadDest->key = uploadSrc->key;
  475. uploadDest->uploadId = uploadSrc->uploadId;
  476. uploadDest->initiatorId = uploadSrc->initiatorId;
  477. uploadDest->initiatorDisplayName = uploadSrc->initiatorDisplayName;
  478. uploadDest->ownerId =
  479. uploadSrc->ownerId[0] ?uploadSrc->ownerId : 0;
  480. uploadDest->ownerDisplayName = (uploadSrc->ownerDisplayName[0] ?
  481. uploadSrc->ownerDisplayName : 0);
  482. uploadDest->storageClass = uploadSrc->storageClass;
  483. uploadDest->initiated = parseIso8601Time(uploadSrc->initiated);
  484. }
  485. // Make the common prefixes array
  486. int commonPrefixesCount = lmData->commonPrefixesCount;
  487. char **commonPrefixes = new char*[commonPrefixesCount]; // WINSCP (heap allocation)
  488. for (i = 0; i < commonPrefixesCount; i++) {
  489. commonPrefixes[i] = lmData->commonPrefixes[i];
  490. }
  491. S3Status status = (*(lmData->listMultipartCallback))
  492. (isTruncated, lmData->nextKeyMarker, lmData->nextUploadIdMarker,
  493. uploadsCount, uploads, commonPrefixesCount,
  494. (const char **) commonPrefixes, lmData->callbackData);
  495. delete[] uploads; // WINSCP (heap allocation)
  496. delete[] commonPrefixes;
  497. return status;
  498. }
  499. static S3Status make_list_parts_callback(ListPartsData *lpData)
  500. {
  501. int i;
  502. // Convert IsTruncated
  503. int isTruncated = (!strcmp(lpData->isTruncated, "true") ||
  504. !strcmp(lpData->isTruncated, "1")) ? 1 : 0;
  505. // Convert the contents
  506. S3ListPart * Parts = new S3ListPart[lpData->partsCount]; // WINSCP (heap allocation)
  507. int partsCount = lpData->partsCount;
  508. for (i = 0; i < partsCount; i++) {
  509. S3ListPart *partDest = &(Parts[i]);
  510. ListPart *partSrc = &(lpData->parts[i]);
  511. partDest->eTag = partSrc->eTag;
  512. partDest->partNumber = parseUnsignedInt(partSrc->partNumber);
  513. partDest->size = parseUnsignedInt(partSrc->size);
  514. partDest->lastModified = parseIso8601Time(partSrc->lastModified);
  515. }
  516. S3Status status =
  517. (*(lpData->listPartsCallback))
  518. (isTruncated, lpData->nextPartNumberMarker, lpData->initiatorId,
  519. lpData->initiatorDisplayName, lpData->ownerId,
  520. lpData->ownerDisplayName, lpData->storageClass, partsCount,
  521. lpData->handlePartsStart, Parts, lpData->callbackData);
  522. delete[] Parts; // WINSCP (heap allocation)
  523. return status;
  524. }
  525. static void listMultipartCompleteCallback(S3Status requestStatus,
  526. const S3ErrorDetails *s3ErrorDetails,
  527. void *callbackData)
  528. {
  529. ListMultipartData *lmData = (ListMultipartData *) callbackData;
  530. // Make the callback if there is anything
  531. if (lmData->uploadsCount || lmData->commonPrefixesCount) {
  532. make_list_multipart_callback(lmData);
  533. }
  534. (*(lmData->responseCompleteCallback))
  535. (requestStatus, s3ErrorDetails, lmData->callbackData);
  536. simplexml_deinitialize(&(lmData->simpleXml));
  537. free(lmData);
  538. }
  539. static void listPartsCompleteCallback(S3Status requestStatus,
  540. const S3ErrorDetails *s3ErrorDetails,
  541. void *callbackData)
  542. {
  543. ListPartsData *lpData = (ListPartsData *) callbackData;
  544. // Make the callback if there is anything
  545. if (lpData->partsCount) {
  546. make_list_parts_callback(lpData);
  547. }
  548. (*(lpData->responseCompleteCallback))
  549. (requestStatus, s3ErrorDetails, lpData->callbackData);
  550. simplexml_deinitialize(&(lpData->simpleXml));
  551. free(lpData);
  552. }
  553. static S3Status listMultipartXmlCallback(const char *elementPath,
  554. const char *data, int dataLen,
  555. void *callbackData)
  556. {
  557. ListMultipartData *lmData = (ListMultipartData *) callbackData;
  558. int fit;
  559. if (data) {
  560. if (!strcmp(elementPath, "ListMultipartUploadsResult/IsTruncated")) {
  561. string_buffer_append(lmData->isTruncated, data, dataLen, fit);
  562. }
  563. else if (!strcmp(elementPath,
  564. "ListMultipartUploadsResult/NextKeyMarker")) {
  565. string_buffer_append(lmData->nextKeyMarker, data, dataLen, fit);
  566. }
  567. else if (!strcmp(elementPath,
  568. "ListMultipartUploadsResult/NextUploadIdMarker")) {
  569. string_buffer_append(lmData->nextUploadIdMarker, data, dataLen,
  570. fit);
  571. }
  572. else if (!strcmp(elementPath,
  573. "ListMultipartUploadsResult/Upload/Key")) {
  574. ListMultipartUpload *uploads =
  575. &(lmData->uploads[lmData->uploadsCount]);
  576. string_buffer_append(uploads->key, data, dataLen, fit);
  577. }
  578. else if (!strcmp(elementPath,
  579. "ListMultipartUploadsResult/Upload/Initiated")) {
  580. ListMultipartUpload *uploads =
  581. &(lmData->uploads[lmData->uploadsCount]);
  582. string_buffer_append(uploads->initiated, data, dataLen, fit);
  583. }
  584. else if (!strcmp(elementPath,
  585. "ListMultipartUploadsResult/Upload/UploadId")) {
  586. ListMultipartUpload *uploads =
  587. &(lmData->uploads[lmData->uploadsCount]);
  588. string_buffer_append(uploads->uploadId, data, dataLen, fit);
  589. }
  590. else if (!strcmp(elementPath,
  591. "ListMultipartUploadsResult/Upload/Initiator/ID")) {
  592. ListMultipartUpload *uploads =
  593. &(lmData->uploads[lmData->uploadsCount]);
  594. string_buffer_append(uploads->initiatorId, data, dataLen, fit);
  595. }
  596. else if (!strcmp
  597. (elementPath,
  598. "ListMultipartUploadsResult/Upload/Initiator/DisplayName")) {
  599. ListMultipartUpload *uploads =
  600. &(lmData->uploads[lmData->uploadsCount]);
  601. string_buffer_append(uploads->initiatorDisplayName, data, dataLen,
  602. fit);
  603. }
  604. else if (!strcmp(elementPath,
  605. "ListMultipartUploadsResult/Upload/Owner/ID")) {
  606. ListMultipartUpload *uploads =
  607. &(lmData->uploads[lmData->uploadsCount]);
  608. string_buffer_append(uploads->ownerId, data, dataLen, fit);
  609. }
  610. else if (!strcmp
  611. (elementPath,
  612. "ListMultipartUploadsResult/Upload/Owner/DisplayName")) {
  613. ListMultipartUpload *uploads =
  614. &(lmData->uploads[lmData->uploadsCount]);
  615. string_buffer_append
  616. (uploads->ownerDisplayName, data, dataLen, fit);
  617. }
  618. else if (!strcmp(elementPath,
  619. "ListMultipartUploadsResult/Upload/StorageClass")) {
  620. ListMultipartUpload *uploads =
  621. &(lmData->uploads[lmData->uploadsCount]);
  622. string_buffer_append(uploads->storageClass, data, dataLen, fit);
  623. }
  624. else if (!strcmp(elementPath,
  625. "ListMultipartUploadsResult/CommonPrefixes/Prefix")) {
  626. int which = lmData->commonPrefixesCount;
  627. lmData->commonPrefixLens[which] +=
  628. snprintf(lmData->commonPrefixes[which],
  629. sizeof(lmData->commonPrefixes[which]) -
  630. lmData->commonPrefixLens[which] - 1,
  631. "%.*s", dataLen, data);
  632. if (lmData->commonPrefixLens[which] >=
  633. (int) sizeof(lmData->commonPrefixes[which])) {
  634. return S3StatusXmlParseFailure;
  635. }
  636. }
  637. }
  638. else {
  639. if (!strcmp(elementPath, "ListMultipartUploadsResult/Upload")) {
  640. // Finished a Contents
  641. lmData->uploadsCount++;
  642. if (lmData->uploadsCount == MAX_UPLOADS) {
  643. // Make the callback
  644. S3Status status = make_list_multipart_callback(lmData);
  645. if (status != S3StatusOK) {
  646. return status;
  647. }
  648. initialize_list_multipart_data(lmData);
  649. }
  650. else {
  651. // Initialize the next one
  652. initialize_list_multipart_upload
  653. (&(lmData->uploads[lmData->uploadsCount]));
  654. }
  655. }
  656. else if (!strcmp(elementPath,
  657. "ListMultipartUploadsResult/CommonPrefixes/Prefix")) {
  658. // Finished a Prefix
  659. lmData->commonPrefixesCount++;
  660. if (lmData->commonPrefixesCount == MAX_COMMON_PREFIXES) {
  661. // Make the callback
  662. S3Status status = make_list_multipart_callback(lmData);
  663. if (status != S3StatusOK) {
  664. return status;
  665. }
  666. initialize_list_multipart_data(lmData);
  667. }
  668. else {
  669. // Initialize the next one
  670. lmData->commonPrefixes[lmData->commonPrefixesCount][0] = 0;
  671. lmData->commonPrefixLens[lmData->commonPrefixesCount] = 0;
  672. }
  673. }
  674. }
  675. /* Avoid compiler error about variable set but not used */
  676. (void) fit;
  677. return S3StatusOK;
  678. }
  679. static S3Status listPartsXmlCallback(const char *elementPath,
  680. const char *data, int dataLen,
  681. void *callbackData)
  682. {
  683. ListPartsData *lpData = (ListPartsData *) callbackData;
  684. int fit;
  685. if (data) {
  686. if (!strcmp(elementPath, "ListPartsResult/IsTruncated")) {
  687. string_buffer_append(lpData->isTruncated, data, dataLen, fit);
  688. }
  689. else if (!strcmp(elementPath,
  690. "ListPartsResult/NextPartNumberMarker")) {
  691. string_buffer_append(lpData->nextPartNumberMarker, data, dataLen,
  692. fit);
  693. }
  694. else if (!strcmp(elementPath, "ListPartsResult/StorageClass")) {
  695. string_buffer_append(lpData->storageClass, data, dataLen, fit);
  696. }
  697. else if (!strcmp(elementPath, "ListPartsResult/Initiator/ID")) {
  698. string_buffer_append(lpData->initiatorId, data, dataLen, fit);
  699. }
  700. else if (!strcmp(elementPath,
  701. "ListPartsResult/Initiator/DisplayName")) {
  702. string_buffer_append(lpData->initiatorDisplayName, data, dataLen,
  703. fit);
  704. }
  705. else if (!strcmp(elementPath, "ListPartsResult/Owner/ID")) {
  706. string_buffer_append(lpData->ownerId, data, dataLen, fit);
  707. }
  708. else if (!strcmp(elementPath, "ListPartsResult/Owner/DisplayName")) {
  709. string_buffer_append(lpData->ownerDisplayName, data, dataLen, fit);
  710. }
  711. else if (!strcmp(elementPath, "ListPartsResult/Part/PartNumber")) {
  712. ListPart *parts = &(lpData->parts[lpData->partsCount]);
  713. string_buffer_append(parts->partNumber, data, dataLen, fit);
  714. }
  715. else if (!strcmp(elementPath, "ListPartsResult/Part/LastModified")) {
  716. ListPart *parts = &(lpData->parts[lpData->partsCount]);
  717. string_buffer_append(parts->lastModified, data, dataLen, fit);
  718. }
  719. else if (!strcmp(elementPath, "ListPartsResult/Part/ETag")) {
  720. ListPart *parts = &(lpData->parts[lpData->partsCount]);
  721. string_buffer_append(parts->eTag, data, dataLen, fit);
  722. }
  723. else if (!strcmp(elementPath, "ListPartsResult/Part/Size")) {
  724. ListPart *parts = &(lpData->parts[lpData->partsCount]);
  725. string_buffer_append(parts->size, data, dataLen, fit);
  726. }
  727. }
  728. else {
  729. if (!strcmp(elementPath, "ListPartsResult/Part")) {
  730. // Finished a Contents
  731. lpData->partsCount++;
  732. if (lpData->partsCount == MAX_PARTS) {
  733. // Make the callback
  734. S3Status status = make_list_parts_callback(lpData);
  735. if (status != S3StatusOK) {
  736. return status;
  737. }
  738. lpData->handlePartsStart += lpData->partsCount;
  739. initialize_list_parts_data(lpData);
  740. }
  741. else {
  742. // Initialize the next one
  743. initialize_list_part(&(lpData->parts[lpData->partsCount]));
  744. }
  745. }
  746. }
  747. /* Avoid compiler error about variable set but not used */
  748. (void) fit;
  749. return S3StatusOK;
  750. }
  751. void S3_list_multipart_uploads(S3BucketContext *bucketContext,
  752. const char *prefix, const char *keymarker,
  753. const char *uploadidmarker,
  754. const char *encodingtype, const char *delimiter,
  755. int maxuploads, S3RequestContext *requestContext,
  756. int timeoutMs,
  757. const S3ListMultipartUploadsHandler *handler,
  758. void *callbackData)
  759. {
  760. // Compose the query params
  761. string_buffer(queryParams, 4096);
  762. string_buffer_initialize(queryParams);
  763. #define safe_append(name, value) \
  764. do { \
  765. int fit; \
  766. if (amp) { \
  767. string_buffer_append(queryParams, "&", 1, fit); \
  768. if (!fit) { \
  769. (*(handler->responseHandler.completeCallback)) \
  770. (S3StatusQueryParamsTooLong, 0, callbackData); \
  771. return; \
  772. } \
  773. } \
  774. string_buffer_append(queryParams, name "=", \
  775. sizeof(name "=") - 1, fit); \
  776. if (!fit) { \
  777. (*(handler->responseHandler.completeCallback)) \
  778. (S3StatusQueryParamsTooLong, 0, callbackData); \
  779. return; \
  780. } \
  781. amp = 1; \
  782. char encoded[3 * 1024]; \
  783. if (!urlEncode(encoded, value, 1024, 1)) { \
  784. (*(handler->responseHandler.completeCallback)) \
  785. (S3StatusQueryParamsTooLong, 0, callbackData); \
  786. return; \
  787. } \
  788. string_buffer_append(queryParams, encoded, strlen(encoded), \
  789. fit); \
  790. if (!fit) { \
  791. (*(handler->responseHandler.completeCallback)) \
  792. (S3StatusQueryParamsTooLong, 0, callbackData); \
  793. return; \
  794. } \
  795. } while (0)
  796. int amp = 0;
  797. if (prefix && *prefix) {
  798. safe_append("prefix", prefix);
  799. }
  800. if (keymarker && *keymarker) {
  801. safe_append("key-marker", keymarker);
  802. }
  803. if (delimiter && *delimiter) {
  804. safe_append("delimiter", delimiter);
  805. }
  806. if (uploadidmarker && *uploadidmarker) {
  807. safe_append("upload-id-marker", uploadidmarker);
  808. }
  809. if (encodingtype && *encodingtype) {
  810. safe_append("encoding-type", encodingtype);
  811. }
  812. if (maxuploads) {
  813. char maxUploadsString[64];
  814. snprintf(maxUploadsString, sizeof(maxUploadsString), "%d",
  815. maxuploads);
  816. safe_append("max-uploads", maxUploadsString);
  817. }
  818. ListMultipartData *lmData =
  819. (ListMultipartData *) malloc(sizeof(ListMultipartData));
  820. if (!lmData) {
  821. (*(handler->responseHandler.completeCallback))
  822. (S3StatusOutOfMemory, 0, callbackData);
  823. return;
  824. }
  825. simplexml_initialize(&(lmData->simpleXml), &listMultipartXmlCallback,
  826. lmData);
  827. lmData->responsePropertiesCallback =
  828. handler->responseHandler.propertiesCallback;
  829. lmData->listMultipartCallback = handler->responseXmlCallback;
  830. lmData->responseCompleteCallback =
  831. handler->responseHandler.completeCallback;
  832. lmData->callbackData = callbackData;
  833. string_buffer_initialize(lmData->isTruncated);
  834. string_buffer_initialize(lmData->nextKeyMarker);
  835. string_buffer_initialize(lmData->nextUploadIdMarker);
  836. initialize_list_multipart_data(lmData);
  837. // Set up the RequestParams
  838. RequestParams params =
  839. {
  840. HttpRequestTypeGET, // httpRequestType
  841. { bucketContext->hostName, // hostName
  842. bucketContext->bucketName, // bucketName
  843. bucketContext->protocol, // protocol
  844. bucketContext->uriStyle, // uriStyle
  845. bucketContext->accessKeyId, // accessKeyId
  846. bucketContext->secretAccessKey, // secretAccessKey
  847. bucketContext->securityToken, // securityToken
  848. bucketContext->authRegion }, // authRegion
  849. 0, // key
  850. queryParams[0] ? queryParams : 0, // queryParams
  851. "uploads", // subResource
  852. 0, // copySourceBucketName
  853. 0, // copySourceKey
  854. 0, // getConditions
  855. 0, // startByte
  856. 0, // byteCount
  857. 0, // putProperties
  858. &listMultipartPropertiesCallback, // propertiesCallback
  859. 0, // toS3Callback
  860. 0, // toS3CallbackTotalSize
  861. &listMultipartDataCallback, // fromS3Callback
  862. &listMultipartCompleteCallback, // completeCallback
  863. lmData, // callbackData
  864. timeoutMs // timeoutMs
  865. };
  866. // Perform the request
  867. request_perform(&params, requestContext);
  868. }
  869. void S3_list_parts(S3BucketContext *bucketContext, const char *key,
  870. const char *partnumbermarker, const char *uploadid,
  871. const char *encodingtype, int maxparts,
  872. S3RequestContext *requestContext,
  873. int timeoutMs,
  874. const S3ListPartsHandler *handler, void *callbackData)
  875. {
  876. // Compose the query params
  877. string_buffer(queryParams, 4096);
  878. string_buffer_initialize(queryParams);
  879. #define safe_append(name, value) \
  880. do { \
  881. int fit; \
  882. if (amp) { \
  883. string_buffer_append(queryParams, "&", 1, fit); \
  884. if (!fit) { \
  885. (*(handler->responseHandler.completeCallback)) \
  886. (S3StatusQueryParamsTooLong, 0, callbackData); \
  887. return; \
  888. } \
  889. } \
  890. string_buffer_append(queryParams, name "=", \
  891. sizeof(name "=") - 1, fit); \
  892. if (!fit) { \
  893. (*(handler->responseHandler.completeCallback)) \
  894. (S3StatusQueryParamsTooLong, 0, callbackData); \
  895. return; \
  896. } \
  897. amp = 1; \
  898. char encoded[3 * 1024]; \
  899. if (!urlEncode(encoded, value, 1024, 1)) { \
  900. (*(handler->responseHandler.completeCallback)) \
  901. (S3StatusQueryParamsTooLong, 0, callbackData); \
  902. return; \
  903. } \
  904. string_buffer_append(queryParams, encoded, strlen(encoded), \
  905. fit); \
  906. if (!fit) { \
  907. (*(handler->responseHandler.completeCallback)) \
  908. (S3StatusQueryParamsTooLong, 0, callbackData); \
  909. return; \
  910. } \
  911. } while (0)
  912. char subResource[512];
  913. snprintf(subResource, 512, "uploadId=%s", uploadid);
  914. int amp = 0;
  915. if (partnumbermarker && *partnumbermarker) {
  916. safe_append("part-number-marker", partnumbermarker);
  917. }
  918. if (encodingtype && *encodingtype) {
  919. safe_append("encoding-type", encodingtype);
  920. }
  921. if (maxparts) {
  922. char maxPartsString[64];
  923. snprintf(maxPartsString, sizeof(maxPartsString), "%d", maxparts);
  924. safe_append("max-parts", maxPartsString);
  925. }
  926. ListPartsData *lpData =
  927. (ListPartsData *) malloc(sizeof(ListPartsData));
  928. if (!lpData) {
  929. (*(handler->responseHandler.completeCallback))
  930. (S3StatusOutOfMemory, 0, callbackData);
  931. return;
  932. }
  933. simplexml_initialize(&(lpData->simpleXml), &listPartsXmlCallback,
  934. lpData);
  935. lpData->responsePropertiesCallback =
  936. handler->responseHandler.propertiesCallback;
  937. lpData->listPartsCallback = handler->responseXmlCallback;
  938. lpData->responseCompleteCallback =
  939. handler->responseHandler.completeCallback;
  940. lpData->callbackData = callbackData;
  941. string_buffer_initialize(lpData->isTruncated);
  942. string_buffer_initialize(lpData->nextPartNumberMarker);
  943. string_buffer_initialize(lpData->initiatorId);
  944. string_buffer_initialize(lpData->initiatorDisplayName);
  945. string_buffer_initialize(lpData->ownerId);
  946. string_buffer_initialize(lpData->ownerDisplayName);
  947. string_buffer_initialize(lpData->storageClass);
  948. initialize_list_parts_data(lpData);
  949. lpData->handlePartsStart = 0;
  950. // Set up the RequestParams
  951. RequestParams params =
  952. {
  953. HttpRequestTypeGET, // httpRequestType
  954. { bucketContext->hostName, // hostName
  955. bucketContext->bucketName, // bucketName
  956. bucketContext->protocol, // protocol
  957. bucketContext->uriStyle, // uriStyle
  958. bucketContext->accessKeyId, // accessKeyId
  959. bucketContext->secretAccessKey, // secretAccessKey
  960. bucketContext->securityToken, // securityToken
  961. bucketContext->authRegion }, // authRegion
  962. key, // key
  963. queryParams[0] ? queryParams : 0, // queryParams
  964. subResource, // subResource
  965. 0, // copySourceBucketName
  966. 0, // copySourceKey
  967. 0, // getConditions
  968. 0, // startByte
  969. 0, // byteCount
  970. 0, // putProperties
  971. &listPartsPropertiesCallback, // propertiesCallback
  972. 0, // toS3Callback
  973. 0, // toS3CallbackTotalSize
  974. &listPartsDataCallback, // fromS3Callback
  975. &listPartsCompleteCallback, // completeCallback
  976. lpData, // callbackData
  977. timeoutMs // timeoutMs
  978. };
  979. // Perform the request
  980. request_perform(&params, requestContext);
  981. }