PageRenderTime 138ms CodeModel.GetById 19ms RepoModel.GetById 2ms app.codeStats 1ms

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

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

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