Imported Upstream version 2.6.1
[debian/amanda] / device-src / tape-device.c
1 /*
2  * Copyright (c) 2005-2008 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., 465 S Mathlida Ave, Suite 300
18  * Sunnyvale, CA 94086, USA, or: http://www.zmanda.com
19  */
20
21 #include <string.h> /* memset() */
22 #include "util.h"
23 #include "tape-device.h"
24 #include "tape-ops.h"
25
26 /* This is equal to 2*1024*1024*1024 - 16*1024*1024 - 1, but written 
27    explicitly to avoid overflow issues. */
28 #define RESETOFS_THRESHOLD (0x7effffff)
29
30 /* Largest possible block size on SCSI systems. */
31 #define LARGEST_BLOCK_ESTIMATE (16 * 1024 * 1024)
32
33 struct TapeDevicePrivate_s {
34     /* This holds the total number of bytes written to the device,
35        modulus RESETOFS_THRESHOLD. */
36     int write_count;
37     char * device_filename;
38     gsize read_buffer_size;
39 };
40
41 /* Possible (abstracted) results from a system I/O operation. */
42 typedef enum {
43     RESULT_SUCCESS,
44     RESULT_ERROR,        /* Undefined error. */
45     RESULT_SMALL_BUFFER, /* Tried to read with a buffer that is too
46                             small. */
47     RESULT_NO_DATA,      /* End of File, while reading */
48     RESULT_NO_SPACE,     /* Out of space. Sometimes we don't know if
49                             it was this or I/O error, but this is the
50                             preferred explanation. */
51     RESULT_MAX
52 } IoResult;
53
54 /*
55  * Our device-specific properties.  These are not static because they are
56  * accessed from the OS-specific tape-*.c files.
57  */
58 DevicePropertyBase device_property_broken_gmt_online;
59 DevicePropertyBase device_property_fsf;
60 DevicePropertyBase device_property_bsf;
61 DevicePropertyBase device_property_fsr;
62 DevicePropertyBase device_property_bsr;
63 DevicePropertyBase device_property_eom;
64 DevicePropertyBase device_property_bsf_after_eom;
65 DevicePropertyBase device_property_final_filemarks;
66
67 void tape_device_register(void);
68
69 #define tape_device_read_size(self) \
70     (((TapeDevice *)(self))->private->read_buffer_size? \
71         ((TapeDevice *)(self))->private->read_buffer_size : ((Device *)(self))->block_size)
72
73 /* here are local prototypes */
74 static void tape_device_init (TapeDevice * o);
75 static void tape_device_class_init (TapeDeviceClass * c);
76 static void tape_device_base_init (TapeDeviceClass * c);
77 static gboolean tape_device_set_feature_property_fn(Device *p_self, DevicePropertyBase *base,
78                                     GValue *val, PropertySurety surety, PropertySource source);
79 static gboolean tape_device_set_final_filemarks_fn(Device *p_self, DevicePropertyBase *base,
80                                     GValue *val, PropertySurety surety, PropertySource source);
81 static gboolean tape_device_set_compression_fn(Device *p_self, DevicePropertyBase *base,
82                                     GValue *val, PropertySurety surety, PropertySource source);
83 static gboolean tape_device_set_read_buffer_size_fn(Device *p_self, DevicePropertyBase *base,
84                                     GValue *val, PropertySurety surety, PropertySource source);
85 static void tape_device_open_device (Device * self, char * device_name, char * device_type, char * device_node);
86 static Device * tape_device_factory (char * device_name, char * device_type, char * device_node);
87 static DeviceStatusFlags tape_device_read_label(Device * self);
88 static gboolean tape_device_write_block(Device * self, guint size, gpointer data);
89 static int tape_device_read_block(Device * self,  gpointer buf,
90                                        int * size_req);
91 static gboolean tape_device_start (Device * self, DeviceAccessMode mode,
92                                    char * label, char * timestamp);
93 static gboolean tape_device_start_file (Device * self, dumpfile_t * ji);
94 static gboolean tape_device_finish_file (Device * self);
95 static dumpfile_t * tape_device_seek_file (Device * self, guint file);
96 static gboolean tape_device_seek_block (Device * self, guint64 block);
97 static gboolean tape_device_finish (Device * self);
98 static IoResult tape_device_robust_read (TapeDevice * self, void * buf,
99                                                int * count);
100 static IoResult tape_device_robust_write (TapeDevice * self, void * buf, int count);
101 static gboolean tape_device_fsf (TapeDevice * self, guint count);
102 static gboolean tape_device_bsf (TapeDevice * self, guint count, guint file);
103 static gboolean tape_device_fsr (TapeDevice * self, guint count);
104 static gboolean tape_device_bsr (TapeDevice * self, guint count, guint file, guint block);
105 static gboolean tape_device_eod (TapeDevice * self);
106
107 /* pointer to the class of our parent */
108 static DeviceClass *parent_class = NULL;
109
110 GType tape_device_get_type (void)
111 {
112     static GType type = 0;
113     
114     if G_UNLIKELY(type == 0) {
115         static const GTypeInfo info = {
116             sizeof (TapeDeviceClass),
117             (GBaseInitFunc) tape_device_base_init,
118             (GBaseFinalizeFunc) NULL,
119             (GClassInitFunc) tape_device_class_init,
120             (GClassFinalizeFunc) NULL,
121             NULL /* class_data */,
122             sizeof (TapeDevice),
123             0 /* n_preallocs */,
124             (GInstanceInitFunc) tape_device_init,
125             NULL
126         };
127         
128         type = g_type_register_static (TYPE_DEVICE, "TapeDevice",
129                                        &info, (GTypeFlags)0);
130     }
131
132     return type;
133 }
134
135 static void 
136 tape_device_init (TapeDevice * self) {
137     Device * d_self;
138     GValue response;
139
140     d_self = DEVICE(self);
141     bzero(&response, sizeof(response));
142
143     self->private = g_new0(TapeDevicePrivate, 1);
144
145     /* Clear all fields. */
146     d_self->block_size = 32768;
147     d_self->min_block_size = 32768;
148     d_self->max_block_size = LARGEST_BLOCK_ESTIMATE;
149     self->broken_gmt_online = FALSE;
150
151     self->fd = -1;
152
153     /* set all of the feature properties to an unsure default of FALSE */
154     self->broken_gmt_online = FALSE;
155     self->fsf = FALSE;
156     self->bsf = FALSE;
157     self->fsr = FALSE;
158     self->bsr = FALSE;
159     self->eom = FALSE;
160     self->bsf_after_eom = FALSE;
161
162     g_value_init(&response, G_TYPE_BOOLEAN);
163     g_value_set_boolean(&response, FALSE);
164     device_set_simple_property(d_self, PROPERTY_BROKEN_GMT_ONLINE,
165             &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
166     device_set_simple_property(d_self, PROPERTY_FSF,
167             &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
168     device_set_simple_property(d_self, PROPERTY_BSF,
169             &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
170     device_set_simple_property(d_self, PROPERTY_FSR,
171             &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
172     device_set_simple_property(d_self, PROPERTY_BSR,
173             &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
174     device_set_simple_property(d_self, PROPERTY_EOM,
175             &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
176     device_set_simple_property(d_self, PROPERTY_BSF_AFTER_EOM,
177             &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
178     g_value_unset(&response);
179
180     self->final_filemarks = 2;
181     g_value_init(&response, G_TYPE_UINT);
182     g_value_set_uint(&response, self->final_filemarks);
183     device_set_simple_property(d_self, PROPERTY_FINAL_FILEMARKS,
184             &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
185     g_value_unset(&response);
186
187     self->private->read_buffer_size = 0;
188     g_value_init(&response, G_TYPE_UINT);
189     g_value_set_uint(&response, self->private->read_buffer_size);
190     device_set_simple_property(d_self, PROPERTY_READ_BUFFER_SIZE,
191             &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DEFAULT);
192     g_value_unset(&response);
193
194     self->private->write_count = 0;
195     self->private->device_filename = NULL;
196
197     /* Static properites */
198     g_value_init(&response, CONCURRENCY_PARADIGM_TYPE);
199     g_value_set_enum(&response, CONCURRENCY_PARADIGM_EXCLUSIVE);
200     device_set_simple_property(d_self, PROPERTY_CONCURRENCY,
201             &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
202     g_value_unset(&response);
203
204     g_value_init(&response, STREAMING_REQUIREMENT_TYPE);
205     g_value_set_enum(&response, STREAMING_REQUIREMENT_DESIRED);
206     device_set_simple_property(d_self, PROPERTY_STREAMING,
207             &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
208     g_value_unset(&response);
209
210     g_value_init(&response, G_TYPE_BOOLEAN);
211     g_value_set_boolean(&response, FALSE);
212     device_set_simple_property(d_self, PROPERTY_APPENDABLE,
213             &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
214     g_value_unset(&response);
215
216     g_value_init(&response, G_TYPE_BOOLEAN);
217     g_value_set_boolean(&response, FALSE);
218     device_set_simple_property(d_self, PROPERTY_PARTIAL_DELETION,
219             &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
220     g_value_unset(&response);
221
222     g_value_init(&response, MEDIA_ACCESS_MODE_TYPE);
223     g_value_set_enum(&response, MEDIA_ACCESS_MODE_READ_WRITE);
224     device_set_simple_property(d_self, PROPERTY_MEDIUM_ACCESS_TYPE,
225             &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
226     g_value_unset(&response);
227 }
228
229 static void tape_device_finalize(GObject * obj_self) {
230     TapeDevice * self = TAPE_DEVICE(obj_self);
231
232     if(G_OBJECT_CLASS(parent_class)->finalize) \
233            (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
234
235     robust_close(self->fd);
236     self->fd = -1;
237     amfree(self->private->device_filename);
238     amfree(self->private);
239 }
240
241 static void 
242 tape_device_class_init (TapeDeviceClass * c)
243 {
244     DeviceClass *device_class = (DeviceClass *)c;
245     GObjectClass *g_object_class = (GObjectClass *)c;
246
247     parent_class = g_type_class_ref (TYPE_DEVICE);
248     
249     device_class->open_device = tape_device_open_device;
250     device_class->read_label = tape_device_read_label;
251     device_class->write_block = tape_device_write_block;
252     device_class->read_block = tape_device_read_block;
253     device_class->start = tape_device_start;
254     device_class->start_file = tape_device_start_file;
255     device_class->finish_file = tape_device_finish_file;
256     device_class->seek_file = tape_device_seek_file;
257     device_class->seek_block = tape_device_seek_block;
258     device_class->finish = tape_device_finish;
259     
260     g_object_class->finalize = tape_device_finalize;
261 }
262
263 static void
264 tape_device_base_init (TapeDeviceClass * c)
265 {
266     DeviceClass *device_class = (DeviceClass *)c;
267
268     device_class_register_property(device_class, PROPERTY_BROKEN_GMT_ONLINE,
269             PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
270             device_simple_property_get_fn,
271             tape_device_set_feature_property_fn);
272
273     device_class_register_property(device_class, PROPERTY_FSF,
274             PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
275             device_simple_property_get_fn,
276             tape_device_set_feature_property_fn);
277
278     device_class_register_property(device_class, PROPERTY_BSF,
279             PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
280             device_simple_property_get_fn,
281             tape_device_set_feature_property_fn);
282
283     device_class_register_property(device_class, PROPERTY_FSR,
284             PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
285             device_simple_property_get_fn,
286             tape_device_set_feature_property_fn);
287
288     device_class_register_property(device_class, PROPERTY_BSR,
289             PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
290             device_simple_property_get_fn,
291             tape_device_set_feature_property_fn);
292
293     device_class_register_property(device_class, PROPERTY_EOM,
294             PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
295             device_simple_property_get_fn,
296             tape_device_set_feature_property_fn);
297
298     device_class_register_property(device_class, PROPERTY_BSF_AFTER_EOM,
299             PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
300             device_simple_property_get_fn,
301             tape_device_set_feature_property_fn);
302
303     device_class_register_property(device_class, PROPERTY_FINAL_FILEMARKS,
304             PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
305             device_simple_property_get_fn,
306             tape_device_set_final_filemarks_fn);
307
308     /* We don't (yet?) support reading the device's compression state, so not
309      * gettable. */
310     device_class_register_property(device_class, PROPERTY_COMPRESSION,
311             PROPERTY_ACCESS_SET_MASK,
312             NULL,
313             tape_device_set_compression_fn);
314
315     device_class_register_property(device_class, PROPERTY_READ_BUFFER_SIZE,
316             PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
317             device_simple_property_get_fn,
318             tape_device_set_read_buffer_size_fn);
319 }
320
321 static gboolean
322 tape_device_set_feature_property_fn(Device *p_self, DevicePropertyBase *base,
323     GValue *val, PropertySurety surety, PropertySource source)
324 {
325     TapeDevice *self = TAPE_DEVICE(p_self);
326     GValue old_val;
327     gboolean old_bool, new_bool;
328     PropertySurety old_surety;
329     PropertySource old_source;
330
331     new_bool = g_value_get_boolean(val);
332
333     /* get the old source and surety and see if we're willing to make this change */
334     bzero(&old_val, sizeof(old_val));
335     if (device_get_simple_property(p_self, base->ID, &old_val, &old_surety, &old_source)) {
336         old_bool = g_value_get_boolean(&old_val);
337
338         if (old_surety == PROPERTY_SURETY_GOOD && old_source == PROPERTY_SOURCE_DETECTED) {
339             if (new_bool != old_bool) {
340                 device_set_error(p_self, vstrallocf(_(
341                            "Value for property '%s' was autodetected and cannot be changed"),
342                            base->name),
343                     DEVICE_STATUS_DEVICE_ERROR);
344                 return FALSE;
345             } else {
346                 /* pretend we set it, but don't change surety/source */
347                 return TRUE;
348             }
349         }
350     }
351
352     /* (note: PROPERTY_* are not constants, so we can't use switch) */
353     if (base->ID == PROPERTY_BROKEN_GMT_ONLINE)
354         self->broken_gmt_online = new_bool;
355     else if (base->ID == PROPERTY_FSF)
356         self->fsf = new_bool;
357     else if (base->ID == PROPERTY_BSF)
358         self->bsf = new_bool;
359     else if (base->ID == PROPERTY_FSR)
360         self->fsr = new_bool;
361     else if (base->ID == PROPERTY_BSR)
362         self->bsr = new_bool;
363     else if (base->ID == PROPERTY_EOM)
364         self->eom = new_bool;
365     else if (base->ID == PROPERTY_BSF_AFTER_EOM)
366         self->bsf_after_eom = new_bool;
367     else
368         return FALSE; /* shouldn't happen */
369
370     return device_simple_property_set_fn(p_self, base, val, surety, source);
371 }
372
373 static gboolean
374 tape_device_set_final_filemarks_fn(Device *p_self, DevicePropertyBase *base,
375     GValue *val, PropertySurety surety, PropertySource source)
376 {
377     TapeDevice *self = TAPE_DEVICE(p_self);
378     GValue old_val;
379     gboolean old_int, new_int;
380     PropertySurety old_surety;
381     PropertySource old_source;
382
383     new_int = g_value_get_uint(val);
384
385     /* get the old source and surety and see if we're willing to make this change */
386     bzero(&old_val, sizeof(old_val));
387     if (device_get_simple_property(p_self, base->ID, &old_val, &old_surety, &old_source)) {
388         old_int = g_value_get_uint(&old_val);
389
390         if (old_surety == PROPERTY_SURETY_GOOD && old_source == PROPERTY_SOURCE_DETECTED) {
391             if (new_int != old_int) {
392                 device_set_error(p_self, vstrallocf(_(
393                            "Value for property '%s' was autodetected and cannot be changed"),
394                            base->name),
395                     DEVICE_STATUS_DEVICE_ERROR);
396                 return FALSE;
397             } else {
398                 /* pretend we set it, but don't change surety/source */
399                 return TRUE;
400             }
401         }
402     }
403
404     self->final_filemarks = new_int;
405
406     return device_simple_property_set_fn(p_self, base, val, surety, source);
407 }
408
409 static gboolean
410 tape_device_set_compression_fn(Device *p_self, DevicePropertyBase *base,
411     GValue *val, PropertySurety surety, PropertySource source)
412 {
413     TapeDevice *self = TAPE_DEVICE(p_self);
414     gboolean request = g_value_get_boolean(val);
415
416     /* We allow this property to be set at any time. This is mostly
417      * because setting compression is a hit-and-miss proposition
418      * at any time; some drives accept the mode setting but don't
419      * actually support compression, while others do support
420      * compression but do it via density settings or some other
421      * way. Set this property whenever you want, but all we'll do
422      * is report whether or not the ioctl succeeded. */
423     if (tape_setcompression(self->fd, request)) {
424         /* looks good .. let's start the device over, though */
425         device_clear_volume_details(p_self);
426     } else {
427         return FALSE;
428     }
429
430     return device_simple_property_set_fn(p_self, base, val, surety, source);
431 }
432
433 static gboolean
434 tape_device_set_read_buffer_size_fn(Device *p_self, DevicePropertyBase *base,
435     GValue *val, PropertySurety surety, PropertySource source)
436 {
437     TapeDevice *self = TAPE_DEVICE(p_self);
438     guint buffer_size = g_value_get_uint(val);
439
440     if (buffer_size != 0 &&
441             ((gsize)buffer_size < p_self->block_size ||
442              (gsize)buffer_size > p_self->max_block_size))
443         return FALSE;
444
445     self->private->read_buffer_size = buffer_size;
446
447     return device_simple_property_set_fn(p_self, base, val, surety, source);
448 }
449
450 void tape_device_register(void) {
451     static const char * device_prefix_list[] = { "tape", NULL };
452
453     /* First register tape-specific properties */
454     device_property_fill_and_register(&device_property_broken_gmt_online,
455                                       G_TYPE_BOOLEAN, "broken_gmt_online",
456       "Does this drive support the GMT_ONLINE macro?");
457
458     device_property_fill_and_register(&device_property_fsf,
459                                       G_TYPE_BOOLEAN, "fsf",
460       "Does this drive support the MTFSF command?");
461
462     device_property_fill_and_register(&device_property_bsf,
463                                       G_TYPE_BOOLEAN, "bsf",
464       "Does this drive support the MTBSF command?" );
465
466     device_property_fill_and_register(&device_property_fsr,
467                                       G_TYPE_BOOLEAN, "fsr",
468       "Does this drive support the MTFSR command?");
469
470     device_property_fill_and_register(&device_property_bsr,
471                                       G_TYPE_BOOLEAN, "bsr",
472       "Does this drive support the MTBSR command?");
473
474     /* FIXME: Is this feature even useful? */
475     device_property_fill_and_register(&device_property_eom,
476                                       G_TYPE_BOOLEAN, "eom",
477       "Does this drive support the MTEOM command?");
478
479     device_property_fill_and_register(&device_property_bsf_after_eom,
480                                       G_TYPE_BOOLEAN,
481                                       "bsf_after_eom",
482       "Does this drive require an MTBSF after MTEOM in order to append?" );
483
484     device_property_fill_and_register(&device_property_final_filemarks,
485                                       G_TYPE_UINT, "final_filemarks",
486       "How many filemarks to write after the last tape file?" );
487
488     /* Then the device itself */
489     register_device(tape_device_factory, device_prefix_list);
490 }
491
492 static int try_open_tape_device(TapeDevice * self, char * device_filename) {
493     int fd;
494     int save_errno;
495     DeviceStatusFlags new_status;
496
497     fd = robust_open(device_filename, O_RDWR,0);
498     save_errno = errno;
499     if (fd >= 0) {
500         self->write_open_errno = 0;
501     } else {
502         if (errno == EACCES || errno == EPERM) {
503             /* Device is write-protected. */
504             self->write_open_errno = errno;
505             fd = robust_open(device_filename, O_RDONLY,0);
506             save_errno = errno;
507         }
508     }
509
510     if (fd < 0) {
511         DeviceStatusFlags status_flag = 0;
512         if (errno == EBUSY)
513             status_flag = DEVICE_STATUS_DEVICE_BUSY;
514         else
515             status_flag = DEVICE_STATUS_DEVICE_ERROR;
516         device_set_error(DEVICE(self),
517             vstrallocf(_("Can't open tape device %s: %s"), self->private->device_filename, strerror(errno)),
518             status_flag);
519         return -1;
520     }
521
522     /* Check that this is actually a tape device. */
523     new_status = tape_is_tape_device(fd);
524     if (new_status & DEVICE_STATUS_DEVICE_ERROR) {
525         device_set_error(DEVICE(self),
526             vstrallocf(_("File %s is not a tape device"), self->private->device_filename),
527             new_status);
528         robust_close(fd);
529         return -1;
530     }
531     if (new_status & DEVICE_STATUS_VOLUME_MISSING) {
532         device_set_error(DEVICE(self),
533             vstrallocf(_("Tape device %s is not ready or is empty"), self->private->device_filename),
534             new_status);
535         robust_close(fd);
536         return -1;
537     }
538
539     new_status = tape_is_ready(fd, self);
540     if (new_status & DEVICE_STATUS_VOLUME_MISSING) {
541         device_set_error(DEVICE(self),
542             vstrallocf(_("Tape device %s is empty"), self->private->device_filename),
543             new_status);
544         robust_close(fd);
545         return -1;
546     }
547     if (new_status != DEVICE_STATUS_SUCCESS) {
548         device_set_error(DEVICE(self),
549             vstrallocf(_("Tape device %s is not ready or is empty"), self->private->device_filename),
550             new_status);
551         robust_close(fd);
552         return -1;
553     }
554
555     return fd;
556 }
557
558 static void
559 tape_device_open_device (Device * d_self, char * device_name G_GNUC_UNUSED,
560                         char * device_type G_GNUC_UNUSED, char * device_node) {
561     TapeDevice * self;
562
563     self = TAPE_DEVICE(d_self);
564
565     self->fd = -1;
566     self->private->device_filename = stralloc(device_node);
567
568     /* Get tape drive/OS info */
569     tape_device_detect_capabilities(self);
570
571     /* Chain up */
572     if (parent_class->open_device) {
573         parent_class->open_device(d_self, device_node, device_type, device_node);
574     }
575 }
576
577 void
578 tape_device_set_capabilities(TapeDevice *self,
579         gboolean fsf, PropertySurety fsf_surety, PropertySource fsf_source,
580         gboolean bsf, PropertySurety bsf_surety, PropertySource bsf_source,
581         gboolean fsr, PropertySurety fsr_surety, PropertySource fsr_source,
582         gboolean bsr, PropertySurety bsr_surety, PropertySource bsr_source,
583         gboolean eom, PropertySurety eom_surety, PropertySource eom_source,
584         gboolean bsf_after_eom, PropertySurety bae_surety, PropertySource bae_source,
585         guint final_filemarks, PropertySurety ff_surety, PropertySource ff_source)
586 {
587     Device *dself = DEVICE(self);
588     GValue val;
589
590     /* this function is called by tape_device_detect_capabilities, and basically
591      * exists to take care of the GValue mechanics in one place */
592
593     g_assert(final_filemarks == 1 || final_filemarks == 2);
594
595     bzero(&val, sizeof(val));
596     g_value_init(&val, G_TYPE_BOOLEAN);
597
598     self->fsf = fsf;
599     g_value_set_boolean(&val, fsf);
600     device_set_simple_property(dself, PROPERTY_FSF, &val, fsf_surety, fsf_source);
601
602     self->bsf = bsf;
603     g_value_set_boolean(&val, bsf);
604     device_set_simple_property(dself, PROPERTY_BSF, &val, bsf_surety, bsf_source);
605
606     self->fsr = fsr;
607     g_value_set_boolean(&val, fsr);
608     device_set_simple_property(dself, PROPERTY_FSR, &val, fsr_surety, fsr_source);
609
610     self->bsr = bsr;
611     g_value_set_boolean(&val, bsr);
612     device_set_simple_property(dself, PROPERTY_BSR, &val, bsr_surety, bsr_source);
613
614     self->eom = eom;
615     g_value_set_boolean(&val, eom);
616     device_set_simple_property(dself, PROPERTY_EOM, &val, eom_surety, eom_source);
617
618     self->bsf_after_eom = bsf_after_eom;
619     g_value_set_boolean(&val, bsf_after_eom);
620     device_set_simple_property(dself, PROPERTY_BSF_AFTER_EOM, &val, bae_surety, bae_source);
621
622     g_value_unset(&val);
623     g_value_init(&val, G_TYPE_UINT);
624
625     self->final_filemarks = final_filemarks;
626     g_value_set_uint(&val, final_filemarks);
627     device_set_simple_property(dself, PROPERTY_FINAL_FILEMARKS, &val, ff_surety, ff_source);
628
629     g_value_unset(&val);
630 }
631
632 static DeviceStatusFlags tape_device_read_label(Device * dself) {
633     TapeDevice * self;
634     char * header_buffer;
635     int buffer_len;
636     IoResult result;
637     dumpfile_t *header;
638     DeviceStatusFlags new_status;
639
640     self = TAPE_DEVICE(dself);
641
642     amfree(dself->volume_label);
643     amfree(dself->volume_time);
644     amfree(dself->volume_header);
645
646     if (device_in_error(self)) return dself->status;
647
648     header = dself->volume_header = g_new(dumpfile_t, 1);
649     fh_init(header);
650
651     if (self->fd == -1) {
652         self->fd = try_open_tape_device(self, self->private->device_filename);
653         /* if the open failed, then try_open_tape_device already set the
654          * approppriate error status */
655         if (self->fd == -1)
656             return dself->status;
657     }
658
659     /* Rewind it. */
660     if (!tape_rewind(self->fd)) {
661         device_set_error(dself,
662             vstrallocf(_("Error rewinding device %s"), self->private->device_filename),
663               DEVICE_STATUS_DEVICE_ERROR
664             | DEVICE_STATUS_VOLUME_ERROR);
665         robust_close(self->fd);
666         return dself->status;
667     }
668
669     buffer_len = tape_device_read_size(self);
670     header_buffer = malloc(buffer_len);
671     result = tape_device_robust_read(self, header_buffer, &buffer_len);
672
673     if (result != RESULT_SUCCESS) {
674         free(header_buffer);
675         tape_rewind(self->fd);
676         /* I/O error. */
677         if (result == RESULT_NO_DATA) {
678             new_status = (DEVICE_STATUS_VOLUME_ERROR |
679                           DEVICE_STATUS_VOLUME_UNLABELED);
680         } else {
681             new_status = (DEVICE_STATUS_DEVICE_ERROR |
682                           DEVICE_STATUS_VOLUME_ERROR |
683                           DEVICE_STATUS_VOLUME_UNLABELED);
684         }
685         device_set_error(dself, stralloc(_("Error reading Amanda header")), new_status);
686         return dself->status;
687     }
688
689     parse_file_header(header_buffer, header, buffer_len);
690     amfree(header_buffer);
691     if (header->type != F_TAPESTART) {
692         device_set_error(dself,
693                 stralloc(_("No tapestart header -- unlabeled device?")),
694                 DEVICE_STATUS_VOLUME_UNLABELED);
695         return dself->status;
696     }
697
698     dself->volume_label = g_strdup(header->name);
699     dself->volume_time = g_strdup(header->datestamp);
700     /* dself->volume_header is already set */
701
702     device_set_error(dself, NULL, DEVICE_STATUS_SUCCESS);
703
704     return dself->status;
705 }
706
707 static gboolean
708 tape_device_write_block(Device * pself, guint size, gpointer data) {
709     TapeDevice * self;
710     char *replacement_buffer = NULL;
711     IoResult result;
712
713     self = TAPE_DEVICE(pself);
714
715     g_assert(self->fd >= 0);
716     if (device_in_error(self)) return FALSE;
717
718     /* zero out to the end of a short block -- tape devices only write
719      * whole blocks. */
720     if (size < pself->block_size) {
721         replacement_buffer = malloc(pself->block_size);
722         memcpy(replacement_buffer, data, size);
723         bzero(replacement_buffer+size, pself->block_size-size);
724
725         data = replacement_buffer;
726         size = pself->block_size;
727     }
728
729     result = tape_device_robust_write(self, data, size);
730     amfree(replacement_buffer);
731
732     switch (result) {
733         case RESULT_SUCCESS:
734             break;
735
736         case RESULT_NO_SPACE:
737             device_set_error(pself,
738                 stralloc(_("No space left on device")),
739                 DEVICE_STATUS_VOLUME_ERROR);
740             pself->is_eof = TRUE;
741             return FALSE;
742
743         default:
744         case RESULT_ERROR:
745             device_set_error(pself,
746                 vstrallocf(_("Error writing block: %s"), strerror(errno)),
747                 DEVICE_STATUS_DEVICE_ERROR);
748             return FALSE;
749     }
750
751     pself->block++;
752
753     return TRUE;
754 }
755
756 static int tape_device_read_block (Device * pself, gpointer buf,
757                                    int * size_req) {
758     TapeDevice * self;
759     int size;
760     IoResult result;
761     gssize read_block_size = tape_device_read_size(pself);
762     
763     self = TAPE_DEVICE(pself);
764
765     g_assert(self->fd >= 0);
766     if (device_in_error(self)) return -1;
767
768     g_assert(read_block_size < INT_MAX); /* data type mismatch */
769     if (buf == NULL || *size_req < (int)read_block_size) {
770         /* Just a size query. */
771         *size_req = (int)read_block_size;
772         return 0;
773     }
774
775     size = *size_req;
776     result = tape_device_robust_read(self, buf, &size);
777     switch (result) {
778     case RESULT_SUCCESS:
779         *size_req = size;
780         pself->block++;
781         return size;
782     case RESULT_SMALL_BUFFER: {
783         gsize new_size;
784         GValue newval;
785
786         /* If this happens, it means that we have:
787          *     (next block size) > (buffer size) >= (read_block_size)
788          * The solution is to ask for an even bigger buffer. We also play
789          * some games to refrain from reading above the SCSI limit or from
790          * integer overflow.  Note that not all devices will tell us about
791          * this problem -- some will just discard the "extra" data. */
792         new_size = MIN(INT_MAX/2 - 1, *size_req) * 2;
793         if (new_size > LARGEST_BLOCK_ESTIMATE &&
794             *size_req < LARGEST_BLOCK_ESTIMATE) {
795             new_size = LARGEST_BLOCK_ESTIMATE;
796         }
797         g_assert (new_size > (gsize)*size_req);
798
799         g_warning("Device %s indicated blocksize %zd was too small; using %zd.",
800             pself->device_name, (gsize)*size_req, new_size);
801         *size_req = (int)new_size;
802         self->private->read_buffer_size = new_size;
803
804         bzero(&newval, sizeof(newval));
805         g_value_init(&newval, G_TYPE_UINT);
806         g_value_set_uint(&newval, self->private->read_buffer_size);
807         device_set_simple_property(pself, PROPERTY_READ_BUFFER_SIZE,
808                 &newval, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
809         g_value_unset(&newval);
810
811         return 0;
812     }
813     case RESULT_NO_DATA:
814         pself->is_eof = TRUE;
815         pself->in_file = FALSE;
816         device_set_error(pself,
817             stralloc(_("EOF")),
818             DEVICE_STATUS_SUCCESS);
819         return -1;
820
821     default:
822         device_set_error(pself,
823             vstrallocf(_("Error reading from tape device: %s"), strerror(errno)),
824             DEVICE_STATUS_VOLUME_ERROR | DEVICE_STATUS_DEVICE_ERROR);
825         return -1;
826     }
827
828     g_assert_not_reached();
829 }
830
831 /* Just a helper function for tape_device_start(). */
832 static gboolean write_tapestart_header(TapeDevice * self, char * label,
833                                        char * timestamp) {
834      IoResult result;
835      dumpfile_t * header;
836      char * header_buf;
837      int header_size;
838      gboolean header_fits;
839      Device * d_self = (Device*)self;
840      tape_rewind(self->fd);
841     
842      header = make_tapestart_header(d_self, label, timestamp);
843      g_assert(header != NULL);
844      header_buf = device_build_amanda_header(d_self, header, &header_size,
845                                              &header_fits);
846      amfree(header);
847      g_assert(header_buf != NULL);
848
849      if (!header_fits) {
850          amfree(header_buf);
851          device_set_error(d_self,
852             stralloc(_("Tapestart header won't fit in a single block!")),
853             DEVICE_STATUS_DEVICE_ERROR);
854          return FALSE;
855      }
856
857      g_assert(header_size >= (int)d_self->min_block_size);
858      result = tape_device_robust_write(self, header_buf, header_size);
859      if (result != RESULT_SUCCESS) {
860          device_set_error(d_self,
861             vstrallocf(_("Error writing tapestart header: %s"), strerror(errno)),
862             DEVICE_STATUS_DEVICE_ERROR);
863         amfree(header_buf);
864         return FALSE;
865      }
866
867      amfree(header_buf);
868
869      if (!tape_weof(self->fd, 1)) {
870         device_set_error(d_self,
871                          vstrallocf(_("Error writing filemark: %s"),
872                                     strerror(errno)),
873                          DEVICE_STATUS_DEVICE_ERROR|DEVICE_STATUS_VOLUME_ERROR);
874         return FALSE;
875      }
876
877      return TRUE;
878
879 }
880
881 static gboolean 
882 tape_device_start (Device * d_self, DeviceAccessMode mode, char * label,
883                    char * timestamp) {
884     TapeDevice * self;
885
886     self = TAPE_DEVICE(d_self);
887
888     if (device_in_error(self)) return FALSE;
889
890     if (self->fd == -1) {
891         self->fd = try_open_tape_device(self, self->private->device_filename);
892         /* if the open failed, then try_open_tape_device already set the
893          * approppriate error status */
894         if (self->fd == -1)
895             return FALSE;
896     }
897
898     if (mode != ACCESS_WRITE && d_self->volume_label == NULL) {
899         /* we need a labeled volume for APPEND and READ */
900         if (tape_device_read_label(d_self) != DEVICE_STATUS_SUCCESS)
901             return FALSE;
902     }
903
904     d_self->access_mode = mode;
905     d_self->in_file = FALSE;
906
907     if (IS_WRITABLE_ACCESS_MODE(mode)) {
908         if (self->write_open_errno != 0) {
909             /* We tried and failed to open the device in write mode. */
910             device_set_error(d_self,
911                 vstrallocf(_("Can't open tape device %s for writing: %s"),
912                             self->private->device_filename, strerror(self->write_open_errno)),
913                 DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
914             return FALSE;
915         } else if (!tape_rewind(self->fd)) {
916             device_set_error(d_self,
917                 vstrallocf(_("Couldn't rewind device: %s"), strerror(errno)),
918                 DEVICE_STATUS_DEVICE_ERROR);
919             return FALSE;
920         }
921     }
922
923     /* Position the tape */
924     switch (mode) {
925     case ACCESS_APPEND:
926         if (d_self->volume_label == NULL && device_read_label(d_self) != DEVICE_STATUS_SUCCESS) {
927             /* device_read_label already set our error message */
928             return FALSE;
929         }
930
931         if (!tape_device_eod(self)) {
932             device_set_error(d_self,
933                 vstrallocf(_("Couldn't seek to end of tape: %s"), strerror(errno)),
934                 DEVICE_STATUS_DEVICE_ERROR);
935             return FALSE;
936         }
937         break;
938         
939     case ACCESS_READ:
940         if (d_self->volume_label == NULL && device_read_label(d_self) != DEVICE_STATUS_SUCCESS) {
941             /* device_read_label already set our error message */
942             return FALSE;
943         }
944
945         if (!tape_rewind(self->fd)) {
946             device_set_error(d_self,
947                 vstrallocf(_("Couldn't rewind device: %s"), strerror(errno)),
948                 DEVICE_STATUS_DEVICE_ERROR);
949             return FALSE;
950         }
951         d_self->file = 0;
952         break;
953
954     case ACCESS_WRITE:
955         if (!write_tapestart_header(self, label, timestamp)) {
956             /* write_tapestart_header already set the error status */
957             return FALSE;
958         }
959
960         d_self->volume_label = newstralloc(d_self->volume_label, label);
961         d_self->volume_time = newstralloc(d_self->volume_time, timestamp);
962
963         /* unset the VOLUME_UNLABELED flag, if it was set */
964         device_set_error(d_self, NULL, DEVICE_STATUS_SUCCESS);
965         d_self->file = 0;
966         break;
967
968     default:
969         g_assert_not_reached();
970     }
971
972     return TRUE;
973 }
974
975 static gboolean tape_device_start_file(Device * d_self,
976                                        dumpfile_t * info) {
977     TapeDevice * self;
978     IoResult result;
979     char * amanda_header;
980     int header_size;
981     gboolean header_fits;
982
983     self = TAPE_DEVICE(d_self);
984
985     g_assert(self->fd >= 0);
986     if (device_in_error(self)) return FALSE;
987
988     /* set the blocksize in the header properly */
989     info->blocksize = d_self->block_size;
990
991     /* Make the Amanda header suitable for writing to the device. */
992     /* Then write the damn thing. */
993     amanda_header = device_build_amanda_header(d_self, info,
994                                                &header_size, &header_fits);
995     if (!header_fits) {
996         device_set_error(d_self,
997             stralloc(_("Amanda file header won't fit in a single block!")),
998             DEVICE_STATUS_DEVICE_ERROR);
999         return FALSE;
1000     }
1001     result = tape_device_robust_write(self, amanda_header, header_size);
1002     if (result != RESULT_SUCCESS) {
1003         device_set_error(d_self,
1004             vstrallocf(_("Error writing file header: %s"), strerror(errno)),
1005             DEVICE_STATUS_DEVICE_ERROR);
1006         amfree(amanda_header);
1007         return FALSE;
1008     }
1009     amfree(amanda_header);
1010
1011     /* arrange the file numbers correctly */
1012     d_self->in_file = TRUE;
1013     d_self->block = 0;
1014     if (d_self->file >= 0)
1015         d_self->file ++;
1016     return TRUE;
1017 }
1018
1019 static gboolean
1020 tape_device_finish_file (Device * d_self) {
1021     TapeDevice * self;
1022
1023     self = TAPE_DEVICE(d_self);
1024     if (device_in_error(d_self)) return FALSE;
1025
1026     if (!tape_weof(self->fd, 1)) {
1027         device_set_error(d_self,
1028                 vstrallocf(_("Error writing filemark: %s"), strerror(errno)),
1029                 DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
1030         return FALSE;
1031     }
1032
1033     d_self->in_file = FALSE;
1034     return TRUE;
1035 }
1036
1037 static dumpfile_t * 
1038 tape_device_seek_file (Device * d_self, guint file) {
1039     TapeDevice * self;
1040     int difference;
1041     char * header_buffer;
1042     dumpfile_t * rval;
1043     int buffer_len;
1044     IoResult result;
1045
1046     self = TAPE_DEVICE(d_self);
1047
1048     if (device_in_error(self)) return NULL;
1049
1050     difference = file - d_self->file;
1051
1052     /* Check if we already read a filemark. */
1053     if (d_self->is_eof) {
1054         difference --;
1055     }
1056
1057     d_self->in_file = FALSE;
1058     d_self->is_eof = FALSE;
1059     d_self->block = 0;
1060
1061     if (difference > 0) {
1062         /* Seeking forwards */
1063         if (!tape_device_fsf(self, difference)) {
1064             tape_rewind(self->fd);
1065             device_set_error(d_self,
1066                 vstrallocf(_("Could not seek forward to file %d"), file),
1067                 DEVICE_STATUS_VOLUME_ERROR | DEVICE_STATUS_DEVICE_ERROR);
1068             return NULL;
1069         }
1070     } else if (difference < 0) {
1071         /* Seeking backwards */
1072         if (!tape_device_bsf(self, -difference, d_self->file)) {
1073             tape_rewind(self->fd);
1074             device_set_error(d_self,
1075                 vstrallocf(_("Could not seek backward to file %d"), file),
1076                 DEVICE_STATUS_VOLUME_ERROR | DEVICE_STATUS_DEVICE_ERROR);
1077             return NULL;
1078         }
1079     }
1080
1081     buffer_len = tape_device_read_size(d_self);
1082     header_buffer = malloc(buffer_len);
1083     d_self->is_eof = FALSE;
1084     result = tape_device_robust_read(self, header_buffer, &buffer_len);
1085
1086     if (result != RESULT_SUCCESS) {
1087         free(header_buffer);
1088         tape_rewind(self->fd);
1089         if (result == RESULT_NO_DATA) {
1090             /* If we read 0 bytes, that means we encountered a double
1091              * filemark, which indicates end of tape. This should
1092              * work even with QIC tapes on operating systems with
1093              * proper support. */
1094             d_self->file = file; /* other attributes are already correct */
1095             return make_tapeend_header();
1096         }
1097         /* I/O error. */
1098         device_set_error(d_self,
1099             stralloc(_("Error reading Amanda header")),
1100             DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
1101         return NULL;
1102     }
1103         
1104     rval = g_new(dumpfile_t, 1);
1105     parse_file_header(header_buffer, rval, buffer_len);
1106     amfree(header_buffer);
1107     switch (rval->type) {
1108     case F_DUMPFILE:
1109     case F_CONT_DUMPFILE:
1110     case F_SPLIT_DUMPFILE:
1111         break;
1112
1113     default:
1114         tape_rewind(self->fd);
1115         device_set_error(d_self,
1116             stralloc(_("Invalid amanda header while reading file header")),
1117             DEVICE_STATUS_VOLUME_ERROR);
1118         amfree(rval);
1119         return NULL;
1120     }
1121
1122     d_self->in_file = TRUE;
1123     d_self->file = file;
1124
1125     return rval;
1126 }
1127
1128 static gboolean 
1129 tape_device_seek_block (Device * d_self, guint64 block) {
1130     TapeDevice * self;
1131     int difference;
1132
1133     self = TAPE_DEVICE(d_self);
1134
1135     if (device_in_error(self)) return FALSE;
1136
1137     difference = block - d_self->block;
1138     
1139     if (difference > 0) {
1140         if (!tape_device_fsr(self, difference)) {
1141             device_set_error(d_self,
1142                 vstrallocf(_("Could not seek forward to block %ju"), (uintmax_t)block),
1143                 DEVICE_STATUS_VOLUME_ERROR | DEVICE_STATUS_DEVICE_ERROR);
1144             return FALSE;
1145         }
1146     } else if (difference < 0) {
1147         if (!tape_device_bsr(self, difference, d_self->file, d_self->block)) {
1148             device_set_error(d_self,
1149                 vstrallocf(_("Could not seek backward to block %ju"), (uintmax_t)block),
1150                 DEVICE_STATUS_VOLUME_ERROR | DEVICE_STATUS_DEVICE_ERROR);
1151             return FALSE;
1152         }
1153     }
1154
1155     d_self->block = block;
1156     return TRUE;
1157 }
1158
1159 static gboolean 
1160 tape_device_finish (Device * d_self) {
1161     TapeDevice * self;
1162
1163     self = TAPE_DEVICE(d_self);
1164
1165     if (device_in_error(self)) return FALSE;
1166
1167     if (d_self->access_mode == ACCESS_NULL)
1168         return TRUE;
1169
1170     /* Polish off this file, if relevant. */
1171     if (d_self->in_file && IS_WRITABLE_ACCESS_MODE(d_self->access_mode)) {
1172         if (!device_finish_file(d_self))
1173             return FALSE;
1174     }
1175
1176     /* Write an extra filemark, if needed. The OS will give us one for
1177        sure. */
1178     /* device_finish_file already wrote one for us */
1179     /*
1180     if (self->final_filemarks > 1 &&
1181         IS_WRITABLE_ACCESS_MODE(d_self->access_mode)) {
1182         if (!tape_weof(self->fd, 1)) {
1183         device_set_error(d_self,
1184             vstrallocf(_("Error writing final filemark: %s"), strerror(errno)),
1185             DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
1186             return FALSE;
1187         }
1188     }
1189     */
1190
1191     /* Rewind. */
1192     if (!tape_rewind(self->fd)) {
1193         device_set_error(d_self,
1194             vstrallocf(_("Couldn't rewind device: %s"), strerror(errno)),
1195             DEVICE_STATUS_DEVICE_ERROR);
1196         return FALSE;
1197     }
1198
1199     d_self->access_mode = ACCESS_NULL;
1200
1201     return TRUE;
1202 }
1203
1204 /* Works just like read(), except for the following:
1205  * 1) Retries on EINTR & friends.
1206  * 2) Stores count in parameter, not return value.
1207  * 3) Provides explicit return result. */
1208 static IoResult
1209 tape_device_robust_read (TapeDevice * self, void * buf, int * count) {
1210     Device * d_self;
1211     int result;
1212
1213     d_self = (Device*)self;
1214
1215     /* Callers should ensure this. */
1216     g_assert(*count >= 0);
1217
1218     for (;;) {
1219         result = read(self->fd, buf, *count);
1220         if (result > 0) {
1221             /* Success. By definition, we read a full block. */
1222             *count = result;
1223             return RESULT_SUCCESS;
1224         } else if (result == 0) {
1225             return RESULT_NO_DATA;
1226         } else {
1227             if (0
1228 #ifdef EAGAIN
1229                 || errno == EAGAIN
1230 #endif
1231 #ifdef EWOULDBLOCK
1232                 || errno == EWOULDBLOCK
1233 #endif
1234 #ifdef EINTR
1235                 || errno == EINTR
1236 #endif
1237                 ) {
1238                 /* Interrupted system call */
1239                 continue;
1240             } else if ((0
1241 #ifdef ENOMEM
1242                         || errno == ENOMEM /* bad user-space buffer */
1243 #endif
1244 #ifdef EOVERFLOW
1245                         || errno == EOVERFLOW /* bad kernel-space buffer */
1246 #endif
1247 #ifdef EINVAL
1248                         || errno == EINVAL /* ??? */
1249 #endif
1250                         )) {
1251                 /* Buffer too small. */
1252                 return RESULT_SMALL_BUFFER;
1253             } else {
1254                 device_set_error(d_self,
1255                     vstrallocf(_("Error reading %d bytes from %s: %s"),
1256                                 *count, self->private->device_filename, strerror(errno)),
1257                     DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
1258                 return RESULT_ERROR;
1259             }
1260         }
1261
1262     }
1263
1264     g_assert_not_reached();
1265 }
1266
1267 /* Kernel workaround: If needed, poke the kernel so it doesn't fail.
1268    at the 2GB boundry. Parameters are G_GNUC_UNUSED in case NEED_RESETOFS
1269    is not defined. */
1270 static void check_resetofs(TapeDevice * self G_GNUC_UNUSED,
1271                            int count G_GNUC_UNUSED) {
1272 #ifdef NEED_RESETOFS
1273     Device * d_self;
1274     int result;
1275
1276     d_self = (Device*)self;
1277
1278     self->private->write_count += count;
1279     if (self->private->write_count < RESETOFS_THRESHOLD) {
1280         return;
1281     }
1282
1283     result = lseek(self->fd, 0, SEEK_SET);
1284     if (result < 0) {
1285         g_warning(_("lseek() failed during kernel 2GB workaround: %s"),
1286                strerror(errno));
1287     }
1288 #endif
1289 }
1290
1291 static IoResult 
1292 tape_device_robust_write (TapeDevice * self, void * buf, int count) {
1293     Device * d_self;
1294     int result;
1295
1296     d_self = (Device*)self;
1297     
1298     check_resetofs(self, count);
1299
1300     for (;;) {
1301         result = write(self->fd, buf, count);
1302
1303         if (result == count) {
1304             /* Success. */
1305
1306             self->private->write_count ++;
1307             return RESULT_SUCCESS;
1308         } else if (result >= 0) {
1309             /* write() returned a short count. This should not happen. */
1310             device_set_error(d_self,
1311                      vstrallocf(_("Mysterious short write on tape device: Tried %d, got %d"),
1312                                 count, result),
1313                     DEVICE_STATUS_DEVICE_ERROR);
1314             return RESULT_ERROR;
1315         } else if (0
1316 #ifdef EAGAIN
1317                    || errno == EAGAIN
1318 #endif
1319 #ifdef EWOULDBLOCK
1320                    || errno == EWOULDBLOCK
1321 #endif
1322 #ifdef EINTR
1323                    || errno == EINTR
1324 #endif
1325                    ) {
1326                 /* Interrupted system call */
1327             continue;
1328         } else if (0
1329 #ifdef ENOSPC
1330                    || errno == ENOSPC
1331 #endif
1332 #ifdef EIO
1333                    || errno == EIO
1334 #endif
1335                    ) {
1336             /* Probably EOT. Print a message if we got EIO. */
1337 #ifdef EIO
1338             if (errno == EIO) {
1339                 g_warning(_("Got EIO on %s, assuming end of tape"),
1340                         self->private->device_filename);
1341             }
1342 #endif
1343             return RESULT_NO_SPACE;
1344         } else {
1345             /* WTF */
1346             device_set_error(d_self,
1347                     vstrallocf(_("Kernel gave unexpected write() result of \"%s\" on device %s"),
1348                                         strerror(errno), self->private->device_filename),
1349                     DEVICE_STATUS_DEVICE_ERROR);
1350             return RESULT_ERROR;
1351         }
1352     }
1353
1354     g_assert_not_reached();
1355 }
1356
1357 /* Reads some number of tape blocks into the bit-bucket. If the count
1358    is negative, then we read the rest of the entire file. Returns the
1359    number of blocks read, or -1 if an error occured. If we encounter
1360    EOF (as opposed to some other error) we return the number of blocks
1361    actually read. */
1362 static int drain_tape_blocks(TapeDevice * self, int count) {
1363     char * buffer;
1364     gsize buffer_size;
1365     int i;
1366
1367     buffer_size = tape_device_read_size(self);
1368
1369     buffer = malloc(sizeof(buffer_size));
1370
1371     for (i = 0; i < count || count < 0;) {
1372         int result;
1373
1374         result = read(self->fd, buffer, buffer_size);
1375         if (result > 0) {
1376             i ++;
1377             continue;
1378         } else if (result == 0) {
1379             amfree(buffer);
1380             return i;
1381         } else {
1382             /* First check for interrupted system call. */
1383             if (0
1384 #ifdef EAGAIN
1385                 || errno == EAGAIN
1386 #endif
1387 #ifdef EWOULDBLOCK
1388                 || errno == EWOULDBLOCK
1389 #endif
1390 #ifdef EINTR
1391                 || errno == EINTR
1392 #endif
1393                 ) {
1394                 /* Interrupted system call */
1395                 continue;
1396             } else if (0
1397 #ifdef ENOSPC
1398                        || errno == ENOSPC /* bad user-space buffer */
1399 #endif
1400 #ifdef EOVERFLOW
1401                        || errno == EOVERFLOW /* bad kernel-space buffer */
1402 #endif
1403 #ifdef EINVAL
1404                        || errno == EINVAL /* ??? */
1405 #endif
1406                        ) {
1407                 /* The buffer may not be big enough. But the OS is not
1408                    100% clear. We double the buffer and try again, but
1409                    in no case allow a buffer bigger than 32 MB. */
1410                 buffer_size *= 2;
1411
1412                 if (buffer_size > 32*1024*1024) {
1413                     amfree(buffer);
1414                     return -1;
1415                 } else {
1416                     buffer = realloc(buffer, buffer_size);
1417                     continue;
1418                 }
1419             }
1420         }
1421     }
1422     
1423     amfree(buffer);
1424     return count;
1425 }
1426
1427 /* FIXME: Make sure that there are no cycles in reimplementation
1428    dependencies. */
1429
1430 static gboolean 
1431 tape_device_fsf (TapeDevice * self, guint count) {
1432     if (self->fsf) {
1433         return tape_fsf(self->fd, count);
1434     } else {
1435         guint i;
1436         for (i = 0; i < count; i ++) {
1437             if (drain_tape_blocks(self, -1) < 0)
1438                 return FALSE;
1439         }
1440         return TRUE;
1441     }
1442 }
1443
1444 /* Seek back over count + 1 filemarks to the start of the given file. */
1445 static gboolean 
1446 tape_device_bsf (TapeDevice * self, guint count, guint file) {
1447     if (self->bsf) {
1448         /* The BSF operation is not very smart; it includes the
1449            filemark of the present file as part of the count, and seeks
1450            to the wrong (BOT) side of the filemark. We compensate for
1451            this by seeking one filemark too many, then FSFing back over
1452            it.
1453
1454            If this procedure fails for some reason, we can still try
1455            the backup plan. */
1456         if (tape_bsf(self->fd, count + 1) &&
1457             tape_device_fsf(self, 1))
1458             return TRUE;
1459     } /* Fall through to backup plan. */
1460
1461     /* We rewind the tape, then seek forward the given number of
1462        files. */
1463     if (!tape_rewind(self->fd))
1464         return FALSE;
1465
1466     return tape_device_fsf(self, file);
1467 }
1468
1469
1470 static gboolean 
1471 tape_device_fsr (TapeDevice * self, guint count) {
1472     if (self->fsr) {
1473         return tape_fsr(self->fd, count);
1474     } else {
1475         int result = drain_tape_blocks(self, count);
1476         return result > 0 && (int)count == result;
1477     }
1478 }
1479
1480 /* Seek back the given number of blocks to block number block within
1481  * the current file, numbered file. */
1482
1483 static gboolean 
1484 tape_device_bsr (TapeDevice * self, guint count, guint file, guint block) {
1485     if (self->bsr) {
1486         return tape_bsr(self->fd, count);
1487     } else {
1488         /* We BSF, then FSR. */
1489         if (!tape_device_bsf(self, 0, file))
1490             return FALSE;
1491         
1492         return tape_device_fsr(self, block);
1493     }
1494     g_assert_not_reached();
1495 }
1496
1497 /* Go to the right place to write more data, and update the file
1498    number if possible. */
1499 static gboolean 
1500 tape_device_eod (TapeDevice * self) {
1501     Device * d_self;
1502     d_self = (Device*)self;
1503
1504     if (self->eom) {
1505         int result;
1506         result = tape_eod(self->fd); 
1507         if (result == TAPE_OP_ERROR) {
1508             return FALSE;
1509         } else if (result == TAPE_POSITION_UNKNOWN) {
1510             d_self->file = -1;
1511         } else {
1512             /* We drop by 1 because Device will increment the first
1513                time the user does start_file. */
1514             d_self->file = result - 1;
1515         }
1516         return TRUE;
1517     } else {
1518         int count = 0;
1519         if (!tape_rewind(self->fd))
1520             return FALSE;
1521         
1522         for (;;) {
1523             /* We alternately read a block and FSF. If the read is
1524                successful, then we are not there yet and should FSF
1525                again. */
1526             int result;
1527             result = drain_tape_blocks(self, 1);
1528             if (result == 1) {
1529                 /* More data, FSF. */
1530                 tape_device_fsf(self, 1);
1531                 count ++;
1532             } else if (result == 0) {
1533                 /* Finished. */
1534                 d_self->file = count;
1535                 return TRUE;
1536             } else {
1537                 return FALSE;
1538             }
1539         }
1540     }
1541 }
1542
1543 static Device *
1544 tape_device_factory (char * device_name, char * device_type, char * device_node) {
1545     Device * rval;
1546     g_assert(0 == strcmp(device_type, "tape"));
1547     rval = DEVICE(g_object_new(TYPE_TAPE_DEVICE, NULL));
1548     device_open_device(rval, device_name, device_type, device_node);
1549     return rval;
1550 }