PageRenderTime 60ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

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

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

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