Check in the synthetic write benchmark results
[bluesky.git] / libs3-1.4 / src / bucket.c
1 /** **************************************************************************
2  * bucket.c
3  * 
4  * Copyright 2008 Bryan Ischo <bryan@ischo.com>
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 General Public License as published by the Free Software
10  * Foundation, version 3 of the License.
11  *
12  * In addition, as a special exception, the copyright holders give
13  * permission to link the code of this library and its programs with the
14  * OpenSSL library, and distribute linked combinations including the two.
15  *
16  * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY
17  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
19  * details.
20  *
21  * You should have received a copy of the GNU General Public License version 3
22  * along with libs3, in a file named COPYING.  If not, see
23  * <http://www.gnu.org/licenses/>.
24  *
25  ************************************************************************** **/
26
27 #include <string.h>
28 #include <stdlib.h>
29 #include "libs3.h"
30 #include "request.h"
31 #include "simplexml.h"
32
33 // test bucket ---------------------------------------------------------------
34
35 typedef struct TestBucketData
36 {
37     SimpleXml simpleXml;
38
39     S3ResponsePropertiesCallback *responsePropertiesCallback;
40     S3ResponseCompleteCallback *responseCompleteCallback;
41     void *callbackData;
42
43     int locationConstraintReturnSize;
44     char *locationConstraintReturn;
45
46     string_buffer(locationConstraint, 256);
47 } TestBucketData;
48
49
50 static S3Status testBucketXmlCallback(const char *elementPath,
51                                       const char *data, int dataLen,
52                                       void *callbackData)
53 {
54     TestBucketData *tbData = (TestBucketData *) callbackData;
55
56     int fit;
57
58     if (data && !strcmp(elementPath, "LocationConstraint")) {
59         string_buffer_append(tbData->locationConstraint, data, dataLen, fit);
60     }
61
62     return S3StatusOK;
63 }
64
65
66 static S3Status testBucketPropertiesCallback
67     (const S3ResponseProperties *responseProperties, void *callbackData)
68 {
69     TestBucketData *tbData = (TestBucketData *) callbackData;
70     
71     return (*(tbData->responsePropertiesCallback))
72         (responseProperties, tbData->callbackData);
73 }
74
75
76 static S3Status testBucketDataCallback(int bufferSize, const char *buffer,
77                                        void *callbackData)
78 {
79     TestBucketData *tbData = (TestBucketData *) callbackData;
80
81     return simplexml_add(&(tbData->simpleXml), buffer, bufferSize);
82 }
83
84
85 static void testBucketCompleteCallback(S3Status requestStatus, 
86                                        const S3ErrorDetails *s3ErrorDetails,
87                                        void *callbackData)
88 {
89     TestBucketData *tbData = (TestBucketData *) callbackData;
90
91     // Copy the location constraint into the return buffer
92     snprintf(tbData->locationConstraintReturn, 
93              tbData->locationConstraintReturnSize, "%s", 
94              tbData->locationConstraint);
95
96     (*(tbData->responseCompleteCallback))
97         (requestStatus, s3ErrorDetails, tbData->callbackData);
98
99     simplexml_deinitialize(&(tbData->simpleXml));
100
101     free(tbData);
102 }
103
104
105 void S3_test_bucket(S3Protocol protocol, S3UriStyle uriStyle,
106                     const char *accessKeyId, const char *secretAccessKey,
107                     const char *bucketName, int locationConstraintReturnSize,
108                     char *locationConstraintReturn,
109                     S3RequestContext *requestContext,
110                     const S3ResponseHandler *handler, void *callbackData)
111 {
112     // Create the callback data
113     TestBucketData *tbData = 
114         (TestBucketData *) malloc(sizeof(TestBucketData));
115     if (!tbData) {
116         (*(handler->completeCallback))(S3StatusOutOfMemory, 0, callbackData);
117         return;
118     }
119
120     simplexml_initialize(&(tbData->simpleXml), &testBucketXmlCallback, tbData);
121
122     tbData->responsePropertiesCallback = handler->propertiesCallback;
123     tbData->responseCompleteCallback = handler->completeCallback;
124     tbData->callbackData = callbackData;
125
126     tbData->locationConstraintReturnSize = locationConstraintReturnSize;
127     tbData->locationConstraintReturn = locationConstraintReturn;
128     string_buffer_initialize(tbData->locationConstraint);
129
130     // Set up the RequestParams
131     RequestParams params =
132     {
133         HttpRequestTypeGET,                           // httpRequestType
134         { bucketName,                                 // bucketName
135           protocol,                                   // protocol
136           uriStyle,                                   // uriStyle
137           accessKeyId,                                // accessKeyId
138           secretAccessKey },                          // secretAccessKey
139         0,                                            // key
140         0,                                            // queryParams
141         "location",                                   // subResource
142         0,                                            // copySourceBucketName
143         0,                                            // copySourceKey
144         0,                                            // getConditions
145         0,                                            // startByte
146         0,                                            // byteCount
147         0,                                            // putProperties
148         &testBucketPropertiesCallback,                // propertiesCallback
149         0,                                            // toS3Callback
150         0,                                            // toS3CallbackTotalSize
151         &testBucketDataCallback,                      // fromS3Callback
152         &testBucketCompleteCallback,                  // completeCallback
153         tbData                                        // callbackData
154     };
155
156     // Perform the request
157     request_perform(&params, requestContext);
158 }
159
160
161 // create bucket -------------------------------------------------------------
162
163 typedef struct CreateBucketData
164 {
165     S3ResponsePropertiesCallback *responsePropertiesCallback;
166     S3ResponseCompleteCallback *responseCompleteCallback;
167     void *callbackData;
168
169     char doc[1024];
170     int docLen, docBytesWritten;
171 } CreateBucketData;                         
172                             
173
174 static S3Status createBucketPropertiesCallback
175     (const S3ResponseProperties *responseProperties, void *callbackData)
176 {
177     CreateBucketData *cbData = (CreateBucketData *) callbackData;
178     
179     return (*(cbData->responsePropertiesCallback))
180         (responseProperties, cbData->callbackData);
181 }
182
183
184 static int createBucketDataCallback(int bufferSize, char *buffer, 
185                                     void *callbackData)
186 {
187     CreateBucketData *cbData = (CreateBucketData *) callbackData;
188
189     if (!cbData->docLen) {
190         return 0;
191     }
192
193     int remaining = (cbData->docLen - cbData->docBytesWritten);
194
195     int toCopy = bufferSize > remaining ? remaining : bufferSize;
196     
197     if (!toCopy) {
198         return 0;
199     }
200
201     memcpy(buffer, &(cbData->doc[cbData->docBytesWritten]), toCopy);
202
203     cbData->docBytesWritten += toCopy;
204
205     return toCopy;
206 }
207
208
209 static void createBucketCompleteCallback(S3Status requestStatus, 
210                                          const S3ErrorDetails *s3ErrorDetails,
211                                          void *callbackData)
212 {
213     CreateBucketData *cbData = (CreateBucketData *) callbackData;
214
215     (*(cbData->responseCompleteCallback))
216         (requestStatus, s3ErrorDetails, cbData->callbackData);
217
218     free(cbData);
219 }
220
221
222 void S3_create_bucket(S3Protocol protocol, const char *accessKeyId,
223                       const char *secretAccessKey, const char *bucketName,
224                       S3CannedAcl cannedAcl, const char *locationConstraint,
225                       S3RequestContext *requestContext,
226                       const S3ResponseHandler *handler, void *callbackData)
227 {
228     // Create the callback data
229     CreateBucketData *cbData = 
230         (CreateBucketData *) malloc(sizeof(CreateBucketData));
231     if (!cbData) {
232         (*(handler->completeCallback))(S3StatusOutOfMemory, 0, callbackData);
233         return;
234     }
235
236     cbData->responsePropertiesCallback = handler->propertiesCallback;
237     cbData->responseCompleteCallback = handler->completeCallback;
238     cbData->callbackData = callbackData;
239
240     if (locationConstraint) {
241         cbData->docLen =
242             snprintf(cbData->doc, sizeof(cbData->doc),
243                      "<CreateBucketConfiguration><LocationConstraint>"
244                      "%s</LocationConstraint></CreateBucketConfiguration>",
245                      locationConstraint);
246         cbData->docBytesWritten = 0;
247     }
248     else {
249         cbData->docLen = 0;
250     }
251     
252     // Set up S3PutProperties
253     S3PutProperties properties =
254     {
255         0,                                       // contentType
256         0,                                       // md5
257         0,                                       // cacheControl
258         0,                                       // contentDispositionFilename
259         0,                                       // contentEncoding
260         0,                                       // expires
261         cannedAcl,                               // cannedAcl
262         0,                                       // metaDataCount
263         0                                        // metaData
264     };
265     
266     // Set up the RequestParams
267     RequestParams params =
268     {
269         HttpRequestTypePUT,                           // httpRequestType
270         { bucketName,                                 // bucketName
271           protocol,                                   // protocol
272           S3UriStylePath,                             // uriStyle
273           accessKeyId,                                // accessKeyId
274           secretAccessKey },                          // secretAccessKey
275         0,                                            // key
276         0,                                            // queryParams
277         0,                                            // subResource
278         0,                                            // copySourceBucketName
279         0,                                            // copySourceKey
280         0,                                            // getConditions
281         0,                                            // startByte
282         0,                                            // byteCount
283         &properties,                                  // putProperties
284         &createBucketPropertiesCallback,              // propertiesCallback
285         &createBucketDataCallback,                    // toS3Callback
286         cbData->docLen,                               // toS3CallbackTotalSize
287         0,                                            // fromS3Callback
288         &createBucketCompleteCallback,                // completeCallback
289         cbData                                        // callbackData
290     };
291
292     // Perform the request
293     request_perform(&params, requestContext);
294 }
295
296                            
297 // delete bucket -------------------------------------------------------------
298
299 typedef struct DeleteBucketData
300 {
301     S3ResponsePropertiesCallback *responsePropertiesCallback;
302     S3ResponseCompleteCallback *responseCompleteCallback;
303     void *callbackData;
304 } DeleteBucketData;
305
306
307 static S3Status deleteBucketPropertiesCallback
308     (const S3ResponseProperties *responseProperties, void *callbackData)
309 {
310     DeleteBucketData *dbData = (DeleteBucketData *) callbackData;
311     
312     return (*(dbData->responsePropertiesCallback))
313         (responseProperties, dbData->callbackData);
314 }
315
316
317 static void deleteBucketCompleteCallback(S3Status requestStatus, 
318                                          const S3ErrorDetails *s3ErrorDetails,
319                                          void *callbackData)
320 {
321     DeleteBucketData *dbData = (DeleteBucketData *) callbackData;
322
323     (*(dbData->responseCompleteCallback))
324         (requestStatus, s3ErrorDetails, dbData->callbackData);
325
326     free(dbData);
327 }
328
329
330 void S3_delete_bucket(S3Protocol protocol, S3UriStyle uriStyle,
331                       const char *accessKeyId, const char *secretAccessKey,
332                       const char *bucketName,
333                       S3RequestContext *requestContext,
334                       const S3ResponseHandler *handler, void *callbackData)
335 {
336     // Create the callback data
337     DeleteBucketData *dbData = 
338         (DeleteBucketData *) malloc(sizeof(DeleteBucketData));
339     if (!dbData) {
340         (*(handler->completeCallback))(S3StatusOutOfMemory, 0, callbackData);
341         return;
342     }
343
344     dbData->responsePropertiesCallback = handler->propertiesCallback;
345     dbData->responseCompleteCallback = handler->completeCallback;
346     dbData->callbackData = callbackData;
347
348     // Set up the RequestParams
349     RequestParams params =
350     {
351         HttpRequestTypeDELETE,                        // httpRequestType
352         { bucketName,                                 // bucketName
353           protocol,                                   // protocol
354           uriStyle,                                   // uriStyle
355           accessKeyId,                                // accessKeyId
356           secretAccessKey },                          // secretAccessKey
357         0,                                            // key
358         0,                                            // queryParams
359         0,                                            // subResource
360         0,                                            // copySourceBucketName
361         0,                                            // copySourceKey
362         0,                                            // getConditions
363         0,                                            // startByte
364         0,                                            // byteCount
365         0,                                            // putProperties
366         &deleteBucketPropertiesCallback,              // propertiesCallback
367         0,                                            // toS3Callback
368         0,                                            // toS3CallbackTotalSize
369         0,                                            // fromS3Callback
370         &deleteBucketCompleteCallback,                // completeCallback
371         dbData                                        // callbackData
372     };
373
374     // Perform the request
375     request_perform(&params, requestContext);
376 }
377
378
379 // list bucket ----------------------------------------------------------------
380
381 typedef struct ListBucketContents
382 {
383     string_buffer(key, 1024);
384     string_buffer(lastModified, 256);
385     string_buffer(eTag, 256);
386     string_buffer(size, 24);
387     string_buffer(ownerId, 256);
388     string_buffer(ownerDisplayName, 256);
389 } ListBucketContents;
390
391
392 static void initialize_list_bucket_contents(ListBucketContents *contents)
393 {
394     string_buffer_initialize(contents->key);
395     string_buffer_initialize(contents->lastModified);
396     string_buffer_initialize(contents->eTag);
397     string_buffer_initialize(contents->size);
398     string_buffer_initialize(contents->ownerId);
399     string_buffer_initialize(contents->ownerDisplayName);
400 }
401
402 // We read up to 32 Contents at a time
403 #define MAX_CONTENTS 32
404 // We read up to 8 CommonPrefixes at a time
405 #define MAX_COMMON_PREFIXES 8
406
407 typedef struct ListBucketData
408 {
409     SimpleXml simpleXml;
410
411     S3ResponsePropertiesCallback *responsePropertiesCallback;
412     S3ListBucketCallback *listBucketCallback;
413     S3ResponseCompleteCallback *responseCompleteCallback;
414     void *callbackData;
415
416     string_buffer(isTruncated, 64);
417     string_buffer(nextMarker, 1024);
418
419     int contentsCount;
420     ListBucketContents contents[MAX_CONTENTS];
421
422     int commonPrefixesCount;
423     char commonPrefixes[MAX_COMMON_PREFIXES][1024];
424     int commonPrefixLens[MAX_COMMON_PREFIXES];
425 } ListBucketData;
426
427
428 static void initialize_list_bucket_data(ListBucketData *lbData)
429 {
430     lbData->contentsCount = 0;
431     initialize_list_bucket_contents(lbData->contents);
432     lbData->commonPrefixesCount = 0;
433     lbData->commonPrefixes[0][0] = 0;
434     lbData->commonPrefixLens[0] = 0;
435 }
436
437
438 static S3Status make_list_bucket_callback(ListBucketData *lbData)
439 {
440     int i;
441
442     // Convert IsTruncated
443     int isTruncated = (!strcmp(lbData->isTruncated, "true") ||
444                        !strcmp(lbData->isTruncated, "1")) ? 1 : 0;
445
446     // Convert the contents
447     S3ListBucketContent contents[lbData->contentsCount];
448
449     int contentsCount = lbData->contentsCount;
450     for (i = 0; i < contentsCount; i++) {
451         S3ListBucketContent *contentDest = &(contents[i]);
452         ListBucketContents *contentSrc = &(lbData->contents[i]);
453         contentDest->key = contentSrc->key;
454         contentDest->lastModified = 
455             parseIso8601Time(contentSrc->lastModified);
456         contentDest->eTag = contentSrc->eTag;
457         contentDest->size = parseUnsignedInt(contentSrc->size);
458         contentDest->ownerId =
459             contentSrc->ownerId[0] ?contentSrc->ownerId : 0;
460         contentDest->ownerDisplayName = (contentSrc->ownerDisplayName[0] ?
461                                          contentSrc->ownerDisplayName : 0);
462     }
463
464     // Make the common prefixes array
465     int commonPrefixesCount = lbData->commonPrefixesCount;
466     char *commonPrefixes[commonPrefixesCount];
467     for (i = 0; i < commonPrefixesCount; i++) {
468         commonPrefixes[i] = lbData->commonPrefixes[i];
469     }
470
471     return (*(lbData->listBucketCallback))
472         (isTruncated, lbData->nextMarker,
473          contentsCount, contents, commonPrefixesCount, 
474          (const char **) commonPrefixes, lbData->callbackData);
475 }
476
477
478 static S3Status listBucketXmlCallback(const char *elementPath,
479                                       const char *data, int dataLen,
480                                       void *callbackData)
481 {
482     ListBucketData *lbData = (ListBucketData *) callbackData;
483
484     int fit;
485
486     if (data) {
487         if (!strcmp(elementPath, "ListBucketResult/IsTruncated")) {
488             string_buffer_append(lbData->isTruncated, data, dataLen, fit);
489         }
490         else if (!strcmp(elementPath, "ListBucketResult/NextMarker")) {
491             string_buffer_append(lbData->nextMarker, data, dataLen, fit);
492         }
493         else if (!strcmp(elementPath, "ListBucketResult/Contents/Key")) {
494             ListBucketContents *contents = 
495                 &(lbData->contents[lbData->contentsCount]);
496             string_buffer_append(contents->key, data, dataLen, fit);
497         }
498         else if (!strcmp(elementPath, 
499                          "ListBucketResult/Contents/LastModified")) {
500             ListBucketContents *contents = 
501                 &(lbData->contents[lbData->contentsCount]);
502             string_buffer_append(contents->lastModified, data, dataLen, fit);
503         }
504         else if (!strcmp(elementPath, "ListBucketResult/Contents/ETag")) {
505             ListBucketContents *contents = 
506                 &(lbData->contents[lbData->contentsCount]);
507             string_buffer_append(contents->eTag, data, dataLen, fit);
508         }
509         else if (!strcmp(elementPath, "ListBucketResult/Contents/Size")) {
510             ListBucketContents *contents = 
511                 &(lbData->contents[lbData->contentsCount]);
512             string_buffer_append(contents->size, data, dataLen, fit);
513         }
514         else if (!strcmp(elementPath, "ListBucketResult/Contents/Owner/ID")) {
515             ListBucketContents *contents = 
516                 &(lbData->contents[lbData->contentsCount]);
517             string_buffer_append(contents->ownerId, data, dataLen, fit);
518         }
519         else if (!strcmp(elementPath, 
520                          "ListBucketResult/Contents/Owner/DisplayName")) {
521             ListBucketContents *contents = 
522                 &(lbData->contents[lbData->contentsCount]);
523             string_buffer_append
524                 (contents->ownerDisplayName, data, dataLen, fit);
525         }
526         else if (!strcmp(elementPath, 
527                          "ListBucketResult/CommonPrefixes/Prefix")) {
528             int which = lbData->commonPrefixesCount;
529             lbData->commonPrefixLens[which] +=
530                 snprintf(lbData->commonPrefixes[which],
531                          sizeof(lbData->commonPrefixes[which]) -
532                          lbData->commonPrefixLens[which] - 1,
533                          "%.*s", dataLen, data);
534             if (lbData->commonPrefixLens[which] >=
535                 (int) sizeof(lbData->commonPrefixes[which])) {
536                 return S3StatusXmlParseFailure;
537             }
538         }
539     }
540     else {
541         if (!strcmp(elementPath, "ListBucketResult/Contents")) {
542             // Finished a Contents
543             lbData->contentsCount++;
544             if (lbData->contentsCount == MAX_CONTENTS) {
545                 // Make the callback
546                 S3Status status = make_list_bucket_callback(lbData);
547                 if (status != S3StatusOK) {
548                     return status;
549                 }
550                 initialize_list_bucket_data(lbData);
551             }
552             else {
553                 // Initialize the next one
554                 initialize_list_bucket_contents
555                     (&(lbData->contents[lbData->contentsCount]));
556             }
557         }
558         else if (!strcmp(elementPath,
559                          "ListBucketResult/CommonPrefixes/Prefix")) {
560             // Finished a Prefix
561             lbData->commonPrefixesCount++;
562             if (lbData->commonPrefixesCount == MAX_COMMON_PREFIXES) {
563                 // Make the callback
564                 S3Status status = make_list_bucket_callback(lbData);
565                 if (status != S3StatusOK) {
566                     return status;
567                 }
568                 initialize_list_bucket_data(lbData);
569             }
570             else {
571                 // Initialize the next one
572                 lbData->commonPrefixes[lbData->commonPrefixesCount][0] = 0;
573                 lbData->commonPrefixLens[lbData->commonPrefixesCount] = 0;
574             }
575         }
576     }
577
578     return S3StatusOK;
579 }
580
581
582 static S3Status listBucketPropertiesCallback
583     (const S3ResponseProperties *responseProperties, void *callbackData)
584 {
585     ListBucketData *lbData = (ListBucketData *) callbackData;
586     
587     return (*(lbData->responsePropertiesCallback))
588         (responseProperties, lbData->callbackData);
589 }
590
591
592 static S3Status listBucketDataCallback(int bufferSize, const char *buffer, 
593                                        void *callbackData)
594 {
595     ListBucketData *lbData = (ListBucketData *) callbackData;
596     
597     return simplexml_add(&(lbData->simpleXml), buffer, bufferSize);
598 }
599
600
601 static void listBucketCompleteCallback(S3Status requestStatus, 
602                                        const S3ErrorDetails *s3ErrorDetails,
603                                        void *callbackData)
604 {
605     ListBucketData *lbData = (ListBucketData *) callbackData;
606
607     // Make the callback if there is anything
608     if (lbData->contentsCount || lbData->commonPrefixesCount) {
609         make_list_bucket_callback(lbData);
610     }
611
612     (*(lbData->responseCompleteCallback))
613         (requestStatus, s3ErrorDetails, lbData->callbackData);
614
615     simplexml_deinitialize(&(lbData->simpleXml));
616
617     free(lbData);
618 }
619
620
621 void S3_list_bucket(const S3BucketContext *bucketContext, const char *prefix,
622                     const char *marker, const char *delimiter, int maxkeys,
623                     S3RequestContext *requestContext,
624                     const S3ListBucketHandler *handler, void *callbackData)
625 {
626     // Compose the query params
627     string_buffer(queryParams, 4096);
628     string_buffer_initialize(queryParams);
629     
630 #define safe_append(name, value)                                        \
631     do {                                                                \
632         int fit;                                                        \
633         if (amp) {                                                      \
634             string_buffer_append(queryParams, "&", 1, fit);             \
635             if (!fit) {                                                 \
636                 (*(handler->responseHandler.completeCallback))          \
637                     (S3StatusQueryParamsTooLong, 0, callbackData);      \
638                 return;                                                 \
639             }                                                           \
640         }                                                               \
641         string_buffer_append(queryParams, name "=",                     \
642                              sizeof(name "=") - 1, fit);                \
643         if (!fit) {                                                     \
644             (*(handler->responseHandler.completeCallback))              \
645                 (S3StatusQueryParamsTooLong, 0, callbackData);          \
646             return;                                                     \
647         }                                                               \
648         amp = 1;                                                        \
649         char encoded[3 * 1024];                                         \
650         if (!urlEncode(encoded, value, 1024)) {                         \
651             (*(handler->responseHandler.completeCallback))              \
652                 (S3StatusQueryParamsTooLong, 0, callbackData);          \
653             return;                                                     \
654         }                                                               \
655         string_buffer_append(queryParams, encoded, strlen(encoded),     \
656                              fit);                                      \
657         if (!fit) {                                                     \
658             (*(handler->responseHandler.completeCallback))              \
659                 (S3StatusQueryParamsTooLong, 0, callbackData);          \
660             return;                                                     \
661         }                                                               \
662     } while (0)
663
664
665     int amp = 0;
666     if (prefix) {
667         safe_append("prefix", prefix);
668     }
669     if (marker) {
670         safe_append("marker", marker);
671     }
672     if (delimiter) {
673         safe_append("delimiter", delimiter);
674     }
675     if (maxkeys) {
676         char maxKeysString[64];
677         snprintf(maxKeysString, sizeof(maxKeysString), "%d", maxkeys);
678         safe_append("max-keys", maxKeysString);
679     }
680
681     ListBucketData *lbData =
682         (ListBucketData *) malloc(sizeof(ListBucketData));
683
684     if (!lbData) {
685         (*(handler->responseHandler.completeCallback))
686             (S3StatusOutOfMemory, 0, callbackData);
687         return;
688     }
689
690     simplexml_initialize(&(lbData->simpleXml), &listBucketXmlCallback, lbData);
691     
692     lbData->responsePropertiesCallback = 
693         handler->responseHandler.propertiesCallback;
694     lbData->listBucketCallback = handler->listBucketCallback;
695     lbData->responseCompleteCallback = 
696         handler->responseHandler.completeCallback;
697     lbData->callbackData = callbackData;
698
699     string_buffer_initialize(lbData->isTruncated);
700     string_buffer_initialize(lbData->nextMarker);
701     initialize_list_bucket_data(lbData);
702
703     // Set up the RequestParams
704     RequestParams params =
705     {
706         HttpRequestTypeGET,                           // httpRequestType
707         { bucketContext->bucketName,                  // bucketName
708           bucketContext->protocol,                    // protocol
709           bucketContext->uriStyle,                    // uriStyle
710           bucketContext->accessKeyId,                 // accessKeyId
711           bucketContext->secretAccessKey },           // secretAccessKey
712         0,                                            // key
713         queryParams[0] ? queryParams : 0,             // queryParams
714         0,                                            // subResource
715         0,                                            // copySourceBucketName
716         0,                                            // copySourceKey
717         0,                                            // getConditions
718         0,                                            // startByte
719         0,                                            // byteCount
720         0,                                            // putProperties
721         &listBucketPropertiesCallback,                // propertiesCallback
722         0,                                            // toS3Callback
723         0,                                            // toS3CallbackTotalSize
724         &listBucketDataCallback,                      // fromS3Callback
725         &listBucketCompleteCallback,                  // completeCallback
726         lbData                                        // callbackData
727     };
728
729     // Perform the request
730     request_perform(&params, requestContext);
731 }