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

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

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

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