VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/misc/s3.cpp@ 38285

最後變更 在這個檔案從38285是 38285,由 vboxsync 提交於 14 年 前

comment typo.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 33.9 KB
 
1/* $Id: s3.cpp 38285 2011-08-02 18:50:37Z vboxsync $ */
2/** @file
3 * IPRT - S3 communication API.
4 */
5
6/*
7 * Copyright (C) 2009 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <iprt/s3.h>
32#include "internal/iprt.h"
33
34#include <iprt/err.h>
35#include <iprt/mem.h>
36#include <iprt/string.h>
37#include <iprt/base64.h>
38#include <iprt/file.h>
39#include <iprt/stream.h>
40
41#include <curl/curl.h>
42#include <openssl/hmac.h>
43#include <libxml/parser.h>
44
45#include "internal/magics.h"
46
47
48/*******************************************************************************
49* Structures and Typedefs *
50*******************************************************************************/
51typedef struct RTS3INTERNAL
52{
53 uint32_t u32Magic;
54 CURL *pCurl;
55 char *pszAccessKey;
56 char *pszSecretKey;
57 char *pszBaseUrl;
58 char *pszUserAgent;
59
60 PFNRTS3PROGRESS pfnProgressCallback;
61 void *pvUser;
62
63 long lLastResp;
64} RTS3INTERNAL;
65typedef RTS3INTERNAL* PRTS3INTERNAL;
66
67typedef struct RTS3TMPMEMCHUNK
68{
69 char *pszMem;
70 size_t cSize;
71} RTS3TMPMEMCHUNK;
72typedef RTS3TMPMEMCHUNK *PRTS3TMPMEMCHUNK;
73
74
75/*******************************************************************************
76* Defined Constants And Macros *
77*******************************************************************************/
78
79/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
80#define RTS3_VALID_RETURN_RC(hS3, rc) \
81 do { \
82 AssertPtrReturn((hS3), (rc)); \
83 AssertReturn((hS3)->u32Magic == RTS3_MAGIC, (rc)); \
84 } while (0)
85
86/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
87#define RTS3_VALID_RETURN(hS3) RTS3_VALID_RETURN_RC((hS3), VERR_INVALID_HANDLE)
88
89/** Validates a handle and returns (void) if not valid. */
90#define RTS3_VALID_RETURN_VOID(hS3) \
91 do { \
92 AssertPtrReturnVoid(hS3); \
93 AssertReturnVoid((hS3)->u32Magic == RTS3_MAGIC); \
94 } while (0)
95
96
97/*******************************************************************************
98* Private RTS3 helper *
99*******************************************************************************/
100
101static char* rtS3Host(const char* pszBucket, const char* pszKey, const char* pszBaseUrl)
102{
103 char* pszUrl;
104 /* Host header entry */
105 if (pszBucket[0] == 0)
106 RTStrAPrintf(&pszUrl, "%s", pszBaseUrl);
107 else if (pszKey[0] == 0)
108 RTStrAPrintf(&pszUrl, "%s.%s", pszBucket, pszBaseUrl);
109 else
110 RTStrAPrintf(&pszUrl, "%s.%s/%s", pszBucket, pszBaseUrl, pszKey);
111 return pszUrl;
112}
113
114static char* rtS3HostHeader(const char* pszBucket, const char* pszBaseUrl)
115{
116 char* pszUrl;
117 /* Host header entry */
118 if (pszBucket[0] != 0)
119 RTStrAPrintf(&pszUrl, "Host: %s.%s", pszBucket, pszBaseUrl);
120 else
121 RTStrAPrintf(&pszUrl, "Host: %s", pszBaseUrl);
122 return pszUrl;
123}
124
125static char* rtS3DateHeader()
126{
127 /* Date header entry */
128 time_t tt = time(NULL);
129 char* pszDate = (char*)RTMemAlloc(128);
130 strftime(pszDate, 128, "Date: %a, %d %b %Y %H:%M:%S UTC", gmtime(&tt));
131
132 return pszDate;
133}
134
135static char* rtS3ParseHeaders(char** ppHeaders, size_t cHeadEnts)
136{
137 char pszEmpty[] = "";
138 char *pszRes = NULL;
139 char *pszDate = pszEmpty;
140 char *pszType = pszEmpty;
141 for(size_t i=0; i < cHeadEnts; ++i)
142 {
143 if(ppHeaders[i] != NULL)
144 {
145 if (RTStrStr(ppHeaders[i], "Date: ") == ppHeaders[i])
146 {
147 pszDate = &(ppHeaders[i][6]);
148 }
149 else if(RTStrStr(ppHeaders[i], "Content-Type: ") == ppHeaders[i])
150 {
151 pszType = &(ppHeaders[i][14]);
152// char *pszTmp = RTStrDup (&(ppHeaders[i][14]));
153// if (pszRes)
154// {
155// char *pszTmp1 = pszRes;
156// RTStrAPrintf(&pszRes, "%s\n%s", pszRes, pszTmp);
157// RTStrFree(pszTmp);
158// RTStrFree(pszTmp1);
159// }
160// else
161// pszRes = pszTmp;
162 }
163 }
164 }
165 RTStrAPrintf(&pszRes, "\n%s\n%s", pszType, pszDate);
166 return pszRes;
167}
168
169static char* rtS3Canonicalize(const char* pszAction, const char* pszBucket, const char* pszKey, char** papszHeadEnts, size_t cHeadEnts)
170{
171 char* pszRes;
172 /* Grep the necessary info out of the headers & put them in a string */
173 char* pszHead = rtS3ParseHeaders(papszHeadEnts, cHeadEnts);
174 /* Create the string which will be used as signature */
175 RTStrAPrintf(&pszRes, "%s\n%s\n/",
176 pszAction,
177 pszHead);
178 RTStrFree(pszHead);
179 /* Add the bucket if the bucket isn't empty */
180 if (pszBucket[0] != 0)
181 {
182 char* pszTmp = pszRes;
183 RTStrAPrintf(&pszRes, "%s%s/", pszRes, pszBucket);
184 RTStrFree(pszTmp);
185 }
186 /* Add the key if the key isn't empty. */
187 if (pszKey[0] != 0)
188 {
189 char* pszTmp = pszRes;
190 RTStrAPrintf(&pszRes, "%s%s", pszRes, pszKey);
191 RTStrFree(pszTmp);
192 }
193
194 return pszRes;
195}
196
197static char* rtS3CreateSignature(PRTS3INTERNAL pS3Int, const char* pszAction, const char* pszBucket, const char* pszKey,
198 char** papszHeadEnts, size_t cHeadEnts)
199{
200 /* Create a string we can sign */
201 char* pszSig = rtS3Canonicalize(pszAction, pszBucket, pszKey, papszHeadEnts, cHeadEnts);
202// printf ("Sig %s\n", pszSig);
203 /* Sign the string by creating a SHA1 finger print */
204 char pszSigEnc[1024];
205 unsigned int cSigEnc = sizeof(pszSigEnc);
206 HMAC(EVP_sha1(), pS3Int->pszSecretKey, (int)strlen(pS3Int->pszSecretKey),
207 (const unsigned char*)pszSig, strlen(pszSig),
208 (unsigned char*)pszSigEnc, &cSigEnc);
209 RTStrFree(pszSig);
210 /* Convert the signature to Base64 */
211 size_t cSigBase64Enc = RTBase64EncodedLength(cSigEnc) + 1; /* +1 for the 0 */
212 char *pszSigBase64Enc = (char*)RTMemAlloc(cSigBase64Enc);
213 size_t cRes;
214 RTBase64Encode(pszSigEnc, cSigEnc, pszSigBase64Enc, cSigBase64Enc, &cRes);
215
216 return pszSigBase64Enc;
217}
218
219static char* rtS3CreateAuthHeader(PRTS3INTERNAL pS3Int, const char* pszAction, const char* pszBucket, const char* pszKey,
220 char** papszHeadEnts, size_t cHeadEnts)
221{
222 char *pszAuth;
223 /* Create a signature out of the header & the bucket/key info */
224 char *pszSigBase64Enc = rtS3CreateSignature(pS3Int, pszAction, pszBucket, pszKey, papszHeadEnts, cHeadEnts);
225 /* Create the authorization header entry */
226 RTStrAPrintf(&pszAuth, "Authorization: AWS %s:%s",
227 pS3Int->pszAccessKey,
228 pszSigBase64Enc);
229 RTStrFree(pszSigBase64Enc);
230 return pszAuth;
231}
232
233static int rtS3Perform(PRTS3INTERNAL pS3Int)
234{
235 int rc = VERR_INTERNAL_ERROR;
236 CURLcode code = curl_easy_perform(pS3Int->pCurl);
237 if (code == CURLE_OK)
238 {
239 curl_easy_getinfo(pS3Int->pCurl, CURLINFO_RESPONSE_CODE, &pS3Int->lLastResp);
240 switch (pS3Int->lLastResp)
241 {
242 case 200:
243 case 204: rc = VINF_SUCCESS; break; /* No content */
244 case 403: rc = VERR_S3_ACCESS_DENIED; break; /* Access denied */
245 case 404: rc = VERR_S3_NOT_FOUND; break; /* Site not found */
246 }
247 }else
248 {
249 switch(code)
250 {
251 case CURLE_URL_MALFORMAT:
252 case CURLE_COULDNT_RESOLVE_HOST:
253#if defined(CURLE_REMOTE_FILE_NOT_FOUND)
254 case CURLE_REMOTE_FILE_NOT_FOUND: rc = VERR_S3_NOT_FOUND; break;
255#elif defined(CURLE_FILE_COULDNT_READ_FILE)
256 case CURLE_FILE_COULDNT_READ_FILE: rc = VERR_S3_NOT_FOUND; break;
257#endif
258#if defined(CURLE_REMOTE_ACCESS_DENIED)
259 case CURLE_REMOTE_ACCESS_DENIED: rc = VERR_S3_ACCESS_DENIED; break;
260#elif defined(CURLE_FTP_ACCESS_DENIED)
261 case CURLE_FTP_ACCESS_DENIED: rc = VERR_S3_ACCESS_DENIED; break;
262#endif
263 case CURLE_ABORTED_BY_CALLBACK: rc = VERR_S3_CANCELED; break;
264 default: break;
265 }
266 }
267 return rc;
268}
269
270static size_t rtS3WriteNothingCallback(void *pvBuf, size_t cSize, size_t cBSize, void *pvUser)
271{
272 return cSize*cBSize;
273}
274
275static size_t rtS3WriteMemoryCallback(void *pvBuf, size_t cSize, size_t cBSize, void *pvUser)
276{
277 PRTS3TMPMEMCHUNK pTmpMem = (PRTS3TMPMEMCHUNK)pvUser;
278 size_t cRSize = cSize * cBSize;
279
280 pTmpMem->pszMem = (char*)RTMemRealloc(pTmpMem->pszMem, pTmpMem->cSize + cRSize + 1);
281 if (pTmpMem->pszMem)
282 {
283 memcpy(&(pTmpMem->pszMem[pTmpMem->cSize]), pvBuf, cRSize);
284 pTmpMem->cSize += cRSize;
285 pTmpMem->pszMem[pTmpMem->cSize] = 0;
286 }
287 return cRSize;
288}
289
290static size_t rtS3WriteFileCallback(void *pvBuf, size_t cSize, size_t cBSize, void *pvUser)
291{
292 size_t cWritten;
293 RTFileWrite(*(RTFILE*)pvUser, pvBuf, cSize * cBSize, &cWritten);
294 return cWritten;
295}
296
297static size_t rtS3ReadFileCallback(void *pvBuf, size_t cSize, size_t cBSize, void *pvUser)
298{
299 size_t cRead;
300 RTFileRead(*(RTFILE*)pvUser, pvBuf, cSize * cBSize, &cRead);
301
302 return cRead;
303}
304
305static int rtS3ProgressCallback(void *pvUser, double dDlTotal, double dDlNow, double dUlTotal, double dUlNow)
306{
307 if (pvUser)
308 {
309 PRTS3INTERNAL pS3Int = (PRTS3INTERNAL)pvUser;
310 if (pS3Int->pfnProgressCallback)
311 {
312 int rc = VINF_SUCCESS;
313 if (dDlTotal > 0)
314 rc = pS3Int->pfnProgressCallback((unsigned)(100.0/dDlTotal*dDlNow), pS3Int->pvUser);
315 else if (dUlTotal > 0)
316 rc = pS3Int->pfnProgressCallback((unsigned)(100.0/dUlTotal*dUlNow), pS3Int->pvUser);
317 if (rc != VINF_SUCCESS)
318 return -1;
319 }
320 }
321 return CURLE_OK;
322}
323
324static void rtS3ReinitCurl(PRTS3INTERNAL pS3Int)
325{
326 if (pS3Int &&
327 pS3Int->pCurl)
328 {
329 /* Reset the CURL object to an defined state */
330 curl_easy_reset(pS3Int->pCurl);
331 /* Make sure HTTP 1.1 is used */
332 curl_easy_setopt(pS3Int->pCurl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
333 /* We are cool we are a user agent now */
334 if (pS3Int->pszUserAgent)
335 curl_easy_setopt(pS3Int->pCurl, CURLOPT_USERAGENT, pS3Int->pszUserAgent);
336 /* Check if the user has a progress callback requested */
337 if (pS3Int->pfnProgressCallback)
338 {
339 /* Yes, we are willing to receive progress info */
340 curl_easy_setopt(pS3Int->pCurl, CURLOPT_NOPROGRESS, 0);
341 /* Callback for the progress info */
342 curl_easy_setopt(pS3Int->pCurl, CURLOPT_PROGRESSFUNCTION, rtS3ProgressCallback);
343 curl_easy_setopt(pS3Int->pCurl, CURLOPT_PROGRESSDATA, pS3Int);
344 }
345 /* Disable the internal cURL write function by providing one which does
346 * nothing */
347 curl_easy_setopt(pS3Int->pCurl, CURLOPT_WRITEFUNCTION, rtS3WriteNothingCallback);
348 /* Set this do get some verbose info what CURL is doing */
349// curl_easy_setopt(pS3Int->pCurl, CURLOPT_VERBOSE, 1);
350 }
351}
352
353/*******************************************************************************
354* Private XML helper *
355*******************************************************************************/
356
357static xmlNodePtr rtS3FindNode(xmlNodePtr pNode, const char *pszName)
358{
359 pNode = pNode->xmlChildrenNode;
360 while (pNode != NULL)
361 {
362 /* Check this level. */
363 if (!xmlStrcmp(pNode->name, (const xmlChar *)pszName))
364 return pNode;
365
366 /* Recursively check the children of this node. */
367 xmlNodePtr pChildNode = rtS3FindNode(pNode, pszName);
368 if (pChildNode != NULL)
369 return pChildNode;
370
371 /* Next node. */
372 pNode = pNode->next;
373 }
374 return pNode;
375}
376
377static int rtS3ReadXmlFromMemory(PRTS3TMPMEMCHUNK pChunk, const char* pszRootElement, xmlDocPtr *ppDoc, xmlNodePtr *ppCur)
378{
379 *ppDoc = xmlReadMemory(pChunk->pszMem, (int)pChunk->cSize, "", "ISO-8859-1", XML_PARSE_NOBLANKS);
380 if (*ppDoc == NULL)
381 return VERR_PARSE_ERROR;
382
383 *ppCur = xmlDocGetRootElement(*ppDoc);
384 if (*ppCur == NULL)
385 {
386 xmlFreeDoc(*ppDoc);
387 return VERR_PARSE_ERROR;
388 }
389 if (xmlStrcmp((*ppCur)->name, (const xmlChar *) pszRootElement))
390 {
391 xmlFreeDoc(*ppDoc);
392 return VERR_PARSE_ERROR;
393 }
394 return VINF_SUCCESS;
395}
396
397static void rtS3ExtractAllBuckets(xmlDocPtr pDoc, xmlNodePtr pNode, PCRTS3BUCKETENTRY *ppBuckets)
398{
399 pNode = rtS3FindNode(pNode, "Buckets");
400 if (pNode != NULL)
401 {
402 PRTS3BUCKETENTRY pPrevBucket = NULL;
403 xmlNodePtr pCurBucket = pNode->xmlChildrenNode;
404 while (pCurBucket != NULL)
405 {
406 if ((!xmlStrcmp(pCurBucket->name, (const xmlChar *)"Bucket")))
407 {
408 PRTS3BUCKETENTRY pBucket = (PRTS3BUCKETENTRY)RTMemAllocZ(sizeof(RTS3BUCKETENTRY));
409 pBucket->pPrev = pPrevBucket;
410 if (pPrevBucket)
411 pPrevBucket->pNext = pBucket;
412 else
413 (*ppBuckets) = pBucket;
414 pPrevBucket = pBucket;
415 xmlNodePtr pCurCont = pCurBucket->xmlChildrenNode;
416 while (pCurCont != NULL)
417 {
418 if ((!xmlStrcmp(pCurCont->name, (const xmlChar *)"Name")))
419 {
420 xmlChar *pszKey = xmlNodeListGetString(pDoc, pCurCont->xmlChildrenNode, 1);
421 pBucket->pszName = RTStrDup((const char*)pszKey);
422 xmlFree(pszKey);
423 }
424 if ((!xmlStrcmp(pCurCont->name, (const xmlChar*)"CreationDate")))
425 {
426 xmlChar *pszKey = xmlNodeListGetString(pDoc, pCurCont->xmlChildrenNode, 1);
427 pBucket->pszCreationDate = RTStrDup((const char*)pszKey);
428 xmlFree(pszKey);
429 }
430 pCurCont = pCurCont->next;
431 }
432 }
433 pCurBucket = pCurBucket->next;
434 }
435 }
436}
437
438static void rtS3ExtractAllKeys(xmlDocPtr pDoc, xmlNodePtr pNode, PCRTS3KEYENTRY *ppKeys)
439{
440 if (pNode != NULL)
441 {
442 PRTS3KEYENTRY pPrevKey = NULL;
443 xmlNodePtr pCurKey = pNode->xmlChildrenNode;
444 while (pCurKey != NULL)
445 {
446 if ((!xmlStrcmp(pCurKey->name, (const xmlChar *)"Contents")))
447 {
448 PRTS3KEYENTRY pKey = (PRTS3KEYENTRY)RTMemAllocZ(sizeof(RTS3KEYENTRY));
449 pKey->pPrev = pPrevKey;
450 if (pPrevKey)
451 pPrevKey->pNext = pKey;
452 else
453 (*ppKeys) = pKey;
454 pPrevKey = pKey;
455 xmlNodePtr pCurCont = pCurKey->xmlChildrenNode;
456 while (pCurCont != NULL)
457 {
458 if ((!xmlStrcmp(pCurCont->name, (const xmlChar *)"Key")))
459 {
460 xmlChar *pszKey = xmlNodeListGetString(pDoc, pCurCont->xmlChildrenNode, 1);
461 pKey->pszName = RTStrDup((const char*)pszKey);
462 xmlFree(pszKey);
463 }
464 if ((!xmlStrcmp(pCurCont->name, (const xmlChar*)"LastModified")))
465 {
466 xmlChar *pszKey = xmlNodeListGetString(pDoc, pCurCont->xmlChildrenNode, 1);
467 pKey->pszLastModified = RTStrDup((const char*)pszKey);
468 xmlFree(pszKey);
469 }
470 if ((!xmlStrcmp(pCurCont->name, (const xmlChar*)"Size")))
471 {
472 xmlChar *pszKey = xmlNodeListGetString(pDoc, pCurCont->xmlChildrenNode, 1);
473 pKey->cbFile = RTStrToUInt64((const char*)pszKey);
474 xmlFree(pszKey);
475 }
476 pCurCont = pCurCont->next;
477 }
478 }
479 pCurKey = pCurKey->next;
480 }
481 }
482}
483
484/*******************************************************************************
485* Public RTS3 interface *
486*******************************************************************************/
487
488RTR3DECL(int) RTS3Create(PRTS3 ppS3, const char* pszAccessKey, const char* pszSecretKey, const char* pszBaseUrl, const char* pszUserAgent /* = NULL */)
489{
490 AssertPtrReturn(ppS3, VERR_INVALID_POINTER);
491
492 /* We need at least an URL to connect with */
493 if (pszBaseUrl == NULL ||
494 pszBaseUrl[0] == 0)
495 return VERR_INVALID_PARAMETER;
496
497 /* In windows, this will init the winsock stuff */
498 if (curl_global_init(CURL_GLOBAL_ALL) != 0)
499 return VERR_INTERNAL_ERROR;
500
501 CURL* pCurl = curl_easy_init();
502 if (!pCurl)
503 return VERR_INTERNAL_ERROR;
504
505 PRTS3INTERNAL pS3Int = (PRTS3INTERNAL)RTMemAllocZ(sizeof(RTS3INTERNAL));
506 if (pS3Int == NULL)
507 return VERR_NO_MEMORY;
508
509 pS3Int->u32Magic = RTS3_MAGIC;
510 pS3Int->pCurl = pCurl;
511 pS3Int->pszAccessKey = RTStrDup(pszAccessKey);
512 pS3Int->pszSecretKey = RTStrDup(pszSecretKey);
513 pS3Int->pszBaseUrl = RTStrDup(pszBaseUrl);
514 if (pszUserAgent)
515 pS3Int->pszUserAgent = RTStrDup(pszUserAgent);
516
517 *ppS3 = (RTS3)pS3Int;
518
519 return VINF_SUCCESS;
520}
521
522RTR3DECL(void) RTS3Destroy(RTS3 hS3)
523{
524 if (hS3 == NIL_RTS3)
525 return;
526
527 PRTS3INTERNAL pS3Int = hS3;
528 RTS3_VALID_RETURN_VOID(pS3Int);
529
530 curl_easy_cleanup(pS3Int->pCurl);
531
532 pS3Int->u32Magic = RTS3_MAGIC_DEAD;
533
534 if (pS3Int->pszUserAgent)
535 RTStrFree(pS3Int->pszUserAgent);
536 RTStrFree(pS3Int->pszBaseUrl);
537 RTStrFree(pS3Int->pszSecretKey);
538 RTStrFree(pS3Int->pszAccessKey);
539
540 RTMemFree(pS3Int);
541
542 curl_global_cleanup();
543}
544
545RTR3DECL(void) RTS3SetProgressCallback(RTS3 hS3, PFNRTS3PROGRESS pfnProgressCallback, void *pvUser /* = NULL */)
546{
547 PRTS3INTERNAL pS3Int = hS3;
548 RTS3_VALID_RETURN_VOID(pS3Int);
549
550 pS3Int->pfnProgressCallback = pfnProgressCallback;
551 pS3Int->pvUser = pvUser;
552}
553
554RTR3DECL(int) RTS3GetBuckets(RTS3 hS3, PCRTS3BUCKETENTRY *ppBuckets)
555{
556 PRTS3INTERNAL pS3Int = hS3;
557 RTS3_VALID_RETURN(pS3Int);
558
559 /* Properly initialize this */
560 *ppBuckets = NULL;
561
562 /* Reset the CURL object to an defined state */
563 rtS3ReinitCurl(pS3Int);
564 /* Create the CURL object to operate on */
565 curl_easy_setopt(pS3Int->pCurl, CURLOPT_URL, pS3Int->pszBaseUrl);
566
567 /* Create the three basic header entries */
568 char *apszHead[3] =
569 {
570 rtS3HostHeader("", pS3Int->pszBaseUrl), /* Host entry */
571 rtS3DateHeader(), /* Date entry */
572 NULL /* Authorization entry */
573 };
574 /* Create the authorization header entry */
575 apszHead[RT_ELEMENTS(apszHead)-1] = rtS3CreateAuthHeader(pS3Int, "GET", "", "", apszHead, RT_ELEMENTS(apszHead));
576
577 /* Add all headers to curl */
578 struct curl_slist* pHeaders = NULL; /* Init to NULL is important */
579 for(size_t i=0; i < RT_ELEMENTS(apszHead); ++i)
580 pHeaders = curl_slist_append(pHeaders, apszHead[i]);
581
582 /* Pass our list of custom made headers */
583 curl_easy_setopt(pS3Int->pCurl, CURLOPT_HTTPHEADER, pHeaders);
584
585 RTS3TMPMEMCHUNK chunk = { NULL, 0 };
586 /* Set the callback which receive the content */
587 curl_easy_setopt(pS3Int->pCurl, CURLOPT_WRITEFUNCTION, rtS3WriteMemoryCallback);
588 curl_easy_setopt(pS3Int->pCurl, CURLOPT_WRITEDATA, (void *)&chunk);
589 /* Start the request */
590 int rc = rtS3Perform(pS3Int);
591
592 /* Regardless of the result, free all used resources first*/
593 curl_slist_free_all(pHeaders);
594 for(size_t i=0; i < RT_ELEMENTS(apszHead); ++i)
595 RTStrFree(apszHead[i]);
596
597 /* On success parse the result */
598 if (RT_SUCCESS(rc))
599 {
600 xmlDocPtr pDoc;
601 xmlNodePtr pCur;
602 /* Parse the xml memory for "ListAllMyBucketsResult" */
603 rc = rtS3ReadXmlFromMemory(&chunk, "ListAllMyBucketsResult", &pDoc, &pCur);
604 if (RT_SUCCESS(rc))
605 {
606 /* Now extract all buckets */
607 rtS3ExtractAllBuckets(pDoc, pCur, ppBuckets);
608 /* Free the xml stuff */
609 xmlFreeDoc(pDoc);
610 }
611 }
612 /* Free the temporary memory */
613 RTMemFree(chunk.pszMem);
614
615 return rc;
616}
617
618RTR3DECL(int) RTS3BucketsDestroy(PCRTS3BUCKETENTRY pBuckets)
619{
620 if (!pBuckets)
621 return VINF_SUCCESS;
622
623 while (pBuckets)
624 {
625 PCRTS3BUCKETENTRY pTemp = pBuckets;
626 RTStrFree((char*)pBuckets->pszName);
627 RTStrFree((char*)pBuckets->pszCreationDate);
628 pBuckets = pBuckets->pNext;
629 RTMemFree((PRTS3BUCKETENTRY )pTemp);
630 }
631 return VINF_SUCCESS;
632}
633
634RTR3DECL(int) RTS3CreateBucket(RTS3 hS3, const char* pszBucketName)
635{
636 PRTS3INTERNAL pS3Int = hS3;
637 RTS3_VALID_RETURN(pS3Int);
638
639 /* Reset the CURL object to an defined state */
640 rtS3ReinitCurl(pS3Int);
641
642 char* pszUrl = rtS3Host(pszBucketName, "", pS3Int->pszBaseUrl);
643 curl_easy_setopt(pS3Int->pCurl, CURLOPT_URL, pszUrl);
644 RTStrFree(pszUrl);
645
646 /* Create the basic header entries */
647 char *apszHead[4] =
648 {
649 RTStrDup("Content-Length: 0"), /* Content length entry */
650 rtS3HostHeader(pszBucketName, pS3Int->pszBaseUrl), /* Host entry */
651 rtS3DateHeader(), /* Date entry */
652 NULL /* Authorization entry */
653 };
654 /* Create the authorization header entry */
655 apszHead[RT_ELEMENTS(apszHead)-1] = rtS3CreateAuthHeader(pS3Int, "PUT", pszBucketName, "", apszHead, RT_ELEMENTS(apszHead));
656
657 /* Add all headers to curl */
658 struct curl_slist* pHeaders = NULL; /* Init to NULL is important */
659 for(size_t i=0; i < RT_ELEMENTS(apszHead); ++i)
660 pHeaders = curl_slist_append(pHeaders, apszHead[i]);
661
662 /* Pass our list of custom made headers */
663 curl_easy_setopt(pS3Int->pCurl, CURLOPT_HTTPHEADER, pHeaders);
664
665 /* Set CURL in upload mode */
666 curl_easy_setopt(pS3Int->pCurl, CURLOPT_PUT, 1);
667 curl_easy_setopt(pS3Int->pCurl, CURLOPT_UPLOAD, 1);
668
669 /* Set the size of the file we like to transfer */
670 curl_easy_setopt(pS3Int->pCurl, CURLOPT_INFILESIZE_LARGE, 0);
671
672 /* Start the request */
673 int rc = rtS3Perform(pS3Int);
674 if (RT_FAILURE(rc))
675 {
676 /* Handle special failures */
677 if (pS3Int->lLastResp == 409)
678 rc = VERR_S3_BUCKET_ALREADY_EXISTS;
679 }
680
681 /* Regardless of the result, free all used resources first*/
682 curl_slist_free_all(pHeaders);
683 for(size_t i=0; i < RT_ELEMENTS(apszHead); ++i)
684 RTStrFree(apszHead[i]);
685
686 return rc;
687}
688
689RTR3DECL(int) RTS3DeleteBucket(RTS3 hS3, const char* pszBucketName)
690{
691 PRTS3INTERNAL pS3Int = hS3;
692 RTS3_VALID_RETURN(pS3Int);
693
694 /* Reset the CURL object to an defined state */
695 rtS3ReinitCurl(pS3Int);
696
697 char* pszUrl = rtS3Host(pszBucketName, "", pS3Int->pszBaseUrl);
698 curl_easy_setopt(pS3Int->pCurl, CURLOPT_URL, pszUrl);
699 RTStrFree(pszUrl);
700
701 /* Create the three basic header entries */
702 char *apszHead[3] =
703 {
704 rtS3HostHeader(pszBucketName, pS3Int->pszBaseUrl), /* Host entry */
705 rtS3DateHeader(), /* Date entry */
706 NULL /* Authorization entry */
707 };
708 /* Create the authorization header entry */
709 apszHead[RT_ELEMENTS(apszHead)-1] = rtS3CreateAuthHeader(pS3Int, "DELETE", pszBucketName, "", apszHead, RT_ELEMENTS(apszHead));
710
711 /* Add all headers to curl */
712 struct curl_slist* pHeaders = NULL; /* Init to NULL is important */
713 for(size_t i=0; i < RT_ELEMENTS(apszHead); ++i)
714 pHeaders = curl_slist_append(pHeaders, apszHead[i]);
715
716 /* Pass our list of custom made headers */
717 curl_easy_setopt(pS3Int->pCurl, CURLOPT_HTTPHEADER, pHeaders);
718
719 /* Set CURL in delete mode */
720 curl_easy_setopt(pS3Int->pCurl, CURLOPT_CUSTOMREQUEST, "DELETE");
721
722 /* Start the request */
723 int rc = rtS3Perform(pS3Int);
724 if (RT_FAILURE(rc))
725 {
726 /* Handle special failures */
727 if (pS3Int->lLastResp == 409)
728 rc = VERR_S3_BUCKET_NOT_EMPTY;
729 }
730
731 /* Regardless of the result, free all used resources first*/
732 curl_slist_free_all(pHeaders);
733 for(size_t i=0; i < RT_ELEMENTS(apszHead); ++i)
734 RTStrFree(apszHead[i]);
735
736 return rc;
737}
738
739RTR3DECL(int) RTS3GetBucketKeys(RTS3 hS3, const char* pszBucketName, PCRTS3KEYENTRY *ppKeys)
740{
741 PRTS3INTERNAL pS3Int = hS3;
742 RTS3_VALID_RETURN(pS3Int);
743
744 *ppKeys = NULL;
745
746 /* Reset the CURL object to an defined state */
747 rtS3ReinitCurl(pS3Int);
748
749 char* pszUrl = rtS3Host(pszBucketName, "", pS3Int->pszBaseUrl);
750 curl_easy_setopt(pS3Int->pCurl, CURLOPT_URL, pszUrl);
751 RTStrFree(pszUrl);
752
753 /* Create the three basic header entries */
754 char *apszHead[3] =
755 {
756 rtS3HostHeader(pszBucketName, pS3Int->pszBaseUrl), /* Host entry */
757 rtS3DateHeader(), /* Date entry */
758 NULL /* Authorization entry */
759 };
760 /* Create the authorization header entry */
761 apszHead[RT_ELEMENTS(apszHead)-1] = rtS3CreateAuthHeader(pS3Int, "GET", pszBucketName, "", apszHead, RT_ELEMENTS(apszHead));
762
763 /* Add all headers to curl */
764 struct curl_slist* pHeaders = NULL; /* Init to NULL is important */
765 for(size_t i=0; i < RT_ELEMENTS(apszHead); ++i)
766 pHeaders = curl_slist_append(pHeaders, apszHead[i]);
767
768 /* Pass our list of custom made headers */
769 curl_easy_setopt(pS3Int->pCurl, CURLOPT_HTTPHEADER, pHeaders);
770
771 RTS3TMPMEMCHUNK chunk = { NULL, 0 };
772 /* Set the callback which receive the content */
773 curl_easy_setopt(pS3Int->pCurl, CURLOPT_WRITEFUNCTION, rtS3WriteMemoryCallback);
774 curl_easy_setopt(pS3Int->pCurl, CURLOPT_WRITEDATA, (void *)&chunk);
775
776 /* Start the request */
777 int rc = rtS3Perform(pS3Int);
778
779 /* Regardless of the result, free all used resources first*/
780 curl_slist_free_all(pHeaders);
781 for(size_t i=0; i < RT_ELEMENTS(apszHead); ++i)
782 RTStrFree(apszHead[i]);
783
784 /* On success parse the result */
785 if (RT_SUCCESS(rc))
786 {
787 xmlDocPtr pDoc;
788 xmlNodePtr pCur;
789 /* Parse the xml memory for "ListBucketResult" */
790 rc = rtS3ReadXmlFromMemory(&chunk, "ListBucketResult", &pDoc, &pCur);
791 if (RT_SUCCESS(rc))
792 {
793 /* Now extract all buckets */
794 rtS3ExtractAllKeys(pDoc, pCur, ppKeys);
795 /* Free the xml stuff */
796 xmlFreeDoc(pDoc);
797 }
798 }
799 /* Free the temporary memory */
800 RTMemFree(chunk.pszMem);
801
802 return rc;
803}
804
805RTR3DECL(int) RTS3KeysDestroy(PCRTS3KEYENTRY pKeys)
806{
807 if (!pKeys)
808 return VINF_SUCCESS;
809
810 while (pKeys)
811 {
812 PCRTS3KEYENTRY pTemp = pKeys;
813 RTStrFree((char*)pKeys->pszName);
814 RTStrFree((char*)pKeys->pszLastModified);
815 pKeys = pKeys->pNext;
816 RTMemFree((PRTS3KEYENTRY)pTemp);
817 }
818 return VINF_SUCCESS;
819}
820
821RTR3DECL(int) RTS3DeleteKey(RTS3 hS3, const char* pszBucketName, const char* pszKeyName)
822{
823 PRTS3INTERNAL pS3Int = hS3;
824 RTS3_VALID_RETURN(pS3Int);
825
826 /* Reset the CURL object to an defined state */
827 rtS3ReinitCurl(pS3Int);
828
829 char* pszUrl = rtS3Host(pszBucketName, pszKeyName, pS3Int->pszBaseUrl);
830 curl_easy_setopt(pS3Int->pCurl, CURLOPT_URL, pszUrl);
831 RTStrFree(pszUrl);
832
833 /* Create the three basic header entries */
834 char *apszHead[3] =
835 {
836 rtS3HostHeader(pszBucketName, pS3Int->pszBaseUrl), /* Host entry */
837 rtS3DateHeader(), /* Date entry */
838 NULL /* Authorization entry */
839 };
840 /* Create the authorization header entry */
841 apszHead[RT_ELEMENTS(apszHead)-1] = rtS3CreateAuthHeader(pS3Int, "DELETE", pszBucketName, pszKeyName, apszHead, RT_ELEMENTS(apszHead));
842
843 /* Add all headers to curl */
844 struct curl_slist* pHeaders = NULL; /* Init to NULL is important */
845 for(size_t i=0; i < RT_ELEMENTS(apszHead); ++i)
846 pHeaders = curl_slist_append(pHeaders, apszHead[i]);
847
848 /* Pass our list of custom made headers */
849 curl_easy_setopt(pS3Int->pCurl, CURLOPT_HTTPHEADER, pHeaders);
850
851 /* Set CURL in delete mode */
852 curl_easy_setopt(pS3Int->pCurl, CURLOPT_CUSTOMREQUEST, "DELETE");
853
854 /* Start the request */
855 int rc = rtS3Perform(pS3Int);
856
857 /* Regardless of the result, free all used resources first*/
858 curl_slist_free_all(pHeaders);
859 for(size_t i=0; i < RT_ELEMENTS(apszHead); ++i)
860 RTStrFree(apszHead[i]);
861
862 return rc;
863}
864
865RTR3DECL(int) RTS3GetKey(RTS3 hS3, const char *pszBucketName, const char *pszKeyName, const char *pszFilename)
866{
867 PRTS3INTERNAL pS3Int = hS3;
868 RTS3_VALID_RETURN(pS3Int);
869
870 /* Reset the CURL object to an defined state */
871 rtS3ReinitCurl(pS3Int);
872
873 /* Open the file */
874 RTFILE hFile;
875 int rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
876 if (RT_FAILURE(rc))
877 return rc;
878
879 char* pszUrl = rtS3Host(pszBucketName, pszKeyName, pS3Int->pszBaseUrl);
880 curl_easy_setopt(pS3Int->pCurl, CURLOPT_URL, pszUrl);
881 RTStrFree(pszUrl);
882
883 /* Create the three basic header entries */
884 char *apszHead[3] =
885 {
886 rtS3HostHeader(pszBucketName, pS3Int->pszBaseUrl), /* Host entry */
887 rtS3DateHeader(), /* Date entry */
888 NULL /* Authorization entry */
889 };
890 /* Create the authorization header entry */
891 apszHead[RT_ELEMENTS(apszHead)-1] = rtS3CreateAuthHeader(pS3Int, "GET", pszBucketName, pszKeyName, apszHead, RT_ELEMENTS(apszHead));
892
893 /* Add all headers to curl */
894 struct curl_slist* pHeaders = NULL; /* Init to NULL is important */
895 for(size_t i=0; i < RT_ELEMENTS(apszHead); ++i)
896 pHeaders = curl_slist_append(pHeaders, apszHead[i]);
897
898 /* Pass our list of custom made headers */
899 curl_easy_setopt(pS3Int->pCurl, CURLOPT_HTTPHEADER, pHeaders);
900
901 /* Set the callback which receive the content */
902 curl_easy_setopt(pS3Int->pCurl, CURLOPT_WRITEFUNCTION, rtS3WriteFileCallback);
903 curl_easy_setopt(pS3Int->pCurl, CURLOPT_WRITEDATA, &hFile);
904
905 /* Start the request */
906 rc = rtS3Perform(pS3Int);
907
908 /* Regardless of the result, free all used resources first*/
909 curl_slist_free_all(pHeaders);
910 for(size_t i=0; i < RT_ELEMENTS(apszHead); ++i)
911 RTStrFree(apszHead[i]);
912
913 /* Close the open file */
914 RTFileClose(hFile);
915
916 /* If there was an error delete the newly created file */
917 if (RT_FAILURE(rc))
918 RTFileDelete(pszFilename);
919
920 return rc;
921}
922
923RTR3DECL(int) RTS3PutKey(RTS3 hS3, const char *pszBucketName, const char *pszKeyName, const char *pszFilename)
924{
925 PRTS3INTERNAL pS3Int = hS3;
926 RTS3_VALID_RETURN(pS3Int);
927
928 /* Reset the CURL object to an defined state */
929 rtS3ReinitCurl(pS3Int);
930
931 /* Open the file */
932 RTFILE hFile;
933 int rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_NONE);
934 if (RT_FAILURE(rc))
935 return rc;
936
937 uint64_t cbFileSize;
938 rc = RTFileGetSize(hFile, &cbFileSize);
939 if (RT_FAILURE(rc))
940 {
941 RTFileClose(hFile);
942 return rc;
943 }
944
945 char* pszUrl = rtS3Host(pszBucketName, pszKeyName, pS3Int->pszBaseUrl);
946 curl_easy_setopt(pS3Int->pCurl, CURLOPT_URL, pszUrl);
947 RTStrFree(pszUrl);
948
949 char* pszContentLength;
950 RTStrAPrintf(&pszContentLength, "Content-Length: %lu", cbFileSize);
951 /* Create the three basic header entries */
952 char *apszHead[5] =
953 {
954 /* todo: For now we use octet-stream for all types. Later we should try
955 * to set the right one (libmagic from the file packet could be a
956 * candidate for finding the right type). */
957 RTStrDup("Content-Type: octet-stream"), /* Content type entry */
958 pszContentLength, /* Content length entry */
959 rtS3HostHeader(pszBucketName, pS3Int->pszBaseUrl), /* Host entry */
960 rtS3DateHeader(), /* Date entry */
961 NULL /* Authorization entry */
962 };
963 /* Create the authorization header entry */
964 apszHead[RT_ELEMENTS(apszHead)-1] = rtS3CreateAuthHeader(pS3Int, "PUT", pszBucketName, pszKeyName, apszHead, RT_ELEMENTS(apszHead));
965
966 /* Add all headers to curl */
967 struct curl_slist* pHeaders = NULL; /* Init to NULL is important */
968 for(size_t i=0; i < RT_ELEMENTS(apszHead); ++i)
969 pHeaders = curl_slist_append(pHeaders, apszHead[i]);
970
971 /* Pass our list of custom made headers */
972 curl_easy_setopt(pS3Int->pCurl, CURLOPT_HTTPHEADER, pHeaders);
973
974 /* Set CURL in upload mode */
975 curl_easy_setopt(pS3Int->pCurl, CURLOPT_PUT, 1);
976 curl_easy_setopt(pS3Int->pCurl, CURLOPT_UPLOAD, 1);
977
978 /* Set the size of the file we like to transfer */
979 curl_easy_setopt(pS3Int->pCurl, CURLOPT_INFILESIZE_LARGE, cbFileSize);
980
981 /* Set the callback which send the content */
982 curl_easy_setopt(pS3Int->pCurl, CURLOPT_READFUNCTION, rtS3ReadFileCallback);
983 curl_easy_setopt(pS3Int->pCurl, CURLOPT_READDATA, &hFile);
984
985 /* Start the request */
986 rc = rtS3Perform(pS3Int);
987
988 /* Regardless of the result, free all used resources first*/
989 curl_slist_free_all(pHeaders);
990 for(size_t i=0; i < RT_ELEMENTS(apszHead); ++i)
991 RTStrFree(apszHead[i]);
992
993 /* Close the open file */
994 RTFileClose(hFile);
995
996 return rc;
997}
998
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette