PageRenderTime 69ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 1ms

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

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

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