bf8cbd4e5dc30d0c16fa067393449a13f26e9d48
[debian/amanda] / device-src / device.c
1 /*
2  * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
3  * 
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.
7  * 
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.
12  * 
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.
16  * 
17  * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
18  * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
19  */
20
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. */
24
25 #include "amanda.h"
26 #include "conffile.h"
27
28 #include <regex.h>
29
30 #include "device.h"
31 #include "queueing.h"
32 #include "property.h"
33
34 #include "null-device.h"
35 #include "timestamp.h"
36 #include "vfs-device.h"
37 #include "util.h"
38 #ifdef WANT_TAPE_DEVICE
39 #include "tape-device.h"
40 #endif
41 #include "rait-device.h"
42 #ifdef WANT_S3_DEVICE
43   #include "s3-device.h"
44 #endif
45
46 static GHashTable* driverList = NULL;
47
48 void device_api_init(void) {
49     g_type_init();
50     amanda_thread_init();
51     device_property_init();
52     driverList = g_hash_table_new(g_str_hash, g_str_equal);
53
54     /* register other types and devices. */
55     null_device_register();
56     vfs_device_register();
57 #ifdef WANT_TAPE_DEVICE
58     tape_device_register();
59 #endif
60     rait_device_register();
61 #ifdef WANT_S3_DEVICE
62     s3_device_register();
63 #endif
64 }
65
66 void register_device(DeviceFactory factory,
67                      const char ** device_prefix_list) {
68     char ** tmp;
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);
73
74     tmp = (char**)device_prefix_list;
75     while (*tmp != NULL) {
76         g_hash_table_insert(driverList, *tmp, (gpointer)factory);
77         tmp ++;
78     }
79 }
80
81 static DeviceFactory lookup_device_factory(const char *device_name) {
82     gpointer key, value;
83     g_assert(driverList != NULL);
84
85     if (g_hash_table_lookup_extended(driverList, device_name, &key, &value)) {
86         return (DeviceFactory)value;
87     } else {
88         return NULL;
89     }
90 }
91
92 static const GFlagsValue read_label_status_flags_values[] = {
93     { READ_LABEL_STATUS_SUCCESS,
94       "READ_LABEL_STATUS_SUCCESS",
95       "Success" },
96     { READ_LABEL_STATUS_DEVICE_MISSING,
97       "READ_LABEL_STATUS_DEVICE_MISSING",
98       "Device not found" },
99     { READ_LABEL_STATUS_DEVICE_ERROR,
100       "READ_LABEL_STATUS_DEVICE_ERROR",
101       "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",
110       "Volume error" },
111     { 0, NULL, NULL }
112 };
113
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);
119     }
120     return type;
121 }
122
123 /* Device class definition starts here. */
124
125 struct DevicePrivate_s {
126     /* This is the return value of the device_get_property_list()
127        method. */
128     GArray *property_list;
129     GHashTable * property_response;
130 };
131
132 /* This holds the default response to a particular property. */
133 typedef struct {
134     PropertyAccessFlags access;
135     GValue response;
136 } PropertyResponse;
137
138 #define selfp (self->private)
139
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;
143
144 static void property_response_free(PropertyResponse *o);
145
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,
159                                       int * size);
160 static gboolean default_device_read_to_fd(Device *self, int fd);
161 static gboolean default_device_property_get(Device * self, DevicePropertyId ID,
162                                             GValue * value);
163
164 /* pointer to the class of our parent */
165 static GObjectClass *parent_class = NULL;
166
167 GType
168 device_get_type (void)
169 {
170     static GType type = 0;
171     
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 */,
180             sizeof (Device),
181             0 /* n_preallocs */,
182             (GInstanceInitFunc) device_init,
183             NULL
184         };
185         
186         type = g_type_register_static (G_TYPE_OBJECT, "Device", &info,
187                                        (GTypeFlags)G_TYPE_FLAG_ABSTRACT);
188     }
189     
190     return type;
191 }
192
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);
197
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) {
201         device_finish(self);
202     }
203
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);
210 }
211
212 static void 
213 device_init (Device * self G_GNUC_UNUSED)
214 {
215     self->private = malloc(sizeof(DevicePrivate));
216     self->device_name = NULL;
217     self->access_mode = ACCESS_NULL;
218     self->is_eof = FALSE;
219     self->file = -1;
220     self->block = 0;
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,
227                               g_direct_equal,
228                               NULL,
229                               (GDestroyNotify) property_response_free);
230 }
231
232 static void 
233 device_class_init (DeviceClass * c G_GNUC_UNUSED)
234 {
235     GObjectClass *g_object_class G_GNUC_UNUSED = (GObjectClass*) c;
236     
237     parent_class = g_type_class_ref (G_TYPE_OBJECT);
238     
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;
255 }
256
257 static void property_response_free(PropertyResponse * resp) {
258     g_value_unset(&(resp->response));
259     amfree(resp);
260 }
261
262 static char *
263 regex_message(int result, regex_t *regex) {
264     char * rval;
265     size_t size;
266
267     size = regerror(result, regex, NULL, 0);
268     rval = malloc(size);
269     regerror(result, regex, rval, size);
270
271     return rval;
272 }
273
274 static gboolean
275 handle_device_regex(const char * user_name, char ** driver_name,
276                     char ** device) {
277     regex_t regex;
278     int reg_result;
279     regmatch_t pmatch[3];
280     static const char * regex_string = "^([a-z0-9]+):(.*)$";
281
282     bzero(&regex, sizeof(regex));
283
284     reg_result = regcomp(&regex, regex_string, REG_EXTENDED | REG_ICASE);
285     if (reg_result != 0) {
286         char * message = regex_message(reg_result, &regex);
287         g_fprintf(stderr, "Error compiling regular expression \"%s\": %s\n",
288                regex_string, message);
289         amfree(message);
290         return FALSE;
291     }
292
293     reg_result = regexec(&regex, user_name, 3, pmatch, 0);
294     if (reg_result != 0 && reg_result != REG_NOMATCH) {
295         char * message = regex_message(reg_result, &regex);
296         g_fprintf(stderr, "Error applying regular expression \"%s\" to string \"%s\":\n"
297                "%s\n", user_name, regex_string, message);
298         regfree(&regex);
299         return FALSE;
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);
309         regfree(&regex);
310         return FALSE;
311 #endif /* WANT_TAPE_DEVICE */
312     } else {
313         *driver_name = find_regex_substring(user_name, pmatch[1]);
314         *device = find_regex_substring(user_name, pmatch[2]);
315     }
316     regfree(&regex);
317     return TRUE;
318 }
319
320 Device* 
321 device_open (char * device_name)
322 {
323     char *device_driver_name = NULL;
324     char *device_node_name = NULL;
325     DeviceFactory factory;
326     Device *device;
327
328     g_return_val_if_fail (device_name != NULL, NULL);
329
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();
334     }
335
336     if (!handle_device_regex(device_name, &device_driver_name, &device_node_name)) {
337         amfree(device_driver_name);
338         amfree(device_node_name);
339         return NULL;
340     }
341
342     factory = lookup_device_factory(device_driver_name);
343
344     if (factory == NULL) {
345         g_fprintf(stderr, "Device driver %s is not known.\n",
346                 device_driver_name);
347         amfree(device_driver_name);
348         amfree(device_node_name);
349         return NULL;
350     }
351
352     device = factory(device_driver_name, device_node_name);
353     amfree(device_driver_name);
354     amfree(device_node_name);
355     return device;
356 }
357
358 void 
359 device_add_property (Device * self, DeviceProperty * prop, GValue * response)
360 {
361     unsigned int i;
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);
366
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);
372             break;
373         }
374     }
375
376     g_array_append_val(selfp->property_list, *prop);
377     
378     if (response != NULL) {
379         PropertyResponse * property_response;
380         
381         g_return_if_fail(G_IS_VALUE(response));
382         
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));
390         
391         g_hash_table_insert(selfp->property_response,
392                             GINT_TO_POINTER(prop->base->ID),
393                             property_response);
394     }
395 }
396
397 const DeviceProperty * 
398 device_property_get_list (Device * self)
399 {
400         g_return_val_if_fail (self != NULL, (const DeviceProperty * )0);
401         g_return_val_if_fail (IS_DEVICE (self), (const DeviceProperty * )0);
402
403         return (const DeviceProperty*) selfp->property_list->data;
404 }
405
406 guint device_write_min_size(Device * self) {
407     GValue g_tmp;
408     int block_size, min_block_size;
409     
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) {
415         return block_size;
416     }
417
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;
423 }
424
425 guint device_write_max_size(Device * self) {
426     GValue g_tmp;
427     int block_size, max_block_size;
428     
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) {
434         return block_size;
435     }
436
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;
442 }
443
444 guint device_read_max_size(Device * self) {
445     GValue g_tmp;
446     
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);
451         return rval;
452     } else {
453         return device_write_max_size(self);
454     }
455 }
456
457 char * device_build_amanda_header(Device * self, const dumpfile_t * info,
458                                   int * size, gboolean * oneblock) {
459     char *amanda_header;
460     unsigned int min_header_length;
461     unsigned int header_buffer_size;
462
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);
466     if (size != NULL)
467         *size = header_buffer_size;
468     if (oneblock != NULL)
469         *oneblock = (header_buffer_size <=  device_write_max_size(self));
470     return amanda_header;
471 }
472
473 dumpfile_t * make_tapestart_header(Device * self, char * label,
474                                    char * timestamp) {
475     dumpfile_t * rval;
476
477     g_return_val_if_fail(label != NULL, NULL);
478
479     rval = malloc(sizeof(*rval));
480     fh_init(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));
485     } else {
486         self->volume_time = g_strdup(timestamp);
487     }
488     strncpy(rval->datestamp, self->volume_time, sizeof(rval->datestamp));
489     strncpy(rval->name, label, sizeof(rval->name));
490
491     return rval;
492 }
493
494 dumpfile_t * make_tapeend_header(void) {
495     dumpfile_t * rval;
496     char * timestamp;
497
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));
502     amfree(timestamp);
503     return rval;
504 }
505
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) {
510     GValue val;
511     gboolean success;
512     bzero(&val, sizeof(val));
513     g_value_init(&val, G_TYPE_UINT);
514     g_value_set_uint(&val, blocksize);
515     if (try_max_first) {
516         success = device_property_set(device,
517                                       PROPERTY_MAX_BLOCK_SIZE,
518                                       &val);
519         if (!success) {
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);
524         } else {
525             g_value_unset(&val);
526             return;
527         }
528     }
529
530     g_value_unset(&val);
531     g_value_init(&val, G_TYPE_INT);
532     g_value_set_int(&val, blocksize);
533     success = device_property_set(device,
534                                   PROPERTY_BLOCK_SIZE,
535                                   &val);
536     if (!success) {
537         g_fprintf(stderr, "Setting BLOCK_SIZE to %u "
538                 "not supported for device %s.\n",
539                 blocksize, device->device_name);
540     }
541     g_value_unset(&val);
542 }
543
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;
552
553     g_return_if_fail(IS_DEVICE(device));
554     g_return_if_fail(property_s != NULL);
555     g_return_if_fail(value_s != NULL);
556
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);
561         return;
562     }
563     
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. */
568         g_fprintf(stderr,
569                 _("Could not parse property value %s for property type %s.\n"),
570                 value_s, g_type_name(property_base->type));
571         return;
572     } else {
573         g_assert (G_VALUE_HOLDS(&property_value, property_base->type));
574     }
575
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);
580         return;
581     }
582 }
583
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) {
591             GValue val;
592             guint64 length;
593             guint blocksize_kb;
594             gboolean success;
595
596             bzero(&val, sizeof(GValue));
597
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);
604                 g_value_unset(&val);
605             }
606
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,
613                                               &val);
614                 g_value_unset(&val);
615                 if (!success) {
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);
620                 }
621             }
622
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));
627             }
628         }
629     }
630
631     g_hash_table_foreach(getconf_proplist(CNF_DEVICE_PROPERTY),
632                          set_device_property, device);
633 }
634
635 void device_clear_volume_details(Device * device) {
636     if (device == NULL || device->access_mode != ACCESS_NULL) {
637         return;
638     }
639
640     amfree(device->volume_label);
641     amfree(device->volume_time);
642 }
643
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. */
648
649 /* This function only updates access_mode, volume_label, and volume_time. */
650 static gboolean
651 default_device_start (Device * self, DeviceAccessMode mode, char * label,
652                       char * timestamp) {
653     if (mode != ACCESS_WRITE && self->volume_label == NULL) {
654         if (device_read_label(self) != READ_LABEL_STATUS_SUCCESS)
655             return FALSE;
656     } else if (mode == ACCESS_WRITE) {
657         self->volume_label = newstralloc(self->volume_label, label);
658         self->volume_time = newstralloc(self->volume_time, timestamp);
659     }
660     self->access_mode = mode;
661
662     return TRUE;
663 }
664
665 static gboolean default_device_open_device(Device * self,
666                                            char * device_name) {
667     DeviceProperty prop;
668     guint i;
669
670     self->device_name = stralloc(device_name);
671
672     prop.base = &device_property_canonical_name;
673     prop.access = PROPERTY_ACCESS_GET_MASK;
674
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) {
678             return TRUE;
679         }
680     }
681     /* If we got here, the property was not registered. */
682     device_add_property(self, &prop, NULL);
683
684     return TRUE;
685 }
686
687 /* This default implementation does very little. */
688 static gboolean
689 default_device_finish (Device * self) {
690     self->access_mode = ACCESS_NULL;
691     return TRUE;
692 }
693
694 /* This function updates the file, in_file, and block attributes. */
695 static gboolean
696 default_device_start_file (Device * self,
697                            const dumpfile_t * jobInfo G_GNUC_UNUSED) {
698     self->in_file = TRUE;
699     if (self->file <= 0)
700         self->file = 1;
701     else
702         self->file ++;
703     self->block = 0;
704     return TRUE;
705 }
706
707 /* This function lies: It updates the block number and maybe calls
708    device_finish_file(), but returns FALSE. */
709 static gboolean
710 default_device_write_block(Device * self, guint size G_GNUC_UNUSED,
711                            gpointer data G_GNUC_UNUSED, gboolean last_block) {
712     self->block ++;
713     if (last_block)
714         device_finish_file(self);
715     return FALSE;
716 }
717
718 /* This function lies: It updates the block number, but returns
719    -1. */
720 static int
721 default_device_read_block(Device * self, gpointer buf G_GNUC_UNUSED,
722                           int * size G_GNUC_UNUSED) {
723     self->block ++;
724     return -1;
725 }
726
727 /* This function just updates the in_file field. */
728 static gboolean
729 default_device_finish_file(Device * self) {
730     self->in_file = FALSE;
731     return TRUE;
732 }
733
734 /* This function just updates the file number. */
735 static dumpfile_t *
736 default_device_seek_file(Device * self, guint file) {
737     self->in_file = TRUE;
738     self->file = file;
739     return NULL;
740 }
741
742 /* This function just updates the block number. */
743 static gboolean
744 default_device_seek_block(Device * self, guint64 block) {
745     self->block = block;
746     return TRUE;
747 }
748
749 /* This default implementation serves up static responses, and
750    implements a default response to the "canonical name" property. */
751
752 static gboolean
753 default_device_property_get(Device * self, DevicePropertyId ID,
754                             GValue * value) {
755     const PropertyResponse * resp;
756
757     resp = (PropertyResponse*)g_hash_table_lookup(selfp->property_response,
758                                                   GINT_TO_POINTER(ID));
759     if (resp == NULL) {
760         if (ID == PROPERTY_CANONICAL_NAME) {
761             g_value_unset_init(value, G_TYPE_STRING);
762             g_value_set_string(value, self->device_name);
763             return TRUE;
764         } else {
765             return FALSE;
766         }
767     }
768
769     g_value_unset_copy(&resp->response, value);
770
771     return TRUE;
772 }
773
774 static gboolean
775 default_device_read_to_fd(Device *self, int fd) {
776     return do_consumer_producer_queue(device_read_producer,
777                                       self,
778                                       fd_write_consumer,
779                                       GINT_TO_POINTER(fd));
780 }
781
782 static gboolean
783 default_device_write_from_fd(Device *self, int fd) {
784     return do_consumer_producer_queue(fd_read_producer,
785                                       GINT_TO_POINTER(fd),
786                                       device_write_consumer,
787                                       self);
788 }
789
790 /* XXX WARNING XXX
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. */
795
796 gboolean 
797 device_open_device (Device * self, char * device_name)
798 {
799         DeviceClass *klass;
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);
804
805         if(klass->open_device)
806             return (*klass->open_device)(self,device_name);
807         else
808                 return FALSE;
809 }
810
811 ReadLabelStatusFlags device_read_label(Device * self) {
812     DeviceClass * klass;
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);
816
817     klass = DEVICE_GET_CLASS(self);
818     if (klass->read_label) {
819         return (klass->read_label)(self);
820     } else {
821         return ~ READ_LABEL_STATUS_SUCCESS;
822     }
823 }
824
825 gboolean
826 device_finish (Device * self) {
827         DeviceClass *klass;
828         g_return_val_if_fail (self != NULL, FALSE);
829         g_return_val_if_fail (IS_DEVICE (self), FALSE);
830
831         if (self->access_mode == ACCESS_NULL)
832             return TRUE;
833
834         klass = DEVICE_GET_CLASS(self);
835         if (klass->finish) {
836             return (*klass->finish)(self);
837         } else {
838             return FALSE;
839         }
840 }
841
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
845    time(). */
846 gboolean 
847 device_start (Device * self, DeviceAccessMode mode,
848               char * label, char * timestamp)
849 {
850         DeviceClass *klass;
851
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,
856                               FALSE);
857         klass = DEVICE_GET_CLASS(self);
858
859         if(klass->start) {
860             char * local_timestamp = NULL;
861             gboolean rv;
862
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));
868             }
869
870             rv = (*klass->start)(self, mode, label, timestamp);
871             amfree(local_timestamp);
872             return rv;
873         } else {
874             return FALSE;
875         }
876 }
877
878 gboolean
879 device_write_block (Device * self, guint size, gpointer block,
880                     gboolean short_block)
881 {
882     DeviceClass *klass;
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),
891                           FALSE);
892
893     klass = DEVICE_GET_CLASS(self);
894     
895     if(klass->write_block)
896         return (*klass->write_block)(self,size, block, short_block);
897     else
898         return FALSE;
899 }
900
901 gboolean 
902 device_write_from_fd (Device * self, int fd)
903 {
904         DeviceClass *klass;
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),
909                               FALSE);
910
911         klass = DEVICE_GET_CLASS(self);
912
913         if(klass->write_from_fd)
914                 return (*klass->write_from_fd)(self,fd);
915         else
916                 return FALSE;
917 }
918
919 gboolean
920 device_start_file (Device * self, const dumpfile_t * jobInfo) {
921     DeviceClass * klass;
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);
926
927     klass = DEVICE_GET_CLASS(self);
928     
929     if(klass->start_file)
930         return (*klass->start_file)(self, jobInfo );
931     else
932         return FALSE;
933 }
934
935 gboolean 
936 device_finish_file (Device * self)
937 {
938         DeviceClass *klass;
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),
942                               FALSE);
943         g_return_val_if_fail (self->in_file, FALSE);
944
945         klass = DEVICE_GET_CLASS(self);
946
947         if(klass->finish_file)
948                 return (*klass->finish_file)(self);
949         else
950                 return FALSE;
951 }
952
953 dumpfile_t*
954 device_seek_file (Device * self, guint file)
955 {
956         DeviceClass *klass;
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,
960                               NULL);
961
962         klass = DEVICE_GET_CLASS(self);
963
964         if(klass->seek_file)
965                 return (*klass->seek_file)(self,file);
966         else
967                 return FALSE;
968 }
969
970 gboolean 
971 device_seek_block (Device * self, guint64 block)
972 {
973         DeviceClass *klass;
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,
977                               FALSE);
978         g_return_val_if_fail (self->in_file, FALSE);
979
980         klass = DEVICE_GET_CLASS(self);
981
982         if(klass->seek_block)
983                 return (*klass->seek_block)(self,block);
984         else
985                 return FALSE;
986 }
987
988 int
989 device_read_block (Device * self, gpointer buffer, int * size)
990 {
991         DeviceClass *klass;
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);
996         if (*size != 0) {
997             g_return_val_if_fail (buffer != NULL, -1);
998         }
999
1000         /* Do a quick check here, so fixed-block subclasses don't have to. */
1001         if (*size == 0 &&
1002             device_write_min_size(self) == device_write_max_size(self)) {
1003             *size = device_write_min_size(self);
1004             return 0;
1005         }
1006
1007         klass = DEVICE_GET_CLASS(self);
1008
1009         if(klass->read_block)
1010             return (*klass->read_block)(self,buffer,size);
1011         else
1012             return -1;
1013 }
1014
1015 gboolean 
1016 device_read_to_fd (Device * self, int fd)
1017 {
1018         DeviceClass *klass;
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);
1023
1024         klass = DEVICE_GET_CLASS(self);
1025
1026         if(klass->read_to_fd)
1027                 return (*klass->read_to_fd)(self,fd);
1028         else
1029                 return FALSE;
1030 }
1031
1032
1033 gboolean 
1034 device_property_get (Device * self, DevicePropertyId id, GValue * val)
1035 {
1036         DeviceClass *klass;
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);
1040
1041         klass = DEVICE_GET_CLASS(self);
1042
1043         /* FIXME: Check access flags? */
1044
1045         if(klass->property_get)
1046                 return (*klass->property_get)(self,id,val);
1047         else
1048                 return FALSE;
1049 }
1050
1051 gboolean 
1052 device_property_set (Device * self, DevicePropertyId id, GValue * val)
1053 {
1054         DeviceClass *klass;
1055         g_return_val_if_fail (self != NULL, FALSE);
1056         g_return_val_if_fail (IS_DEVICE (self), FALSE);
1057
1058         klass = DEVICE_GET_CLASS(self);
1059
1060         /* FIXME: Check access flags? */
1061
1062         if(klass->property_set)
1063                 return (*klass->property_set)(self,id,val);
1064         else
1065                 return FALSE;
1066 }
1067
1068 gboolean 
1069 device_recycle_file (Device * self, guint filenum)
1070 {
1071         DeviceClass *klass;
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);
1075
1076         klass = DEVICE_GET_CLASS(self);
1077
1078         if(klass->recycle_file)
1079                 return (*klass->recycle_file)(self,filenum);
1080         else
1081                 return FALSE;
1082 }
1083