Imported Upstream version 2.6.0p2
[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         g_debug("default_device_start calling device_read_label with mode %d", mode);
655         if (device_read_label(self) != READ_LABEL_STATUS_SUCCESS)
656             return FALSE;
657     } else if (mode == ACCESS_WRITE) {
658         self->volume_label = newstralloc(self->volume_label, label);
659         self->volume_time = newstralloc(self->volume_time, timestamp);
660     }
661     self->access_mode = mode;
662
663     return TRUE;
664 }
665
666 static gboolean default_device_open_device(Device * self,
667                                            char * device_name) {
668     DeviceProperty prop;
669     guint i;
670
671     self->device_name = stralloc(device_name);
672
673     prop.base = &device_property_canonical_name;
674     prop.access = PROPERTY_ACCESS_GET_MASK;
675
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) {
679             return TRUE;
680         }
681     }
682     /* If we got here, the property was not registered. */
683     device_add_property(self, &prop, NULL);
684
685     return TRUE;
686 }
687
688 /* This default implementation does very little. */
689 static gboolean
690 default_device_finish (Device * self) {
691     self->access_mode = ACCESS_NULL;
692     return TRUE;
693 }
694
695 /* This function updates the file, in_file, and block attributes. */
696 static gboolean
697 default_device_start_file (Device * self,
698                            const dumpfile_t * jobInfo G_GNUC_UNUSED) {
699     self->in_file = TRUE;
700     if (self->file <= 0)
701         self->file = 1;
702     else
703         self->file ++;
704     self->block = 0;
705     return TRUE;
706 }
707
708 /* This function lies: It updates the block number and maybe calls
709    device_finish_file(), but returns FALSE. */
710 static gboolean
711 default_device_write_block(Device * self, guint size G_GNUC_UNUSED,
712                            gpointer data G_GNUC_UNUSED, gboolean last_block) {
713     self->block ++;
714     if (last_block)
715         device_finish_file(self);
716     return FALSE;
717 }
718
719 /* This function lies: It updates the block number, but returns
720    -1. */
721 static int
722 default_device_read_block(Device * self, gpointer buf G_GNUC_UNUSED,
723                           int * size G_GNUC_UNUSED) {
724     self->block ++;
725     return -1;
726 }
727
728 /* This function just updates the in_file field. */
729 static gboolean
730 default_device_finish_file(Device * self) {
731     self->in_file = FALSE;
732     return TRUE;
733 }
734
735 /* This function just updates the file number. */
736 static dumpfile_t *
737 default_device_seek_file(Device * self, guint file) {
738     self->in_file = TRUE;
739     self->file = file;
740     return NULL;
741 }
742
743 /* This function just updates the block number. */
744 static gboolean
745 default_device_seek_block(Device * self, guint64 block) {
746     self->block = block;
747     return TRUE;
748 }
749
750 /* This default implementation serves up static responses, and
751    implements a default response to the "canonical name" property. */
752
753 static gboolean
754 default_device_property_get(Device * self, DevicePropertyId ID,
755                             GValue * value) {
756     const PropertyResponse * resp;
757
758     resp = (PropertyResponse*)g_hash_table_lookup(selfp->property_response,
759                                                   GINT_TO_POINTER(ID));
760     if (resp == NULL) {
761         if (ID == PROPERTY_CANONICAL_NAME) {
762             g_value_unset_init(value, G_TYPE_STRING);
763             g_value_set_string(value, self->device_name);
764             return TRUE;
765         } else {
766             return FALSE;
767         }
768     }
769
770     g_value_unset_copy(&resp->response, value);
771
772     return TRUE;
773 }
774
775 static gboolean
776 default_device_read_to_fd(Device *self, int fd) {
777     GValue val;
778     StreamingRequirement streaming_mode;
779
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;
785     } else {
786         streaming_mode = g_value_get_enum(&val);
787     }
788
789     return QUEUE_SUCCESS ==
790         do_consumer_producer_queue_full(
791             device_read_producer,
792             self,
793             fd_write_consumer,
794             GINT_TO_POINTER(fd),
795             device_read_max_size(self),
796             DEFAULT_MAX_BUFFER_MEMORY,
797             streaming_mode);
798 }
799
800 static gboolean
801 default_device_write_from_fd(Device *self, int fd) {
802     GValue val;
803     StreamingRequirement streaming_mode;
804
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;
810     } else {
811         streaming_mode = g_value_get_enum(&val);
812     }
813
814     return QUEUE_SUCCESS ==
815         do_consumer_producer_queue_full(
816             fd_read_producer,
817             GINT_TO_POINTER(fd),
818             device_write_consumer,
819             self,
820             device_write_max_size(self),
821             DEFAULT_MAX_BUFFER_MEMORY,
822             streaming_mode);
823 }
824
825 /* XXX WARNING XXX
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. */
830
831 gboolean 
832 device_open_device (Device * self, char * device_name)
833 {
834         DeviceClass *klass;
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);
839
840         if(klass->open_device)
841             return (*klass->open_device)(self,device_name);
842         else
843                 return FALSE;
844 }
845
846 ReadLabelStatusFlags device_read_label(Device * self) {
847     DeviceClass * klass;
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);
852
853     klass = DEVICE_GET_CLASS(self);
854     if (klass->read_label) {
855         return (klass->read_label)(self);
856     } else {
857         return ~ READ_LABEL_STATUS_SUCCESS;
858     }
859 }
860
861 gboolean
862 device_finish (Device * self) {
863         DeviceClass *klass;
864         g_return_val_if_fail (self != NULL, FALSE);
865         g_return_val_if_fail (IS_DEVICE (self), FALSE);
866
867         if (self->access_mode == ACCESS_NULL)
868             return TRUE;
869
870         klass = DEVICE_GET_CLASS(self);
871         if (klass->finish) {
872             return (*klass->finish)(self);
873         } else {
874             return FALSE;
875         }
876 }
877
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
881    time(). */
882 gboolean 
883 device_start (Device * self, DeviceAccessMode mode,
884               char * label, char * timestamp)
885 {
886         DeviceClass *klass;
887
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,
893                               FALSE);
894         klass = DEVICE_GET_CLASS(self);
895
896         if(klass->start) {
897             char * local_timestamp = NULL;
898             gboolean rv;
899
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));
905             }
906
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);
910             return rv;
911         } else {
912             return FALSE;
913         }
914 }
915
916 gboolean
917 device_write_block (Device * self, guint size, gpointer block,
918                     gboolean short_block)
919 {
920     DeviceClass *klass;
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),
929                           FALSE);
930
931     klass = DEVICE_GET_CLASS(self);
932     
933     if(klass->write_block)
934         return (*klass->write_block)(self,size, block, short_block);
935     else
936         return FALSE;
937 }
938
939 gboolean 
940 device_write_from_fd (Device * self, int fd)
941 {
942         DeviceClass *klass;
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),
947                               FALSE);
948
949         klass = DEVICE_GET_CLASS(self);
950
951         if(klass->write_from_fd)
952                 return (*klass->write_from_fd)(self,fd);
953         else
954                 return FALSE;
955 }
956
957 gboolean
958 device_start_file (Device * self, const dumpfile_t * jobInfo) {
959     DeviceClass * klass;
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);
964
965     klass = DEVICE_GET_CLASS(self);
966     
967     if(klass->start_file)
968         return (*klass->start_file)(self, jobInfo );
969     else
970         return FALSE;
971 }
972
973 gboolean 
974 device_finish_file (Device * self)
975 {
976         DeviceClass *klass;
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),
980                               FALSE);
981         g_return_val_if_fail (self->in_file, FALSE);
982
983         klass = DEVICE_GET_CLASS(self);
984
985         if(klass->finish_file)
986                 return (*klass->finish_file)(self);
987         else
988                 return FALSE;
989 }
990
991 dumpfile_t*
992 device_seek_file (Device * self, guint file)
993 {
994         DeviceClass *klass;
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,
998                               NULL);
999
1000         klass = DEVICE_GET_CLASS(self);
1001
1002         if(klass->seek_file)
1003                 return (*klass->seek_file)(self,file);
1004         else
1005                 return FALSE;
1006 }
1007
1008 gboolean 
1009 device_seek_block (Device * self, guint64 block)
1010 {
1011         DeviceClass *klass;
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,
1015                               FALSE);
1016         g_return_val_if_fail (self->in_file, FALSE);
1017
1018         klass = DEVICE_GET_CLASS(self);
1019
1020         if(klass->seek_block)
1021                 return (*klass->seek_block)(self,block);
1022         else
1023                 return FALSE;
1024 }
1025
1026 int
1027 device_read_block (Device * self, gpointer buffer, int * size)
1028 {
1029         DeviceClass *klass;
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);
1034         if (*size != 0) {
1035             g_return_val_if_fail (buffer != NULL, -1);
1036         }
1037
1038         /* Do a quick check here, so fixed-block subclasses don't have to. */
1039         if (*size == 0 &&
1040             device_write_min_size(self) == device_write_max_size(self)) {
1041             *size = device_write_min_size(self);
1042             return 0;
1043         }
1044
1045         klass = DEVICE_GET_CLASS(self);
1046
1047         if(klass->read_block)
1048             return (*klass->read_block)(self,buffer,size);
1049         else
1050             return -1;
1051 }
1052
1053 gboolean 
1054 device_read_to_fd (Device * self, int fd)
1055 {
1056         DeviceClass *klass;
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);
1061
1062         klass = DEVICE_GET_CLASS(self);
1063
1064         if(klass->read_to_fd)
1065                 return (*klass->read_to_fd)(self,fd);
1066         else
1067                 return FALSE;
1068 }
1069
1070
1071 gboolean 
1072 device_property_get (Device * self, DevicePropertyId id, GValue * val)
1073 {
1074         DeviceClass *klass;
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);
1078
1079         klass = DEVICE_GET_CLASS(self);
1080
1081         /* FIXME: Check access flags? */
1082
1083         if(klass->property_get)
1084                 return (*klass->property_get)(self,id,val);
1085         else
1086                 return FALSE;
1087 }
1088
1089 gboolean 
1090 device_property_set (Device * self, DevicePropertyId id, GValue * val)
1091 {
1092         DeviceClass *klass;
1093         g_return_val_if_fail (self != NULL, FALSE);
1094         g_return_val_if_fail (IS_DEVICE (self), FALSE);
1095
1096         klass = DEVICE_GET_CLASS(self);
1097
1098         /* FIXME: Check access flags? */
1099
1100         if(klass->property_set)
1101                 return (*klass->property_set)(self,id,val);
1102         else
1103                 return FALSE;
1104 }
1105
1106 gboolean 
1107 device_recycle_file (Device * self, guint filenum)
1108 {
1109         DeviceClass *klass;
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);
1113
1114         klass = DEVICE_GET_CLASS(self);
1115
1116         if(klass->recycle_file)
1117                 return (*klass->recycle_file)(self,filenum);
1118         else
1119                 return FALSE;
1120 }
1121