PageRenderTime 62ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

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

#
C | 1711 lines | 1180 code | 302 blank | 229 comment | 181 complexity | ee081ca5f911f8c76b1e6ed239692e3e MD5 | raw 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, FALSE);
  626. device_set_simple_property(dself, PROPERTY_COMPRESSION,
  627. &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
  628. g_value_unset(&response);
  629. g_value_init(&response, MEDIA_ACCESS_MODE_TYPE);
  630. g_value_set_enum(&response, MEDIA_ACCESS_MODE_READ_WRITE);
  631. device_set_simple_property(dself, PROPERTY_MEDIUM_ACCESS_TYPE,
  632. &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
  633. g_value_unset(&response);
  634. }
  635. static void
  636. s3_device_class_init(S3DeviceClass * c G_GNUC_UNUSED)
  637. {
  638. GObjectClass *g_object_class = (GObjectClass*) c;
  639. DeviceClass *device_class = (DeviceClass *)c;
  640. parent_class = g_type_class_ref (TYPE_DEVICE);
  641. device_class->open_device = s3_device_open_device;
  642. device_class->read_label = s3_device_read_label;
  643. device_class->start = s3_device_start;
  644. device_class->finish = s3_device_finish;
  645. device_class->start_file = s3_device_start_file;
  646. device_class->write_block = s3_device_write_block;
  647. device_class->finish_file = s3_device_finish_file;
  648. device_class->seek_file = s3_device_seek_file;
  649. device_class->seek_block = s3_device_seek_block;
  650. device_class->read_block = s3_device_read_block;
  651. device_class->recycle_file = s3_device_recycle_file;
  652. device_class->erase = s3_device_erase;
  653. g_object_class->finalize = s3_device_finalize;
  654. device_class_register_property(device_class, PROPERTY_S3_ACCESS_KEY,
  655. PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
  656. device_simple_property_get_fn,
  657. s3_device_set_access_key_fn);
  658. device_class_register_property(device_class, PROPERTY_S3_SECRET_KEY,
  659. PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
  660. device_simple_property_get_fn,
  661. s3_device_set_secret_key_fn);
  662. device_class_register_property(device_class, PROPERTY_S3_USER_TOKEN,
  663. PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
  664. device_simple_property_get_fn,
  665. s3_device_set_user_token_fn);
  666. device_class_register_property(device_class, PROPERTY_S3_BUCKET_LOCATION,
  667. PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
  668. device_simple_property_get_fn,
  669. s3_device_set_bucket_location_fn);
  670. device_class_register_property(device_class, PROPERTY_S3_STORAGE_CLASS,
  671. PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
  672. device_simple_property_get_fn,
  673. s3_device_set_storage_class_fn);
  674. device_class_register_property(device_class, PROPERTY_SSL_CA_INFO,
  675. PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
  676. device_simple_property_get_fn,
  677. s3_device_set_ca_info_fn);
  678. device_class_register_property(device_class, PROPERTY_VERBOSE,
  679. PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
  680. device_simple_property_get_fn,
  681. s3_device_set_verbose_fn);
  682. device_class_register_property(device_class, PROPERTY_S3_SSL,
  683. PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
  684. device_simple_property_get_fn,
  685. s3_device_set_ssl_fn);
  686. device_class_register_property(device_class, PROPERTY_MAX_SEND_SPEED,
  687. PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
  688. device_simple_property_get_fn,
  689. s3_device_set_max_send_speed_fn);
  690. device_class_register_property(device_class, PROPERTY_MAX_RECV_SPEED,
  691. PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
  692. device_simple_property_get_fn,
  693. s3_device_set_max_recv_speed_fn);
  694. device_class_register_property(device_class, PROPERTY_COMPRESSION,
  695. PROPERTY_ACCESS_GET_MASK,
  696. device_simple_property_get_fn,
  697. NULL);
  698. }
  699. static gboolean
  700. s3_device_set_access_key_fn(Device *p_self, DevicePropertyBase *base,
  701. GValue *val, PropertySurety surety, PropertySource source)
  702. {
  703. S3Device *self = S3_DEVICE(p_self);
  704. amfree(self->access_key);
  705. self->access_key = g_value_dup_string(val);
  706. device_clear_volume_details(p_self);
  707. return device_simple_property_set_fn(p_self, base, val, surety, source);
  708. }
  709. static gboolean
  710. s3_device_set_secret_key_fn(Device *p_self, DevicePropertyBase *base,
  711. GValue *val, PropertySurety surety, PropertySource source)
  712. {
  713. S3Device *self = S3_DEVICE(p_self);
  714. amfree(self->secret_key);
  715. self->secret_key = g_value_dup_string(val);
  716. device_clear_volume_details(p_self);
  717. return device_simple_property_set_fn(p_self, base, val, surety, source);
  718. }
  719. static gboolean
  720. s3_device_set_user_token_fn(Device *p_self, DevicePropertyBase *base,
  721. GValue *val, PropertySurety surety, PropertySource source)
  722. {
  723. S3Device *self = S3_DEVICE(p_self);
  724. amfree(self->user_token);
  725. self->user_token = g_value_dup_string(val);
  726. device_clear_volume_details(p_self);
  727. return device_simple_property_set_fn(p_self, base, val, surety, source);
  728. }
  729. static gboolean
  730. s3_device_set_bucket_location_fn(Device *p_self, DevicePropertyBase *base,
  731. GValue *val, PropertySurety surety, PropertySource source)
  732. {
  733. S3Device *self = S3_DEVICE(p_self);
  734. char *str_val = g_value_dup_string(val);
  735. if (str_val[0] && self->use_ssl && !s3_curl_location_compat()) {
  736. device_set_error(p_self, stralloc(_(
  737. "Location constraint given for Amazon S3 bucket, "
  738. "but libcurl is too old support wildcard certificates.")),
  739. DEVICE_STATUS_DEVICE_ERROR);
  740. goto fail;
  741. }
  742. if (str_val[0] && !s3_bucket_location_compat(self->bucket)) {
  743. device_set_error(p_self, g_strdup_printf(_(
  744. "Location constraint given for Amazon S3 bucket, "
  745. "but the bucket name (%s) is not usable as a subdomain."),
  746. self->bucket),
  747. DEVICE_STATUS_DEVICE_ERROR);
  748. goto fail;
  749. }
  750. amfree(self->bucket_location);
  751. self->bucket_location = str_val;
  752. device_clear_volume_details(p_self);
  753. return device_simple_property_set_fn(p_self, base, val, surety, source);
  754. fail:
  755. g_free(str_val);
  756. return FALSE;
  757. }
  758. static gboolean
  759. s3_device_set_storage_class_fn(Device *p_self, DevicePropertyBase *base,
  760. GValue *val, PropertySurety surety, PropertySource source)
  761. {
  762. S3Device *self = S3_DEVICE(p_self);
  763. char *str_val = g_value_dup_string(val);
  764. amfree(self->storage_class);
  765. self->storage_class = str_val;
  766. device_clear_volume_details(p_self);
  767. return device_simple_property_set_fn(p_self, base, val, surety, source);
  768. }
  769. static gboolean
  770. s3_device_set_ca_info_fn(Device *p_self, DevicePropertyBase *base,
  771. GValue *val, PropertySurety surety, PropertySource source)
  772. {
  773. S3Device *self = S3_DEVICE(p_self);
  774. if (!self->use_ssl) {
  775. device_set_error(p_self, stralloc(_(
  776. "Path to certificate authority certificate can not be "
  777. "set if SSL/TLS is not being used.")),
  778. DEVICE_STATUS_DEVICE_ERROR);
  779. return FALSE;
  780. }
  781. amfree(self->ca_info);
  782. self->ca_info = g_value_dup_string(val);
  783. device_clear_volume_details(p_self);
  784. return device_simple_property_set_fn(p_self, base, val, surety, source);
  785. }
  786. static gboolean
  787. s3_device_set_verbose_fn(Device *p_self, DevicePropertyBase *base,
  788. GValue *val, PropertySurety surety, PropertySource source)
  789. {
  790. S3Device *self = S3_DEVICE(p_self);
  791. self->verbose = g_value_get_boolean(val);
  792. /* Our S3 handle may not yet have been instantiated; if so, it will
  793. * get the proper verbose setting when it is created */
  794. if (self->s3)
  795. s3_verbose(self->s3, self->verbose);
  796. return device_simple_property_set_fn(p_self, base, val, surety, source);
  797. }
  798. static gboolean
  799. s3_device_set_ssl_fn(Device *p_self, DevicePropertyBase *base,
  800. GValue *val, PropertySurety surety, PropertySource source)
  801. {
  802. S3Device *self = S3_DEVICE(p_self);
  803. gboolean new_val;
  804. new_val = g_value_get_boolean(val);
  805. /* Our S3 handle may not yet have been instantiated; if so, it will
  806. * get the proper use_ssl setting when it is created */
  807. if (self->s3 && !s3_use_ssl(self->s3, new_val)) {
  808. device_set_error(p_self, g_strdup_printf(_(
  809. "Error setting S3 SSL/TLS use "
  810. "(tried to enable SSL/TLS for S3, but curl doesn't support it?)")),
  811. DEVICE_STATUS_DEVICE_ERROR);
  812. return FALSE;
  813. }
  814. self->use_ssl = new_val;
  815. return device_simple_property_set_fn(p_self, base, val, surety, source);
  816. }
  817. static gboolean
  818. s3_device_set_max_send_speed_fn(Device *p_self,
  819. DevicePropertyBase *base, GValue *val,
  820. PropertySurety surety, PropertySource source)
  821. {
  822. S3Device *self = S3_DEVICE(p_self);
  823. guint64 new_val;
  824. new_val = g_value_get_uint64(val);
  825. if (self->s3 && !s3_set_max_send_speed(self->s3, new_val)) {
  826. device_set_error(p_self,
  827. g_strdup("Could not set S3 maximum send speed"),
  828. DEVICE_STATUS_DEVICE_ERROR);
  829. return FALSE;
  830. }
  831. self->max_send_speed = new_val;
  832. return device_simple_property_set_fn(p_self, base, val, surety, source);
  833. }
  834. static gboolean
  835. s3_device_set_max_recv_speed_fn(Device *p_self,
  836. DevicePropertyBase *base, GValue *val,
  837. PropertySurety surety, PropertySource source)
  838. {
  839. S3Device *self = S3_DEVICE(p_self);
  840. guint64 new_val;
  841. new_val = g_value_get_uint64(val);
  842. if (self->s3 && !s3_set_max_recv_speed(self->s3, new_val)) {
  843. device_set_error(p_self,
  844. g_strdup("Could not set S3 maximum recv speed"),
  845. DEVICE_STATUS_DEVICE_ERROR);
  846. return FALSE;
  847. }
  848. self->max_recv_speed = new_val;
  849. return device_simple_property_set_fn(p_self, base, val, surety, source);
  850. }
  851. static Device*
  852. s3_device_factory(char * device_name, char * device_type, char * device_node)
  853. {
  854. Device *rval;
  855. S3Device * s3_rval;
  856. g_assert(0 == strcmp(device_type, S3_DEVICE_NAME));
  857. rval = DEVICE(g_object_new(TYPE_S3_DEVICE, NULL));
  858. s3_rval = (S3Device*)rval;
  859. device_open_device(rval, device_name, device_type, device_node);
  860. return rval;
  861. }
  862. /*
  863. * Virtual function overrides
  864. */
  865. static void
  866. s3_device_open_device(Device *pself, char *device_name,
  867. char * device_type, char * device_node)
  868. {
  869. S3Device *self = S3_DEVICE(pself);
  870. char * name_colon;
  871. GValue tmp_value;
  872. pself->min_block_size = S3_DEVICE_MIN_BLOCK_SIZE;
  873. pself->max_block_size = S3_DEVICE_MAX_BLOCK_SIZE;
  874. pself->block_size = S3_DEVICE_DEFAULT_BLOCK_SIZE;
  875. /* Device name may be bucket/prefix, to support multiple volumes in a
  876. * single bucket. */
  877. name_colon = strchr(device_node, '/');
  878. if (name_colon == NULL) {
  879. self->bucket = g_strdup(device_node);
  880. self->prefix = g_strdup("");
  881. } else {
  882. self->bucket = g_strndup(device_node, name_colon - device_node);
  883. self->prefix = g_strdup(name_colon + 1);
  884. }
  885. if (self->bucket == NULL || self->bucket[0] == '\0') {
  886. device_set_error(pself,
  887. vstrallocf(_("Empty bucket name in device %s"), device_name),
  888. DEVICE_STATUS_DEVICE_ERROR);
  889. amfree(self->bucket);
  890. amfree(self->prefix);
  891. return;
  892. }
  893. g_debug(_("S3 driver using bucket '%s', prefix '%s'"), self->bucket, self->prefix);
  894. /* default values */
  895. self->verbose = FALSE;
  896. /* use SSL if available */
  897. self->use_ssl = s3_curl_supports_ssl();
  898. bzero(&tmp_value, sizeof(GValue));
  899. g_value_init(&tmp_value, G_TYPE_BOOLEAN);
  900. g_value_set_boolean(&tmp_value, self->use_ssl);
  901. device_set_simple_property(pself, device_property_s3_ssl.ID,
  902. &tmp_value, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DEFAULT);
  903. if (parent_class->open_device) {
  904. parent_class->open_device(pself, device_name, device_type, device_node);
  905. }
  906. }
  907. static void s3_device_finalize(GObject * obj_self) {
  908. S3Device *self = S3_DEVICE (obj_self);
  909. if(G_OBJECT_CLASS(parent_class)->finalize)
  910. (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
  911. if(self->s3) s3_free(self->s3);
  912. if(self->bucket) g_free(self->bucket);
  913. if(self->prefix) g_free(self->prefix);
  914. if(self->access_key) g_free(self->access_key);
  915. if(self->secret_key) g_free(self->secret_key);
  916. if(self->user_token) g_free(self->user_token);
  917. if(self->bucket_location) g_free(self->bucket_location);
  918. if(self->storage_class) g_free(self->storage_class);
  919. if(self->ca_info) g_free(self->ca_info);
  920. }
  921. static gboolean setup_handle(S3Device * self) {
  922. Device *d_self = DEVICE(self);
  923. if (self->s3 == NULL) {
  924. if (self->access_key == NULL || self->access_key[0] == '\0') {
  925. device_set_error(d_self,
  926. stralloc(_("No Amazon access key specified")),
  927. DEVICE_STATUS_DEVICE_ERROR);
  928. return FALSE;
  929. }
  930. if (self->secret_key == NULL || self->secret_key[0] == '\0') {
  931. device_set_error(d_self,
  932. stralloc(_("No Amazon secret key specified")),
  933. DEVICE_STATUS_DEVICE_ERROR);
  934. return FALSE;
  935. }
  936. self->s3 = s3_open(self->access_key, self->secret_key, self->user_token,
  937. self->bucket_location, self->storage_class, self->ca_info);
  938. if (self->s3 == NULL) {
  939. device_set_error(d_self,
  940. stralloc(_("Internal error creating S3 handle")),
  941. DEVICE_STATUS_DEVICE_ERROR);
  942. return FALSE;
  943. }
  944. }
  945. s3_verbose(self->s3, self->verbose);
  946. if (!s3_use_ssl(self->s3, self->use_ssl)) {
  947. device_set_error(d_self, g_strdup_printf(_(
  948. "Error setting S3 SSL/TLS use "
  949. "(tried to enable SSL/TLS for S3, but curl doesn't support it?)")),
  950. DEVICE_STATUS_DEVICE_ERROR);
  951. return FALSE;
  952. }
  953. if (self->max_send_speed &&
  954. !s3_set_max_send_speed(self->s3, self->max_send_speed)) {
  955. device_set_error(d_self,
  956. g_strdup("Could not set S3 maximum send speed"),
  957. DEVICE_STATUS_DEVICE_ERROR);
  958. return FALSE;
  959. }
  960. if (self->max_recv_speed &&
  961. !s3_set_max_recv_speed(self->s3, self->max_recv_speed)) {
  962. device_set_error(d_self,
  963. g_strdup("Could not set S3 maximum recv speed"),
  964. DEVICE_STATUS_DEVICE_ERROR);
  965. return FALSE;
  966. }
  967. return TRUE;
  968. }
  969. static DeviceStatusFlags
  970. s3_device_read_label(Device *pself) {
  971. S3Device *self = S3_DEVICE(pself);
  972. char *key;
  973. CurlBuffer buf = {NULL, 0, 0, S3_DEVICE_MAX_BLOCK_SIZE};
  974. dumpfile_t *amanda_header;
  975. /* note that this may be called from s3_device_start, when
  976. * self->access_mode is not ACCESS_NULL */
  977. amfree(pself->volume_label);
  978. amfree(pself->volume_time);
  979. dumpfile_free(pself->volume_header);
  980. pself->volume_header = NULL;
  981. if (device_in_error(self)) return pself->status;
  982. if (!setup_handle(self)) {
  983. /* setup_handle already set our error message */
  984. return pself->status;
  985. }
  986. key = special_file_to_key(self, "tapestart", -1);
  987. if (!s3_read(self->s3, self->bucket, key, S3_BUFFER_WRITE_FUNCS, &buf, NULL, NULL)) {
  988. guint response_code;
  989. s3_error_code_t s3_error_code;
  990. s3_error(self->s3, NULL, &response_code, &s3_error_code, NULL, NULL, NULL);
  991. /* if it's an expected error (not found), just return FALSE */
  992. if (response_code == 404 &&
  993. (s3_error_code == S3_ERROR_NoSuchKey || s3_error_code == S3_ERROR_NoSuchBucket)) {
  994. g_debug(_("Amanda header not found while reading tapestart header (this is expected for empty tapes)"));
  995. device_set_error(pself,
  996. stralloc(_("Amanda header not found -- unlabeled volume?")),
  997. DEVICE_STATUS_DEVICE_ERROR
  998. | DEVICE_STATUS_VOLUME_ERROR
  999. | DEVICE_STATUS_VOLUME_UNLABELED);
  1000. return pself->status;
  1001. }
  1002. /* otherwise, log it and return */
  1003. device_set_error(pself,
  1004. vstrallocf(_("While trying to read tapestart header: %s"), s3_strerror(self->s3)),
  1005. DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
  1006. return pself->status;
  1007. }
  1008. /* handle an empty file gracefully */
  1009. if (buf.buffer_len == 0) {
  1010. device_set_error(pself, stralloc(_("Empty header file")), DEVICE_STATUS_VOLUME_ERROR);
  1011. return pself->status;
  1012. }
  1013. g_assert(buf.buffer != NULL);
  1014. amanda_header = g_new(dumpfile_t, 1);
  1015. parse_file_header(buf.buffer, amanda_header, buf.buffer_pos);
  1016. pself->volume_header = amanda_header;
  1017. g_free(buf.buffer);
  1018. if (amanda_header->type != F_TAPESTART) {
  1019. device_set_error(pself, stralloc(_("Invalid amanda header")), DEVICE_STATUS_VOLUME_ERROR);
  1020. return pself->status;
  1021. }
  1022. pself->volume_label = g_strdup(amanda_header->name);
  1023. pself->volume_time = g_strdup(amanda_header->datestamp);
  1024. /* pself->volume_header is already set */
  1025. device_set_error(pself, NULL, DEVICE_STATUS_SUCCESS);
  1026. return pself->status;
  1027. }
  1028. static gboolean
  1029. s3_device_start (Device * pself, DeviceAccessMode mode,
  1030. char * label, char * timestamp) {
  1031. S3Device * self;
  1032. self = S3_DEVICE(pself);
  1033. if (device_in_error(self)) return FALSE;
  1034. if (!setup_handle(self)) {
  1035. /* setup_handle already set our error message */
  1036. return FALSE;
  1037. }
  1038. pself->access_mode = mode;
  1039. pself->in_file = FALSE;
  1040. /* try creating the bucket, in case it doesn't exist */
  1041. if (mode != ACCESS_READ && !s3_make_bucket(self->s3, self->bucket)) {
  1042. guint response_code;
  1043. s3_error_code_t s3_error_code;
  1044. s3_error(self->s3, NULL, &response_code, &s3_error_code, NULL, NULL, NULL);
  1045. /* if it isn't an expected error (bucket already exists),
  1046. * return FALSE */
  1047. if (response_code != 409 ||
  1048. s3_error_code != S3_ERROR_BucketAlreadyExists) {
  1049. device_set_error(pself,
  1050. vstrallocf(_("While creating new S3 bucket: %s"), s3_strerror(self->s3)),
  1051. DEVICE_STATUS_DEVICE_ERROR);
  1052. return FALSE;
  1053. }
  1054. }
  1055. /* take care of any dirty work for this mode */
  1056. switch (mode) {
  1057. case ACCESS_READ:
  1058. if (pself->volume_label == NULL && s3_device_read_label(pself) != DEVICE_STATUS_SUCCESS) {
  1059. /* s3_device_read_label already set our error message */
  1060. return FALSE;
  1061. }
  1062. break;
  1063. case ACCESS_WRITE:
  1064. delete_all_files(self);
  1065. /* write a new amanda header */
  1066. if (!write_amanda_header(self, label, timestamp)) {
  1067. return FALSE;
  1068. }
  1069. pself->volume_label = newstralloc(pself->volume_label, label);
  1070. pself->volume_time = newstralloc(pself->volume_time, timestamp);
  1071. /* unset the VOLUME_UNLABELED flag, if it was set */
  1072. device_set_error(pself, NULL, DEVICE_STATUS_SUCCESS);
  1073. break;
  1074. case ACCESS_APPEND:
  1075. if (pself->volume_label == NULL && s3_device_read_label(pself) != DEVICE_STATUS_SUCCESS) {
  1076. /* s3_device_read_label already set our error message */
  1077. return FALSE;
  1078. }
  1079. return seek_to_end(self);
  1080. break;
  1081. case ACCESS_NULL:
  1082. g_assert_not_reached();
  1083. }
  1084. return TRUE;
  1085. }
  1086. static gboolean
  1087. s3_device_finish (Device * pself) {
  1088. if (device_in_error(pself)) return FALSE;
  1089. /* we're not in a file anymore */
  1090. pself->access_mode = ACCESS_NULL;
  1091. return TRUE;
  1092. }
  1093. /* functions for writing */
  1094. static gboolean
  1095. s3_device_start_file (Device *pself, dumpfile_t *jobInfo) {
  1096. S3Device *self = S3_DEVICE(pself);
  1097. CurlBuffer amanda_header = {NULL, 0, 0, 0};
  1098. gboolean result;
  1099. size_t header_size;
  1100. char *key;
  1101. if (device_in_error(self)) return FALSE;
  1102. pself->is_eom = FALSE;
  1103. /* Set the blocksize to zero, since there's no header to skip (it's stored
  1104. * in a distinct file, rather than block zero) */
  1105. jobInfo->blocksize = 0;
  1106. /* Build the amanda header. */
  1107. header_size = 0; /* no minimum size */
  1108. amanda_header.buffer = device_build_amanda_header(pself, jobInfo,
  1109. &header_size);
  1110. if (amanda_header.buffer == NULL) {
  1111. device_set_error(pself,
  1112. stralloc(_("Amanda file header won't fit in a single block!")),
  1113. DEVICE_STATUS_DEVICE_ERROR);
  1114. return FALSE;
  1115. }
  1116. amanda_header.buffer_len = header_size;
  1117. /* set the file and block numbers correctly */
  1118. pself->file = (pself->file > 0)? pself->file+1 : 1;
  1119. pself->block = 0;
  1120. pself->in_file = TRUE;
  1121. /* write it out as a special block (not the 0th) */
  1122. key = special_file_to_key(self, "filestart", pself->file);
  1123. result = s3_upload(self->s3, self->bucket, key, S3_BUFFER_READ_FUNCS,
  1124. &amanda_header, NULL, NULL);
  1125. g_free(amanda_header.buffer);
  1126. g_free(key);
  1127. if (!result) {
  1128. device_set_error(pself,
  1129. vstrallocf(_("While writing filestart header: %s"), s3_strerror(self->s3)),
  1130. DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
  1131. return FALSE;
  1132. }
  1133. return TRUE;
  1134. }
  1135. static gboolean
  1136. s3_device_write_block (Device * pself, guint size, gpointer data) {
  1137. gboolean result;
  1138. char *filename;
  1139. S3Device * self = S3_DEVICE(pself);
  1140. CurlBuffer to_write = {data, size, 0, 0};
  1141. g_assert (self != NULL);
  1142. g_assert (data != NULL);
  1143. if (device_in_error(self)) return FALSE;
  1144. filename = file_and_block_to_key(self, pself->file, pself->block);
  1145. result = s3_upload(self->s3, self->bucket, filename, S3_BUFFER_READ_FUNCS,
  1146. &to_write, NULL, NULL);
  1147. g_free(filename);
  1148. if (!result) {
  1149. device_set_error(pself,
  1150. vstrallocf(_("While writing data block to S3: %s"), s3_strerror(self->s3)),
  1151. DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
  1152. return FALSE;
  1153. }
  1154. pself->block++;
  1155. return TRUE;
  1156. }
  1157. static gboolean
  1158. s3_device_finish_file (Device * pself) {
  1159. if (device_in_error(pself)) return FALSE;
  1160. /* we're not in a file anymore */
  1161. pself->in_file = FALSE;
  1162. return TRUE;
  1163. }
  1164. static gboolean
  1165. s3_device_recycle_file(Device *pself, guint file) {
  1166. S3Device *self = S3_DEVICE(pself);
  1167. if (device_in_error(self)) return FALSE;
  1168. return delete_file(self, file);
  1169. /* delete_file already set our error message if necessary */
  1170. }
  1171. static gboolean
  1172. s3_device_erase(Device *pself) {
  1173. S3Device *self = S3_DEVICE(pself);
  1174. char *key = NULL;
  1175. const char *errmsg = NULL;
  1176. guint response_code;
  1177. s3_error_code_t s3_error_code;
  1178. if (!setup_handle(self)) {
  1179. /* error set by setup_handle */
  1180. return FALSE;
  1181. }
  1182. key = special_file_to_key(self, "tapestart", -1);
  1183. if (!s3_delete(self->s3, self->bucket, key)) {
  1184. s3_error(self->s3, &errmsg, NULL, NULL, NULL, NULL, NULL);
  1185. device_set_error(pself,
  1186. stralloc(errmsg),
  1187. DEVICE_STATUS_DEVICE_ERROR);
  1188. return FALSE;
  1189. }
  1190. g_free(key);
  1191. if (!delete_all_files(self))
  1192. return FALSE;
  1193. if (!s3_delete_bucket(self->s3, self->bucket)) {
  1194. s3_error(self->s3, NULL, &response_code, &s3_error_code, NULL, NULL, NULL);
  1195. /*
  1196. * ignore the error if the bucket isn't empty (there may be data from elsewhere)
  1197. * or the bucket not existing (already deleted perhaps?)
  1198. */
  1199. if (!(
  1200. (response_code == 409 && s3_error_code == S3_ERROR_BucketNotEmpty) ||
  1201. (response_code == 404 && s3_error_code == S3_ERROR_NoSuchBucket))) {
  1202. device_set_error(pself,
  1203. stralloc(errmsg),
  1204. DEVICE_STATUS_DEVICE_ERROR);
  1205. return FALSE;
  1206. }
  1207. }
  1208. return TRUE;
  1209. }
  1210. /* functions for reading */
  1211. static dumpfile_t*
  1212. s3_device_seek_file(Device *pself, guint file) {
  1213. S3Device *self = S3_DEVICE(pself);
  1214. gboolean result;
  1215. char *key;
  1216. CurlBuffer buf = {NULL, 0, 0, S3_DEVICE_MAX_BLOCK_SIZE};
  1217. dumpfile_t *amanda_header;
  1218. const char *errmsg = NULL;
  1219. if (device_in_error(self)) return NULL;
  1220. pself->file = file;
  1221. pself->is_eof = FALSE;
  1222. pself->in_file = FALSE;
  1223. pself->block = 0;
  1224. /* read it in */
  1225. key = special_file_to_key(self, "filestart", pself->file);
  1226. result = s3_read(self->s3, self->bucket, key, S3_BUFFER_WRITE_FUNCS,
  1227. &buf, NULL, NULL);
  1228. g_free(key);
  1229. if (!result) {
  1230. guint response_code;
  1231. s3_error_code_t s3_error_code;
  1232. s3_error(self->s3, &errmsg, &response_code, &s3_error_code, NULL, NULL, NULL);
  1233. /* if it's an expected error (not found), check what to do. */
  1234. if (response_code == 404 && s3_error_code == S3_ERROR_NoSuchKey) {
  1235. int next_file;
  1236. next_file = find_next_file(self, pself->file);
  1237. if (next_file > 0) {
  1238. /* Note short-circut of dispatcher. */
  1239. return s3_device_seek_file(pself, next_file);
  1240. } else if (next_file == 0) {
  1241. /* No next file. Check if we are one past the end. */
  1242. key = special_file_to_key(self, "filestart", pself->file - 1);
  1243. result = s3_read(self->s3, self->bucket, key,
  1244. S3_BUFFER_WRITE_FUNCS, &buf, NULL, NULL);
  1245. g_free(key);
  1246. if (result) {
  1247. /* pself->file, etc. are already correct */
  1248. return make_tapeend_header();
  1249. } else {
  1250. device_set_error(pself,
  1251. stralloc(_("Attempt to read past tape-end file")),
  1252. DEVICE_STATUS_SUCCESS);
  1253. return NULL;
  1254. }
  1255. }
  1256. } else {
  1257. /* An unexpected error occured finding out if we are the last file. */
  1258. device_set_error(pself,
  1259. stralloc(errmsg),
  1260. DEVICE_STATUS_DEVICE_ERROR);
  1261. return NULL;
  1262. }
  1263. }
  1264. /* and make a dumpfile_t out of it */
  1265. g_assert(buf.buffer != NULL);
  1266. amanda_header = g_new(dumpfile_t, 1);
  1267. fh_init(amanda_header);
  1268. parse_file_header(buf.buffer, amanda_header, buf.buffer_pos);
  1269. g_free(buf.buffer);
  1270. switch (amanda_header->type) {
  1271. case F_DUMPFILE:
  1272. case F_CONT_DUMPFILE:
  1273. case F_SPLIT_DUMPFILE:
  1274. break;
  1275. default:
  1276. device_set_error(pself,
  1277. stralloc(_("Invalid amanda header while reading file header")),
  1278. DEVICE_STATUS_VOLUME_ERROR);
  1279. g_free(amanda_header);
  1280. return NULL;
  1281. }
  1282. pself->in_file = TRUE;
  1283. return amanda_header;
  1284. }
  1285. static gboolean
  1286. s3_device_seek_block(Device *pself, guint64 block) {
  1287. if (device_in_error(pself)) return FALSE;
  1288. pself->block = block;
  1289. return TRUE;
  1290. }
  1291. typedef struct s3_read_block_data {
  1292. gpointer data;
  1293. int size_req;
  1294. int size_written;
  1295. CurlBuffer curl;
  1296. } s3_read_block_data;
  1297. /* wrapper around s3_buffer_write_func to write as much data as possible to
  1298. * the user's buffer, and switch to a dynamically allocated buffer if that
  1299. * isn't large enough */
  1300. static size_t
  1301. s3_read_block_write_func(void *ptr, size_t size, size_t nmemb, void *stream)
  1302. {
  1303. s3_read_block_data *dat = stream;
  1304. guint new_bytes, bytes_needed;
  1305. /* if data is NULL, call through to s3_buffer_write_func */
  1306. if (!dat->data) {
  1307. return s3_buffer_write_func(ptr, size, nmemb, (void *)(&dat->curl));
  1308. }
  1309. new_bytes = (guint) size * nmemb;
  1310. bytes_needed = dat->size_written + new_bytes;
  1311. if (bytes_needed > (guint)dat->size_req) {
  1312. /* this read will overflow the user's buffer, so malloc ourselves
  1313. * a new buffer and keep reading */
  1314. dat->curl.buffer = g_malloc(bytes_needed);
  1315. dat->curl.buffer_len = bytes_needed;
  1316. dat->curl.buffer_pos = dat->size_written;
  1317. memcpy(dat->curl.buffer, dat->data, dat->size_written);
  1318. dat->data = NULL; /* signal that the user's buffer is too small */
  1319. return s3_buffer_write_func(ptr, size, nmemb, (void *)(&dat->curl));
  1320. }
  1321. /* copy it into the dat->data buffer, and increment the size */
  1322. memcpy(dat->data + dat->size_written, ptr, new_bytes);
  1323. dat->size_written += new_bytes;
  1324. return new_bytes;
  1325. }
  1326. static int
  1327. s3_device_read_block (Device * pself, gpointer data, int *size_req) {
  1328. S3Device * self = S3_DEVICE(pself);
  1329. char *key;
  1330. s3_read_block_data dat = {NULL, 0, 0, { NULL, 0, 0, S3_DEVICE_MAX_BLOCK_SIZE} };
  1331. gboolean result;
  1332. g_assert (self != NULL);
  1333. if (device_in_error(self)) return -1;
  1334. /* get the file*/
  1335. key = file_and_block_to_key(self, pself->file, pself->block);
  1336. g_assert(key != NULL);
  1337. if (self->cached_key && (0 == strcmp(key, self->cached_key))) {
  1338. if (*size_req >= self->cached_size) {
  1339. /* use the cached copy and clear the cache */
  1340. memcpy(data, self->cached_buf, self->cached_size);
  1341. *size_req = self->cached_size;
  1342. g_free(key);
  1343. g_free(self->cached_key);
  1344. self->cached_key = NULL;
  1345. g_free(self->cached_buf);
  1346. self->cached_buf = NULL;
  1347. pself->block++;
  1348. return *size_req;
  1349. } else {
  1350. *size_req = self->cached_size;
  1351. g_free(key);
  1352. return 0;
  1353. }
  1354. }
  1355. /* clear the cache, as it's useless to us */
  1356. if (self->cached_key) {
  1357. g_free(self->cached_key);
  1358. self->cached_key = NULL;
  1359. g_free(self->cached_buf);
  1360. self->cached_buf = NULL;
  1361. }
  1362. /* set up dat for the write_func callback */
  1363. if (!data || *size_req <= 0) {
  1364. dat.data = NULL;
  1365. dat.size_req = 0;
  1366. } else {
  1367. dat.data = data;
  1368. dat.size_req = *size_req;
  1369. }
  1370. result = s3_read(self->s3, self->bucket, key, s3_read_block_write_func,
  1371. s3_buffer_reset_func, &dat, NULL, NULL);
  1372. if (!result) {
  1373. guint response_code;
  1374. s3_error_code_t s3_error_code;
  1375. s3_error(self->s3, NULL, &response_code, &s3_error_code, NULL, NULL, NULL);
  1376. g_free(key);
  1377. key = NULL;
  1378. /* if it's an expected error (not found), just return -1 */
  1379. if (response_code == 404 && s3_error_code == S3_ERROR_NoSuchKey) {
  1380. pself->is_eof = TRUE;
  1381. pself->in_file = FALSE;
  1382. device_set_error(pself,
  1383. stralloc(_("EOF")),
  1384. DEVICE_STATUS_SUCCESS);
  1385. return -1;
  1386. }
  1387. /* otherwise, log it and return FALSE */
  1388. device_set_error(pself,
  1389. vstrallocf(_("While reading data block from S3: %s"), s3_strerror(self->s3)),
  1390. DEVICE_STATUS_VOLUME_ERROR);
  1391. return -1;
  1392. }
  1393. if (dat.data == NULL) {
  1394. /* data was larger than the available space, so cache it and return
  1395. * the actual size */
  1396. self->cached_buf = dat.curl.buffer;
  1397. self->cached_size = dat.curl.buffer_pos;
  1398. self->cached_key = key;
  1399. key = NULL;
  1400. *size_req = dat.curl.buffer_pos;
  1401. return 0;
  1402. }
  1403. /* ok, the read went directly to the user's buffer, so we need only
  1404. * set and return the size */
  1405. pself->block++;
  1406. g_free(key);
  1407. *size_req = dat.size_written;
  1408. return dat.size_written;
  1409. }