PageRenderTime 52ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/amanda/tags/3_3_0beta1/device-src/s3-device.c

#
C | 1885 lines | 1325 code | 331 blank | 229 comment | 198 complexity | 9bbbdf2f3f81b2f5ac3abf14e5459da0 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  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. /* An S3 device uses Amazon's S3 service (http://www.amazon.com/s3) to store
  21. * data. It stores data in keys named with a user-specified prefix, inside a
  22. * user-specified bucket. Data is stored in the form of numbered (large)
  23. * blocks.
  24. */
  25. #include "amanda.h"
  26. #include <string.h>
  27. #include <sys/types.h>
  28. #include <sys/stat.h>
  29. #include <unistd.h>
  30. #include <dirent.h>
  31. #include <regex.h>
  32. #include <time.h>
  33. #include "util.h"
  34. #include "conffile.h"
  35. #include "device.h"
  36. #include "s3.h"
  37. #include <curl/curl.h>
  38. #ifdef HAVE_OPENSSL_HMAC_H
  39. # include <openssl/hmac.h>
  40. #else
  41. # ifdef HAVE_CRYPTO_HMAC_H
  42. # include <crypto/hmac.h>
  43. # else
  44. # ifdef HAVE_HMAC_H
  45. # include <hmac.h>
  46. # endif
  47. # endif
  48. #endif
  49. /*
  50. * Type checking and casting macros
  51. */
  52. #define TYPE_S3_DEVICE (s3_device_get_type())
  53. #define S3_DEVICE(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), s3_device_get_type(), S3Device)
  54. #define S3_DEVICE_CONST(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), s3_device_get_type(), S3Device const)
  55. #define S3_DEVICE_CLASS(klass) G_TYPE_CHECK_CLASS_CAST((klass), s3_device_get_type(), S3DeviceClass)
  56. #define IS_S3_DEVICE(obj) G_TYPE_CHECK_INSTANCE_TYPE((obj), s3_device_get_type ())
  57. #define S3_DEVICE_GET_CLASS(obj) G_TYPE_INSTANCE_GET_CLASS((obj), s3_device_get_type(), S3DeviceClass)
  58. static GType s3_device_get_type (void);
  59. /*
  60. * Main object structure
  61. */
  62. typedef struct _S3MetadataFile S3MetadataFile;
  63. typedef struct _S3Device S3Device;
  64. struct _S3Device {
  65. Device __parent__;
  66. /* The "easy" curl handle we use to access Amazon S3 */
  67. S3Handle *s3;
  68. /* S3 access information */
  69. char *bucket;
  70. char *prefix;
  71. /* The S3 access information. */
  72. char *secret_key;
  73. char *access_key;
  74. char *user_token;
  75. char *bucket_location;
  76. char *storage_class;
  77. char *ca_info;
  78. /* a cache for unsuccessful reads (where we get the file but the caller
  79. * doesn't have space for it or doesn't want it), where we expect the
  80. * next call will request the same file.
  81. */
  82. char *cached_buf;
  83. char *cached_key;
  84. int cached_size;
  85. /* Produce verbose output? */
  86. gboolean verbose;
  87. /* Use SSL? */
  88. gboolean use_ssl;
  89. /* Throttling */
  90. guint64 max_send_speed;
  91. guint64 max_recv_speed;
  92. gboolean leom;
  93. guint64 volume_bytes;
  94. guint64 volume_limit;
  95. gboolean enforce_volume_limit;
  96. };
  97. /*
  98. * Class definition
  99. */
  100. typedef struct _S3DeviceClass S3DeviceClass;
  101. struct _S3DeviceClass {
  102. DeviceClass __parent__;
  103. };
  104. /*
  105. * Constants and static data
  106. */
  107. #define S3_DEVICE_NAME "s3"
  108. /* Maximum key length as specified in the S3 documentation
  109. * (*excluding* null terminator) */
  110. #define S3_MAX_KEY_LENGTH 1024
  111. /* Note: for compatability, min can only be decreased and max increased */
  112. #define S3_DEVICE_MIN_BLOCK_SIZE 1024
  113. #define S3_DEVICE_MAX_BLOCK_SIZE (100*1024*1024)
  114. #define S3_DEVICE_DEFAULT_BLOCK_SIZE (10*1024*1024)
  115. #define EOM_EARLY_WARNING_ZONE_BLOCKS 4
  116. /* This goes in lieu of file number for metadata. */
  117. #define SPECIAL_INFIX "special-"
  118. /* pointer to the class of our parent */
  119. static DeviceClass *parent_class = NULL;
  120. /*
  121. * device-specific properties
  122. */
  123. /* Authentication information for Amazon S3. Both of these are strings. */
  124. static DevicePropertyBase device_property_s3_access_key;
  125. static DevicePropertyBase device_property_s3_secret_key;
  126. #define PROPERTY_S3_SECRET_KEY (device_property_s3_secret_key.ID)
  127. #define PROPERTY_S3_ACCESS_KEY (device_property_s3_access_key.ID)
  128. /* Same, but for S3 with DevPay. */
  129. static DevicePropertyBase device_property_s3_user_token;
  130. #define PROPERTY_S3_USER_TOKEN (device_property_s3_user_token.ID)
  131. /* Location constraint for new buckets created on Amazon S3. */
  132. static DevicePropertyBase device_property_s3_bucket_location;
  133. #define PROPERTY_S3_BUCKET_LOCATION (device_property_s3_bucket_location.ID)
  134. /* Storage class */
  135. static DevicePropertyBase device_property_s3_storage_class;
  136. #define PROPERTY_S3_STORAGE_CLASS (device_property_s3_storage_class.ID)
  137. /* Path to certificate authority certificate */
  138. static DevicePropertyBase device_property_ssl_ca_info;
  139. #define PROPERTY_SSL_CA_INFO (device_property_ssl_ca_info.ID)
  140. /* Whether to use SSL with Amazon S3. */
  141. static DevicePropertyBase device_property_s3_ssl;
  142. #define PROPERTY_S3_SSL (device_property_s3_ssl.ID)
  143. /* Speed limits for sending and receiving */
  144. static DevicePropertyBase device_property_max_send_speed;
  145. static DevicePropertyBase device_property_max_recv_speed;
  146. #define PROPERTY_MAX_SEND_SPEED (device_property_max_send_speed.ID)
  147. #define PROPERTY_MAX_RECV_SPEED (device_property_max_recv_speed.ID)
  148. /*
  149. * prototypes
  150. */
  151. void s3_device_register(void);
  152. /*
  153. * utility functions */
  154. /* Given file and block numbers, return an S3 key.
  155. *
  156. * @param self: the S3Device object
  157. * @param file: the file number
  158. * @param block: the block within that file
  159. * @returns: a newly allocated string containing an S3 key.
  160. */
  161. static char *
  162. file_and_block_to_key(S3Device *self,
  163. int file,
  164. guint64 block);
  165. /* Given the name of a special file (such as 'tapestart'), generate
  166. * the S3 key to use for that file.
  167. *
  168. * @param self: the S3Device object
  169. * @param special_name: name of the special file
  170. * @param file: a file number to include; omitted if -1
  171. * @returns: a newly alocated string containing an S3 key.
  172. */
  173. static char *
  174. special_file_to_key(S3Device *self,
  175. char *special_name,
  176. int file);
  177. /* Write an amanda header file to S3.
  178. *
  179. * @param self: the S3Device object
  180. * @param label: the volume label
  181. * @param timestamp: the volume timestamp
  182. */
  183. static gboolean
  184. write_amanda_header(S3Device *self,
  185. char *label,
  186. char * timestamp);
  187. /* "Fast forward" this device to the end by looking up the largest file number
  188. * present and setting the current file number one greater.
  189. *
  190. * @param self: the S3Device object
  191. */
  192. static gboolean
  193. seek_to_end(S3Device *self);
  194. /* Find the number of the last file that contains any data (even just a header).
  195. *
  196. * @param self: the S3Device object
  197. * @returns: the last file, or -1 in event of an error
  198. */
  199. static int
  200. find_last_file(S3Device *self);
  201. /* Delete all blocks in the given file, including the filestart block
  202. *
  203. * @param self: the S3Device object
  204. * @param file: the file to delete
  205. */
  206. static gboolean
  207. delete_file(S3Device *self,
  208. int file);
  209. /* Delete all files in the given device
  210. *
  211. * @param self: the S3Device object
  212. */
  213. static gboolean
  214. delete_all_files(S3Device *self);
  215. /* Set up self->s3 as best as possible.
  216. *
  217. * The return value is TRUE iff self->s3 is useable.
  218. *
  219. * @param self: the S3Device object
  220. * @returns: TRUE if the handle is set up
  221. */
  222. static gboolean
  223. setup_handle(S3Device * self);
  224. /*
  225. * class mechanics */
  226. static void
  227. s3_device_init(S3Device * o);
  228. static void
  229. s3_device_class_init(S3DeviceClass * c);
  230. static void
  231. s3_device_finalize(GObject * o);
  232. static Device*
  233. s3_device_factory(char * device_name, char * device_type, char * device_node);
  234. /*
  235. * Property{Get,Set}Fns */
  236. static gboolean s3_device_set_access_key_fn(Device *self,
  237. DevicePropertyBase *base, GValue *val,
  238. PropertySurety surety, PropertySource source);
  239. static gboolean s3_device_set_secret_key_fn(Device *self,
  240. DevicePropertyBase *base, GValue *val,
  241. PropertySurety surety, PropertySource source);
  242. static gboolean s3_device_set_user_token_fn(Device *self,
  243. DevicePropertyBase *base, GValue *val,
  244. PropertySurety surety, PropertySource source);
  245. static gboolean s3_device_set_bucket_location_fn(Device *self,
  246. DevicePropertyBase *base, GValue *val,
  247. PropertySurety surety, PropertySource source);
  248. static gboolean s3_device_set_storage_class_fn(Device *self,
  249. DevicePropertyBase *base, GValue *val,
  250. PropertySurety surety, PropertySource source);
  251. static gboolean s3_device_set_ca_info_fn(Device *self,
  252. DevicePropertyBase *base, GValue *val,
  253. PropertySurety surety, PropertySource source);
  254. static gboolean s3_device_set_verbose_fn(Device *self,
  255. DevicePropertyBase *base, GValue *val,
  256. PropertySurety surety, PropertySource source);
  257. static gboolean s3_device_set_ssl_fn(Device *self,
  258. DevicePropertyBase *base, GValue *val,
  259. PropertySurety surety, PropertySource source);
  260. static gboolean s3_device_set_max_send_speed_fn(Device *self,
  261. DevicePropertyBase *base, GValue *val,
  262. PropertySurety surety, PropertySource source);
  263. static gboolean s3_device_set_max_recv_speed_fn(Device *self,
  264. DevicePropertyBase *base, GValue *val,
  265. PropertySurety surety, PropertySource source);
  266. static gboolean s3_device_set_max_volume_usage_fn(Device *p_self,
  267. DevicePropertyBase *base, GValue *val,
  268. PropertySurety surety, PropertySource source);
  269. static gboolean property_set_leom_fn(Device *p_self,
  270. DevicePropertyBase *base, GValue *val,
  271. PropertySurety surety, PropertySource source);
  272. static gboolean s3_device_set_enforce_max_volume_usage_fn(Device *p_self,
  273. DevicePropertyBase *base, GValue *val,
  274. PropertySurety surety, PropertySource source);
  275. /*
  276. * virtual functions */
  277. static void
  278. s3_device_open_device(Device *pself, char *device_name,
  279. char * device_type, char * device_node);
  280. static DeviceStatusFlags s3_device_read_label(Device * self);
  281. static gboolean
  282. s3_device_start(Device * self,
  283. DeviceAccessMode mode,
  284. char * label,
  285. char * timestamp);
  286. static gboolean
  287. s3_device_finish(Device * self);
  288. static gboolean
  289. s3_device_start_file(Device * self,
  290. dumpfile_t * jobInfo);
  291. static gboolean
  292. s3_device_write_block(Device * self,
  293. guint size,
  294. gpointer data);
  295. static gboolean
  296. s3_device_finish_file(Device * self);
  297. static dumpfile_t*
  298. s3_device_seek_file(Device *pself,
  299. guint file);
  300. static gboolean
  301. s3_device_seek_block(Device *pself,
  302. guint64 block);
  303. static int
  304. s3_device_read_block(Device * pself,
  305. gpointer data,
  306. int *size_req);
  307. static gboolean
  308. s3_device_recycle_file(Device *pself,
  309. guint file);
  310. static gboolean
  311. s3_device_erase(Device *pself);
  312. static gboolean
  313. check_at_leom(S3Device *self,
  314. guint64 size);
  315. static gboolean
  316. check_at_peom(S3Device *self,
  317. guint64 size);
  318. /*
  319. * Private functions
  320. */
  321. static char *
  322. file_and_block_to_key(S3Device *self,
  323. int file,
  324. guint64 block)
  325. {
  326. char *s3_key = g_strdup_printf("%sf%08x-b%016llx.data",
  327. self->prefix, file, (long long unsigned int)block);
  328. g_assert(strlen(s3_key) <= S3_MAX_KEY_LENGTH);
  329. return s3_key;
  330. }
  331. static char *
  332. special_file_to_key(S3Device *self,
  333. char *special_name,
  334. int file)
  335. {
  336. if (file == -1)
  337. return g_strdup_printf("%s" SPECIAL_INFIX "%s", self->prefix, special_name);
  338. else
  339. return g_strdup_printf("%sf%08x-%s", self->prefix, file, special_name);
  340. }
  341. static gboolean
  342. write_amanda_header(S3Device *self,
  343. char *label,
  344. char * timestamp)
  345. {
  346. CurlBuffer amanda_header = {NULL, 0, 0, 0};
  347. char * key = NULL;
  348. gboolean result;
  349. dumpfile_t * dumpinfo = NULL;
  350. Device *d_self = DEVICE(self);
  351. size_t header_size;
  352. /* build the header */
  353. header_size = 0; /* no minimum size */
  354. dumpinfo = make_tapestart_header(DEVICE(self), label, timestamp);
  355. amanda_header.buffer = device_build_amanda_header(DEVICE(self), dumpinfo,
  356. &header_size);
  357. if (amanda_header.buffer == NULL) {
  358. device_set_error(d_self,
  359. stralloc(_("Amanda tapestart header won't fit in a single block!")),
  360. DEVICE_STATUS_DEVICE_ERROR);
  361. dumpfile_free(dumpinfo);
  362. g_free(amanda_header.buffer);
  363. return FALSE;
  364. }
  365. if(check_at_leom(self, header_size))
  366. d_self->is_eom = TRUE;
  367. if(check_at_peom(self, header_size)) {
  368. d_self->is_eom = TRUE;
  369. device_set_error(d_self,
  370. stralloc(_("No space left on device")),
  371. DEVICE_STATUS_DEVICE_ERROR);
  372. g_free(amanda_header.buffer);
  373. return FALSE;
  374. }
  375. /* write out the header and flush the uploads. */
  376. key = special_file_to_key(self, "tapestart", -1);
  377. g_assert(header_size < G_MAXUINT); /* for cast to guint */
  378. amanda_header.buffer_len = (guint)header_size;
  379. result = s3_upload(self->s3, self->bucket, key, S3_BUFFER_READ_FUNCS,
  380. &amanda_header, NULL, NULL);
  381. g_free(amanda_header.buffer);
  382. g_free(key);
  383. if (!result) {
  384. device_set_error(d_self,
  385. vstrallocf(_("While writing amanda header: %s"), s3_strerror(self->s3)),
  386. DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
  387. dumpfile_free(dumpinfo);
  388. } else {
  389. dumpfile_free(d_self->volume_header);
  390. d_self->volume_header = dumpinfo;
  391. self->volume_bytes += header_size;
  392. }
  393. return result;
  394. }
  395. static gboolean
  396. seek_to_end(S3Device *self) {
  397. int last_file;
  398. Device *pself = DEVICE(self);
  399. last_file = find_last_file(self);
  400. if (last_file < 0)
  401. return FALSE;
  402. pself->file = last_file;
  403. return TRUE;
  404. }
  405. /* Convert an object name into a file number, assuming the given prefix
  406. * length. Returns -1 if the object name is invalid, or 0 if the object name
  407. * is a "special" key. */
  408. static int key_to_file(guint prefix_len, const char * key) {
  409. int file;
  410. int i;
  411. /* skip the prefix */
  412. if (strlen(key) <= prefix_len)
  413. return -1;
  414. key += prefix_len;
  415. if (strncmp(key, SPECIAL_INFIX, strlen(SPECIAL_INFIX)) == 0) {
  416. return 0;
  417. }
  418. /* check that key starts with 'f' */
  419. if (key[0] != 'f')
  420. return -1;
  421. key++;
  422. /* check that key is of the form "%08x-" */
  423. for (i = 0; i < 8; i++) {
  424. if (!(key[i] >= '0' && key[i] <= '9') &&
  425. !(key[i] >= 'a' && key[i] <= 'f') &&
  426. !(key[i] >= 'A' && key[i] <= 'F')) break;
  427. }
  428. if (key[i] != '-') return -1;
  429. if (i < 8) return -1;
  430. /* convert the file number */
  431. errno = 0;
  432. file = strtoul(key, NULL, 16);
  433. if (errno != 0) {
  434. g_warning(_("unparseable file number '%s'"), key);
  435. return -1;
  436. }
  437. return file;
  438. }
  439. /* Find the number of the last file that contains any data (even just a header).
  440. * Returns -1 in event of an error
  441. */
  442. static int
  443. find_last_file(S3Device *self) {
  444. gboolean result;
  445. GSList *keys;
  446. unsigned int prefix_len = strlen(self->prefix);
  447. int last_file = 0;
  448. Device *d_self = DEVICE(self);
  449. /* list all keys matching C{PREFIX*-*}, stripping the C{-*} */
  450. result = s3_list_keys(self->s3, self->bucket, self->prefix, "-", &keys, NULL);
  451. if (!result) {
  452. device_set_error(d_self,
  453. vstrallocf(_("While listing S3 keys: %s"), s3_strerror(self->s3)),
  454. DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
  455. return -1;
  456. }
  457. for (; keys; keys = g_slist_remove(keys, keys->data)) {
  458. int file = key_to_file(prefix_len, keys->data);
  459. /* and if it's the last, keep it */
  460. if (file > last_file)
  461. last_file = file;
  462. }
  463. return last_file;
  464. }
  465. /* Find the number of the file following the requested one, if any.
  466. * Returns 0 if there is no such file or -1 in event of an error
  467. */
  468. static int
  469. find_next_file(S3Device *self, int last_file) {
  470. gboolean result;
  471. GSList *keys;
  472. unsigned int prefix_len = strlen(self->prefix);
  473. int next_file = 0;
  474. Device *d_self = DEVICE(self);
  475. /* list all keys matching C{PREFIX*-*}, stripping the C{-*} */
  476. result = s3_list_keys(self->s3, self->bucket, self->prefix, "-", &keys, NULL);
  477. if (!result) {
  478. device_set_error(d_self,
  479. vstrallocf(_("While listing S3 keys: %s"), s3_strerror(self->s3)),
  480. DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
  481. return -1;
  482. }
  483. for (; keys; keys = g_slist_remove(keys, keys->data)) {
  484. int file;
  485. file = key_to_file(prefix_len, (char*)keys->data);
  486. if (file < 0) {
  487. /* Set this in case we don't find a next file; this is not a
  488. * hard error, so if we can find a next file we'll return that
  489. * instead. */
  490. next_file = -1;
  491. }
  492. if (file < next_file && file > last_file) {
  493. next_file = file;
  494. }
  495. }
  496. return next_file;
  497. }
  498. static gboolean
  499. delete_file(S3Device *self,
  500. int file)
  501. {
  502. gboolean result;
  503. GSList *keys;
  504. guint64 total_size = 0;
  505. char *my_prefix = g_strdup_printf("%sf%08x-", self->prefix, file);
  506. Device *d_self = DEVICE(self);
  507. result = s3_list_keys(self->s3, self->bucket, my_prefix, NULL, &keys, &total_size);
  508. if (!result) {
  509. device_set_error(d_self,
  510. vstrallocf(_("While listing S3 keys: %s"), s3_strerror(self->s3)),
  511. DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
  512. return FALSE;
  513. }
  514. /* this will likely be a *lot* of keys */
  515. for (; keys; keys = g_slist_remove(keys, keys->data)) {
  516. if (self->verbose) g_debug(_("Deleting %s"), (char*)keys->data);
  517. if (!s3_delete(self->s3, self->bucket, keys->data)) {
  518. device_set_error(d_self,
  519. vstrallocf(_("While deleting key '%s': %s"),
  520. (char*)keys->data, s3_strerror(self->s3)),
  521. DEVICE_STATUS_DEVICE_ERROR);
  522. g_slist_free(keys);
  523. return FALSE;
  524. }
  525. }
  526. self->volume_bytes = total_size;
  527. return TRUE;
  528. }
  529. static gboolean
  530. delete_all_files(S3Device *self)
  531. {
  532. int file, last_file;
  533. /*
  534. * Note: this has to be allowed to retry for a while because the bucket
  535. * may have been created and not yet appeared
  536. */
  537. last_file = find_last_file(self);
  538. if (last_file < 0) {
  539. guint response_code;
  540. s3_error_code_t s3_error_code;
  541. s3_error(self->s3, NULL, &response_code, &s3_error_code, NULL, NULL, NULL);
  542. /*
  543. * if the bucket doesn't exist, it doesn't conatin any files,
  544. * so the operation is a success
  545. */
  546. if ((response_code == 404 && s3_error_code == S3_ERROR_NoSuchBucket)) {
  547. /* find_last_file set an error; clear it */
  548. device_set_error(DEVICE(self), NULL, DEVICE_STATUS_SUCCESS);
  549. return TRUE;
  550. } else {
  551. /* find_last_file already set the error */
  552. return FALSE;
  553. }
  554. }
  555. for (file = 1; file <= last_file; file++) {
  556. if (!delete_file(self, file))
  557. /* delete_file already set our error message */
  558. return FALSE;
  559. }
  560. return TRUE;
  561. }
  562. /*
  563. * Class mechanics
  564. */
  565. void
  566. s3_device_register(void)
  567. {
  568. static const char * device_prefix_list[] = { S3_DEVICE_NAME, NULL };
  569. g_assert(s3_init());
  570. /* set up our properties */
  571. device_property_fill_and_register(&device_property_s3_secret_key,
  572. G_TYPE_STRING, "s3_secret_key",
  573. "Secret access key to authenticate with Amazon S3");
  574. device_property_fill_and_register(&device_property_s3_access_key,
  575. G_TYPE_STRING, "s3_access_key",
  576. "Access key ID to authenticate with Amazon S3");
  577. device_property_fill_and_register(&device_property_s3_user_token,
  578. G_TYPE_STRING, "s3_user_token",
  579. "User token for authentication Amazon devpay requests");
  580. device_property_fill_and_register(&device_property_s3_bucket_location,
  581. G_TYPE_STRING, "s3_bucket_location",
  582. "Location constraint for buckets on Amazon S3");
  583. device_property_fill_and_register(&device_property_s3_storage_class,
  584. G_TYPE_STRING, "s3_storage_class",
  585. "Storage class as specified by Amazon (STANDARD or REDUCED_REDUNDANCY)");
  586. device_property_fill_and_register(&device_property_ssl_ca_info,
  587. G_TYPE_STRING, "ssl_ca_info",
  588. "Path to certificate authority certificate");
  589. device_property_fill_and_register(&device_property_s3_ssl,
  590. G_TYPE_BOOLEAN, "s3_ssl",
  591. "Whether to use SSL with Amazon S3");
  592. device_property_fill_and_register(&device_property_max_send_speed,
  593. G_TYPE_UINT64, "max_send_speed",
  594. "Maximum average upload speed (bytes/sec)");
  595. device_property_fill_and_register(&device_property_max_recv_speed,
  596. G_TYPE_UINT64, "max_recv_speed",
  597. "Maximum average download speed (bytes/sec)");
  598. /* register the device itself */
  599. register_device(s3_device_factory, device_prefix_list);
  600. }
  601. static GType
  602. s3_device_get_type(void)
  603. {
  604. static GType type = 0;
  605. if G_UNLIKELY(type == 0) {
  606. static const GTypeInfo info = {
  607. sizeof (S3DeviceClass),
  608. (GBaseInitFunc) NULL,
  609. (GBaseFinalizeFunc) NULL,
  610. (GClassInitFunc) s3_device_class_init,
  611. (GClassFinalizeFunc) NULL,
  612. NULL /* class_data */,
  613. sizeof (S3Device),
  614. 0 /* n_preallocs */,
  615. (GInstanceInitFunc) s3_device_init,
  616. NULL
  617. };
  618. type = g_type_register_static (TYPE_DEVICE, "S3Device", &info,
  619. (GTypeFlags)0);
  620. }
  621. return type;
  622. }
  623. static void
  624. s3_device_init(S3Device * self)
  625. {
  626. Device * dself = DEVICE(self);
  627. GValue response;
  628. self->volume_bytes = 0;
  629. self->volume_limit = 0;
  630. self->leom = TRUE;
  631. self->enforce_volume_limit = FALSE;
  632. /* Register property values
  633. * Note: Some aren't added until s3_device_open_device()
  634. */
  635. bzero(&response, sizeof(response));
  636. g_value_init(&response, CONCURRENCY_PARADIGM_TYPE);
  637. g_value_set_enum(&response, CONCURRENCY_PARADIGM_SHARED_READ);
  638. device_set_simple_property(dself, PROPERTY_CONCURRENCY,
  639. &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
  640. g_value_unset(&response);
  641. g_value_init(&response, STREAMING_REQUIREMENT_TYPE);
  642. g_value_set_enum(&response, STREAMING_REQUIREMENT_NONE);
  643. device_set_simple_property(dself, PROPERTY_STREAMING,
  644. &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
  645. g_value_unset(&response);
  646. g_value_init(&response, G_TYPE_BOOLEAN);
  647. g_value_set_boolean(&response, TRUE);
  648. device_set_simple_property(dself, PROPERTY_APPENDABLE,
  649. &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
  650. g_value_unset(&response);
  651. g_value_init(&response, G_TYPE_BOOLEAN);
  652. g_value_set_boolean(&response, TRUE);
  653. device_set_simple_property(dself, PROPERTY_PARTIAL_DELETION,
  654. &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
  655. g_value_unset(&response);
  656. g_value_init(&response, G_TYPE_BOOLEAN);
  657. g_value_set_boolean(&response, TRUE);
  658. device_set_simple_property(dself, PROPERTY_FULL_DELETION,
  659. &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
  660. g_value_unset(&response);
  661. g_value_init(&response, G_TYPE_BOOLEAN);
  662. g_value_set_boolean(&response, TRUE); /* well, there *is* no EOM on S3 .. */
  663. device_set_simple_property(dself, PROPERTY_LEOM,
  664. &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
  665. g_value_unset(&response);
  666. g_value_init(&response, G_TYPE_BOOLEAN);
  667. g_value_set_boolean(&response, FALSE);
  668. device_set_simple_property(dself, PROPERTY_ENFORCE_MAX_VOLUME_USAGE,
  669. &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
  670. g_value_unset(&response);
  671. g_value_init(&response, G_TYPE_BOOLEAN);
  672. g_value_set_boolean(&response, FALSE);
  673. device_set_simple_property(dself, PROPERTY_COMPRESSION,
  674. &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
  675. g_value_unset(&response);
  676. g_value_init(&response, MEDIA_ACCESS_MODE_TYPE);
  677. g_value_set_enum(&response, MEDIA_ACCESS_MODE_READ_WRITE);
  678. device_set_simple_property(dself, PROPERTY_MEDIUM_ACCESS_TYPE,
  679. &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
  680. g_value_unset(&response);
  681. }
  682. static void
  683. s3_device_class_init(S3DeviceClass * c G_GNUC_UNUSED)
  684. {
  685. GObjectClass *g_object_class = (GObjectClass*) c;
  686. DeviceClass *device_class = (DeviceClass *)c;
  687. parent_class = g_type_class_ref (TYPE_DEVICE);
  688. device_class->open_device = s3_device_open_device;
  689. device_class->read_label = s3_device_read_label;
  690. device_class->start = s3_device_start;
  691. device_class->finish = s3_device_finish;
  692. device_class->start_file = s3_device_start_file;
  693. device_class->write_block = s3_device_write_block;
  694. device_class->finish_file = s3_device_finish_file;
  695. device_class->seek_file = s3_device_seek_file;
  696. device_class->seek_block = s3_device_seek_block;
  697. device_class->read_block = s3_device_read_block;
  698. device_class->recycle_file = s3_device_recycle_file;
  699. device_class->erase = s3_device_erase;
  700. g_object_class->finalize = s3_device_finalize;
  701. device_class_register_property(device_class, PROPERTY_S3_ACCESS_KEY,
  702. PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
  703. device_simple_property_get_fn,
  704. s3_device_set_access_key_fn);
  705. device_class_register_property(device_class, PROPERTY_S3_SECRET_KEY,
  706. PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
  707. device_simple_property_get_fn,
  708. s3_device_set_secret_key_fn);
  709. device_class_register_property(device_class, PROPERTY_S3_USER_TOKEN,
  710. PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
  711. device_simple_property_get_fn,
  712. s3_device_set_user_token_fn);
  713. device_class_register_property(device_class, PROPERTY_S3_BUCKET_LOCATION,
  714. PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
  715. device_simple_property_get_fn,
  716. s3_device_set_bucket_location_fn);
  717. device_class_register_property(device_class, PROPERTY_S3_STORAGE_CLASS,
  718. PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
  719. device_simple_property_get_fn,
  720. s3_device_set_storage_class_fn);
  721. device_class_register_property(device_class, PROPERTY_SSL_CA_INFO,
  722. PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
  723. device_simple_property_get_fn,
  724. s3_device_set_ca_info_fn);
  725. device_class_register_property(device_class, PROPERTY_VERBOSE,
  726. PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
  727. device_simple_property_get_fn,
  728. s3_device_set_verbose_fn);
  729. device_class_register_property(device_class, PROPERTY_S3_SSL,
  730. PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
  731. device_simple_property_get_fn,
  732. s3_device_set_ssl_fn);
  733. device_class_register_property(device_class, PROPERTY_MAX_SEND_SPEED,
  734. PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
  735. device_simple_property_get_fn,
  736. s3_device_set_max_send_speed_fn);
  737. device_class_register_property(device_class, PROPERTY_MAX_RECV_SPEED,
  738. PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
  739. device_simple_property_get_fn,
  740. s3_device_set_max_recv_speed_fn);
  741. device_class_register_property(device_class, PROPERTY_COMPRESSION,
  742. PROPERTY_ACCESS_GET_MASK,
  743. device_simple_property_get_fn,
  744. NULL);
  745. device_class_register_property(device_class, PROPERTY_LEOM,
  746. PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
  747. device_simple_property_get_fn,
  748. property_set_leom_fn);
  749. device_class_register_property(device_class, PROPERTY_MAX_VOLUME_USAGE,
  750. (PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_MASK) &
  751. (~ PROPERTY_ACCESS_SET_INSIDE_FILE_WRITE),
  752. device_simple_property_get_fn,
  753. s3_device_set_max_volume_usage_fn);
  754. device_class_register_property(device_class, PROPERTY_ENFORCE_MAX_VOLUME_USAGE,
  755. (PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_MASK) &
  756. (~ PROPERTY_ACCESS_SET_INSIDE_FILE_WRITE),
  757. device_simple_property_get_fn,
  758. s3_device_set_enforce_max_volume_usage_fn);
  759. }
  760. static gboolean
  761. s3_device_set_access_key_fn(Device *p_self, DevicePropertyBase *base,
  762. GValue *val, PropertySurety surety, PropertySource source)
  763. {
  764. S3Device *self = S3_DEVICE(p_self);
  765. amfree(self->access_key);
  766. self->access_key = g_value_dup_string(val);
  767. device_clear_volume_details(p_self);
  768. return device_simple_property_set_fn(p_self, base, val, surety, source);
  769. }
  770. static gboolean
  771. s3_device_set_secret_key_fn(Device *p_self, DevicePropertyBase *base,
  772. GValue *val, PropertySurety surety, PropertySource source)
  773. {
  774. S3Device *self = S3_DEVICE(p_self);
  775. amfree(self->secret_key);
  776. self->secret_key = g_value_dup_string(val);
  777. device_clear_volume_details(p_self);
  778. return device_simple_property_set_fn(p_self, base, val, surety, source);
  779. }
  780. static gboolean
  781. s3_device_set_user_token_fn(Device *p_self, DevicePropertyBase *base,
  782. GValue *val, PropertySurety surety, PropertySource source)
  783. {
  784. S3Device *self = S3_DEVICE(p_self);
  785. amfree(self->user_token);
  786. self->user_token = g_value_dup_string(val);
  787. device_clear_volume_details(p_self);
  788. return device_simple_property_set_fn(p_self, base, val, surety, source);
  789. }
  790. static gboolean
  791. s3_device_set_bucket_location_fn(Device *p_self, DevicePropertyBase *base,
  792. GValue *val, PropertySurety surety, PropertySource source)
  793. {
  794. S3Device *self = S3_DEVICE(p_self);
  795. char *str_val = g_value_dup_string(val);
  796. if (str_val[0] && self->use_ssl && !s3_curl_location_compat()) {
  797. device_set_error(p_self, stralloc(_(
  798. "Location constraint given for Amazon S3 bucket, "
  799. "but libcurl is too old support wildcard certificates.")),
  800. DEVICE_STATUS_DEVICE_ERROR);
  801. goto fail;
  802. }
  803. if (str_val[0] && !s3_bucket_location_compat(self->bucket)) {
  804. device_set_error(p_self, g_strdup_printf(_(
  805. "Location constraint given for Amazon S3 bucket, "
  806. "but the bucket name (%s) is not usable as a subdomain."),
  807. self->bucket),
  808. DEVICE_STATUS_DEVICE_ERROR);
  809. goto fail;
  810. }
  811. amfree(self->bucket_location);
  812. self->bucket_location = str_val;
  813. device_clear_volume_details(p_self);
  814. return device_simple_property_set_fn(p_self, base, val, surety, source);
  815. fail:
  816. g_free(str_val);
  817. return FALSE;
  818. }
  819. static gboolean
  820. s3_device_set_storage_class_fn(Device *p_self, DevicePropertyBase *base,
  821. GValue *val, PropertySurety surety, PropertySource source)
  822. {
  823. S3Device *self = S3_DEVICE(p_self);
  824. char *str_val = g_value_dup_string(val);
  825. amfree(self->storage_class);
  826. self->storage_class = str_val;
  827. device_clear_volume_details(p_self);
  828. return device_simple_property_set_fn(p_self, base, val, surety, source);
  829. }
  830. static gboolean
  831. s3_device_set_ca_info_fn(Device *p_self, DevicePropertyBase *base,
  832. GValue *val, PropertySurety surety, PropertySource source)
  833. {
  834. S3Device *self = S3_DEVICE(p_self);
  835. amfree(self->ca_info);
  836. self->ca_info = g_value_dup_string(val);
  837. device_clear_volume_details(p_self);
  838. return device_simple_property_set_fn(p_self, base, val, surety, source);
  839. }
  840. static gboolean
  841. s3_device_set_verbose_fn(Device *p_self, DevicePropertyBase *base,
  842. GValue *val, PropertySurety surety, PropertySource source)
  843. {
  844. S3Device *self = S3_DEVICE(p_self);
  845. self->verbose = g_value_get_boolean(val);
  846. /* Our S3 handle may not yet have been instantiated; if so, it will
  847. * get the proper verbose setting when it is created */
  848. if (self->s3)
  849. s3_verbose(self->s3, self->verbose);
  850. return device_simple_property_set_fn(p_self, base, val, surety, source);
  851. }
  852. static gboolean
  853. s3_device_set_ssl_fn(Device *p_self, DevicePropertyBase *base,
  854. GValue *val, PropertySurety surety, PropertySource source)
  855. {
  856. S3Device *self = S3_DEVICE(p_self);
  857. gboolean new_val;
  858. new_val = g_value_get_boolean(val);
  859. /* Our S3 handle may not yet have been instantiated; if so, it will
  860. * get the proper use_ssl setting when it is created */
  861. if (self->s3 && !s3_use_ssl(self->s3, new_val)) {
  862. device_set_error(p_self, g_strdup_printf(_(
  863. "Error setting S3 SSL/TLS use "
  864. "(tried to enable SSL/TLS for S3, but curl doesn't support it?)")),
  865. DEVICE_STATUS_DEVICE_ERROR);
  866. return FALSE;
  867. }
  868. self->use_ssl = new_val;
  869. return device_simple_property_set_fn(p_self, base, val, surety, source);
  870. }
  871. static gboolean
  872. s3_device_set_max_send_speed_fn(Device *p_self,
  873. DevicePropertyBase *base, GValue *val,
  874. PropertySurety surety, PropertySource source)
  875. {
  876. S3Device *self = S3_DEVICE(p_self);
  877. guint64 new_val;
  878. new_val = g_value_get_uint64(val);
  879. if (self->s3 && !s3_set_max_send_speed(self->s3, new_val)) {
  880. device_set_error(p_self,
  881. g_strdup("Could not set S3 maximum send speed"),
  882. DEVICE_STATUS_DEVICE_ERROR);
  883. return FALSE;
  884. }
  885. self->max_send_speed = new_val;
  886. return device_simple_property_set_fn(p_self, base, val, surety, source);
  887. }
  888. static gboolean
  889. s3_device_set_max_recv_speed_fn(Device *p_self,
  890. DevicePropertyBase *base, GValue *val,
  891. PropertySurety surety, PropertySource source)
  892. {
  893. S3Device *self = S3_DEVICE(p_self);
  894. guint64 new_val;
  895. new_val = g_value_get_uint64(val);
  896. if (self->s3 && !s3_set_max_recv_speed(self->s3, new_val)) {
  897. device_set_error(p_self,
  898. g_strdup("Could not set S3 maximum recv speed"),
  899. DEVICE_STATUS_DEVICE_ERROR);
  900. return FALSE;
  901. }
  902. self->max_recv_speed = new_val;
  903. return device_simple_property_set_fn(p_self, base, val, surety, source);
  904. }
  905. static gboolean
  906. s3_device_set_max_volume_usage_fn(Device *p_self,
  907. DevicePropertyBase *base, GValue *val,
  908. PropertySurety surety, PropertySource source)
  909. {
  910. S3Device *self = S3_DEVICE(p_self);
  911. self->volume_limit = g_value_get_uint64(val);
  912. return device_simple_property_set_fn(p_self, base, val, surety, source);
  913. }
  914. static gboolean
  915. s3_device_set_enforce_max_volume_usage_fn(Device *p_self,
  916. DevicePropertyBase *base, GValue *val,
  917. PropertySurety surety, PropertySource source)
  918. {
  919. S3Device *self = S3_DEVICE(p_self);
  920. self->enforce_volume_limit = g_value_get_boolean(val);
  921. return device_simple_property_set_fn(p_self, base, val, surety, source);
  922. }
  923. static gboolean
  924. property_set_leom_fn(Device *p_self,
  925. DevicePropertyBase *base, GValue *val,
  926. PropertySurety surety, PropertySource source)
  927. {
  928. S3Device *self = S3_DEVICE(p_self);
  929. self->leom = g_value_get_boolean(val);
  930. return device_simple_property_set_fn(p_self, base, val, surety, source);
  931. }
  932. static Device*
  933. s3_device_factory(char * device_name, char * device_type, char * device_node)
  934. {
  935. Device *rval;
  936. S3Device * s3_rval;
  937. g_assert(0 == strcmp(device_type, S3_DEVICE_NAME));
  938. rval = DEVICE(g_object_new(TYPE_S3_DEVICE, NULL));
  939. s3_rval = (S3Device*)rval;
  940. device_open_device(rval, device_name, device_type, device_node);
  941. return rval;
  942. }
  943. /*
  944. * Virtual function overrides
  945. */
  946. static void
  947. s3_device_open_device(Device *pself, char *device_name,
  948. char * device_type, char * device_node)
  949. {
  950. S3Device *self = S3_DEVICE(pself);
  951. char * name_colon;
  952. GValue tmp_value;
  953. pself->min_block_size = S3_DEVICE_MIN_BLOCK_SIZE;
  954. pself->max_block_size = S3_DEVICE_MAX_BLOCK_SIZE;
  955. pself->block_size = S3_DEVICE_DEFAULT_BLOCK_SIZE;
  956. /* Device name may be bucket/prefix, to support multiple volumes in a
  957. * single bucket. */
  958. name_colon = strchr(device_node, '/');
  959. if (name_colon == NULL) {
  960. self->bucket = g_strdup(device_node);
  961. self->prefix = g_strdup("");
  962. } else {
  963. self->bucket = g_strndup(device_node, name_colon - device_node);
  964. self->prefix = g_strdup(name_colon + 1);
  965. }
  966. if (self->bucket == NULL || self->bucket[0] == '\0') {
  967. device_set_error(pself,
  968. vstrallocf(_("Empty bucket name in device %s"), device_name),
  969. DEVICE_STATUS_DEVICE_ERROR);
  970. amfree(self->bucket);
  971. amfree(self->prefix);
  972. return;
  973. }
  974. g_debug(_("S3 driver using bucket '%s', prefix '%s'"), self->bucket, self->prefix);
  975. /* default values */
  976. self->verbose = FALSE;
  977. /* use SSL if available */
  978. self->use_ssl = s3_curl_supports_ssl();
  979. bzero(&tmp_value, sizeof(GValue));
  980. g_value_init(&tmp_value, G_TYPE_BOOLEAN);
  981. g_value_set_boolean(&tmp_value, self->use_ssl);
  982. device_set_simple_property(pself, device_property_s3_ssl.ID,
  983. &tmp_value, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DEFAULT);
  984. if (parent_class->open_device) {
  985. parent_class->open_device(pself, device_name, device_type, device_node);
  986. }
  987. }
  988. static void s3_device_finalize(GObject * obj_self) {
  989. S3Device *self = S3_DEVICE (obj_self);
  990. if(G_OBJECT_CLASS(parent_class)->finalize)
  991. (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
  992. if(self->s3) s3_free(self->s3);
  993. if(self->bucket) g_free(self->bucket);
  994. if(self->prefix) g_free(self->prefix);
  995. if(self->access_key) g_free(self->access_key);
  996. if(self->secret_key) g_free(self->secret_key);
  997. if(self->user_token) g_free(self->user_token);
  998. if(self->bucket_location) g_free(self->bucket_location);
  999. if(self->storage_class) g_free(self->storage_class);
  1000. if(self->ca_info) g_free(self->ca_info);
  1001. }
  1002. static gboolean setup_handle(S3Device * self) {
  1003. Device *d_self = DEVICE(self);
  1004. if (self->s3 == NULL) {
  1005. if (self->access_key == NULL || self->access_key[0] == '\0') {
  1006. device_set_error(d_self,
  1007. stralloc(_("No Amazon access key specified")),
  1008. DEVICE_STATUS_DEVICE_ERROR);
  1009. return FALSE;
  1010. }
  1011. if (self->secret_key == NULL || self->secret_key[0] == '\0') {
  1012. device_set_error(d_self,
  1013. stralloc(_("No Amazon secret key specified")),
  1014. DEVICE_STATUS_DEVICE_ERROR);
  1015. return FALSE;
  1016. }
  1017. if (!self->use_ssl && self->ca_info) {
  1018. amfree(self->ca_info);
  1019. }
  1020. self->s3 = s3_open(self->access_key, self->secret_key, self->user_token,
  1021. self->bucket_location, self->storage_class, self->ca_info);
  1022. if (self->s3 == NULL) {
  1023. device_set_error(d_self,
  1024. stralloc(_("Internal error creating S3 handle")),
  1025. DEVICE_STATUS_DEVICE_ERROR);
  1026. return FALSE;
  1027. }
  1028. }
  1029. s3_verbose(self->s3, self->verbose);
  1030. if (!s3_use_ssl(self->s3, self->use_ssl)) {
  1031. device_set_error(d_self, g_strdup_printf(_(
  1032. "Error setting S3 SSL/TLS use "
  1033. "(tried to enable SSL/TLS for S3, but curl doesn't support it?)")),
  1034. DEVICE_STATUS_DEVICE_ERROR);
  1035. return FALSE;
  1036. }
  1037. if (self->max_send_speed &&
  1038. !s3_set_max_send_speed(self->s3, self->max_send_speed)) {
  1039. device_set_error(d_self,
  1040. g_strdup("Could not set S3 maximum send speed"),
  1041. DEVICE_STATUS_DEVICE_ERROR);
  1042. return FALSE;
  1043. }
  1044. if (self->max_recv_speed &&
  1045. !s3_set_max_recv_speed(self->s3, self->max_recv_speed)) {
  1046. device_set_error(d_self,
  1047. g_strdup("Could not set S3 maximum recv speed"),
  1048. DEVICE_STATUS_DEVICE_ERROR);
  1049. return FALSE;
  1050. }
  1051. return TRUE;
  1052. }
  1053. static DeviceStatusFlags
  1054. s3_device_read_label(Device *pself) {
  1055. S3Device *self = S3_DEVICE(pself);
  1056. char *key;
  1057. CurlBuffer buf = {NULL, 0, 0, S3_DEVICE_MAX_BLOCK_SIZE};
  1058. dumpfile_t *amanda_header;
  1059. /* note that this may be called from s3_device_start, when
  1060. * self->access_mode is not ACCESS_NULL */
  1061. amfree(pself->volume_label);
  1062. amfree(pself->volume_time);
  1063. dumpfile_free(pself->volume_header);
  1064. pself->volume_header = NULL;
  1065. if (device_in_error(self)) return pself->status;
  1066. if (!setup_handle(self)) {
  1067. /* setup_handle already set our error message */
  1068. return pself->status;
  1069. }
  1070. key = special_file_to_key(self, "tapestart", -1);
  1071. if (!s3_read(self->s3, self->bucket, key, S3_BUFFER_WRITE_FUNCS, &buf, NULL, NULL)) {
  1072. guint response_code;
  1073. s3_error_code_t s3_error_code;
  1074. s3_error(self->s3, NULL, &response_code, &s3_error_code, NULL, NULL, NULL);
  1075. /* if it's an expected error (not found), just return FALSE */
  1076. if (response_code == 404 &&
  1077. (s3_error_code == S3_ERROR_NoSuchKey || s3_error_code == S3_ERROR_NoSuchBucket)) {
  1078. g_debug(_("Amanda header not found while reading tapestart header (this is expected for empty tapes)"));
  1079. device_set_error(pself,
  1080. stralloc(_("Amanda header not found -- unlabeled volume?")),
  1081. DEVICE_STATUS_DEVICE_ERROR
  1082. | DEVICE_STATUS_VOLUME_ERROR
  1083. | DEVICE_STATUS_VOLUME_UNLABELED);
  1084. return pself->status;
  1085. }
  1086. /* otherwise, log it and return */
  1087. device_set_error(pself,
  1088. vstrallocf(_("While trying to read tapestart header: %s"), s3_strerror(self->s3)),
  1089. DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
  1090. return pself->status;
  1091. }
  1092. /* handle an empty file gracefully */
  1093. if (buf.buffer_len == 0) {
  1094. device_set_error(pself, stralloc(_("Empty header file")), DEVICE_STATUS_VOLUME_ERROR);
  1095. return pself->status;
  1096. }
  1097. g_assert(buf.buffer != NULL);
  1098. amanda_header = g_new(dumpfile_t, 1);
  1099. parse_file_header(buf.buffer, amanda_header, buf.buffer_pos);
  1100. pself->volume_header = amanda_header;
  1101. g_free(buf.buffer);
  1102. if (amanda_header->type != F_TAPESTART) {
  1103. device_set_error(pself, stralloc(_("Invalid amanda header")), DEVICE_STATUS_VOLUME_ERROR);
  1104. return pself->status;
  1105. }
  1106. pself->volume_label = g_strdup(amanda_header->name);
  1107. pself->volume_time = g_strdup(amanda_header->datestamp);
  1108. /* pself->volume_header is already set */
  1109. device_set_error(pself, NULL, DEVICE_STATUS_SUCCESS);
  1110. return pself->status;
  1111. }
  1112. static gboolean
  1113. s3_device_start (Device * pself, DeviceAccessMode mode,
  1114. char * label, char * timestamp) {
  1115. S3Device * self;
  1116. GSList *keys;
  1117. guint64 total_size = 0;
  1118. gboolean result;
  1119. self = S3_DEVICE(pself);
  1120. if (device_in_error(self)) return FALSE;
  1121. if (!setup_handle(self)) {
  1122. /* setup_handle already set our error message */
  1123. return FALSE;
  1124. }
  1125. pself->access_mode = mode;
  1126. pself->in_file = FALSE;
  1127. /* try creating the bucket, in case it doesn't exist */
  1128. if (mode != ACCESS_READ && !s3_make_bucket(self->s3, self->bucket)) {
  1129. guint response_code;
  1130. s3_error_code_t s3_error_code;
  1131. s3_error(self->s3, NULL, &response_code, &s3_error_code, NULL, NULL, NULL);
  1132. /* if it isn't an expected error (bucket already exists),
  1133. * return FALSE */
  1134. if (response_code != 409 ||
  1135. s3_error_code != S3_ERROR_BucketAlreadyExists) {
  1136. device_set_error(pself,
  1137. vstrallocf(_("While creating new S3 bucket: %s"), s3_strerror(self->s3)),
  1138. DEVICE_STATUS_DEVICE_ERROR);
  1139. return FALSE;
  1140. }
  1141. }
  1142. /* take care of any dirty work for this mode */
  1143. switch (mode) {
  1144. case ACCESS_READ:
  1145. if (pself->volume_label == NULL && s3_device_read_label(pself) != DEVICE_STATUS_SUCCESS) {
  1146. /* s3_device_read_label already set our error message */
  1147. return FALSE;
  1148. }
  1149. break;
  1150. case ACCESS_WRITE:
  1151. delete_all_files(self);
  1152. /* write a new amanda header */
  1153. if (!write_amanda_header(self, label, timestamp)) {
  1154. return FALSE;
  1155. }
  1156. pself->volume_label = newstralloc(pself->volume_label, label);
  1157. pself->volume_time = newstralloc(pself->volume_time, timestamp);
  1158. /* unset the VOLUME_UNLABELED flag, if it was set */
  1159. device_set_error(pself, NULL, DEVICE_STATUS_SUCCESS);
  1160. break;
  1161. case ACCESS_APPEND:
  1162. if (pself->volume_label == NULL && s3_device_read_label(pself) != DEVICE_STATUS_SUCCESS) {
  1163. /* s3_device_read_label already set our error message */
  1164. return FALSE;
  1165. } else {
  1166. result = s3_list_keys(self->s3, self->bucket, NULL, NULL, &keys, &total_size);
  1167. if(!result) {
  1168. device_set_error(pself,
  1169. vstrallocf(_("While listing S3 keys: %s"), s3_strerror(self->s3)),
  1170. DEVICE_STATUS_DEVICE_ERROR|DEVICE_STATUS_VOLUME_ERROR);
  1171. return FALSE;
  1172. } else {
  1173. self->volume_bytes = total_size;
  1174. }
  1175. }
  1176. return seek_to_end(self);
  1177. break;
  1178. case ACCESS_NULL:
  1179. g_assert_not_reached();
  1180. }
  1181. return TRUE;
  1182. }
  1183. static gboolean
  1184. s3_device_finish (Device * pself) {
  1185. /* we're not in a file anymore */
  1186. pself->access_mode = ACCESS_NULL;
  1187. if (device_in_error(pself)) return FALSE;
  1188. return TRUE;
  1189. }
  1190. /* functions for writing */
  1191. static gboolean
  1192. s3_device_start_file (Device *pself, dumpfile_t *jobInfo) {
  1193. S3Device *self = S3_DEVICE(pself);
  1194. CurlBuffer amanda_header = {NULL, 0, 0, 0};
  1195. gboolean result;
  1196. size_t header_size;
  1197. char *key;
  1198. if (device_in_error(self)) return FALSE;
  1199. pself->is_eom = FALSE;
  1200. /* Set the blocksize to zero, since there's no header to skip (it's stored
  1201. * in a distinct file, rather than block zero) */
  1202. jobInfo->blocksize = 0;
  1203. /* Build the amanda header. */
  1204. header_size = 0; /* no minimum size */
  1205. amanda_header.buffer = device_build_amanda_header(pself, jobInfo,
  1206. &header_size);
  1207. if (amanda_header.buffer == NULL) {
  1208. device_set_error(pself,
  1209. stralloc(_("Amanda file header won't fit in a single block!")),
  1210. DEVICE_STATUS_DEVICE_ERROR);
  1211. return FALSE;
  1212. }
  1213. amanda_header.buffer_len = header_size;
  1214. if(check_at_leom(self, header_size))
  1215. pself->is_eom = TRUE;
  1216. if(check_at_peom(self, header_size)) {
  1217. pself->is_eom = TRUE;
  1218. device_set_error(pself,
  1219. stralloc(_("No space left on device")),
  1220. DEVICE_STATUS_DEVICE_ERROR);
  1221. g_free(amanda_header.buffer);
  1222. return FALSE;
  1223. }
  1224. /* set the file and block numbers correctly */
  1225. pself->file = (pself->file > 0)? pself->file+1 : 1;
  1226. pself->block = 0;
  1227. pself->in_file = TRUE;
  1228. /* write it out as a special block (not the 0th) */
  1229. key = special_file_to_key(self, "filestart", pself->file);
  1230. result = s3_upload(self->s3, self->bucket, key, S3_BUFFER_READ_FUNCS,
  1231. &amanda_header, NULL, NULL);
  1232. g_free(amanda_header.buffer);
  1233. g_free(key);
  1234. if (!result) {
  1235. device_set_error(pself,
  1236. vstrallocf(_("While writing filestart header: %s"), s3_strerror(self->s3)),
  1237. DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
  1238. return FALSE;
  1239. }
  1240. self->volume_bytes += header_size;
  1241. return TRUE;
  1242. }
  1243. static gboolean
  1244. s3_device_write_block (Device * pself, guint size, gpointer data) {
  1245. gboolean result;
  1246. char *filename;
  1247. S3Device * self = S3_DEVICE(pself);
  1248. CurlBuffer to_write = {data, size, 0, 0};
  1249. g_assert (self != NULL);
  1250. g_assert (data != NULL);
  1251. if (device_in_error(self)) return FALSE;
  1252. if(check_at_leom(self, size))
  1253. pself->is_eom = TRUE;
  1254. if(check_at_peom(self, size)) {
  1255. pself->is_eom = TRUE;
  1256. device_set_error(pself,
  1257. stralloc(_("No space left on device")),
  1258. DEVICE_STATUS_DEVICE_ERROR);
  1259. return FALSE;
  1260. }
  1261. filename = file_and_block_to_key(self, pself->file, pself->block);
  1262. result = s3_upload(self->s3, self->bucket, filename, S3_BUFFER_READ_FUNCS,
  1263. &to_write, NULL, NULL);
  1264. g_free(filename);
  1265. if (!result) {
  1266. device_set_error(pself,
  1267. vstrallocf(_("While writing data block to S3: %s"), s3_strerror(self->s3)),
  1268. DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
  1269. return FALSE;
  1270. }
  1271. pself->block++;
  1272. self->volume_bytes += size;
  1273. return TRUE;
  1274. }
  1275. static gboolean
  1276. s3_device_finish_file (Device * pself) {
  1277. if (device_in_error(pself)) return FALSE;
  1278. /* we're not in a file anymore */
  1279. pself->in_file = FALSE;
  1280. return TRUE;
  1281. }
  1282. static gboolean
  1283. s3_device_recycle_file(Device *pself, guint file) {
  1284. S3Device *self = S3_DEVICE(pself);
  1285. if (device_in_error(self)) return FALSE;
  1286. return delete_file(self, file);
  1287. /* delete_file already set our error message if necessary */
  1288. }
  1289. static gboolean
  1290. s3_device_erase(Device *pself) {
  1291. S3Device *self = S3_DEVICE(pself);
  1292. char *key = NULL;
  1293. const char *errmsg = NULL;
  1294. guint response_code;
  1295. s3_error_code_t s3_error_code;
  1296. if (!setup_handle(self)) {
  1297. /* error set by setup_handle */
  1298. return FALSE;
  1299. }
  1300. key = special_file_to_key(self, "tapestart", -1);
  1301. if (!s3_delete(self->s3, self->bucket, key)) {
  1302. s3_error(self->s3, &errmsg, NULL, NULL, NULL, NULL, NULL);
  1303. device_set_error(pself,
  1304. stralloc(errmsg),
  1305. DEVICE_STATUS_DEVICE_ERROR);
  1306. return FALSE;
  1307. }
  1308. g_free(key);
  1309. if (!delete_all_files(self))
  1310. return FALSE;
  1311. if (!s3_delete_bucket(self->s3, self->bucket)) {
  1312. s3_error(self->s3, NULL, &response_code, &s3_error_code, NULL, NULL, NULL);
  1313. /*
  1314. * ignore the error if the bucket isn't empty (there may be data from elsewhere)
  1315. * or the bucket not existing (already deleted perhaps?)
  1316. */
  1317. if (!(
  1318. (response_code == 409 && s3_error_code == S3_ERROR_BucketNotEmpty) ||
  1319. (response_code == 404 && s3_error_code == S3_ERROR_NoSuchBucket))) {
  1320. device_set_error(pself,
  1321. stralloc(errmsg),
  1322. DEVICE_STATUS_DEVICE_ERROR);
  1323. re

Large files files are truncated, but you can click here to view the full file