+ amfree(self->server_side_encryption);
+ self->server_side_encryption = str_val;
+ device_clear_volume_details(p_self);
+
+ return device_simple_property_set_fn(p_self, base, val, surety, source);
+}
+
+static gboolean
+s3_device_set_ca_info_fn(Device *p_self, DevicePropertyBase *base,
+ GValue *val, PropertySurety surety, PropertySource source)
+{
+ S3Device *self = S3_DEVICE(p_self);
+
+ amfree(self->ca_info);
+ self->ca_info = g_value_dup_string(val);
+ device_clear_volume_details(p_self);
+
+ return device_simple_property_set_fn(p_self, base, val, surety, source);
+}
+
+static gboolean
+s3_device_set_verbose_fn(Device *p_self, DevicePropertyBase *base,
+ GValue *val, PropertySurety surety, PropertySource source)
+{
+ S3Device *self = S3_DEVICE(p_self);
+ int thread;
+
+ self->verbose = g_value_get_boolean(val);
+ /* Our S3 handle may not yet have been instantiated; if so, it will
+ * get the proper verbose setting when it is created */
+ if (self->s3t) {
+ for (thread = 0; thread < self->nb_threads; thread++) {
+ if (self->s3t[thread].s3)
+ s3_verbose(self->s3t[thread].s3, self->verbose);
+ }
+ }
+
+ return device_simple_property_set_fn(p_self, base, val, surety, source);
+}
+
+static gboolean
+s3_device_set_openstack_swift_api_fn(Device *p_self, DevicePropertyBase *base,
+ GValue *val, PropertySurety surety, PropertySource source)
+{
+ S3Device *self = S3_DEVICE(p_self);
+
+ self->openstack_swift_api = g_value_get_boolean(val);
+
+ return device_simple_property_set_fn(p_self, base, val, surety, source);
+}
+
+static gboolean
+s3_device_set_ssl_fn(Device *p_self, DevicePropertyBase *base,
+ GValue *val, PropertySurety surety, PropertySource source)
+{
+ S3Device *self = S3_DEVICE(p_self);
+ gboolean new_val;
+ int thread;
+
+ new_val = g_value_get_boolean(val);
+ /* Our S3 handle may not yet have been instantiated; if so, it will
+ * get the proper use_ssl setting when it is created */
+ if (self->s3t) {
+ for (thread = 0; thread < self->nb_threads; thread++) {
+ if (self->s3t[thread].s3 && !s3_use_ssl(self->s3t[thread].s3, new_val)) {
+ device_set_error(p_self, g_strdup_printf(_(
+ "Error setting S3 SSL/TLS use "
+ "(tried to enable SSL/TLS for S3, but curl doesn't support it?)")),
+ DEVICE_STATUS_DEVICE_ERROR);
+ return FALSE;
+ }
+ }
+ }
+ self->use_ssl = new_val;
+
+ return device_simple_property_set_fn(p_self, base, val, surety, source);
+}
+
+static gboolean
+s3_device_set_max_send_speed_fn(Device *p_self,
+ DevicePropertyBase *base, GValue *val,
+ PropertySurety surety, PropertySource source)
+{
+ S3Device *self = S3_DEVICE(p_self);
+ guint64 new_val;
+ int thread;
+
+ new_val = g_value_get_uint64(val);
+ if (self->s3t) {
+ for (thread = 0; thread < self->nb_threads; thread++) {
+ if (self->s3t[thread].s3 && !s3_set_max_send_speed(self->s3t[thread].s3, new_val)) {
+ device_set_error(p_self,
+ g_strdup("Could not set S3 maximum send speed"),
+ DEVICE_STATUS_DEVICE_ERROR);
+ return FALSE;
+ }
+ }
+ }
+ self->max_send_speed = new_val;
+
+ return device_simple_property_set_fn(p_self, base, val, surety, source);
+}
+
+static gboolean
+s3_device_set_max_recv_speed_fn(Device *p_self,
+ DevicePropertyBase *base, GValue *val,
+ PropertySurety surety, PropertySource source)
+{
+ S3Device *self = S3_DEVICE(p_self);
+ guint64 new_val;
+ int thread;
+
+ new_val = g_value_get_uint64(val);
+ if (self->s3t) {
+ for (thread = 0; thread < self->nb_threads; thread++) {
+ if (self->s3t[thread].s3 &&
+ !s3_set_max_recv_speed(self->s3t[thread].s3, new_val)) {
+ device_set_error(p_self,
+ g_strdup("Could not set S3 maximum recv speed"),
+ DEVICE_STATUS_DEVICE_ERROR);
+ return FALSE;
+ }
+ }
+ }
+ self->max_recv_speed = new_val;
+
+ return device_simple_property_set_fn(p_self, base, val, surety, source);
+}
+
+static gboolean
+s3_device_set_nb_threads_backup(Device *p_self,
+ DevicePropertyBase *base, GValue *val,
+ PropertySurety surety, PropertySource source)
+{
+ S3Device *self = S3_DEVICE(p_self);
+ guint64 new_val;
+
+ new_val = g_value_get_uint64(val);
+ self->nb_threads_backup = new_val;
+ if (self->nb_threads_backup > self->nb_threads) {
+ self->nb_threads = self->nb_threads_backup;
+ }
+
+ return device_simple_property_set_fn(p_self, base, val, surety, source);
+}
+
+static gboolean
+s3_device_set_nb_threads_recovery(Device *p_self,
+ DevicePropertyBase *base, GValue *val,
+ PropertySurety surety, PropertySource source)
+{
+ S3Device *self = S3_DEVICE(p_self);
+ guint64 new_val;
+
+ new_val = g_value_get_uint64(val);
+ self->nb_threads_recovery = new_val;
+ if (self->nb_threads_recovery > self->nb_threads) {
+ self->nb_threads = self->nb_threads_recovery;
+ }
+
+ return device_simple_property_set_fn(p_self, base, val, surety, source);
+}
+
+static gboolean
+s3_device_set_max_volume_usage_fn(Device *p_self,
+ DevicePropertyBase *base, GValue *val,
+ PropertySurety surety, PropertySource source)
+{
+ S3Device *self = S3_DEVICE(p_self);
+
+ self->volume_limit = g_value_get_uint64(val);
+
+ return device_simple_property_set_fn(p_self, base, val, surety, source);
+
+}
+
+static gboolean
+s3_device_set_enforce_max_volume_usage_fn(Device *p_self,
+ DevicePropertyBase *base, GValue *val,
+ PropertySurety surety, PropertySource source)
+{
+ S3Device *self = S3_DEVICE(p_self);
+
+ self->enforce_volume_limit = g_value_get_boolean(val);
+
+ return device_simple_property_set_fn(p_self, base, val, surety, source);
+
+}
+
+static gboolean
+s3_device_set_use_subdomain_fn(Device *p_self,
+ DevicePropertyBase *base, GValue *val,
+ PropertySurety surety, PropertySource source)
+{
+ S3Device *self = S3_DEVICE(p_self);
+
+ self->use_subdomain = g_value_get_boolean(val);
+
+ return device_simple_property_set_fn(p_self, base, val, surety, source);
+}
+
+static gboolean
+property_set_leom_fn(Device *p_self,
+ DevicePropertyBase *base, GValue *val,
+ PropertySurety surety, PropertySource source)
+{
+ S3Device *self = S3_DEVICE(p_self);
+
+ self->leom = g_value_get_boolean(val);
+
+ return device_simple_property_set_fn(p_self, base, val, surety, source);
+}
+static Device*
+s3_device_factory(char * device_name, char * device_type, char * device_node)
+{
+ Device *rval;
+ g_assert(0 == strcmp(device_type, S3_DEVICE_NAME));
+ rval = DEVICE(g_object_new(TYPE_S3_DEVICE, NULL));
+
+ device_open_device(rval, device_name, device_type, device_node);
+ return rval;
+}
+
+/*
+ * Virtual function overrides
+ */
+
+static void
+s3_device_open_device(Device *pself, char *device_name,
+ char * device_type, char * device_node)
+{
+ S3Device *self = S3_DEVICE(pself);
+ char * name_colon;
+ GValue tmp_value;
+
+ pself->min_block_size = S3_DEVICE_MIN_BLOCK_SIZE;
+ pself->max_block_size = S3_DEVICE_MAX_BLOCK_SIZE;
+ pself->block_size = S3_DEVICE_DEFAULT_BLOCK_SIZE;
+
+ /* Device name may be bucket/prefix, to support multiple volumes in a
+ * single bucket. */
+ name_colon = strchr(device_node, '/');
+ if (name_colon == NULL) {
+ self->bucket = g_strdup(device_node);
+ self->prefix = g_strdup("");
+ } else {
+ self->bucket = g_strndup(device_node, name_colon - device_node);
+ self->prefix = g_strdup(name_colon + 1);
+ }
+
+ if (self->bucket == NULL || self->bucket[0] == '\0') {
+ device_set_error(pself,
+ vstrallocf(_("Empty bucket name in device %s"), device_name),
+ DEVICE_STATUS_DEVICE_ERROR);
+ amfree(self->bucket);
+ amfree(self->prefix);
+ return;
+ }
+
+ g_debug(_("S3 driver using bucket '%s', prefix '%s'"), self->bucket, self->prefix);
+
+ /* default values */
+ self->verbose = FALSE;
+ self->openstack_swift_api = FALSE;
+
+ /* use SSL if available */
+ self->use_ssl = s3_curl_supports_ssl();
+ bzero(&tmp_value, sizeof(GValue));
+ g_value_init(&tmp_value, G_TYPE_BOOLEAN);
+ g_value_set_boolean(&tmp_value, self->use_ssl);
+ device_set_simple_property(pself, device_property_s3_ssl.ID,
+ &tmp_value, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DEFAULT);
+
+ if (parent_class->open_device) {
+ parent_class->open_device(pself, device_name, device_type, device_node);
+ }
+}
+
+static void s3_device_finalize(GObject * obj_self) {
+ S3Device *self = S3_DEVICE (obj_self);
+ int thread;
+
+ if(G_OBJECT_CLASS(parent_class)->finalize)
+ (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
+
+ if (self->thread_pool_delete) {
+ g_thread_pool_free(self->thread_pool_delete, 1, 1);
+ self->thread_pool_delete = NULL;
+ }
+ if (self->thread_pool_write) {
+ g_thread_pool_free(self->thread_pool_write, 1, 1);
+ self->thread_pool_write = NULL;
+ }
+ if (self->thread_pool_read) {
+ g_thread_pool_free(self->thread_pool_read, 1, 1);
+ self->thread_pool_read = NULL;
+ }
+ if (self->thread_idle_mutex) {
+ g_mutex_free(self->thread_idle_mutex);
+ self->thread_idle_mutex = NULL;
+ }
+ if (self->thread_idle_cond) {
+ g_cond_free(self->thread_idle_cond);
+ self->thread_idle_cond = NULL;
+ }
+ if (self->s3t) {
+ for (thread = 0; thread < self->nb_threads; thread++) {
+ if(self->s3t[thread].s3) s3_free(self->s3t[thread].s3);
+ }
+ g_free(self->s3t);
+ }
+ if(self->bucket) g_free(self->bucket);
+ if(self->prefix) g_free(self->prefix);
+ if(self->access_key) g_free(self->access_key);
+ if(self->secret_key) g_free(self->secret_key);
+ if(self->swift_account_id) g_free(self->swift_account_id);
+ if(self->swift_access_key) g_free(self->swift_access_key);
+ if(self->host) g_free(self->host);
+ if(self->service_path) g_free(self->service_path);
+ if(self->user_token) g_free(self->user_token);
+ if(self->bucket_location) g_free(self->bucket_location);
+ if(self->storage_class) g_free(self->storage_class);
+ if(self->server_side_encryption) g_free(self->server_side_encryption);
+ if(self->ca_info) g_free(self->ca_info);
+}
+
+static gboolean setup_handle(S3Device * self) {
+ Device *d_self = DEVICE(self);
+ int thread;
+ guint response_code;
+ s3_error_code_t s3_error_code;
+ CURLcode curl_code;
+
+ if (self->s3t == NULL) {
+ self->s3t = g_new(S3_by_thread, self->nb_threads);
+ if (self->s3t == NULL) {
+ device_set_error(d_self,
+ stralloc(_("Can't allocate S3Handle array")),
+ DEVICE_STATUS_DEVICE_ERROR);