X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=device-src%2Fdevice.c;h=6eed5238e43fa14f973c55ebd9b540996a90685c;hb=HEAD;hp=ddb357cc8acf468262c3d2f5abd39cc917255689;hpb=2627875b7d18858bc1f9f7652811e4d8c15a23eb;p=debian%2Famanda diff --git a/device-src/device.c b/device-src/device.c index ddb357c..6eed523 100644 --- a/device-src/device.c +++ b/device-src/device.c @@ -1,21 +1,22 @@ /* - * Copyright (c) 2005-2008 Zmanda Inc. All Rights Reserved. - * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License version 2.1 as - * published by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but + * Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * Contact information: Zmanda Inc., 465 S Mathlida Ave, Suite 300 - * Sunnyvale, CA 94086, USA, or: http://www.zmanda.com + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300 + * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com */ /* The Device API abstracts device workings, interaction, properties, and @@ -28,8 +29,6 @@ #include #include "device.h" -#include "queueing.h" -#include "device-queueing.h" #include "property.h" #include "timestamp.h" @@ -48,6 +47,12 @@ void s3_device_register (void); void tape_device_register (void); #endif void vfs_device_register (void); +#ifdef WANT_DVDRW_DEVICE +void dvdrw_device_register (void); +#endif +#ifdef WANT_NDMP_DEVICE +void ndmp_device_register (void); +#endif /* * Registration infrastructure @@ -70,6 +75,12 @@ void device_api_init(void) { #ifdef WANT_S3_DEVICE s3_device_register(); #endif +#ifdef WANT_DVDRW_DEVICE + dvdrw_device_register(); +#endif +#ifdef WANT_NDMP_DEVICE + ndmp_device_register(); +#endif } void @@ -172,9 +183,6 @@ static void simple_property_free(SimpleProperty *o); static void default_device_open_device(Device * self, char * device_name, char * device_type, char * device_node); static gboolean default_device_configure(Device *self, gboolean use_global_config); -static gboolean default_device_write_from_fd(Device *self, - queue_fd_t *queue_fd); -static gboolean default_device_read_to_fd(Device *self, queue_fd_t *queue_fd); static gboolean default_device_property_get_ex(Device * self, DevicePropertyId id, GValue * val, PropertySurety *surety, @@ -228,11 +236,11 @@ device_get_type (void) (GInstanceInitFunc) device_init, NULL }; - + type = g_type_register_static (G_TYPE_OBJECT, "Device", &info, (GTypeFlags)G_TYPE_FLAG_ABSTRACT); } - + return type; } @@ -257,13 +265,14 @@ static void device_finalize(GObject *obj_self) { amfree(self->private); } -static void +static void device_init (Device * self) { self->private = malloc(sizeof(DevicePrivate)); self->device_name = NULL; self->access_mode = ACCESS_NULL; self->is_eof = FALSE; + self->is_eom = FALSE; self->file = -1; self->block = 0; self->in_file = FALSE; @@ -283,17 +292,17 @@ device_init (Device * self) (GDestroyNotify) simple_property_free); } -static void +static void device_class_init (DeviceClass * device_class) { GObjectClass *g_object_class = (GObjectClass*) device_class; - + parent_class = g_type_class_ref (G_TYPE_OBJECT); - + + device_class->directtcp_supported = FALSE; + device_class->open_device = default_device_open_device; device_class->configure = default_device_configure; - device_class->write_from_fd = default_device_write_from_fd; - device_class->read_to_fd = default_device_read_to_fd; device_class->property_get_ex = default_device_property_get_ex; device_class->property_set_ex = default_device_property_set_ex; g_object_class->finalize = device_finalize; @@ -348,10 +357,25 @@ device_base_init (DeviceClass * device_class) device_simple_property_get_fn, device_simple_property_set_fn); + device_class_register_property(device_class, PROPERTY_FULL_DELETION, + PROPERTY_ACCESS_GET_MASK, + device_simple_property_get_fn, + device_simple_property_set_fn); + device_class_register_property(device_class, PROPERTY_MEDIUM_ACCESS_TYPE, PROPERTY_ACCESS_GET_MASK, device_simple_property_get_fn, device_simple_property_set_fn); + + device_class_register_property(device_class, PROPERTY_COMMENT, + PROPERTY_ACCESS_GET_MASK|PROPERTY_ACCESS_SET_MASK, + device_simple_property_get_fn, + device_simple_property_set_fn); + + device_class_register_property(device_class, PROPERTY_LEOM, + PROPERTY_ACCESS_GET_MASK, + device_simple_property_get_fn, + device_simple_property_set_fn); } static void simple_property_free(SimpleProperty * resp) { @@ -408,7 +432,7 @@ handle_device_regex(const char * user_name, char ** driver_name, *driver_name = stralloc("tape"); *device = stralloc(user_name); #else /* !WANT_TAPE_DEVICE */ - errmsg = newvstrallocf(errmsg, "\"%s\" is not a valid device name.\n", user_name); + *errmsg = newvstrallocf(*errmsg, "\"%s\" is not a valid device name.\n", user_name); regfree(®ex); return FALSE; #endif /* WANT_TAPE_DEVICE */ @@ -436,7 +460,27 @@ make_null_error(char *errmsg, DeviceStatusFlags status) return device; } -Device* +char * +device_unaliased_name( + char *device_name) +{ + device_config_t *dc; + char *unaliased_name; + + /* look up the unaliased device name in the configuration */ + if ((dc = lookup_device_config(device_name))) { + if (!(unaliased_name = device_config_get_tapedev(dc)) + || unaliased_name[0] == '\0') { + return NULL; + } + } else { + unaliased_name = device_name; + } + + return unaliased_name; +} + +Device* device_open (char * device_name) { char *device_type = NULL; @@ -445,7 +489,6 @@ device_open (char * device_name) char *unaliased_name = NULL; DeviceFactory factory; Device *device; - device_config_t *dc; g_assert(device_name != NULL); @@ -457,16 +500,11 @@ device_open (char * device_name) if (device_name == NULL) return make_null_error(stralloc(_("No device name specified")), DEVICE_STATUS_DEVICE_ERROR); - /* look up the unaliased device name in the configuration */ - if ((dc = lookup_device_config(device_name))) { - if (!(unaliased_name = device_config_get_tapedev(dc)) - || unaliased_name[0] == '\0') { - return make_null_error( + unaliased_name = device_unaliased_name(device_name); + if (!unaliased_name) { + return make_null_error( vstrallocf(_("Device '%s' has no tapedev"), device_name), DEVICE_STATUS_DEVICE_ERROR); - } - } else { - unaliased_name = device_name; } if (!handle_device_regex(unaliased_name, &device_type, &device_node, @@ -489,6 +527,7 @@ device_open (char * device_name) device = factory(device_name, device_type, device_node); g_assert(device != NULL); /* factories must always return a device */ + device->device_mutex = g_mutex_new(); amfree(device_type); amfree(device_node); @@ -585,19 +624,8 @@ device_set_error(Device *self, char *errmsg, DeviceStatusFlags new_flags) } char * device_build_amanda_header(Device * self, const dumpfile_t * info, - int * size, gboolean * oneblock) { - char *amanda_header; - size_t min_header_length; - size_t header_buffer_size; - - min_header_length = self->block_size; - amanda_header = build_header(info, min_header_length); - header_buffer_size = MAX(min_header_length, strlen(amanda_header)+1); - if (size != NULL) - *size = header_buffer_size; - if (oneblock != NULL) - *oneblock = (header_buffer_size <= self->block_size); - return amanda_header; + size_t *size) { + return build_header(info, size, self->block_size); } dumpfile_t * make_tapestart_header(Device * self, char * label, @@ -622,8 +650,8 @@ dumpfile_t * make_tapestart_header(Device * self, char * label, } else { self->volume_time = g_strdup(timestamp); } - strncpy(rval->datestamp, self->volume_time, sizeof(rval->datestamp)); - strncpy(rval->name, label, sizeof(rval->name)); + g_strlcpy(rval->datestamp, self->volume_time, sizeof(rval->datestamp)); + g_strlcpy(rval->name, label, sizeof(rval->name)); return rval; } @@ -635,7 +663,7 @@ dumpfile_t * make_tapeend_header(void) { rval = malloc(sizeof(*rval)); rval->type = F_TAPEEND; timestamp = get_timestamp_from_time(time(NULL)); - strncpy(rval->datestamp, timestamp, sizeof(rval->datestamp)); + g_strlcpy(rval->datestamp, timestamp, sizeof(rval->datestamp)); amfree(timestamp); return rval; } @@ -696,15 +724,15 @@ static void set_device_property(gpointer key_p, gpointer value_p, DEVICE_STATUS_DEVICE_ERROR); return; } - + bzero(&property_value, sizeof(property_value)); g_value_init(&property_value, property_base->type); value = property->values->data; if (!g_value_set_from_string(&property_value, value)) { /* Value type could not be interpreted. */ device_set_error(device, - vstrallocf(_("Could not parse property value '%s' for property '%s'"), - value, g_type_name(property_base->type)), + vstrallocf(_("Could not parse property value '%s' for property '%s' (property type %s)"), + value, property_base->name, g_type_name(property_base->type)), DEVICE_STATUS_DEVICE_ERROR); return; } else { @@ -753,12 +781,12 @@ set_properties_from_global_config(Device * device) { g_value_init(&val, G_TYPE_UINT); g_value_set_uint(&val, blocksize_kb * 1024); success = device_property_set(device, - PROPERTY_READ_BUFFER_SIZE, + PROPERTY_READ_BLOCK_SIZE, &val); g_value_unset(&val); if (!success) { /* a non-fatal error */ - g_warning("Setting READ_BUFFER_SIZE to %ju not supported for device %s.", + g_warning("Setting READ_BLOCK_SIZE to %ju not supported for device %s.", 1024*(uintmax_t)blocksize_kb, device->device_name); } } @@ -855,8 +883,12 @@ property_set_block_size_fn( g_assert(block_size >= 0); /* int -> gsize (unsigned) */ if ((gsize)block_size < self->min_block_size - || (gsize)block_size > self->max_block_size) + || (gsize)block_size > self->max_block_size) { + device_set_error(self, + g_strdup_printf("Error setting BLOCK-SIZE property to '%zu', it must be between %zu and %zu", (gsize)block_size, self->min_block_size, self->max_block_size), + DEVICE_STATUS_DEVICE_ERROR); return FALSE; + } self->block_size = block_size; self->block_size_surety = surety; @@ -967,9 +999,6 @@ default_device_property_get_ex( /* Most of this function's job is to sanity-check everything, then * call the relevant getter. */ - if (device_in_error(self)) - return FALSE; - class_properties = DEVICE_GET_CLASS(self)->class_properties; if (id >= class_properties->len) return FALSE; @@ -1046,60 +1075,6 @@ device_property_get_list (Device * self) return DEVICE_GET_CLASS(self)->class_properties_list; } -static gboolean -default_device_read_to_fd(Device *self, queue_fd_t *queue_fd) { - GValue val; - StreamingRequirement streaming_mode; - - if (device_in_error(self)) return FALSE; - - /* Get the device's parameters */ - bzero(&val, sizeof(val)); - if (!device_property_get(self, PROPERTY_STREAMING, &val) - || !G_VALUE_HOLDS(&val, STREAMING_REQUIREMENT_TYPE)) { - streaming_mode = STREAMING_REQUIREMENT_REQUIRED; - } else { - streaming_mode = g_value_get_enum(&val); - } - - return QUEUE_SUCCESS == - do_consumer_producer_queue_full( - device_read_producer, - self, - fd_write_consumer, - queue_fd, - self->block_size, - DEFAULT_MAX_BUFFER_MEMORY, - streaming_mode); -} - -static gboolean -default_device_write_from_fd(Device *self, queue_fd_t *queue_fd) { - GValue val; - StreamingRequirement streaming_mode; - - if (device_in_error(self)) return FALSE; - - /* Get the device's parameters */ - bzero(&val, sizeof(val)); - if (!device_property_get(self, PROPERTY_STREAMING, &val) - || !G_VALUE_HOLDS(&val, STREAMING_REQUIREMENT_TYPE)) { - streaming_mode = STREAMING_REQUIREMENT_REQUIRED; - } else { - streaming_mode = g_value_get_enum(&val); - } - - return QUEUE_SUCCESS == - do_consumer_producer_queue_full( - fd_read_producer, - queue_fd, - device_write_consumer, - self, - self->block_size, - DEFAULT_MAX_BUFFER_MEMORY, - streaming_mode); -} - /* XXX WARNING XXX * All the functions below this comment are stub functions that do nothing * but implement the virtual function table. Call these functions and they @@ -1143,6 +1118,46 @@ device_finish (Device * self) { return (klass->finish)(self); } +guint64 +device_get_bytes_read (Device * self) { + DeviceClass *klass; + guint64 bytes = 0; + + g_assert(IS_DEVICE (self)); + + g_mutex_lock(self->device_mutex); + if (self->in_file) { + klass = DEVICE_GET_CLASS(self); + if (klass->get_bytes_read) { + bytes = (klass->get_bytes_read)(self); + } else { + bytes = self->bytes_read; + } + } + g_mutex_unlock(self->device_mutex); + return bytes; +} + +guint64 +device_get_bytes_written (Device * self) { + DeviceClass *klass; + guint64 bytes = 0; + + g_assert(IS_DEVICE (self)); + + g_mutex_lock(self->device_mutex); + if (self->in_file) { + klass = DEVICE_GET_CLASS(self); + if (klass->get_bytes_written) { + bytes = (klass->get_bytes_written)(self); + } else { + bytes = self->bytes_written; + } + } + g_mutex_unlock(self->device_mutex); + return bytes; +} + gboolean device_configure (Device * self, gboolean use_global_config) { @@ -1162,7 +1177,7 @@ device_configure (Device * self, gboolean use_global_config) } } -gboolean +gboolean device_start (Device * self, DeviceAccessMode mode, char * label, char * timestamp) { @@ -1216,20 +1231,6 @@ device_write_block (Device * self, guint size, gpointer block) return (*klass->write_block)(self,size, block); } -gboolean -device_write_from_fd (Device * self, queue_fd_t * queue_fd) -{ - DeviceClass *klass; - - g_assert(IS_DEVICE (self)); - g_assert(queue_fd->fd >= 0); - g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode)); - - klass = DEVICE_GET_CLASS(self); - g_assert(klass->write_from_fd); - return (klass->write_from_fd)(self,queue_fd); -} - gboolean device_start_file (Device * self, dumpfile_t * jobInfo) { DeviceClass * klass; @@ -1245,7 +1246,7 @@ device_start_file (Device * self, dumpfile_t * jobInfo) { return (klass->start_file)(self, jobInfo ); } -gboolean +gboolean device_finish_file (Device * self) { DeviceClass *klass; @@ -1272,7 +1273,7 @@ device_seek_file (Device * self, guint file) return (klass->seek_file)(self,file); } -gboolean +gboolean device_seek_block (Device * self, guint64 block) { DeviceClass *klass; @@ -1304,22 +1305,7 @@ device_read_block (Device * self, gpointer buffer, int * size) return (klass->read_block)(self,buffer,size); } -gboolean -device_read_to_fd (Device * self, queue_fd_t *queue_fd) -{ - DeviceClass *klass; - - g_assert(IS_DEVICE (self)); - g_assert(queue_fd->fd >= 0); - g_assert(self->access_mode == ACCESS_READ); - - klass = DEVICE_GET_CLASS(self); - g_assert(klass->read_to_fd); - return (klass->read_to_fd)(self,queue_fd); -} - - -gboolean +gboolean device_property_get_ex( Device * self, DevicePropertyId id, @@ -1356,7 +1342,7 @@ device_property_set_ex( return (klass->property_set_ex)(self, id, val, surety, source); } -gboolean +gboolean device_recycle_file (Device * self, guint filenum) { DeviceClass *klass; @@ -1372,6 +1358,182 @@ device_recycle_file (Device * self, guint filenum) return (klass->recycle_file)(self,filenum); } +gboolean +device_erase (Device * self) +{ + DeviceClass *klass; + + g_assert(IS_DEVICE (self)); + g_assert(self->access_mode == ACCESS_NULL); + g_assert(!self->in_file); + + klass = DEVICE_GET_CLASS(self); + if(klass->erase) { + return (klass->erase)(self); + } else { + device_set_error(self, + stralloc(_("Unimplemented method")), + DEVICE_STATUS_DEVICE_ERROR); + return FALSE; + } +} + +gboolean +device_eject (Device * self) +{ + DeviceClass *klass; + + g_assert(IS_DEVICE (self)); + g_assert(self->access_mode == ACCESS_NULL); + g_assert(!self->in_file); + + klass = DEVICE_GET_CLASS(self); + if (klass->eject) { + return (klass->eject)(self); + } else { + return TRUE; + } +} + +gboolean +device_listen( + Device *self, + gboolean for_writing, + DirectTCPAddr **addrs) +{ + DeviceClass *klass; + + klass = DEVICE_GET_CLASS(self); + if(klass->listen) { + return (klass->listen)(self, for_writing, addrs); + } else { + device_set_error(self, + stralloc(_("Unimplemented method")), + DEVICE_STATUS_DEVICE_ERROR); + return FALSE; + } +} + +int +device_accept( + Device *self, + DirectTCPConnection **conn, + int *cancelled, + GMutex *abort_mutex, + GCond *abort_cond) +{ + DeviceClass *klass; + + klass = DEVICE_GET_CLASS(self); + if(klass->accept) { + return (klass->accept)(self, conn, cancelled, abort_mutex, abort_cond); + } else { + device_set_error(self, + g_strdup(_("Unimplemented method")), + DEVICE_STATUS_DEVICE_ERROR); + return 1; + } +} + + +int +device_connect( + Device *self, + gboolean for_writing, + DirectTCPAddr *addrs, + DirectTCPConnection **conn, + int *cancelled, + GMutex *abort_mutex, + GCond *abort_cond) +{ + DeviceClass *klass; + + klass = DEVICE_GET_CLASS(self); + if(klass->connect) { + return (klass->connect)(self, for_writing, addrs, conn, cancelled, + abort_mutex, abort_cond); + } else { + device_set_error(self, + g_strdup(_("Unimplemented method")), + DEVICE_STATUS_DEVICE_ERROR); + return 1; + } +} + +int +device_write_from_connection( + Device *self, + guint64 size, + guint64 *actual_size, + int *cancelled, + GMutex *abort_mutex, + GCond *abort_cond) +{ + DeviceClass *klass; + + klass = DEVICE_GET_CLASS(self); + + g_assert(self->in_file); + g_assert(IS_WRITABLE_ACCESS_MODE(self->access_mode)); + + if(klass->write_from_connection) { + return (klass->write_from_connection)(self, size, actual_size, + cancelled, + abort_mutex, abort_cond); + } else { + device_set_error(self, + stralloc(_("Unimplemented method")), + DEVICE_STATUS_DEVICE_ERROR); + return 1; + } +} + +int +device_read_to_connection( + Device *self, + guint64 size, + guint64 *actual_size, + int *cancelled, + GMutex *abort_mutex, + GCond *abort_cond) +{ + DeviceClass *klass; + + g_assert(self->in_file); + g_assert(self->access_mode == ACCESS_READ); + + klass = DEVICE_GET_CLASS(self); + if(klass->read_to_connection) { + return (klass->read_to_connection)(self, size, actual_size, + cancelled, abort_mutex, abort_cond); + } else { + device_set_error(self, + stralloc(_("Unimplemented method")), + DEVICE_STATUS_DEVICE_ERROR); + return 1; + } +} + +gboolean +device_use_connection( + Device *self, + DirectTCPConnection *conn) +{ + DeviceClass *klass; + + g_assert(self->access_mode == ACCESS_NULL); + + klass = DEVICE_GET_CLASS(self); + if(klass->use_connection) { + return (klass->use_connection)(self, conn); + } else { + device_set_error(self, + stralloc(_("Unimplemented method")), + DEVICE_STATUS_DEVICE_ERROR); + return FALSE; + } +} + /* Property handling */ void