PageRenderTime 61ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

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

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

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