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 if (device_read_label(self) != READ_LABEL_STATUS_SUCCESS)
656 } else if (mode == ACCESS_WRITE) {
657 self->volume_label = newstralloc(self->volume_label, label);
658 self->volume_time = newstralloc(self->volume_time, timestamp);
660 self->access_mode = mode;
665 static gboolean default_device_open_device(Device * self,
666 char * device_name) {
670 self->device_name = stralloc(device_name);
672 prop.base = &device_property_canonical_name;
673 prop.access = PROPERTY_ACCESS_GET_MASK;
675 for(i = 0; i < selfp->property_list->len; i ++) {
676 if (g_array_index(selfp->property_list,
677 DeviceProperty, i).base->ID == prop.base->ID) {
681 /* If we got here, the property was not registered. */
682 device_add_property(self, &prop, NULL);
687 /* This default implementation does very little. */
689 default_device_finish (Device * self) {
690 self->access_mode = ACCESS_NULL;
694 /* This function updates the file, in_file, and block attributes. */
696 default_device_start_file (Device * self,
697 const dumpfile_t * jobInfo G_GNUC_UNUSED) {
698 self->in_file = TRUE;
707 /* This function lies: It updates the block number and maybe calls
708 device_finish_file(), but returns FALSE. */
710 default_device_write_block(Device * self, guint size G_GNUC_UNUSED,
711 gpointer data G_GNUC_UNUSED, gboolean last_block) {
714 device_finish_file(self);
718 /* This function lies: It updates the block number, but returns
721 default_device_read_block(Device * self, gpointer buf G_GNUC_UNUSED,
722 int * size G_GNUC_UNUSED) {
727 /* This function just updates the in_file field. */
729 default_device_finish_file(Device * self) {
730 self->in_file = FALSE;
734 /* This function just updates the file number. */
736 default_device_seek_file(Device * self, guint file) {
737 self->in_file = TRUE;
742 /* This function just updates the block number. */
744 default_device_seek_block(Device * self, guint64 block) {
749 /* This default implementation serves up static responses, and
750 implements a default response to the "canonical name" property. */
753 default_device_property_get(Device * self, DevicePropertyId ID,
755 const PropertyResponse * resp;
757 resp = (PropertyResponse*)g_hash_table_lookup(selfp->property_response,
758 GINT_TO_POINTER(ID));
760 if (ID == PROPERTY_CANONICAL_NAME) {
761 g_value_unset_init(value, G_TYPE_STRING);
762 g_value_set_string(value, self->device_name);
769 g_value_unset_copy(&resp->response, value);
775 default_device_read_to_fd(Device *self, int fd) {
776 return do_consumer_producer_queue(device_read_producer,
779 GINT_TO_POINTER(fd));
783 default_device_write_from_fd(Device *self, int fd) {
784 return do_consumer_producer_queue(fd_read_producer,
786 device_write_consumer,
791 * All the functions below this comment are stub functions that do nothing
792 * but implement the virtual function table. Call these functions and they
793 * will do what you expect vis-a-vis virtual functions. But don't put code
794 * in them beyond error checking and VFT lookup. */
797 device_open_device (Device * self, char * device_name)
800 g_return_val_if_fail (self != NULL, FALSE);
801 g_return_val_if_fail (IS_DEVICE (self), FALSE);
802 g_return_val_if_fail (device_name != NULL, FALSE);
803 klass = DEVICE_GET_CLASS(self);
805 if(klass->open_device)
806 return (*klass->open_device)(self,device_name);
811 ReadLabelStatusFlags device_read_label(Device * self) {
813 g_return_val_if_fail(self != NULL, FALSE);
814 g_return_val_if_fail(IS_DEVICE(self), FALSE);
815 g_return_val_if_fail(self->access_mode == ACCESS_NULL, FALSE);
817 klass = DEVICE_GET_CLASS(self);
818 if (klass->read_label) {
819 return (klass->read_label)(self);
821 return ~ READ_LABEL_STATUS_SUCCESS;
826 device_finish (Device * self) {
828 g_return_val_if_fail (self != NULL, FALSE);
829 g_return_val_if_fail (IS_DEVICE (self), FALSE);
831 if (self->access_mode == ACCESS_NULL)
834 klass = DEVICE_GET_CLASS(self);
836 return (*klass->finish)(self);
842 /* For a good combination of synchronization and public simplicity,
843 this stub function does not take a timestamp, but the actual
844 implementation function does. We generate the timestamp here with
847 device_start (Device * self, DeviceAccessMode mode,
848 char * label, char * timestamp)
852 g_return_val_if_fail (self != NULL, FALSE);
853 g_return_val_if_fail (IS_DEVICE (self), FALSE);
854 g_return_val_if_fail (mode != ACCESS_NULL, FALSE);
855 g_return_val_if_fail (mode != ACCESS_WRITE || label != NULL,
857 klass = DEVICE_GET_CLASS(self);
860 char * local_timestamp = NULL;
863 /* fill in a timestamp if none was given */
864 if (mode == ACCESS_WRITE &&
865 get_timestamp_state(timestamp) == TIME_STATE_REPLACE) {
866 local_timestamp = timestamp =
867 get_proper_stamp_from_time(time(NULL));
870 rv = (*klass->start)(self, mode, label, timestamp);
871 amfree(local_timestamp);
879 device_write_block (Device * self, guint size, gpointer block,
880 gboolean short_block)
883 g_return_val_if_fail (self != NULL, FALSE);
884 g_return_val_if_fail (IS_DEVICE (self), FALSE);
885 g_return_val_if_fail (size > 0, FALSE);
886 g_return_val_if_fail (short_block ||
887 size >= device_write_min_size(self), FALSE);
888 g_return_val_if_fail (size <= device_write_max_size(self), FALSE);
889 g_return_val_if_fail (block != NULL, FALSE);
890 g_return_val_if_fail (IS_WRITABLE_ACCESS_MODE(self->access_mode),
893 klass = DEVICE_GET_CLASS(self);
895 if(klass->write_block)
896 return (*klass->write_block)(self,size, block, short_block);
902 device_write_from_fd (Device * self, int fd)
905 g_return_val_if_fail (self != NULL, FALSE);
906 g_return_val_if_fail (IS_DEVICE (self), FALSE);
907 g_return_val_if_fail (fd >= 0, FALSE);
908 g_return_val_if_fail (IS_WRITABLE_ACCESS_MODE(self->access_mode),
911 klass = DEVICE_GET_CLASS(self);
913 if(klass->write_from_fd)
914 return (*klass->write_from_fd)(self,fd);
920 device_start_file (Device * self, const dumpfile_t * jobInfo) {
922 g_return_val_if_fail (self != NULL, FALSE);
923 g_return_val_if_fail (IS_DEVICE (self), FALSE);
924 g_return_val_if_fail (!(self->in_file), FALSE);
925 g_return_val_if_fail (jobInfo != NULL, FALSE);
927 klass = DEVICE_GET_CLASS(self);
929 if(klass->start_file)
930 return (*klass->start_file)(self, jobInfo );
936 device_finish_file (Device * self)
939 g_return_val_if_fail (self != NULL, FALSE);
940 g_return_val_if_fail (IS_DEVICE (self), FALSE);
941 g_return_val_if_fail (IS_WRITABLE_ACCESS_MODE(self->access_mode),
943 g_return_val_if_fail (self->in_file, FALSE);
945 klass = DEVICE_GET_CLASS(self);
947 if(klass->finish_file)
948 return (*klass->finish_file)(self);
954 device_seek_file (Device * self, guint file)
957 g_return_val_if_fail (self != NULL, NULL);
958 g_return_val_if_fail (IS_DEVICE (self), NULL);
959 g_return_val_if_fail (self->access_mode == ACCESS_READ,
962 klass = DEVICE_GET_CLASS(self);
965 return (*klass->seek_file)(self,file);
971 device_seek_block (Device * self, guint64 block)
974 g_return_val_if_fail (self != NULL, FALSE);
975 g_return_val_if_fail (IS_DEVICE (self), FALSE);
976 g_return_val_if_fail (self->access_mode == ACCESS_READ,
978 g_return_val_if_fail (self->in_file, FALSE);
980 klass = DEVICE_GET_CLASS(self);
982 if(klass->seek_block)
983 return (*klass->seek_block)(self,block);
989 device_read_block (Device * self, gpointer buffer, int * size)
992 g_return_val_if_fail (self != NULL, -1);
993 g_return_val_if_fail (IS_DEVICE (self), -1);
994 g_return_val_if_fail (size != NULL, -1);
995 g_return_val_if_fail (self->access_mode == ACCESS_READ, -1);
997 g_return_val_if_fail (buffer != NULL, -1);
1000 /* Do a quick check here, so fixed-block subclasses don't have to. */
1002 device_write_min_size(self) == device_write_max_size(self)) {
1003 *size = device_write_min_size(self);
1007 klass = DEVICE_GET_CLASS(self);
1009 if(klass->read_block)
1010 return (*klass->read_block)(self,buffer,size);
1016 device_read_to_fd (Device * self, int fd)
1019 g_return_val_if_fail (self != NULL, FALSE);
1020 g_return_val_if_fail (IS_DEVICE (self), FALSE);
1021 g_return_val_if_fail (fd >= 0, FALSE);
1022 g_return_val_if_fail (self->access_mode == ACCESS_READ, FALSE);
1024 klass = DEVICE_GET_CLASS(self);
1026 if(klass->read_to_fd)
1027 return (*klass->read_to_fd)(self,fd);
1034 device_property_get (Device * self, DevicePropertyId id, GValue * val)
1037 g_return_val_if_fail (self != NULL, FALSE);
1038 g_return_val_if_fail (IS_DEVICE (self), FALSE);
1039 g_return_val_if_fail (device_property_get_by_id(id) != NULL, FALSE);
1041 klass = DEVICE_GET_CLASS(self);
1043 /* FIXME: Check access flags? */
1045 if(klass->property_get)
1046 return (*klass->property_get)(self,id,val);
1052 device_property_set (Device * self, DevicePropertyId id, GValue * val)
1055 g_return_val_if_fail (self != NULL, FALSE);
1056 g_return_val_if_fail (IS_DEVICE (self), FALSE);
1058 klass = DEVICE_GET_CLASS(self);
1060 /* FIXME: Check access flags? */
1062 if(klass->property_set)
1063 return (*klass->property_set)(self,id,val);
1069 device_recycle_file (Device * self, guint filenum)
1072 g_return_val_if_fail (self != NULL, FALSE);
1073 g_return_val_if_fail (IS_DEVICE (self), FALSE);
1074 g_return_val_if_fail (self->access_mode == ACCESS_APPEND, FALSE);
1076 klass = DEVICE_GET_CLASS(self);
1078 if(klass->recycle_file)
1079 return (*klass->recycle_file)(self,filenum);