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