PageRenderTime 66ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

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

#
C | 2073 lines | 1512 code | 345 blank | 216 comment | 209 complexity | 8597b70a9c3771dc7dddf397dd05e2a1 MD5 | raw file

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

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

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