2 * Copyright (c) 2005 Zmanda, Inc. All Rights Reserved.
4 * This library is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License version 2.1 as
6 * published by the Free Software Foundation.
8 * This library 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 Lesser General Public
11 * License for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17 * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
18 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
21 /* The Device API abstracts device workings, interaction, properties, and
22 * capabilities from the rest of the Amanda code base. It supports
23 * pluggable modules for different kinds of devices. */
34 #include "null-device.h"
35 #include "timestamp.h"
36 #include "vfs-device.h"
38 #ifdef WANT_TAPE_DEVICE
39 #include "tape-device.h"
41 #include "rait-device.h"
43 #include "s3-device.h"
46 static GHashTable* driverList = NULL;
48 void device_api_init(void) {
51 device_property_init();
52 driverList = g_hash_table_new(g_str_hash, g_str_equal);
54 /* register other types and devices. */
55 null_device_register();
56 vfs_device_register();
57 #ifdef WANT_TAPE_DEVICE
58 tape_device_register();
60 rait_device_register();
66 void register_device(DeviceFactory factory,
67 const char ** device_prefix_list) {
69 g_assert(driverList != NULL);
70 g_assert(factory != NULL);
71 g_return_if_fail(device_prefix_list != NULL);
72 g_return_if_fail(*device_prefix_list != NULL);
74 tmp = (char**)device_prefix_list;
75 while (*tmp != NULL) {
76 g_hash_table_insert(driverList, *tmp, (gpointer)factory);
81 static DeviceFactory lookup_device_factory(const char *device_name) {
83 g_assert(driverList != NULL);
85 if (g_hash_table_lookup_extended(driverList, device_name, &key, &value)) {
86 return (DeviceFactory)value;
92 static const GFlagsValue read_label_status_flags_values[] = {
93 { READ_LABEL_STATUS_SUCCESS,
94 "READ_LABEL_STATUS_SUCCESS",
96 { READ_LABEL_STATUS_DEVICE_MISSING,
97 "READ_LABEL_STATUS_DEVICE_MISSING",
99 { READ_LABEL_STATUS_DEVICE_ERROR,
100 "READ_LABEL_STATUS_DEVICE_ERROR",
102 { READ_LABEL_STATUS_VOLUME_MISSING,
103 "READ_LABEL_STATUS_VOLUME_MISSING",
104 "Volume not found" },
105 { READ_LABEL_STATUS_VOLUME_UNLABELED,
106 "READ_LABEL_STATUS_VOLUME_UNLABELED",
107 "Volume not labeled" },
108 { READ_LABEL_STATUS_VOLUME_ERROR,
109 "READ_LABEL_STATUS_VOLUME_ERROR",
114 GType read_label_status_flags_get_type(void) {
115 static GType type = 0;
116 if (G_UNLIKELY(type == 0)) {
117 type = g_flags_register_static("ReadLabelStatusFlags",
118 read_label_status_flags_values);
123 /* Device class definition starts here. */
125 struct DevicePrivate_s {
126 /* This is the return value of the device_get_property_list()
128 GArray *property_list;
129 GHashTable * property_response;
132 /* This holds the default response to a particular property. */
134 PropertyAccessFlags access;
138 #define selfp (self->private)
140 /* here are local prototypes, so we can make function pointers. */
141 static void device_init (Device * o) G_GNUC_UNUSED;
142 static void device_class_init (DeviceClass * c) G_GNUC_UNUSED;
144 static void property_response_free(PropertyResponse *o);
146 static gboolean default_device_open_device(Device * self, char * device_name);
147 static gboolean default_device_finish(Device * self);
148 static gboolean default_device_start(Device * self, DeviceAccessMode mode,
149 char * label, char * timestamp);
150 static gboolean default_device_start_file (Device * self,
151 const dumpfile_t * jobinfo);
152 static gboolean default_device_write_block (Device * self, guint size,
153 gpointer data, gboolean last);
154 static gboolean default_device_write_from_fd(Device *self, int fd);
155 static gboolean default_device_finish_file (Device * self);
156 static dumpfile_t* default_device_seek_file (Device * self, guint file);
157 static gboolean default_device_seek_block (Device * self, guint64 block);
158 static int default_device_read_block (Device * self, gpointer buffer,
160 static gboolean default_device_read_to_fd(Device *self, int fd);
161 static gboolean default_device_property_get(Device * self, DevicePropertyId ID,
164 /* pointer to the class of our parent */
165 static GObjectClass *parent_class = NULL;
168 device_get_type (void)
170 static GType type = 0;
172 if G_UNLIKELY(type == 0) {
173 static const GTypeInfo info = {
174 sizeof (DeviceClass),
175 (GBaseInitFunc) NULL,
176 (GBaseFinalizeFunc) NULL,
177 (GClassInitFunc) device_class_init,
178 (GClassFinalizeFunc) NULL,
179 NULL /* class_data */,
182 (GInstanceInitFunc) device_init,
186 type = g_type_register_static (G_TYPE_OBJECT, "Device", &info,
187 (GTypeFlags)G_TYPE_FLAG_ABSTRACT);
193 static void device_finalize(GObject *obj_self) {
194 Device *self G_GNUC_UNUSED = DEVICE (obj_self);
195 if(G_OBJECT_CLASS(parent_class)->finalize)
196 (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
198 /* Here we call device_finish() if it hasn't been done
199 yet. Subclasses may need to do this same check earlier. */
200 if (self->access_mode != ACCESS_NULL) {
204 amfree(self->device_name);
205 amfree(self->volume_label);
206 amfree(self->volume_time);
207 g_array_free(selfp->property_list, TRUE);
208 g_hash_table_destroy(selfp->property_response);
209 amfree(self->private);
213 device_init (Device * self G_GNUC_UNUSED)
215 self->private = malloc(sizeof(DevicePrivate));
216 self->device_name = NULL;
217 self->access_mode = ACCESS_NULL;
218 self->is_eof = FALSE;
221 self->in_file = FALSE;
222 self->volume_label = NULL;
223 self->volume_time = NULL;
224 selfp->property_list = g_array_new(TRUE, FALSE, sizeof(DeviceProperty));
225 selfp->property_response =
226 g_hash_table_new_full(g_direct_hash,
229 (GDestroyNotify) property_response_free);
233 device_class_init (DeviceClass * c G_GNUC_UNUSED)
235 GObjectClass *g_object_class G_GNUC_UNUSED = (GObjectClass*) c;
237 parent_class = g_type_class_ref (G_TYPE_OBJECT);
239 c->open_device = default_device_open_device;
240 c->finish = default_device_finish;
241 c->read_label = NULL;
242 c->start = default_device_start;
243 c->start_file = default_device_start_file;
244 c->write_block = default_device_write_block;
245 c->write_from_fd = default_device_write_from_fd;
246 c->finish_file = default_device_finish_file;
247 c->seek_file = default_device_seek_file;
248 c->seek_block = default_device_seek_block;
249 c->read_block = default_device_read_block;
250 c->read_to_fd = default_device_read_to_fd;
251 c->property_get = default_device_property_get;
252 c->property_set = NULL;
253 c->recycle_file = NULL;
254 g_object_class->finalize = device_finalize;
257 static void property_response_free(PropertyResponse * resp) {
258 g_value_unset(&(resp->response));
263 regex_message(int result, regex_t *regex) {
267 size = regerror(result, regex, NULL, 0);
269 regerror(result, regex, rval, size);
275 handle_device_regex(const char * user_name, char ** driver_name,
279 regmatch_t pmatch[3];
280 static const char * regex_string = "^([a-z0-9]+):(.*)$";
282 bzero(®ex, sizeof(regex));
284 reg_result = regcomp(®ex, regex_string, REG_EXTENDED | REG_ICASE);
285 if (reg_result != 0) {
286 char * message = regex_message(reg_result, ®ex);
287 g_fprintf(stderr, "Error compiling regular expression \"%s\": %s\n",
288 regex_string, message);
293 reg_result = regexec(®ex, user_name, 3, pmatch, 0);
294 if (reg_result != 0 && reg_result != REG_NOMATCH) {
295 char * message = regex_message(reg_result, ®ex);
296 g_fprintf(stderr, "Error applying regular expression \"%s\" to string \"%s\":\n"
297 "%s\n", user_name, regex_string, message);
300 } else if (reg_result == REG_NOMATCH) {
301 #ifdef WANT_TAPE_DEVICE
302 g_fprintf(stderr, "\"%s\" uses deprecated device naming convention; \n"
303 "using \"tape:%s\" instead.\n",
304 user_name, user_name);
305 *driver_name = stralloc("tape");
306 *device = stralloc(user_name);
307 #else /* !WANT_TAPE_DEVICE */
308 g_fprintf(stderr, "\"%s\" is not a valid device name.\n", user_name);
311 #endif /* WANT_TAPE_DEVICE */
313 *driver_name = find_regex_substring(user_name, pmatch[1]);
314 *device = find_regex_substring(user_name, pmatch[2]);
321 device_open (char * device_name)
323 char *device_driver_name = NULL;
324 char *device_node_name = NULL;
325 DeviceFactory factory;
328 g_return_val_if_fail (device_name != NULL, NULL);
330 if (driverList == NULL) {
331 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_ERROR,
332 "device_open() called without device_api_init()!\n");
333 g_assert_not_reached();
336 if (!handle_device_regex(device_name, &device_driver_name, &device_node_name)) {
337 amfree(device_driver_name);
338 amfree(device_node_name);
342 factory = lookup_device_factory(device_driver_name);
344 if (factory == NULL) {
345 g_fprintf(stderr, "Device driver %s is not known.\n",
347 amfree(device_driver_name);
348 amfree(device_node_name);
352 device = factory(device_driver_name, device_node_name);
353 amfree(device_driver_name);
354 amfree(device_node_name);
359 device_add_property (Device * self, DeviceProperty * prop, GValue * response)
362 g_return_if_fail (self != NULL);
363 g_return_if_fail (IS_DEVICE (self));
364 g_assert(selfp->property_list != NULL);
365 g_assert(selfp->property_response != NULL);
367 /* Delete it if it already exists. */
368 for(i = 0; i < selfp->property_list->len; i ++) {
369 if (g_array_index(selfp->property_list,
370 DeviceProperty, i).base->ID == prop->base->ID) {
371 g_array_remove_index_fast(selfp->property_list, i);
376 g_array_append_val(selfp->property_list, *prop);
378 if (response != NULL) {
379 PropertyResponse * property_response;
381 g_return_if_fail(G_IS_VALUE(response));
383 property_response = malloc(sizeof(*property_response));
384 property_response->access = prop->access;
385 bzero(&(property_response->response),
386 sizeof(property_response->response));
387 g_value_init(&(property_response->response),
388 G_VALUE_TYPE(response));
389 g_value_copy(response, &(property_response->response));
391 g_hash_table_insert(selfp->property_response,
392 GINT_TO_POINTER(prop->base->ID),
397 const DeviceProperty *
398 device_property_get_list (Device * self)
400 g_return_val_if_fail (self != NULL, (const DeviceProperty * )0);
401 g_return_val_if_fail (IS_DEVICE (self), (const DeviceProperty * )0);
403 return (const DeviceProperty*) selfp->property_list->data;
406 guint device_write_min_size(Device * self) {
408 int block_size, min_block_size;
410 bzero(&g_tmp, sizeof(g_tmp));
411 device_property_get(self, PROPERTY_BLOCK_SIZE, &g_tmp);
412 block_size = g_value_get_int(&g_tmp);
413 g_value_unset(&g_tmp);
414 if (block_size > 0) {
418 /* variable block size */
419 device_property_get(self, PROPERTY_MIN_BLOCK_SIZE, &g_tmp);
420 min_block_size = g_value_get_uint(&g_tmp);
421 g_value_unset(&g_tmp);
422 return min_block_size;
425 guint device_write_max_size(Device * self) {
427 int block_size, max_block_size;
429 bzero(&g_tmp, sizeof(g_tmp));
430 device_property_get(self, PROPERTY_BLOCK_SIZE, &g_tmp);
431 block_size = g_value_get_int(&g_tmp);
432 g_value_unset(&g_tmp);
433 if (block_size > 0) {
437 /* variable block size */
438 device_property_get(self, PROPERTY_MAX_BLOCK_SIZE, &g_tmp);
439 max_block_size = g_value_get_uint(&g_tmp);
440 g_value_unset(&g_tmp);
441 return max_block_size;
444 guint device_read_max_size(Device * self) {
447 bzero(&g_tmp, sizeof(g_tmp));
448 if (device_property_get(self, PROPERTY_READ_BUFFER_SIZE, &g_tmp)) {
449 guint rval = g_value_get_uint(&g_tmp);
450 g_value_unset(&g_tmp);
453 return device_write_max_size(self);
457 char * device_build_amanda_header(Device * self, const dumpfile_t * info,
458 int * size, gboolean * oneblock) {
460 unsigned int min_header_length;
461 unsigned int header_buffer_size;
463 min_header_length = device_write_min_size(self);
464 amanda_header = build_header(info, min_header_length);
465 header_buffer_size = MAX(min_header_length, strlen(amanda_header)+1);
467 *size = header_buffer_size;
468 if (oneblock != NULL)
469 *oneblock = (header_buffer_size <= device_write_max_size(self));
470 return amanda_header;
473 dumpfile_t * make_tapestart_header(Device * self, char * label,
477 g_return_val_if_fail(label != NULL, NULL);
479 rval = malloc(sizeof(*rval));
481 rval->type = F_TAPESTART;
482 amfree(self->volume_time);
483 if (get_timestamp_state(timestamp) == TIME_STATE_REPLACE) {
484 self->volume_time = get_proper_stamp_from_time(time(NULL));
486 self->volume_time = g_strdup(timestamp);
488 strncpy(rval->datestamp, self->volume_time, sizeof(rval->datestamp));
489 strncpy(rval->name, label, sizeof(rval->name));
494 dumpfile_t * make_tapeend_header(void) {
498 rval = malloc(sizeof(*rval));
499 rval->type = F_TAPEEND;
500 timestamp = get_timestamp_from_time(time(NULL));
501 strncpy(rval->datestamp, timestamp, sizeof(rval->datestamp));
506 /* Try setting max/fixed blocksize on a device. Check results, fallback, and
507 * print messages for problems. */
508 static void try_set_blocksize(Device * device, guint blocksize,
509 gboolean try_max_first) {
512 bzero(&val, sizeof(val));
513 g_value_init(&val, G_TYPE_UINT);
514 g_value_set_uint(&val, blocksize);
516 success = device_property_set(device,
517 PROPERTY_MAX_BLOCK_SIZE,
520 g_fprintf(stderr, "Setting MAX_BLOCK_SIZE to %u "
521 "not supported for device %s.\n"
522 "trying BLOCK_SIZE instead.\n",
523 blocksize, device->device_name);
531 g_value_init(&val, G_TYPE_INT);
532 g_value_set_int(&val, blocksize);
533 success = device_property_set(device,
537 g_fprintf(stderr, "Setting BLOCK_SIZE to %u "
538 "not supported for device %s.\n",
539 blocksize, device->device_name);
544 /* A GHFunc (callback for g_hash_table_foreach) */
545 static void set_device_property(gpointer key_p, gpointer value_p,
546 gpointer user_data_p) {
547 char * property_s = key_p;
548 char * value_s = value_p;
549 Device * device = user_data_p;
550 const DevicePropertyBase* property_base;
551 GValue property_value;
553 g_return_if_fail(IS_DEVICE(device));
554 g_return_if_fail(property_s != NULL);
555 g_return_if_fail(value_s != NULL);
557 property_base = device_property_get_by_name(property_s);
558 if (property_base == NULL) {
559 /* Nonexistant property name. */
560 g_fprintf(stderr, _("Unknown device property name %s.\n"), property_s);
564 bzero(&property_value, sizeof(property_value));
565 g_value_init(&property_value, property_base->type);
566 if (!g_value_set_from_string(&property_value, value_s)) {
567 /* Value type could not be interpreted. */
569 _("Could not parse property value %s for property type %s.\n"),
570 value_s, g_type_name(property_base->type));
573 g_assert (G_VALUE_HOLDS(&property_value, property_base->type));
576 if (!device_property_set(device, property_base->ID, &property_value)) {
577 /* Device rejects property. */
578 g_fprintf(stderr, _("Could not set property %s to %s on device %s.\n"),
579 property_base->name, value_s, device->device_name);
584 /* Set up first-run properties, including DEVICE_MAX_VOLUME_USAGE property
585 * based on the tapetype. */
586 void device_set_startup_properties_from_config(Device * device) {
587 char * tapetype_name = getconf_str(CNF_TAPETYPE);
588 if (tapetype_name != NULL) {
589 tapetype_t * tapetype = lookup_tapetype(tapetype_name);
590 if (tapetype != NULL) {
596 bzero(&val, sizeof(GValue));
598 if (tapetype_seen(tapetype, TAPETYPE_LENGTH)) {
599 length = tapetype_get_length(tapetype);
600 g_value_init(&val, G_TYPE_UINT64);
601 g_value_set_uint64(&val, length * 1024);
602 /* If this fails, it's not really an error. */
603 device_property_set(device, PROPERTY_MAX_VOLUME_USAGE, &val);
607 if (tapetype_seen(tapetype, TAPETYPE_READBLOCKSIZE)) {
608 blocksize_kb = tapetype_get_readblocksize(tapetype);
609 g_value_init(&val, G_TYPE_UINT);
610 g_value_set_uint(&val, blocksize_kb * 1024);
611 success = device_property_set(device,
612 PROPERTY_READ_BUFFER_SIZE,
616 g_fprintf(stderr, "Setting READ_BUFFER_SIZE to %llu "
617 "not supported for device %s.\n",
618 1024*(long long unsigned int)blocksize_kb,
619 device->device_name);
623 if (tapetype_seen(tapetype, TAPETYPE_BLOCKSIZE)) {
624 blocksize_kb = tapetype_get_blocksize(tapetype);
625 try_set_blocksize(device, blocksize_kb * 1024,
626 !tapetype_get_file_pad(tapetype));
631 g_hash_table_foreach(getconf_proplist(CNF_DEVICE_PROPERTY),
632 set_device_property, device);
635 void device_clear_volume_details(Device * device) {
636 if (device == NULL || device->access_mode != ACCESS_NULL) {
640 amfree(device->volume_label);
641 amfree(device->volume_time);
644 /* Here we put default implementations of virtual functions. Since
645 this class is virtual, many of these functions offer at best
646 incomplete functionality. But they do offer the useful commonality
647 that all devices can expect to need. */
649 /* This function only updates access_mode, volume_label, and volume_time. */
651 default_device_start (Device * self, DeviceAccessMode mode, char * label,
653 if (mode != ACCESS_WRITE && self->volume_label == NULL) {
654 g_debug("default_device_start calling device_read_label with mode %d", mode);
655 if (device_read_label(self) != READ_LABEL_STATUS_SUCCESS)
657 } else if (mode == ACCESS_WRITE) {
658 self->volume_label = newstralloc(self->volume_label, label);
659 self->volume_time = newstralloc(self->volume_time, timestamp);
661 self->access_mode = mode;
666 static gboolean default_device_open_device(Device * self,
667 char * device_name) {
671 self->device_name = stralloc(device_name);
673 prop.base = &device_property_canonical_name;
674 prop.access = PROPERTY_ACCESS_GET_MASK;
676 for(i = 0; i < selfp->property_list->len; i ++) {
677 if (g_array_index(selfp->property_list,
678 DeviceProperty, i).base->ID == prop.base->ID) {
682 /* If we got here, the property was not registered. */
683 device_add_property(self, &prop, NULL);
688 /* This default implementation does very little. */
690 default_device_finish (Device * self) {
691 self->access_mode = ACCESS_NULL;
695 /* This function updates the file, in_file, and block attributes. */
697 default_device_start_file (Device * self,
698 const dumpfile_t * jobInfo G_GNUC_UNUSED) {
699 self->in_file = TRUE;
708 /* This function lies: It updates the block number and maybe calls
709 device_finish_file(), but returns FALSE. */
711 default_device_write_block(Device * self, guint size G_GNUC_UNUSED,
712 gpointer data G_GNUC_UNUSED, gboolean last_block) {
715 device_finish_file(self);
719 /* This function lies: It updates the block number, but returns
722 default_device_read_block(Device * self, gpointer buf G_GNUC_UNUSED,
723 int * size G_GNUC_UNUSED) {
728 /* This function just updates the in_file field. */
730 default_device_finish_file(Device * self) {
731 self->in_file = FALSE;
735 /* This function just updates the file number. */
737 default_device_seek_file(Device * self, guint file) {
738 self->in_file = TRUE;
743 /* This function just updates the block number. */
745 default_device_seek_block(Device * self, guint64 block) {
750 /* This default implementation serves up static responses, and
751 implements a default response to the "canonical name" property. */
754 default_device_property_get(Device * self, DevicePropertyId ID,
756 const PropertyResponse * resp;
758 resp = (PropertyResponse*)g_hash_table_lookup(selfp->property_response,
759 GINT_TO_POINTER(ID));
761 if (ID == PROPERTY_CANONICAL_NAME) {
762 g_value_unset_init(value, G_TYPE_STRING);
763 g_value_set_string(value, self->device_name);
770 g_value_unset_copy(&resp->response, value);
776 default_device_read_to_fd(Device *self, int fd) {
778 StreamingRequirement streaming_mode;
780 /* Get the device's parameters */
781 bzero(&val, sizeof(val));
782 if (!device_property_get(self, PROPERTY_STREAMING, &val)
783 || !G_VALUE_HOLDS(&val, STREAMING_REQUIREMENT_TYPE)) {
784 streaming_mode = STREAMING_REQUIREMENT_REQUIRED;
786 streaming_mode = g_value_get_enum(&val);
789 return QUEUE_SUCCESS ==
790 do_consumer_producer_queue_full(
791 device_read_producer,
795 device_read_max_size(self),
796 DEFAULT_MAX_BUFFER_MEMORY,
801 default_device_write_from_fd(Device *self, int fd) {
803 StreamingRequirement streaming_mode;
805 /* Get the device's parameters */
806 bzero(&val, sizeof(val));
807 if (!device_property_get(self, PROPERTY_STREAMING, &val)
808 || !G_VALUE_HOLDS(&val, STREAMING_REQUIREMENT_TYPE)) {
809 streaming_mode = STREAMING_REQUIREMENT_REQUIRED;
811 streaming_mode = g_value_get_enum(&val);
814 return QUEUE_SUCCESS ==
815 do_consumer_producer_queue_full(
818 device_write_consumer,
820 device_write_max_size(self),
821 DEFAULT_MAX_BUFFER_MEMORY,
826 * All the functions below this comment are stub functions that do nothing
827 * but implement the virtual function table. Call these functions and they
828 * will do what you expect vis-a-vis virtual functions. But don't put code
829 * in them beyond error checking and VFT lookup. */
832 device_open_device (Device * self, char * device_name)
835 g_return_val_if_fail (self != NULL, FALSE);
836 g_return_val_if_fail (IS_DEVICE (self), FALSE);
837 g_return_val_if_fail (device_name != NULL, FALSE);
838 klass = DEVICE_GET_CLASS(self);
840 if(klass->open_device)
841 return (*klass->open_device)(self,device_name);
846 ReadLabelStatusFlags device_read_label(Device * self) {
848 g_debug("device_read_label; mode = %d", self->access_mode);
849 g_return_val_if_fail(self != NULL, FALSE);
850 g_return_val_if_fail(IS_DEVICE(self), FALSE);
851 g_return_val_if_fail(self->access_mode == ACCESS_NULL, FALSE);
853 klass = DEVICE_GET_CLASS(self);
854 if (klass->read_label) {
855 return (klass->read_label)(self);
857 return ~ READ_LABEL_STATUS_SUCCESS;
862 device_finish (Device * self) {
864 g_return_val_if_fail (self != NULL, FALSE);
865 g_return_val_if_fail (IS_DEVICE (self), FALSE);
867 if (self->access_mode == ACCESS_NULL)
870 klass = DEVICE_GET_CLASS(self);
872 return (*klass->finish)(self);
878 /* For a good combination of synchronization and public simplicity,
879 this stub function does not take a timestamp, but the actual
880 implementation function does. We generate the timestamp here with
883 device_start (Device * self, DeviceAccessMode mode,
884 char * label, char * timestamp)
888 g_debug("device_start mode = %d", mode);
889 g_return_val_if_fail (self != NULL, FALSE);
890 g_return_val_if_fail (IS_DEVICE (self), FALSE);
891 g_return_val_if_fail (mode != ACCESS_NULL, FALSE);
892 g_return_val_if_fail (mode != ACCESS_WRITE || label != NULL,
894 klass = DEVICE_GET_CLASS(self);
897 char * local_timestamp = NULL;
900 /* fill in a timestamp if none was given */
901 if (mode == ACCESS_WRITE &&
902 get_timestamp_state(timestamp) == TIME_STATE_REPLACE) {
903 local_timestamp = timestamp =
904 get_proper_stamp_from_time(time(NULL));
907 rv = (*klass->start)(self, mode, label, timestamp);
908 amfree(local_timestamp);
909 g_debug("device_start done; dev->access_mode = %d, result %d", self->access_mode, rv);
917 device_write_block (Device * self, guint size, gpointer block,
918 gboolean short_block)
921 g_return_val_if_fail (self != NULL, FALSE);
922 g_return_val_if_fail (IS_DEVICE (self), FALSE);
923 g_return_val_if_fail (size > 0, FALSE);
924 g_return_val_if_fail (short_block ||
925 size >= device_write_min_size(self), FALSE);
926 g_return_val_if_fail (size <= device_write_max_size(self), FALSE);
927 g_return_val_if_fail (block != NULL, FALSE);
928 g_return_val_if_fail (IS_WRITABLE_ACCESS_MODE(self->access_mode),
931 klass = DEVICE_GET_CLASS(self);
933 if(klass->write_block)
934 return (*klass->write_block)(self,size, block, short_block);
940 device_write_from_fd (Device * self, int fd)
943 g_return_val_if_fail (self != NULL, FALSE);
944 g_return_val_if_fail (IS_DEVICE (self), FALSE);
945 g_return_val_if_fail (fd >= 0, FALSE);
946 g_return_val_if_fail (IS_WRITABLE_ACCESS_MODE(self->access_mode),
949 klass = DEVICE_GET_CLASS(self);
951 if(klass->write_from_fd)
952 return (*klass->write_from_fd)(self,fd);
958 device_start_file (Device * self, const dumpfile_t * jobInfo) {
960 g_return_val_if_fail (self != NULL, FALSE);
961 g_return_val_if_fail (IS_DEVICE (self), FALSE);
962 g_return_val_if_fail (!(self->in_file), FALSE);
963 g_return_val_if_fail (jobInfo != NULL, FALSE);
965 klass = DEVICE_GET_CLASS(self);
967 if(klass->start_file)
968 return (*klass->start_file)(self, jobInfo );
974 device_finish_file (Device * self)
977 g_return_val_if_fail (self != NULL, FALSE);
978 g_return_val_if_fail (IS_DEVICE (self), FALSE);
979 g_return_val_if_fail (IS_WRITABLE_ACCESS_MODE(self->access_mode),
981 g_return_val_if_fail (self->in_file, FALSE);
983 klass = DEVICE_GET_CLASS(self);
985 if(klass->finish_file)
986 return (*klass->finish_file)(self);
992 device_seek_file (Device * self, guint file)
995 g_return_val_if_fail (self != NULL, NULL);
996 g_return_val_if_fail (IS_DEVICE (self), NULL);
997 g_return_val_if_fail (self->access_mode == ACCESS_READ,
1000 klass = DEVICE_GET_CLASS(self);
1002 if(klass->seek_file)
1003 return (*klass->seek_file)(self,file);
1009 device_seek_block (Device * self, guint64 block)
1012 g_return_val_if_fail (self != NULL, FALSE);
1013 g_return_val_if_fail (IS_DEVICE (self), FALSE);
1014 g_return_val_if_fail (self->access_mode == ACCESS_READ,
1016 g_return_val_if_fail (self->in_file, FALSE);
1018 klass = DEVICE_GET_CLASS(self);
1020 if(klass->seek_block)
1021 return (*klass->seek_block)(self,block);
1027 device_read_block (Device * self, gpointer buffer, int * size)
1030 g_return_val_if_fail (self != NULL, -1);
1031 g_return_val_if_fail (IS_DEVICE (self), -1);
1032 g_return_val_if_fail (size != NULL, -1);
1033 g_return_val_if_fail (self->access_mode == ACCESS_READ, -1);
1035 g_return_val_if_fail (buffer != NULL, -1);
1038 /* Do a quick check here, so fixed-block subclasses don't have to. */
1040 device_write_min_size(self) == device_write_max_size(self)) {
1041 *size = device_write_min_size(self);
1045 klass = DEVICE_GET_CLASS(self);
1047 if(klass->read_block)
1048 return (*klass->read_block)(self,buffer,size);
1054 device_read_to_fd (Device * self, int fd)
1057 g_return_val_if_fail (self != NULL, FALSE);
1058 g_return_val_if_fail (IS_DEVICE (self), FALSE);
1059 g_return_val_if_fail (fd >= 0, FALSE);
1060 g_return_val_if_fail (self->access_mode == ACCESS_READ, FALSE);
1062 klass = DEVICE_GET_CLASS(self);
1064 if(klass->read_to_fd)
1065 return (*klass->read_to_fd)(self,fd);
1072 device_property_get (Device * self, DevicePropertyId id, GValue * val)
1075 g_return_val_if_fail (self != NULL, FALSE);
1076 g_return_val_if_fail (IS_DEVICE (self), FALSE);
1077 g_return_val_if_fail (device_property_get_by_id(id) != NULL, FALSE);
1079 klass = DEVICE_GET_CLASS(self);
1081 /* FIXME: Check access flags? */
1083 if(klass->property_get)
1084 return (*klass->property_get)(self,id,val);
1090 device_property_set (Device * self, DevicePropertyId id, GValue * val)
1093 g_return_val_if_fail (self != NULL, FALSE);
1094 g_return_val_if_fail (IS_DEVICE (self), FALSE);
1096 klass = DEVICE_GET_CLASS(self);
1098 /* FIXME: Check access flags? */
1100 if(klass->property_set)
1101 return (*klass->property_set)(self,id,val);
1107 device_recycle_file (Device * self, guint filenum)
1110 g_return_val_if_fail (self != NULL, FALSE);
1111 g_return_val_if_fail (IS_DEVICE (self), FALSE);
1112 g_return_val_if_fail (self->access_mode == ACCESS_APPEND, FALSE);
1114 klass = DEVICE_GET_CLASS(self);
1116 if(klass->recycle_file)
1117 return (*klass->recycle_file)(self,filenum);