PageRenderTime 416ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/amanda/branches/3_3/device-src/s3-device.c

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