2 * Copyright (c) 2008-2012 Zmanda, Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
19 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
25 #include <curl/curl.h>
39 /* An opaque handle. S3Handles should only be accessed from a single
40 * thread at any given time, although it is fine to use different handles
41 * in different threads simultaneously. */
42 typedef struct S3Handle S3Handle;
44 /* Callback function to read data to upload
46 * @note this is the same as CURLOPT_READFUNCTION
48 * @param data: The pointer to write data to
49 * @param size: The size of each "element" of the data buffer in bytes
50 * @param nmemb: The number of elements in the data buffer.
51 * So, the buffer's size is size*nmemb bytes.
52 * @param stream: The read_data (an opaque pointer)
54 * @return The number of bytes written to the buffer,
55 * CURL_READFUNC_PAUSE to pause, or CURL_READFUNC_ABORT to abort.
56 * Return 0 only if there's no more data to be uploaded.
58 typedef size_t (*s3_read_func)(void *data, size_t size, size_t nmemb, void *stream);
60 /* This function is called to get size of the upload data
62 * @param data: The write_data (opaque pointer)
64 * @return The number of bytes of data, negative for error
66 typedef size_t (*s3_size_func)(void *data);
68 /* This function is called to get MD5 hash of the upload data
70 * @param data: The write_data (opaque pointer)
72 * @return The MD5 hash, NULL on error
74 typedef GByteArray* (*s3_md5_func)(void *data);
76 /* This function is called to reset an upload or download data stream
79 * @param data: The read_data or write_data (opaque pointer)
81 * @return The number of bytes of data, negative for error
83 typedef void (*s3_reset_func)(void *data);
85 /* Callback function to write data that's been downloaded
87 * @note this is the same as CURLOPT_WRITEFUNCTION
89 * @param data: The pointer to read data from
90 * @param size: The size of each "element" of the data buffer in bytes
91 * @param nmemb: The number of elements in the data buffer.
92 * So, the buffer's size is size*nmemb bytes.
93 * @param stream: the write_data (an opaque pointer)
95 * @return The number of bytes written to the buffer or
96 * CURL_WRITEFUNC_PAUSE to pause.
97 * If it's the number of bytes written, it should match the buffer size
99 typedef size_t (*s3_write_func)(void *data, size_t size, size_t nmemb, void *stream);
102 * Callback function to track progress
104 * @note this is the same as CURLOPT_PROGRESSFUNCTION
106 * @param data: The progress_data
107 * @param dltotal: The total number of bytes to downloaded
108 * @param dlnow: The current number of bytes downloaded
109 * @param ultotal: The total number of bytes to downloaded
110 * @param ulnow: The current number of bytes downloaded
112 * @return 0 to continue, non-zero to abort.
114 typedef curl_progress_callback s3_progress_func;
120 /* These are assumed to be already URL-escaped. */
121 # define STS_BASE_URL "https://ls.amazonaws.com/"
122 # define STS_PRODUCT_TOKEN "{ProductToken}AAAGQXBwVGtu4geoGybuwuk8VEEPzJ9ZANpu0yzbf9g4Gs5Iarzff9B7qaDBEEaWcAzWpcN7zmdMO765jOtEFc4DWTRNkpPSzUnTdkHbdYUamath73OreaZtB86jy/JF0gsHZfhxeKc/3aLr8HNT//DsX3r272zYHLDPWWUbFguOwqNjllnt6BshYREx59l8RrWABLSa37dyJeN+faGvz3uQxiDakZRn3LfInOE6d9+fTFl50LPoP08LCqI/SJfpouzWix7D/cep3Jq8yYNyM1rgAOTF7/wh7r8OuPDLJ/xZUDLfykePIAM="
124 /* This preprocessor magic will enumerate constants named S3_ERROR_XxxYyy for
125 * each of the errors in parentheses.
127 * see http://docs.amazonwebservices.com/AmazonS3/latest/API/ErrorResponses.html
128 * for Amazon's breakdown of error responses.
130 #define S3_ERROR_LIST \
132 S3_ERROR(AccountProblem), \
133 S3_ERROR(AllAccessDisabled), \
134 S3_ERROR(AmbiguousGrantByEmailAddress), \
135 S3_ERROR(OperationAborted), \
136 S3_ERROR(BadDigest), \
137 S3_ERROR(BucketAlreadyExists), \
138 S3_ERROR(BucketAlreadyOwnedByYou), \
139 S3_ERROR(BucketNotEmpty), \
140 S3_ERROR(CredentialsNotSupported), \
141 S3_ERROR(EntityTooLarge), \
142 S3_ERROR(IncompleteBody), \
143 S3_ERROR(InternalError), \
144 S3_ERROR(InvalidAccessKeyId), \
145 S3_ERROR(InvalidArgument), \
146 S3_ERROR(InvalidBucketName), \
147 S3_ERROR(InvalidDigest), \
148 S3_ERROR(InvalidRange), \
149 S3_ERROR(InvalidSecurity), \
150 S3_ERROR(InvalidSOAPRequest), \
151 S3_ERROR(InvalidStorageClass), \
152 S3_ERROR(InvalidTargetBucketForLogging), \
153 S3_ERROR(KeyTooLong), \
154 S3_ERROR(InvalidURI), \
155 S3_ERROR(MalformedACLError), \
156 S3_ERROR(MaxMessageLengthExceeded), \
157 S3_ERROR(MetadataTooLarge), \
158 S3_ERROR(MethodNotAllowed), \
159 S3_ERROR(MissingAttachment), \
160 S3_ERROR(MissingContentLength), \
161 S3_ERROR(MissingSecurityElement), \
162 S3_ERROR(MissingSecurityHeader), \
163 S3_ERROR(NoLoggingStatusForKey), \
164 S3_ERROR(NoSuchBucket), \
165 S3_ERROR(NoSuchEntity), \
166 S3_ERROR(NoSuchKey), \
167 S3_ERROR(NotImplemented), \
168 S3_ERROR(NotSignedUp), \
169 S3_ERROR(PreconditionFailed), \
170 S3_ERROR(RequestTimeout), \
171 S3_ERROR(RequestTimeTooSkewed), \
172 S3_ERROR(RequestTorrentOfBucketError), \
173 S3_ERROR(SignatureDoesNotMatch), \
174 S3_ERROR(TooManyBuckets), \
175 S3_ERROR(UnexpectedContent), \
176 S3_ERROR(UnresolvableGrantByEmailAddress), \
178 S3_ERROR(Unauthorized), \
180 S3_ERROR(Accepted), \
181 S3_ERROR(Forbidden), \
182 S3_ERROR(Conflict), \
183 S3_ERROR(AuthenticationRequired), \
187 #define S3_ERROR(NAME) S3_ERROR_ ## NAME
196 /* Does this install of curl support SSL?
201 s3_curl_supports_ssl(void);
203 /* Checks if the version of libcurl being used supports and checks
204 * wildcard certificates correctly (used for the subdomains required
205 * by location constraints).
207 * @returns: true if the version of libcurl is new enough
210 s3_curl_location_compat(void);
212 /* Checks if a bucket name is compatible with setting a location
215 * @note This doesn't guarantee that bucket name is entirely valid,
216 * just that using it as one (or more) subdomain(s) of s3.amazonaws.com
217 * won't fail; that would prevent the reporting of useful messages from
220 * @param bucket: the bucket name
221 * @returns: true if the bucket name is compatible
224 s3_bucket_location_compat(const char *bucket);
226 /* Initialize S3 operation
228 * If an error occurs in this function, diagnostic information is
231 * @returns: false if an error occurred
236 /* Set up an S3Handle.
238 * The concept of a bucket is defined by the Amazon S3 API.
239 * See: "Components of Amazon S3" - API Version 2006-03-01 pg. 8
241 * @param access_key: the secret key for Amazon Web Services
242 * @param secret_key: the secret key for Amazon Web Services
243 * @param user_token: the user token for Amazon DevPay
244 * @param bucket_location: the location constraint for buckets
245 * @param storage_class: the storage class for new objects
246 * @param ca_info: the path to pass to libcurl as the certificate authority.
247 * see curl_easy_setopt() CURLOPT_CAINFO for more
248 * @returns: the new S3Handle
251 s3_open(const char * access_key, const char *secret_key,
252 const char *swift_account_id, const char *swift_access_key,
254 const char *service_path, gboolean use_subdomain,
255 const char * user_token,
256 const char * bucket_location, const char * storage_class,
257 const char * ca_info, const char * server_side_encryption,
260 const char *username,
261 const char *password,
262 const char *tenant_id,
263 const char *tenant_name,
264 const char *client_id,
265 const char *client_secret,
266 const char *refresh_token,
267 const gboolean reuse_connection,
269 const char *reps_bucket);
271 /* latest step of setting up the S3Handle.
273 * Must be done after all properties are set.
275 * @param hdl: the S3Handle to set up.
276 * @returns: false if an error occured
279 s3_open2(S3Handle *hdl);
281 /* Deallocate an S3Handle
283 * @param hdl: the S3Handle object
286 s3_free(S3Handle *hdl);
288 /* Reset the information about the last request, including
289 * freeing any allocated memory. The S3Handle itself is not
290 * freed and may be used again. This function is called
291 * automatically as needed, and should be called to free memory
292 * when the handle will not be used for some time.
294 * @param hdl: the S3Handle object
297 s3_reset(S3Handle *hdl);
299 /* Get the error information for the last operation
301 * All results are returned via result parameters. If any parameter is
302 * NULL, that result will not be returned. Caller is not responsible for
303 * freeing any returned strings, although the results are only valid until
304 * the next call to an S3 function with this handle.
306 * @param hdl: the S3Handle object
307 * @param message: (result) the error message, or NULL if none exists
308 * @param response_code: (result) the HTTP response code (or 0 if none exists)
309 * @param s3_error_code: (result) the S3 error code (see constants, above)
310 * @param s3_error_name: (result) the S3 error name (e.g., "RequestTimeout"),
311 * or NULL if none exists
312 * @param curl_code: (result) the curl error code (or 0 if none exists)
313 * @param num_retries: (result) number of retries
316 s3_error(S3Handle *hdl,
317 const char **message,
318 guint *response_code,
319 s3_error_code_t *s3_error_code,
320 const char **s3_error_name,
324 /* Control verbose output of HTTP transactions, etc.
326 * @param hdl: the S3Handle object
327 * @param verbose: if true, send HTTP transactions, etc. to debug output
330 s3_verbose(S3Handle *hdl,
333 /* Control the use of SSL with HTTP transactions.
335 * @param hdl: the S3Handle object
336 * @param use_ssl: if true, use SSL (if curl supports it)
337 * @returns: true if the setting is valid
340 s3_use_ssl(S3Handle *hdl, gboolean use_ssl);
342 /* Control the throttling of S3 uploads. Only supported with curl >= 7.15.5.
344 * @param hdl: the S3Handle object
345 * @param max_send_speed: max speed (bytes/sec) at which to send
346 * @returns: true if the setting is valid
349 s3_set_max_send_speed(S3Handle *hdl, guint64 max_send_speed);
351 /* Control the throttling of S3 downloads. Only supported with curl >= 7.15.5.
353 * @param hdl: the S3Handle object
354 * @param max_recv_speed: max speed (bytes/sec) at which to receive
355 * @returns: true if the setting is valid
358 s3_set_max_recv_speed(S3Handle *hdl, guint64 max_recv_speed);
360 /* Get the error information from the last operation on this handle,
361 * formatted as a string.
363 * Caller is responsible for freeing the resulting string.
365 * @param hdl: the S3Handle object
366 * @returns: string, or NULL if no error occurred
369 s3_strerror(S3Handle *hdl);
371 /* Perform an upload.
373 * When this function returns, KEY and BUFFER remain the
374 * responsibility of the caller.
376 * @param hdl: the S3Handle object
377 * @param bucket: the bucket to which the upload should be made
378 * @param key: the key to which the upload should be made
379 * @param read_func: the callback for reading data
380 * @param reset_func: the callback for to reset reading data
381 * @param size_func: the callback to get the number of bytes to upload
382 * @param md5_func: the callback to get the MD5 hash of the data to upload
383 * @param read_data: pointer to pass to the above functions
384 * @param progress_func: the callback for progress information
385 * @param progress_data: pointer to pass to C{progress_func}
387 * @returns: false if an error ocurred
390 s3_upload(S3Handle *hdl,
393 s3_read_func read_func,
394 s3_reset_func reset_func,
395 s3_size_func size_func,
396 s3_md5_func md5_func,
398 s3_progress_func progress_func,
399 gpointer progress_data);
401 /* List all of the files matching the pseudo-glob C{PREFIX*DELIMITER*},
402 * returning only that portion which matches C{PREFIX*DELIMITER}. S3 supports
403 * this particular semantics, making it quite efficient. The returned list
404 * should be freed by the caller.
406 * @param hdl: the S3Handle object
407 * @param bucket: the bucket to list
408 * @param prefix: the prefix
409 * @param delimiter: delimiter (any length string)
410 * @param list: (output) the list of files
411 * @param total_size: (output) sum of size of files
412 * @returns: FALSE if an error occurs
415 s3_list_keys(S3Handle *hdl,
418 const char *delimiter,
420 guint64 *total_size);
422 /* Read an entire file, passing the contents to write_func buffer
425 * @param hdl: the S3Handle object
426 * @param bucket: the bucket to read from
427 * @param key: the key to read from
428 * @param write_func: the callback for writing data
429 * @param reset_func: the callback for to reset writing data
430 * @param write_data: pointer to pass to C{write_func}
431 * @param progress_func: the callback for progress information
432 * @param progress_data: pointer to pass to C{progress_func}
433 * @returns: FALSE if an error occurs
436 s3_read(S3Handle *hdl,
439 s3_write_func write_func,
440 s3_reset_func reset_func,
442 s3_progress_func progress_func,
443 gpointer progress_data);
447 * @param hdl: the S3Handle object
448 * @param bucket: the bucket to delete from
449 * @param key: the key to delete
450 * @returns: FALSE if an error occurs; a non-existent file is I{not} considered an error.
453 s3_delete(S3Handle *hdl,
457 /* Delete multiple file.
459 * @param hdl: the S3Handle object
460 * @param bucket: the bucket to delete from
461 * @param key: the key array to delete
462 * @returns: 0 on sucess, 1 if multi_delete is not supported, 2 if an error
463 * occurs; a non-existent file is I{not} considered an error.
466 s3_multi_delete(S3Handle *hdl,
472 * @param hdl: the S3Handle object
473 * @param bucket: the bucket to create
474 * @returns: FALSE if an error occurs
477 s3_make_bucket(S3Handle *hdl,
479 const char *project_id);
481 /* Check if a bucket exists.
483 * @param hdl: the S3Handle object
484 * @param bucket: the bucket to create
485 * @returns: FALSE if an error occur
488 s3_is_bucket_exists(S3Handle *hdl,
490 const char *project_id);
494 * @note A bucket can not be deleted if it still contains keys
496 * @param hdl: the S3Handle object
497 * @param bucket: the bucket to delete
498 * @returns: FALSE if an error occurs
501 s3_delete_bucket(S3Handle *hdl,
504 /* Attempt a RefreshAWSSecurityToken on a token; if it succeeds, the old
505 * token will be freed and replaced by the new. If it fails, the old
506 * token is left unchanged and FALSE is returned. */
507 gboolean sts_refresh_token(char ** token, const char * directory);
509 /* These functions are for if you want to use curl on your own. You get more
510 * control, but it's a lot of work that way: */
515 guint max_buffer_size;
518 #define S3_BUFFER_READ_FUNCS s3_buffer_read_func, s3_buffer_reset_func, s3_buffer_size_func, s3_buffer_md5_func
520 #define S3_BUFFER_WRITE_FUNCS s3_buffer_write_func, s3_buffer_reset_func
522 /* a CURLOPT_READFUNCTION to read data from a buffer. */
524 s3_buffer_read_func(void *ptr, size_t size, size_t nmemb, void * stream);
527 s3_buffer_size_func(void *stream);
530 s3_buffer_md5_func(void *stream);
533 s3_buffer_reset_func(void *stream);
535 #define S3_EMPTY_READ_FUNCS s3_empty_read_func, NULL, s3_empty_size_func, s3_empty_md5_func
537 /* a CURLOPT_WRITEFUNCTION to write data to a buffer. */
539 s3_buffer_write_func(void *ptr, size_t size, size_t nmemb, void *stream);
541 /* a CURLOPT_READFUNCTION that writes nothing. */
543 s3_empty_read_func(void *ptr, size_t size, size_t nmemb, void * stream);
546 s3_empty_size_func(void *stream);
549 s3_empty_md5_func(void *stream);
551 #define S3_COUNTER_WRITE_FUNCS s3_counter_write_func, s3_counter_reset_func
553 /* a CURLOPT_WRITEFUNCTION to write data that just counts data.
554 * s3_write_data should be NULL or a pointer to an gint64.
557 s3_counter_write_func(void *ptr, size_t size, size_t nmemb, void *stream);
560 s3_counter_reset_func(void *stream);
563 /* a CURLOPT_READFUNCTION to read data from a file. */
565 s3_file_read_func(void *ptr, size_t size, size_t nmemb, void * stream);
568 s3_file_size_func(void *stream);
571 s3_file_md5_func(void *stream);
574 s3_file_reset_func(void *stream);
576 /* a CURLOPT_WRITEFUNCTION to write data to a file. */
578 s3_file_write_func(void *ptr, size_t size, size_t nmemb, void *stream);
581 /* Adds a null termination to a buffer. */
582 void terminate_buffer(CurlBuffer *);