📄 device.c
字号:
/* * Copyright (c) 2005 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 * 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., 505 N Mathlida Ave, Suite 120 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com *//* The Device API abstracts device workings, interaction, properties, and * capabilities from the rest of the Amanda code base. It supports * pluggable modules for different kinds of devices. */#include "amanda.h"#include "conffile.h"#include <regex.h>#include "device.h"#include "queueing.h"#include "property.h"#include "null-device.h"#include "timestamp.h"#include "vfs-device.h"#include "util.h"#ifdef WANT_TAPE_DEVICE#include "tape-device.h"#endif#include "rait-device.h"#ifdef WANT_S3_DEVICE #include "s3-device.h"#endifstatic GHashTable* driverList = NULL;void device_api_init(void) { g_type_init(); amanda_thread_init(); device_property_init(); driverList = g_hash_table_new(g_str_hash, g_str_equal); /* register other types and devices. */ null_device_register(); vfs_device_register();#ifdef WANT_TAPE_DEVICE tape_device_register();#endif rait_device_register();#ifdef WANT_S3_DEVICE s3_device_register();#endif}void register_device(DeviceFactory factory, const char ** device_prefix_list) { char ** tmp; g_assert(driverList != NULL); g_assert(factory != NULL); g_return_if_fail(device_prefix_list != NULL); g_return_if_fail(*device_prefix_list != NULL); tmp = (char**)device_prefix_list; while (*tmp != NULL) { g_hash_table_insert(driverList, *tmp, (gpointer)factory); tmp ++; }}static DeviceFactory lookup_device_factory(const char *device_name) { gpointer key, value; g_assert(driverList != NULL); if (g_hash_table_lookup_extended(driverList, device_name, &key, &value)) { return (DeviceFactory)value; } else { return NULL; }}static const GFlagsValue read_label_status_flags_values[] = { { READ_LABEL_STATUS_SUCCESS, "READ_LABEL_STATUS_SUCCESS", "Success" }, { READ_LABEL_STATUS_DEVICE_MISSING, "READ_LABEL_STATUS_DEVICE_MISSING", "Device not found" }, { READ_LABEL_STATUS_DEVICE_ERROR, "READ_LABEL_STATUS_DEVICE_ERROR", "Device error" }, { READ_LABEL_STATUS_VOLUME_MISSING, "READ_LABEL_STATUS_VOLUME_MISSING", "Volume not found" }, { READ_LABEL_STATUS_VOLUME_UNLABELED, "READ_LABEL_STATUS_VOLUME_UNLABELED", "Volume not labeled" }, { READ_LABEL_STATUS_VOLUME_ERROR, "READ_LABEL_STATUS_VOLUME_ERROR", "Volume error" }, { 0, NULL, NULL }};GType read_label_status_flags_get_type(void) { static GType type = 0; if (G_UNLIKELY(type == 0)) { type = g_flags_register_static("ReadLabelStatusFlags", read_label_status_flags_values); } return type;}/* Device class definition starts here. */struct DevicePrivate_s { /* This is the return value of the device_get_property_list() method. */ GArray *property_list; GHashTable * property_response;};/* This holds the default response to a particular property. */typedef struct { PropertyAccessFlags access; GValue response;} PropertyResponse;#define selfp (self->private)/* here are local prototypes, so we can make function pointers. */static void device_init (Device * o) G_GNUC_UNUSED;static void device_class_init (DeviceClass * c) G_GNUC_UNUSED;static void property_response_free(PropertyResponse *o);static gboolean default_device_open_device(Device * self, char * device_name);static gboolean default_device_finish(Device * self);static gboolean default_device_start(Device * self, DeviceAccessMode mode, char * label, char * timestamp);static gboolean default_device_start_file (Device * self, const dumpfile_t * jobinfo);static gboolean default_device_write_block (Device * self, guint size, gpointer data, gboolean last);static gboolean default_device_write_from_fd(Device *self, int fd);static gboolean default_device_finish_file (Device * self);static dumpfile_t* default_device_seek_file (Device * self, guint file);static gboolean default_device_seek_block (Device * self, guint64 block);static int default_device_read_block (Device * self, gpointer buffer, int * size);static gboolean default_device_read_to_fd(Device *self, int fd);static gboolean default_device_property_get(Device * self, DevicePropertyId ID, GValue * value);/* pointer to the class of our parent */static GObjectClass *parent_class = NULL;GTypedevice_get_type (void){ static GType type = 0; if G_UNLIKELY(type == 0) { static const GTypeInfo info = { sizeof (DeviceClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) device_class_init, (GClassFinalizeFunc) NULL, NULL /* class_data */, sizeof (Device), 0 /* n_preallocs */, (GInstanceInitFunc) device_init, NULL }; type = g_type_register_static (G_TYPE_OBJECT, "Device", &info, (GTypeFlags)G_TYPE_FLAG_ABSTRACT); } return type;}static void device_finalize(GObject *obj_self) { Device *self G_GNUC_UNUSED = DEVICE (obj_self); if(G_OBJECT_CLASS(parent_class)->finalize) (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self); /* Here we call device_finish() if it hasn't been done yet. Subclasses may need to do this same check earlier. */ if (self->access_mode != ACCESS_NULL) { device_finish(self); } amfree(self->device_name); amfree(self->volume_label); amfree(self->volume_time); g_array_free(selfp->property_list, TRUE); g_hash_table_destroy(selfp->property_response); amfree(self->private);}static void device_init (Device * self G_GNUC_UNUSED){ self->private = malloc(sizeof(DevicePrivate)); self->device_name = NULL; self->access_mode = ACCESS_NULL; self->is_eof = FALSE; self->file = -1; self->block = 0; self->in_file = FALSE; self->volume_label = NULL; self->volume_time = NULL; selfp->property_list = g_array_new(TRUE, FALSE, sizeof(DeviceProperty)); selfp->property_response = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) property_response_free);}static void device_class_init (DeviceClass * c G_GNUC_UNUSED){ GObjectClass *g_object_class G_GNUC_UNUSED = (GObjectClass*) c; parent_class = g_type_class_ref (G_TYPE_OBJECT); c->open_device = default_device_open_device; c->finish = default_device_finish; c->read_label = NULL; c->start = default_device_start; c->start_file = default_device_start_file; c->write_block = default_device_write_block; c->write_from_fd = default_device_write_from_fd; c->finish_file = default_device_finish_file; c->seek_file = default_device_seek_file; c->seek_block = default_device_seek_block; c->read_block = default_device_read_block; c->read_to_fd = default_device_read_to_fd; c->property_get = default_device_property_get; c->property_set = NULL; c->recycle_file = NULL; g_object_class->finalize = device_finalize;}static void property_response_free(PropertyResponse * resp) { g_value_unset(&(resp->response)); amfree(resp);}static char *regex_message(int result, regex_t *regex) { char * rval; size_t size; size = regerror(result, regex, NULL, 0); rval = malloc(size); regerror(result, regex, rval, size); return rval;}static gbooleanhandle_device_regex(const char * user_name, char ** driver_name, char ** device) { regex_t regex; int reg_result; regmatch_t pmatch[3]; static const char * regex_string = "^([a-z0-9]+):(.*)$"; bzero(®ex, sizeof(regex)); reg_result = regcomp(®ex, regex_string, REG_EXTENDED | REG_ICASE); if (reg_result != 0) { char * message = regex_message(reg_result, ®ex); g_fprintf(stderr, "Error compiling regular expression \"%s\": %s\n", regex_string, message); amfree(message); return FALSE; } reg_result = regexec(®ex, user_name, 3, pmatch, 0); if (reg_result != 0 && reg_result != REG_NOMATCH) { char * message = regex_message(reg_result, ®ex); g_fprintf(stderr, "Error applying regular expression \"%s\" to string \"%s\":\n" "%s\n", user_name, regex_string, message); regfree(®ex); return FALSE; } else if (reg_result == REG_NOMATCH) {#ifdef WANT_TAPE_DEVICE g_fprintf(stderr, "\"%s\" uses deprecated device naming convention; \n" "using \"tape:%s\" instead.\n", user_name, user_name); *driver_name = stralloc("tape"); *device = stralloc(user_name);#else /* !WANT_TAPE_DEVICE */ g_fprintf(stderr, "\"%s\" is not a valid device name.\n", user_name); regfree(®ex); return FALSE;#endif /* WANT_TAPE_DEVICE */ } else { *driver_name = find_regex_substring(user_name, pmatch[1]); *device = find_regex_substring(user_name, pmatch[2]); } regfree(®ex); return TRUE;}Device* device_open (char * device_name){ char *device_driver_name = NULL; char *device_node_name = NULL; DeviceFactory factory; Device *device; g_return_val_if_fail (device_name != NULL, NULL); if (driverList == NULL) { g_log(G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, "device_open() called without device_api_init()!\n"); g_assert_not_reached(); } if (!handle_device_regex(device_name, &device_driver_name, &device_node_name)) { amfree(device_driver_name); amfree(device_node_name); return NULL; } factory = lookup_device_factory(device_driver_name); if (factory == NULL) { g_fprintf(stderr, "Device driver %s is not known.\n", device_driver_name); amfree(device_driver_name); amfree(device_node_name); return NULL; } device = factory(device_driver_name, device_node_name); amfree(device_driver_name); amfree(device_node_name); return device;}void device_add_property (Device * self, DeviceProperty * prop, GValue * response){ unsigned int i; g_return_if_fail (self != NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -