24ad9603fa70a237ba8fbb3d1209c4d7d1490969
[debian/amanda] / device-src / s3.h
1 /*
2  * Copyright (c) 2008, 2009, 2010 Zmanda, Inc.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 as published
6  * by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11  * for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16  *
17  * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
18  * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
19  */
20
21 #ifndef __S3_H__
22 #define __S3_H__
23 #include <glib.h>
24 #include <curl/curl.h>
25
26 /*
27  * Data types
28  */
29
30 /* An opaque handle.  S3Handles should only be accessed from a single
31  * thread at any given time, although it is fine to use different handles
32  * in different threads simultaneously. */
33 typedef struct S3Handle S3Handle;
34
35 /* Callback function to read data to upload
36  * 
37  * @note this is the same as CURLOPT_READFUNCTION
38  *
39  * @param data: The pointer to write data to
40  * @param size: The size of each "element" of the data buffer in bytes
41  * @param nmemb: The number of elements in the data buffer.
42  * So, the buffer's size is size*nmemb bytes.
43  * @param stream: The read_data (an opaque pointer)
44  *
45  * @return The number of bytes written to the buffer,
46  * CURL_READFUNC_PAUSE to pause, or CURL_READFUNC_ABORT to abort.
47  * Return 0 only if there's no more data to be uploaded.
48  */
49 typedef size_t (*s3_read_func)(void *data, size_t size, size_t nmemb, void *stream);
50
51 /* This function is called to get size of the upload data
52  *
53  * @param data: The write_data (opaque pointer)
54  *
55  * @return The number of bytes of data, negative for error
56  */
57 typedef size_t (*s3_size_func)(void *data);
58
59 /* This function is called to get MD5 hash of the upload data
60  *
61  * @param data: The write_data (opaque pointer)
62  *
63  * @return The MD5 hash, NULL on error
64  */
65 typedef GByteArray* (*s3_md5_func)(void *data);
66
67 /* This function is called to reset an upload or download data stream
68  * to the beginning
69  *
70  * @param data: The read_data or write_data (opaque pointer)
71  *
72  * @return The number of bytes of data, negative for error
73  */
74 typedef void (*s3_reset_func)(void *data);
75
76 /* Callback function to write data that's been downloaded
77  * 
78  * @note this is the same as CURLOPT_WRITEFUNCTION
79  *
80  * @param data: The pointer to read data from
81  * @param size: The size of each "element" of the data buffer in bytes
82  * @param nmemb: The number of elements in the data buffer.
83  * So, the buffer's size is size*nmemb bytes.
84  * @param stream: the write_data (an opaque pointer)
85  *
86  * @return The number of bytes written to the buffer or
87  * CURL_WRITEFUNC_PAUSE to pause.
88  * If it's the number of bytes written, it should match the buffer size
89  */
90 typedef size_t (*s3_write_func)(void *data, size_t size, size_t nmemb, void *stream);
91
92 /**
93  * Callback function to track progress
94  *
95  * @note this is the same as CURLOPT_PROGRESSFUNCTION
96  *
97  * @param data: The progress_data
98  * @param dltotal: The total number of bytes to downloaded
99  * @param dlnow: The current number of bytes downloaded
100  * @param ultotal: The total number of bytes to downloaded
101  * @param ulnow: The current number of bytes downloaded
102  *
103  * @return 0 to continue, non-zero to abort.
104  */
105 typedef curl_progress_callback s3_progress_func;
106
107 /*
108  * Constants
109  */
110
111 /* These are assumed to be already URL-escaped. */
112 # define STS_BASE_URL "https://ls.amazonaws.com/"
113 # define STS_PRODUCT_TOKEN "{ProductToken}AAAGQXBwVGtu4geoGybuwuk8VEEPzJ9ZANpu0yzbf9g4Gs5Iarzff9B7qaDBEEaWcAzWpcN7zmdMO765jOtEFc4DWTRNkpPSzUnTdkHbdYUamath73OreaZtB86jy/JF0gsHZfhxeKc/3aLr8HNT//DsX3r272zYHLDPWWUbFguOwqNjllnt6BshYREx59l8RrWABLSa37dyJeN+faGvz3uQxiDakZRn3LfInOE6d9+fTFl50LPoP08LCqI/SJfpouzWix7D/cep3Jq8yYNyM1rgAOTF7/wh7r8OuPDLJ/xZUDLfykePIAM="
114
115 /* This preprocessor magic will enumerate constants named S3_ERROR_XxxYyy for
116  * each of the errors in parentheses.
117  *
118  * see http://docs.amazonwebservices.com/AmazonS3/latest/API/ErrorResponses.html
119  * for Amazon's breakdown of error responses.
120  */
121 #define S3_ERROR_LIST \
122     S3_ERROR(None), \
123     S3_ERROR(AccountProblem), \
124     S3_ERROR(AllAccessDisabled), \
125     S3_ERROR(AmbiguousGrantByEmailAddress), \
126     S3_ERROR(OperationAborted), \
127     S3_ERROR(BadDigest), \
128     S3_ERROR(BucketAlreadyExists), \
129     S3_ERROR(BucketAlreadyOwnedByYou), \
130     S3_ERROR(BucketNotEmpty), \
131     S3_ERROR(CredentialsNotSupported), \
132     S3_ERROR(EntityTooLarge), \
133     S3_ERROR(IncompleteBody), \
134     S3_ERROR(InternalError), \
135     S3_ERROR(InvalidAccessKeyId), \
136     S3_ERROR(InvalidArgument), \
137     S3_ERROR(InvalidBucketName), \
138     S3_ERROR(InvalidDigest), \
139     S3_ERROR(InvalidRange), \
140     S3_ERROR(InvalidSecurity), \
141     S3_ERROR(InvalidSOAPRequest), \
142     S3_ERROR(InvalidStorageClass), \
143     S3_ERROR(InvalidTargetBucketForLogging), \
144     S3_ERROR(KeyTooLong), \
145     S3_ERROR(InvalidURI), \
146     S3_ERROR(MalformedACLError), \
147     S3_ERROR(MaxMessageLengthExceeded), \
148     S3_ERROR(MetadataTooLarge), \
149     S3_ERROR(MethodNotAllowed), \
150     S3_ERROR(MissingAttachment), \
151     S3_ERROR(MissingContentLength), \
152     S3_ERROR(MissingSecurityElement), \
153     S3_ERROR(MissingSecurityHeader), \
154     S3_ERROR(NoLoggingStatusForKey), \
155     S3_ERROR(NoSuchBucket), \
156     S3_ERROR(NoSuchEntity), \
157     S3_ERROR(NoSuchKey), \
158     S3_ERROR(NotImplemented), \
159     S3_ERROR(NotSignedUp), \
160     S3_ERROR(PreconditionFailed), \
161     S3_ERROR(RequestTimeout), \
162     S3_ERROR(RequestTimeTooSkewed), \
163     S3_ERROR(RequestTorrentOfBucketError), \
164     S3_ERROR(SignatureDoesNotMatch), \
165     S3_ERROR(TooManyBuckets), \
166     S3_ERROR(UnexpectedContent), \
167     S3_ERROR(UnresolvableGrantByEmailAddress), \
168     S3_ERROR(Unknown), \
169     S3_ERROR(Unauthorized), \
170     S3_ERROR(Created), \
171     S3_ERROR(Accepted), \
172     S3_ERROR(Forbidden), \
173     S3_ERROR(Conflict), \
174     S3_ERROR(END)
175
176 typedef enum {
177 #define S3_ERROR(NAME) S3_ERROR_ ## NAME
178     S3_ERROR_LIST
179 #undef S3_ERROR
180 } s3_error_code_t;
181
182 /*
183  * Functions
184  */
185
186 /* Does this install of curl support SSL?
187  *
188  * @returns: boolean
189  */
190 gboolean
191 s3_curl_supports_ssl(void);
192
193 /* Checks if the version of libcurl being used supports and checks
194  * wildcard certificates correctly (used for the subdomains required
195  * by location constraints).
196  *
197  * @returns: true if the version of libcurl is new enough
198  */
199 gboolean
200 s3_curl_location_compat(void);
201
202 /* Checks if a bucket name is compatible with setting a location
203  * constraint.
204  *
205  * @note This doesn't guarantee that bucket name is entirely valid,
206  * just that using it as one (or more) subdomain(s) of s3.amazonaws.com
207  * won't fail; that would prevent the reporting of useful messages from
208  * the service.
209  *
210  * @param bucket: the bucket name
211  * @returns: true if the bucket name is compatible
212  */
213 gboolean
214 s3_bucket_location_compat(const char *bucket);
215
216 /* Initialize S3 operation
217  *
218  * If an error occurs in this function, diagnostic information is
219  * printed to stderr.
220  *
221  * @returns: false if an error occurred
222  */
223 gboolean
224 s3_init(void);
225
226 /* Set up an S3Handle.
227  *
228  * The concept of a bucket is defined by the Amazon S3 API.
229  * See: "Components of Amazon S3" - API Version 2006-03-01 pg. 8
230  *
231  * @param access_key: the secret key for Amazon Web Services
232  * @param secret_key: the secret key for Amazon Web Services
233  * @param user_token: the user token for Amazon DevPay
234  * @param bucket_location: the location constraint for buckets
235  * @param storage_class: the storage class for new objects
236  * @param ca_info: the path to pass to libcurl as the certificate authority.
237  *                 see curl_easy_setopt() CURLOPT_CAINFO for more
238  * @returns: the new S3Handle
239  */
240 S3Handle *
241 s3_open(const char * access_key, const char *secret_key,
242         const char *swift_account_id, const char *swift_access_key,
243         const char *host,
244         const char *service_path, gboolean use_subdomain,
245         const char * user_token,
246         const char * bucket_location, const char * storage_class,
247         const char * ca_info, const char * server_side_encryption,
248         const gboolean openstack_swift_api);
249
250 /* Deallocate an S3Handle
251  *
252  * @param hdl: the S3Handle object
253  */
254 void
255 s3_free(S3Handle *hdl);
256
257 /* Reset the information about the last request, including
258  * freeing any allocated memory.  The S3Handle itself is not
259  * freed and may be used again.  This function is called
260  * automatically as needed, and should be called to free memory
261  * when the handle will not be used for some time.
262  *
263  * @param hdl: the S3Handle object
264  */
265 void
266 s3_reset(S3Handle *hdl);
267
268 /* Get the error information for the last operation
269  *
270  * All results are returned via result parameters.  If any parameter is
271  * NULL, that result will not be returned.  Caller is not responsible for
272  * freeing any returned strings, although the results are only valid until
273  * the next call to an S3 function with this handle.
274  *
275  * @param hdl: the S3Handle object
276  * @param message: (result) the error message, or NULL if none exists
277  * @param response_code: (result) the HTTP response code (or 0 if none exists)
278  * @param s3_error_code: (result) the S3 error code (see constants, above)
279  * @param s3_error_name: (result) the S3 error name (e.g., "RequestTimeout"),
280  * or NULL if none exists
281  * @param curl_code: (result) the curl error code (or 0 if none exists)
282  * @param num_retries: (result) number of retries
283  */
284 void
285 s3_error(S3Handle *hdl,
286          const char **message,
287          guint *response_code,
288          s3_error_code_t *s3_error_code,
289          const char **s3_error_name,
290          CURLcode *curl_code,
291          guint *num_retries);
292
293 /* Control verbose output of HTTP transactions, etc.
294  *
295  * @param hdl: the S3Handle object
296  * @param verbose: if true, send HTTP transactions, etc. to debug output
297  */
298 void
299 s3_verbose(S3Handle *hdl,
300        gboolean verbose);
301
302 /* Control the use of SSL with HTTP transactions.
303  *
304  * @param hdl: the S3Handle object
305  * @param use_ssl: if true, use SSL (if curl supports it)
306  * @returns: true if the setting is valid
307  */
308 gboolean
309 s3_use_ssl(S3Handle *hdl, gboolean use_ssl);
310
311 /* Control the throttling of S3 uploads.  Only supported with curl >= 7.15.5.
312  *
313  * @param hdl: the S3Handle object
314  * @param max_send_speed: max speed (bytes/sec) at which to send
315  * @returns: true if the setting is valid
316  */
317 gboolean
318 s3_set_max_send_speed(S3Handle *hdl, guint64 max_send_speed);
319
320 /* Control the throttling of S3 downloads.  Only supported with curl >= 7.15.5.
321  *
322  * @param hdl: the S3Handle object
323  * @param max_recv_speed: max speed (bytes/sec) at which to receive
324  * @returns: true if the setting is valid
325  */
326 gboolean
327 s3_set_max_recv_speed(S3Handle *hdl, guint64 max_recv_speed);
328
329 /* Get the error information from the last operation on this handle,
330  * formatted as a string.
331  *
332  * Caller is responsible for freeing the resulting string.
333  *
334  * @param hdl: the S3Handle object
335  * @returns: string, or NULL if no error occurred
336  */
337 char *
338 s3_strerror(S3Handle *hdl);
339
340 /* Perform an upload.
341  *
342  * When this function returns, KEY and BUFFER remain the
343  * responsibility of the caller.
344  *
345  * @param hdl: the S3Handle object
346  * @param bucket: the bucket to which the upload should be made
347  * @param key: the key to which the upload should be made
348  * @param read_func: the callback for reading data
349  * @param reset_func: the callback for to reset reading data
350  * @param size_func: the callback to get the number of bytes to upload
351  * @param md5_func: the callback to get the MD5 hash of the data to upload
352  * @param read_data: pointer to pass to the above functions
353  * @param progress_func: the callback for progress information
354  * @param progress_data: pointer to pass to C{progress_func}
355  *
356  * @returns: false if an error ocurred
357  */
358 gboolean
359 s3_upload(S3Handle *hdl,
360           const char *bucket,
361           const char *key, 
362           s3_read_func read_func,
363           s3_reset_func reset_func,
364           s3_size_func size_func,
365           s3_md5_func md5_func,
366           gpointer read_data,
367           s3_progress_func progress_func,
368           gpointer progress_data);
369
370 /* List all of the files matching the pseudo-glob C{PREFIX*DELIMITER*},
371  * returning only that portion which matches C{PREFIX*DELIMITER}.  S3 supports
372  * this particular semantics, making it quite efficient.  The returned list
373  * should be freed by the caller.
374  *
375  * @param hdl: the S3Handle object
376  * @param bucket: the bucket to list
377  * @param prefix: the prefix
378  * @param delimiter: delimiter (any length string)
379  * @param list: (output) the list of files
380  * @param total_size: (output) sum of size of files 
381  * @returns: FALSE if an error occurs
382  */
383 gboolean
384 s3_list_keys(S3Handle *hdl,
385               const char *bucket,
386               const char *prefix,
387               const char *delimiter,
388               GSList **list,
389               guint64 *total_size);
390
391 /* Read an entire file, passing the contents to write_func buffer
392  * by buffer.
393  *
394  * @param hdl: the S3Handle object
395  * @param bucket: the bucket to read from
396  * @param key: the key to read from
397  * @param write_func: the callback for writing data
398  * @param reset_func: the callback for to reset writing data
399  * @param write_data: pointer to pass to C{write_func}
400  * @param progress_func: the callback for progress information
401  * @param progress_data: pointer to pass to C{progress_func}
402  * @returns: FALSE if an error occurs
403  */
404 gboolean
405 s3_read(S3Handle *hdl,
406         const char *bucket,
407         const char *key,
408         s3_write_func write_func,
409         s3_reset_func reset_func,
410         gpointer write_data,
411         s3_progress_func progress_func,
412         gpointer progress_data);
413
414 /* Delete a file.
415  *
416  * @param hdl: the S3Handle object
417  * @param bucket: the bucket to delete from
418  * @param key: the key to delete
419  * @returns: FALSE if an error occurs; a non-existent file is I{not} considered an error.
420  */
421 gboolean
422 s3_delete(S3Handle *hdl,
423           const char *bucket,
424           const char *key);
425
426 /* Create a bucket.
427  *
428  * @param hdl: the S3Handle object
429  * @param bucket: the bucket to create
430  * @returns: FALSE if an error occurs
431  */
432 gboolean
433 s3_make_bucket(S3Handle *hdl,
434                const char *bucket);
435
436 /* Check if a bucket exists.
437  *
438  * @param hdl: the S3Handle object
439  * @param bucket: the bucket to create
440  * @returns: FALSE if an error occur
441  */
442 gboolean
443 s3_is_bucket_exists(S3Handle *hdl,
444                     const char *bucket);
445
446 /* Delete a bucket
447  *
448  * @note A bucket can not be deleted if it still contains keys
449  *
450  * @param hdl: the S3Handle object
451  * @param bucket: the bucket to delete
452  * @returns: FALSE if an error occurs
453  */
454 gboolean
455 s3_delete_bucket(S3Handle *hdl,
456                  const char *bucket);
457
458 /* Attempt a RefreshAWSSecurityToken on a token; if it succeeds, the old
459  * token will be freed and replaced by the new. If it fails, the old
460  * token is left unchanged and FALSE is returned. */
461 gboolean sts_refresh_token(char ** token, const char * directory);
462
463 /* These functions are for if you want to use curl on your own. You get more
464  * control, but it's a lot of work that way: */
465 typedef struct {
466     char *buffer;
467     guint buffer_len;
468     guint buffer_pos;
469     guint max_buffer_size;
470 } CurlBuffer;
471
472 #define S3_BUFFER_READ_FUNCS s3_buffer_read_func, s3_buffer_reset_func, s3_buffer_size_func, s3_buffer_md5_func
473
474 #define S3_BUFFER_WRITE_FUNCS s3_buffer_write_func, s3_buffer_reset_func
475
476 /* a CURLOPT_READFUNCTION to read data from a buffer. */
477 size_t
478 s3_buffer_read_func(void *ptr, size_t size, size_t nmemb, void * stream);
479
480 size_t
481 s3_buffer_size_func(void *stream);
482
483 GByteArray*
484 s3_buffer_md5_func(void *stream);
485
486 void
487 s3_buffer_reset_func(void *stream);
488
489 #define S3_EMPTY_READ_FUNCS s3_empty_read_func, NULL, s3_empty_size_func, s3_empty_md5_func
490
491 /* a CURLOPT_WRITEFUNCTION to write data to a buffer. */
492 size_t
493 s3_buffer_write_func(void *ptr, size_t size, size_t nmemb, void *stream);
494
495 /* a CURLOPT_READFUNCTION that writes nothing. */
496 size_t
497 s3_empty_read_func(void *ptr, size_t size, size_t nmemb, void * stream);
498
499 size_t
500 s3_empty_size_func(void *stream);
501
502 GByteArray*
503 s3_empty_md5_func(void *stream);
504
505 #define S3_COUNTER_WRITE_FUNCS s3_counter_write_func, s3_counter_reset_func
506
507 /* a CURLOPT_WRITEFUNCTION to write data that just counts data.
508  * s3_write_data should be NULL or a pointer to an gint64.
509  */
510 size_t
511 s3_counter_write_func(void *ptr, size_t size, size_t nmemb, void *stream);
512
513 void
514 s3_counter_reset_func(void *stream);
515
516 #ifdef _WIN32
517 /* a CURLOPT_READFUNCTION to read data from a file. */
518 size_t
519 s3_file_read_func(void *ptr, size_t size, size_t nmemb, void * stream);
520
521 size_t
522 s3_file_size_func(void *stream);
523
524 GByteArray*
525 s3_file_md5_func(void *stream);
526
527 size_t
528 s3_file_reset_func(void *stream);
529
530 /* a CURLOPT_WRITEFUNCTION to write data to a file. */
531 size_t
532 s3_file_write_func(void *ptr, size_t size, size_t nmemb, void *stream);
533 #endif
534
535 /* Adds a null termination to a buffer. */
536 void terminate_buffer(CurlBuffer *);
537
538 #endif