1274fcd993cfe581ec60a82d8233b12705617dee
[debian/amanda] / device-src / tape-device.c
1 /*
2  * Copyright (c) 2005 Zmanda, Inc.  All Rights Reserved.
3  * 
4  * This library is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License version 2.1 as 
6  * published by the Free Software Foundation.
7  * 
8  * This library is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
11  * License for more details.
12  * 
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this library; if not, write to the Free Software Foundation,
15  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA.
16  * 
17  * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
18  * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
19  */
20
21 #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 };
38
39 /* Possible (abstracted) results from a system I/O operation. */
40 typedef enum {
41     RESULT_SUCCESS,
42     RESULT_ERROR,        /* Undefined error. */
43     RESULT_SMALL_BUFFER, /* Tried to read with a buffer that is too
44                             small. */
45     RESULT_NO_DATA,      /* End of File, while reading */
46     RESULT_NO_SPACE,     /* Out of space. Sometimes we don't know if
47                             it was this or I/O error, but this is the
48                             preferred explanation. */
49     RESULT_MAX
50 } IoResult;
51
52 /* here are local prototypes */
53 static void tape_device_init (TapeDevice * o);
54 static void tape_device_class_init (TapeDeviceClass * c);
55 static gboolean tape_device_open_device (Device * self, char * device_name);
56 static ReadLabelStatusFlags tape_device_read_label(Device * self);
57 static gboolean tape_device_write_block(Device * self, guint size,
58                                         gpointer data, gboolean short_block);
59 static int tape_device_read_block(Device * self,  gpointer buf,
60                                        int * size_req);
61 static gboolean tape_device_start (Device * self, DeviceAccessMode mode,
62                                    char * label, char * timestamp);
63 static gboolean tape_device_start_file (Device * self, const dumpfile_t * ji);
64 static dumpfile_t * tape_device_seek_file (Device * self, guint file);
65 static gboolean tape_device_seek_block (Device * self, guint64 block);
66 static gboolean tape_device_property_get (Device * self, DevicePropertyId id,
67                                           GValue * val);
68 static gboolean tape_device_property_set (Device * self, DevicePropertyId id,
69                                           GValue * val);
70 static gboolean tape_device_finish (Device * self);
71 static IoResult tape_device_robust_read (TapeDevice * self, void * buf,
72                                                int * count);
73 static IoResult tape_device_robust_write (TapeDevice * self, void * buf, int count);
74 static gboolean tape_device_fsf (TapeDevice * self, guint count);
75 static gboolean tape_device_bsf (TapeDevice * self, guint count, guint file);
76 static gboolean tape_device_fsr (TapeDevice * self, guint count);
77 static gboolean tape_device_bsr (TapeDevice * self, guint count, guint file, guint block);
78 static gboolean tape_device_eod (TapeDevice * self);
79
80 /* pointer to the class of our parent */
81 static DeviceClass *parent_class = NULL;
82
83 GType tape_device_get_type (void)
84 {
85     static GType type = 0;
86     
87     if G_UNLIKELY(type == 0) {
88         static const GTypeInfo info = {
89             sizeof (TapeDeviceClass),
90             (GBaseInitFunc) NULL,
91             (GBaseFinalizeFunc) NULL,
92             (GClassInitFunc) tape_device_class_init,
93             (GClassFinalizeFunc) NULL,
94             NULL /* class_data */,
95             sizeof (TapeDevice),
96             0 /* n_preallocs */,
97             (GInstanceInitFunc) tape_device_init,
98             NULL
99         };
100         
101         type = g_type_register_static (TYPE_DEVICE, "TapeDevice",
102                                        &info, (GTypeFlags)0);
103     }
104
105     return type;
106 }
107
108 static void 
109 tape_device_init (TapeDevice * self) {
110     Device * device_self;
111     DeviceProperty prop;
112     GValue response;
113
114     device_self = (Device*)self;
115     bzero(&response, sizeof(response));
116
117     self->private = malloc(sizeof(TapeDevicePrivate));
118
119     /* Clear all fields. */
120     self->min_block_size = self->fixed_block_size = 32768;
121     self->max_block_size = self->read_block_size = MAX_TAPE_BLOCK_BYTES;
122
123     self->fd = -1;
124     
125     self->fsf = self->bsf = self->fsr = self->bsr = self->eom =
126         self->bsf_after_eom = self->compression = self->first_file = 0;
127     self->final_filemarks = 2;
128
129     self->private->write_count = 0;
130
131     /* Register properites */
132     prop.base = &device_property_concurrency;
133     prop.access = PROPERTY_ACCESS_GET_MASK;
134     g_value_init(&response, CONCURRENCY_PARADIGM_TYPE);
135     g_value_set_enum(&response, CONCURRENCY_PARADIGM_EXCLUSIVE);
136     device_add_property(device_self, &prop, &response);
137     g_value_unset(&response);
138
139     prop.base = &device_property_streaming;
140     g_value_init(&response, STREAMING_REQUIREMENT_TYPE);
141     g_value_set_enum(&response, STREAMING_REQUIREMENT_DESIRED);
142     device_add_property(device_self, &prop, &response);
143     g_value_unset(&response);
144
145     prop.base = &device_property_appendable;
146     g_value_init(&response, G_TYPE_BOOLEAN);
147     g_value_set_boolean(&response, TRUE);
148     device_add_property(device_self, &prop, &response);
149
150     prop.base = &device_property_partial_deletion;
151     g_value_set_boolean(&response, FALSE);
152     device_add_property(device_self, &prop, &response);
153     g_value_unset(&response);
154
155     prop.base = &device_property_medium_access_type;
156     g_value_init(&response, MEDIA_ACCESS_MODE_TYPE);
157     g_value_set_enum(&response, MEDIA_ACCESS_MODE_READ_WRITE);
158     device_add_property(device_self, &prop, &response);
159     g_value_unset(&response);
160
161     prop.access = PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_MASK;
162     prop.base = &device_property_compression;
163     device_add_property(device_self, &prop, NULL);
164
165     prop.access = PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START;
166     prop.base = &device_property_min_block_size;
167     device_add_property(device_self, &prop, NULL);
168     prop.base = &device_property_max_block_size;
169     device_add_property(device_self, &prop, NULL);
170     prop.base = &device_property_block_size;
171     device_add_property(device_self, &prop, NULL);
172     prop.base = &device_property_fsf;
173     device_add_property(device_self, &prop, NULL);
174     prop.base = &device_property_bsf;
175     device_add_property(device_self, &prop, NULL);
176     prop.base = &device_property_fsr;
177     device_add_property(device_self, &prop, NULL);
178     prop.base = &device_property_bsr;
179     device_add_property(device_self, &prop, NULL);
180     prop.base = &device_property_eom;
181     device_add_property(device_self, &prop, NULL);
182     prop.base = &device_property_bsf_after_eom;
183     device_add_property(device_self, &prop, NULL);
184     prop.base = &device_property_final_filemarks;
185     device_add_property(device_self, &prop, NULL);
186     
187     prop.access = PROPERTY_ACCESS_GET_MASK;
188     prop.base = &device_property_canonical_name;
189     device_add_property(device_self, &prop, NULL);
190 }
191
192 static void tape_device_finalize(GObject * obj_self) {
193     TapeDevice * self = TAPE_DEVICE(obj_self);
194
195     if(G_OBJECT_CLASS(parent_class)->finalize) \
196            (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
197
198     robust_close(self->fd);
199     self->fd = -1;
200     amfree(self->private);
201 }
202
203 static void 
204 tape_device_class_init (TapeDeviceClass * c)
205 {
206     DeviceClass *device_class = (DeviceClass *)c;
207     GObjectClass *g_object_class = (GObjectClass *)c;
208
209     parent_class = g_type_class_ref (TYPE_DEVICE);
210     
211     device_class->open_device = tape_device_open_device;
212     device_class->read_label = tape_device_read_label;
213     device_class->write_block = tape_device_write_block;
214     device_class->read_block = tape_device_read_block;
215     device_class->start = tape_device_start;
216     device_class->start_file = tape_device_start_file;
217     device_class->seek_file = tape_device_seek_file;
218     device_class->seek_block = tape_device_seek_block;
219     device_class->property_get = tape_device_property_get;
220     device_class->property_set = tape_device_property_set;
221     device_class->finish = tape_device_finish;
222     
223     g_object_class->finalize = tape_device_finalize;
224 }
225
226 void tape_device_register(void) {
227     static const char * device_prefix_list[] = { "tape", NULL };
228     register_device(tape_device_factory, device_prefix_list);
229 }
230
231 /* Open the tape device, trying various combinations of O_RDWR and
232    O_NONBLOCK.  Returns -1 and sets status_result for errors */
233 static int try_open_tape_device(TapeDevice * self, char * device_filename,
234         ReadLabelStatusFlags *status_result) {
235     int fd;
236     int save_errno;
237     ReadLabelStatusFlags new_status;
238     TapeCheckResult tcr;
239     *status_result = READ_LABEL_STATUS_SUCCESS;
240
241 #ifdef O_NONBLOCK
242     fd  = robust_open(device_filename, O_RDWR | O_NONBLOCK, 0);
243     save_errno = errno;
244     if (fd < 0 && (save_errno == EWOULDBLOCK || save_errno == EINVAL)) {
245         /* Maybe we don't support O_NONBLOCK for tape devices. */
246         fd = robust_open(device_filename, O_RDWR, 0);
247         save_errno = errno;
248     }
249 #else
250     fd = robust_open(device_filename, O_RDWR);
251     save_errno = errno;
252 #endif
253     if (fd >= 0) {
254         self->write_open_errno = 0;
255     } else {
256         if (errno == EACCES || errno == EPERM) {
257             /* Device is write-protected. */
258             self->write_open_errno = errno;
259 #ifdef O_NONBLOCK
260             fd = robust_open(device_filename, O_RDONLY | O_NONBLOCK, 0);
261             save_errno = errno;
262             if (fd < 0 && (save_errno == EWOULDBLOCK || save_errno == EINVAL)) {
263                 fd = robust_open(device_filename, O_RDONLY, 0);
264                 save_errno = errno;
265             }
266 #else
267             fd = robust_open(device_filename, O_RDONLY);
268             save_errno = errno;
269 #endif
270         }
271     }
272 #ifdef O_NONBLOCK
273     /* Clear O_NONBLOCK for operations from now on. */
274     if (fd >= 0)
275         fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
276     errno = save_errno;
277     /* function continues after #endif */
278
279 #endif /* O_NONBLOCK */
280
281     if (fd < 0) {
282         g_fprintf(stderr, _("Can't open tape device %s: %s\n"),
283             DEVICE(self)->device_name, strerror(errno));
284         *status_result = READ_LABEL_STATUS_DEVICE_ERROR;
285         return -1;
286     }
287
288     /* Check that this is actually a tape device. */
289     new_status = tape_is_tape_device(fd);
290     if (new_status & (READ_LABEL_STATUS_DEVICE_ERROR | READ_LABEL_STATUS_VOLUME_MISSING)) {
291         g_fprintf(stderr, _("File %s is not a tape device\n"),
292             DEVICE(self)->device_name);
293         robust_close(fd);
294         *status_result = new_status;
295         return -1;
296     }
297
298     tcr = tape_is_ready(fd);
299     if (new_status == TAPE_CHECK_FAILURE) {
300         g_fprintf(stderr, _("Tape device %s is not ready or is empty\n"),
301             DEVICE(self)->device_name);
302         robust_close(fd);
303         *status_result = READ_LABEL_STATUS_DEVICE_ERROR;
304         return -1;
305     }
306
307     return fd;
308 }
309
310 static gboolean 
311 tape_device_open_device (Device * d_self, char * device_name) {
312     TapeDevice * self;
313
314     self = TAPE_DEVICE(d_self);
315     g_return_val_if_fail (self != NULL, FALSE);
316     g_return_val_if_fail (device_name != NULL, FALSE);
317
318     /* Get tape drive/OS info */
319     tape_device_discover_capabilities(self);
320
321     /* And verify the above. */
322     g_assert(feature_support_flags_is_valid(self->fsf));
323     g_assert(feature_support_flags_is_valid(self->bsf));
324     g_assert(feature_support_flags_is_valid(self->fsr));
325     g_assert(feature_support_flags_is_valid(self->bsr));
326     g_assert(feature_support_flags_is_valid(self->eom));
327     g_assert(feature_support_flags_is_valid(self->bsf_after_eom));
328     g_assert(self->final_filemarks == 1 ||
329              self->final_filemarks == 2);
330
331     /* Chain up */
332     if (parent_class->open_device) {
333         if (!(parent_class->open_device)(d_self, device_name)) {
334             robust_close(self->fd);
335             return FALSE;
336         }
337     }
338
339     return TRUE;
340 }
341
342 static ReadLabelStatusFlags tape_device_read_label(Device * dself) {
343     TapeDevice * self;
344     char * header_buffer;
345     int buffer_len;
346     IoResult result;
347     dumpfile_t header;
348
349     self = TAPE_DEVICE(dself);
350     g_return_val_if_fail(self != NULL, FALSE);
351
352     amfree(dself->volume_label);
353     amfree(dself->volume_time);
354
355     if (self->fd == -1) {
356         ReadLabelStatusFlags status;
357         self->fd = try_open_tape_device(self, dself->device_name, &status);
358         if (self->fd == -1)
359             return status;
360     }
361
362     /* Rewind it. */
363     if (!tape_rewind(self->fd)) {
364         g_fprintf(stderr, "Error rewinding device %s\n",
365                 dself->device_name);
366         return (READ_LABEL_STATUS_DEVICE_ERROR |
367                 READ_LABEL_STATUS_VOLUME_ERROR);
368     }   
369
370     buffer_len = self->read_block_size;
371     header_buffer = malloc(buffer_len);
372     result = tape_device_robust_read(self, header_buffer, &buffer_len);
373
374     if (result != RESULT_SUCCESS) {
375         free(header_buffer);
376         tape_rewind(self->fd);
377         /* I/O error. */
378         g_fprintf(stderr, "Error reading Amanda header.\n");
379         if (result == RESULT_NO_DATA) {
380             return (READ_LABEL_STATUS_VOLUME_ERROR |
381                     READ_LABEL_STATUS_VOLUME_UNLABELED);
382         } else {
383             return (READ_LABEL_STATUS_DEVICE_ERROR |
384                     READ_LABEL_STATUS_VOLUME_ERROR |
385                     READ_LABEL_STATUS_VOLUME_UNLABELED);
386         }
387     }
388
389     parse_file_header(header_buffer, &header, buffer_len);
390     amfree(header_buffer);
391     if (header.type != F_TAPESTART) {
392         return READ_LABEL_STATUS_VOLUME_UNLABELED;
393     }
394      
395     dself->volume_label = g_strdup(header.name);
396     dself->volume_time = g_strdup(header.datestamp);
397    
398     if (parent_class->read_label) {
399         return parent_class->read_label(dself);
400     } else {
401         return READ_LABEL_STATUS_SUCCESS;
402     }
403 }
404
405 static gboolean
406 tape_device_write_block(Device * pself, guint size,
407                         gpointer data, gboolean short_block) {
408     TapeDevice * self;
409     char *replacement_buffer = NULL;
410     IoResult result;
411
412     self = TAPE_DEVICE(pself);
413     g_return_val_if_fail (self != NULL, FALSE);
414     g_return_val_if_fail (self->fd >= 0, FALSE);
415    
416     if (short_block && self->min_block_size > size) {
417         replacement_buffer = malloc(self->min_block_size);
418         memcpy(replacement_buffer, data, size);
419         bzero(replacement_buffer+size, self->min_block_size-size);
420         
421         data = replacement_buffer;
422         size = self->min_block_size;
423     }
424
425     result = tape_device_robust_write(self, data, size);
426     if (result == RESULT_SUCCESS) {
427         if (parent_class->write_block) {
428             (parent_class->write_block)(pself, size, data, short_block);
429         }
430         amfree(replacement_buffer);
431         return TRUE;
432     } else {
433         amfree(replacement_buffer);
434         return FALSE;
435     }
436     
437     g_assert_not_reached();
438 }
439
440 static int tape_device_read_block (Device * pself, gpointer buf,
441                                    int * size_req) {
442     TapeDevice * self;
443     int size;
444     IoResult result;
445     
446     self = TAPE_DEVICE(pself);
447     g_return_val_if_fail (self != NULL, -1);
448
449     if (buf == NULL || *size_req < (int)self->read_block_size) {
450         /* Just a size query. */
451         *size_req = self->read_block_size;
452         return 0;
453     }
454
455     size = *size_req;
456     result = tape_device_robust_read(self, buf, &size);
457     switch (result) {
458     case RESULT_SUCCESS:
459         *size_req = size;
460         return size;
461     case RESULT_SMALL_BUFFER: {
462         int new_size;
463         /* If this happens, it means that we have:
464          *     (next block size) > (buffer size) >= (read_block_size)
465          * The solution is to ask for an even bigger buffer. We also play
466          * some games to refrain from reading above the SCSI limit or from
467          * integer overflow. */
468         new_size = MIN(INT_MAX/2 - 1, *size_req) * 2;
469         if (new_size > LARGEST_BLOCK_ESTIMATE &&
470             *size_req < LARGEST_BLOCK_ESTIMATE) {
471             new_size = LARGEST_BLOCK_ESTIMATE;
472         }
473         if (new_size <= *size_req) {
474             return -1;
475         } else {
476             *size_req = new_size;
477             return 0;
478         }
479     }
480     case RESULT_NO_DATA:
481         pself->is_eof = TRUE;
482         pself->in_file = FALSE;
483         return -1;
484
485     default:
486         return -1;
487     }
488
489     g_assert_not_reached();
490 }
491
492 /* Just a helper function for tape_device_start(). */
493 static gboolean write_tapestart_header(TapeDevice * self, char * label,
494                                        char * timestamp) {
495      IoResult result;
496      dumpfile_t * header;
497      char * header_buf;
498      int header_size;
499      gboolean header_fits;
500      Device * d_self = (Device*)self;
501      tape_rewind(self->fd);
502     
503      header = make_tapestart_header(d_self, label, timestamp);
504      g_assert(header != NULL);
505      header_buf = device_build_amanda_header(d_self, header, &header_size,
506                                              &header_fits);
507      amfree(header);
508      g_assert(header_buf != NULL);
509                                              
510      if (!header_fits) {
511          amfree(header_buf);
512          g_fprintf(stderr, "Tapestart header won't fit in a single block!\n");
513          return FALSE;
514      }
515
516      g_assert(header_size >= (int)self->min_block_size);
517      result = tape_device_robust_write(self, header_buf, header_size);
518      amfree(header_buf);
519      return (result == RESULT_SUCCESS);
520 }
521
522 static gboolean 
523 tape_device_start (Device * d_self, DeviceAccessMode mode, char * label,
524                    char * timestamp) {
525     TapeDevice * self;
526
527     self = TAPE_DEVICE(d_self);
528     g_return_val_if_fail(self != NULL, FALSE);
529
530     if (self->fd == -1) {
531         ReadLabelStatusFlags status;
532         self->fd = try_open_tape_device(self, d_self->device_name, &status);
533         if (self->fd == -1)
534             return FALSE;   /* can't do anything with status here */
535     }
536
537     if (mode != ACCESS_WRITE && d_self->volume_label == NULL) {
538         /* we need a labeled volume for APPEND and READ */
539         if (tape_device_read_label(d_self) != READ_LABEL_STATUS_SUCCESS)
540             return FALSE;
541     }
542
543     d_self->access_mode = mode;
544     d_self->in_file = FALSE;
545
546     if (IS_WRITABLE_ACCESS_MODE(mode)) {
547         if (self->write_open_errno != 0) {
548             /* We tried and failed to open the device in write mode. */
549             g_fprintf(stderr, "Can't open tape device %s for writing: %s\n",
550                     d_self->device_name, strerror(self->write_open_errno));
551             return FALSE;
552         } else if (!tape_rewind(self->fd)) {
553             g_fprintf(stderr, "Couldn't rewind device: %s\n",
554                     strerror(errno));
555         }
556     }
557
558     /* Position the tape */
559     switch (mode) {
560     case ACCESS_APPEND:
561         if (!tape_device_eod(self))
562             return FALSE;
563         self->first_file = TRUE;
564         break;
565         
566     case ACCESS_READ:
567         if (!tape_rewind(self->fd)) {
568             g_fprintf(stderr, "Error rewinding device %s\n",
569                     d_self->device_name);
570             return FALSE;
571         }
572         d_self->file = 0;
573         break;
574
575     case ACCESS_WRITE:
576         if (!write_tapestart_header(self, label, timestamp)) {
577             return FALSE;
578         }
579         self->first_file = TRUE;
580         break;
581
582     default:
583         g_assert_not_reached();
584     }
585
586     if (parent_class->start) {
587         return parent_class->start(d_self, mode, label, timestamp);
588     } else {
589         return TRUE;
590     }
591 }
592
593 static gboolean tape_device_start_file(Device * d_self,
594                                        const dumpfile_t * info) {
595     TapeDevice * self;
596     IoResult result;
597     char * amanda_header;
598     int header_size;
599     gboolean header_fits;
600
601     self = TAPE_DEVICE(d_self);
602     g_return_val_if_fail(self != NULL, FALSE);
603     g_return_val_if_fail (self->fd >= 0, FALSE);
604
605     if (!(d_self->access_mode == ACCESS_APPEND && self->first_file)) {
606         if (!tape_weof(self->fd, 1)) {
607             g_fprintf(stderr, "Error writing filemark: %s\n", strerror(errno));
608             return FALSE;
609         }
610     }
611
612     self->first_file = FALSE;
613
614     /* Make the Amanda header suitable for writing to the device. */
615     /* Then write the damn thing. */
616     amanda_header = device_build_amanda_header(d_self, info,
617                                                &header_size, &header_fits);
618     g_return_val_if_fail(amanda_header != NULL, FALSE);
619     g_return_val_if_fail(header_fits, FALSE);
620     result = tape_device_robust_write(self, amanda_header, header_size);
621     amfree(amanda_header);
622     if (result == RESULT_SUCCESS) {
623         /* Chain up. */
624         if (parent_class->start_file) {
625             parent_class->start_file(d_self, info);
626         }
627         return TRUE;
628     } else {
629         return FALSE;
630     }
631 }
632
633 static dumpfile_t * 
634 tape_device_seek_file (Device * d_self, guint file) {
635     TapeDevice * self;
636     int difference;
637     char * header_buffer;
638     dumpfile_t * rval;
639     int buffer_len;
640     IoResult result;
641
642     self = TAPE_DEVICE(d_self);
643     g_return_val_if_fail(d_self != NULL, NULL);
644
645     d_self->in_file = FALSE;
646
647     difference = file - d_self->file;
648
649     /* Check if we already read a filemark. */
650     if (d_self->is_eof) {
651         difference --;
652     }
653
654     if (difference > 0) {
655         /* Seeking forwards */
656         if (!tape_device_fsf(self, difference)) {
657             tape_rewind(self->fd);
658             return NULL;
659         }
660     } else if (difference < 0) {
661         /* Seeking backwards */
662         if (!tape_device_bsf(self, -difference, d_self->file)) {
663             tape_rewind(self->fd);
664             return NULL;
665         }
666     }
667
668     buffer_len = self->read_block_size;
669     header_buffer = malloc(buffer_len);
670     d_self->is_eof = FALSE;
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         if (result == RESULT_NO_DATA) {
677             /* If we read 0 bytes, that means we encountered a double
678              * filemark, which indicates end of tape. This should
679              * work even with QIC tapes on operating systems with
680              * proper support. */
681             return make_tapeend_header();
682         }
683         /* I/O error. */
684         g_fprintf(stderr, "Error reading Amanda header.\n");
685         return FALSE;
686     }
687         
688     rval = malloc(sizeof(*rval));
689     parse_file_header(header_buffer, rval, buffer_len);
690     amfree(header_buffer);
691     switch (rval->type) {
692     case F_DUMPFILE:
693     case F_CONT_DUMPFILE:
694     case F_SPLIT_DUMPFILE:
695         d_self->in_file = TRUE;
696         d_self->file = file;
697         return rval;
698     default:
699         tape_rewind(self->fd);
700         amfree(rval);
701         return NULL;
702     }
703 }
704
705 static gboolean 
706 tape_device_seek_block (Device * d_self, guint64 block) {
707     TapeDevice * self;
708     int difference;
709
710     self = TAPE_DEVICE(d_self);
711     g_return_val_if_fail(d_self != NULL, FALSE);
712
713     difference = block - d_self->block;
714     
715     if (difference > 0) {
716         if (!tape_device_fsr(self, difference))
717             return FALSE;
718     } else if (difference < 0) {
719         if (!tape_device_bsr(self, difference, d_self->file, d_self->block))
720             return FALSE;
721     }
722
723     if (parent_class->seek_block) {
724         return (parent_class->seek_block)(d_self, block);
725     } else {
726         return TRUE;
727     }
728 }
729
730 /* Just checks that the flag is valid before setting it. */
731 static gboolean get_feature_flag(GValue * val, FeatureSupportFlags f) {
732     if (feature_support_flags_is_valid(f)) {
733         g_value_set_flags(val, f);
734         return TRUE;
735     } else {
736         return FALSE;
737     }
738 }
739
740 static gboolean 
741 tape_device_property_get (Device * d_self, DevicePropertyId id, GValue * val) {
742     TapeDevice * self;
743     const DevicePropertyBase * base;
744
745     self = TAPE_DEVICE(d_self);
746     g_return_val_if_fail(self != NULL, FALSE);
747
748     base = device_property_get_by_id(id);
749     g_return_val_if_fail(self != NULL, FALSE);
750
751     g_value_unset_init(val, base->type);
752
753     if (id == PROPERTY_COMPRESSION) {
754         g_value_set_boolean(val, self->compression);
755         return TRUE;
756     } else if (id == PROPERTY_MIN_BLOCK_SIZE) {
757         g_value_set_uint(val, self->min_block_size);
758         return TRUE;
759     } else if (id == PROPERTY_MAX_BLOCK_SIZE) {
760         g_value_set_uint(val, self->max_block_size);
761         return TRUE;
762     } else if (id == PROPERTY_BLOCK_SIZE) {
763         if (self->fixed_block_size == 0) {
764             g_value_set_int(val, -1);
765         } else {
766             g_value_set_int(val, self->fixed_block_size);
767         }
768         return TRUE;
769     } else if (id == PROPERTY_FSF) {
770         return get_feature_flag(val, self->fsf);
771     } else if (id == PROPERTY_BSF) {
772         return get_feature_flag(val, self->bsf);
773     } else if (id == PROPERTY_FSR) {
774         return get_feature_flag(val, self->fsr);
775     } else if (id == PROPERTY_BSR) {
776         return get_feature_flag(val, self->bsr);
777     } else if (id == PROPERTY_EOM) {
778         return get_feature_flag(val, self->eom);
779     } else if (id == PROPERTY_BSF_AFTER_EOM) {
780         return get_feature_flag(val, self->bsf_after_eom);
781     } else if (id == PROPERTY_FINAL_FILEMARKS) {
782         g_value_set_uint(val, self->final_filemarks);
783         return TRUE;
784     } else {
785         /* Chain up */
786         if (parent_class->property_get) {
787             return (parent_class->property_get)(d_self, id, val);
788         } else {
789             return FALSE;
790         }
791     }
792
793     g_assert_not_reached();
794 }
795
796 /* We don't allow overriding of flags with _GOOD surety. That way, if
797    e.g., a feature has no matching IOCTL on a given platform, we don't
798    ever try to set it. */
799 static gboolean flags_settable(FeatureSupportFlags request,
800                                FeatureSupportFlags existing) {
801     if (!feature_support_flags_is_valid(request))
802         return FALSE;
803     else if (!feature_support_flags_is_valid(existing))
804         return TRUE;
805     else if (request == existing)
806         return TRUE;
807     else if (existing & FEATURE_SURETY_GOOD)
808         return FALSE;
809     else
810         return TRUE;
811 }
812
813 /* If the access listed is NULL, and the provided flags can override the
814    existing ones, then do it and return TRUE. */
815 static gboolean try_set_feature(DeviceAccessMode mode,
816                                 FeatureSupportFlags request,
817                                 FeatureSupportFlags * existing) {
818     if (mode != ACCESS_NULL) {
819         return FALSE;
820     } else if (flags_settable(request, *existing)) {
821         *existing = request;
822         return TRUE;
823     } else {
824         return FALSE;
825     }
826 }
827  
828 static gboolean 
829 tape_device_property_set (Device * d_self, DevicePropertyId id, GValue * val) {
830     TapeDevice * self;
831     FeatureSupportFlags feature_request_flags = 0;
832     const DevicePropertyBase * base;
833
834     self = TAPE_DEVICE(d_self);
835     g_return_val_if_fail(self != NULL, FALSE);
836
837     base = device_property_get_by_id(id);
838     g_return_val_if_fail(self != NULL, FALSE);
839
840     g_return_val_if_fail(G_VALUE_HOLDS(val, base->type), FALSE);
841
842     if (base->type == FEATURE_SUPPORT_FLAGS_TYPE) {
843         feature_request_flags = g_value_get_flags(val);
844         g_return_val_if_fail(
845             feature_support_flags_is_valid(feature_request_flags), FALSE);
846     }
847
848     if (id == PROPERTY_COMPRESSION) {
849         /* We allow this property to be set at any time. This is mostly
850          * because setting compression is a hit-and-miss proposition
851          * at any time; some drives accept the mode setting but don't
852          * actually support compression, while others do support
853          * compression but do it via density settings or some other
854          * way. Set this property whenever you want, but all we'll do
855          * is report whether or not the ioctl succeeded. */
856         gboolean request = g_value_get_boolean(val);
857         if (tape_setcompression(self->fd, request)) {
858             self->compression = request;
859             device_clear_volume_details(d_self);
860             return TRUE;
861         } else {
862             return FALSE;
863         }
864     } else if (id == PROPERTY_MIN_BLOCK_SIZE) {
865         if (d_self->access_mode != ACCESS_NULL)
866             return FALSE;
867         self->min_block_size = g_value_get_uint(val);
868         device_clear_volume_details(d_self);
869         return TRUE;
870     } else if (id == PROPERTY_MAX_BLOCK_SIZE) {
871         if (d_self->access_mode != ACCESS_NULL)
872             return FALSE;
873         self->max_block_size = g_value_get_uint(val);
874         device_clear_volume_details(d_self);
875         return TRUE;
876     } else if (id == PROPERTY_BLOCK_SIZE) {
877         if (d_self->access_mode != ACCESS_NULL)
878             return FALSE;
879
880         self->fixed_block_size = g_value_get_int(val);
881         device_clear_volume_details(d_self);
882         return TRUE;
883     } else if (id == PROPERTY_READ_BUFFER_SIZE) {
884         if (d_self->access_mode != ACCESS_NULL)
885             return FALSE;
886         self->read_block_size = g_value_get_uint(val);
887         device_clear_volume_details(d_self);
888         return TRUE;
889     } else if (id == PROPERTY_FSF) {
890         return try_set_feature(d_self->access_mode,
891                                feature_request_flags,
892                                &(self->fsf));
893     } else if (id == PROPERTY_BSF) {
894         return try_set_feature(d_self->access_mode,
895                                feature_request_flags,
896                                &(self->bsf));
897     } else if (id == PROPERTY_FSR) {
898         return try_set_feature(d_self->access_mode,
899                                feature_request_flags,
900                                &(self->fsr));
901     } else if (id == PROPERTY_BSR) {
902         return try_set_feature(d_self->access_mode,
903                                feature_request_flags,
904                                &(self->bsr));
905     } else if (id == PROPERTY_EOM) {
906         /* Setting this to disabled also clears BSF after EOM. */
907         if (try_set_feature(d_self->access_mode,
908                             feature_request_flags,
909                             &(self->eom))) {
910             feature_request_flags &= ~FEATURE_SUPPORT_FLAGS_STATUS_MASK;
911             feature_request_flags |= FEATURE_STATUS_DISABLED;
912             self->bsf_after_eom = feature_request_flags;
913             return TRUE;
914         } else {
915             return FALSE;
916         }
917     } else if (id == PROPERTY_BSF_AFTER_EOM) {
918         /* You can only set this if EOM is enabled. */
919         if (self->bsf | FEATURE_STATUS_DISABLED)
920             return FALSE;
921         else
922             return try_set_feature(d_self->access_mode,
923                                    feature_request_flags,
924                                    &(self->bsf_after_eom));
925     } else if (id == PROPERTY_FINAL_FILEMARKS) {
926         guint request = g_value_get_uint(val);
927         if (request == 1 || request == 2) {
928             self->final_filemarks = request;
929             return TRUE;
930         } else {
931             return FALSE;
932         }
933     } else {
934         /* Chain up */
935         if (parent_class->property_set) {
936             return (parent_class->property_set)(d_self, id, val);
937         } else {
938             return FALSE;
939         }
940     }
941
942     g_assert_not_reached();
943 }
944
945 static gboolean 
946 tape_device_finish (Device * d_self) {
947     TapeDevice * self;
948
949     self = TAPE_DEVICE(d_self);
950     g_return_val_if_fail(self != NULL, FALSE);
951
952     /* Polish off this file, if relevant. */
953     if (d_self->in_file && IS_WRITABLE_ACCESS_MODE(d_self->access_mode)) {
954         if (!device_finish_file(d_self))
955             return FALSE;
956     }
957
958     /* Write an extra filemark, if needed. The OS will give us one for
959        sure. */
960     if (self->final_filemarks > 1 &&
961         IS_WRITABLE_ACCESS_MODE(d_self->access_mode)) {
962         if (!tape_weof(self->fd, 1)) {
963             g_fprintf(stderr, "Error writing final filemark: %s\n",
964                     strerror(errno));
965             return FALSE;
966         }
967     }
968
969     /* Rewind. */
970     if (!tape_rewind(self->fd)) {
971         g_fprintf(stderr, "Error rewinding tape: %s\n", strerror(errno));
972         return FALSE;
973     }
974
975     d_self->access_mode = ACCESS_NULL;
976
977     if (parent_class->finish) {
978         return (parent_class->finish)(d_self);
979     } else {
980         return TRUE;
981     }
982
983 }
984
985 /* Works just like read(), except for the following:
986  * 1) Retries on EINTR & friends.
987  * 2) Stores count in parameter, not return value.
988  * 3) Provides explicit return result. */
989 static IoResult
990 tape_device_robust_read (TapeDevice * self, void * buf, int * count) {
991     Device * d_self;
992     int result;
993
994     d_self = (Device*)self;
995     g_return_val_if_fail(self != NULL, RESULT_ERROR);
996     g_return_val_if_fail(*count >= 0, RESULT_ERROR);
997     /* Callers should ensure this. */
998     g_assert((guint)(*count) <= self->read_block_size);
999
1000     for (;;) {
1001         result = read(self->fd, buf, *count);
1002         if (result > 0) {
1003             /* Success. By definition, we read a full block. */
1004             *count = result;
1005             return RESULT_SUCCESS;
1006         } else if (result == 0) {
1007             return RESULT_NO_DATA;
1008         } else {
1009             if (0
1010 #ifdef EAGAIN
1011                 || errno == EAGAIN
1012 #endif
1013 #ifdef EWOULDBLOCK
1014                 || errno == EWOULDBLOCK
1015 #endif
1016 #ifdef EINTR
1017                 || errno == EINTR
1018 #endif
1019                 ) {
1020                 /* Interrupted system call */
1021                 continue;
1022             } else if ((self->fixed_block_size == 0) &&
1023                        (0
1024 #ifdef ENOMEM
1025                         || errno == ENOMEM /* bad user-space buffer */
1026 #endif
1027 #ifdef EOVERFLOW
1028                         || errno == EOVERFLOW /* bad kernel-space buffer */
1029 #endif
1030 #ifdef EINVAL
1031                         || errno == EINVAL /* ??? */
1032 #endif
1033                         )) {
1034                 /* Buffer too small. */
1035                 return RESULT_SMALL_BUFFER;
1036             } else {
1037                 g_fprintf(stderr, "Error reading %d bytes from %s: %s\n",
1038                         *count, d_self->device_name, strerror(errno));
1039                 return RESULT_ERROR;
1040             }
1041         }
1042
1043     }
1044
1045     g_assert_not_reached();
1046 }
1047
1048 /* Kernel workaround: If needed, poke the kernel so it doesn't fail.
1049    at the 2GB boundry. Parameters are G_GNUC_UNUSED in case NEED_RESETOFS
1050    is not defined. */
1051 static void check_resetofs(TapeDevice * self G_GNUC_UNUSED,
1052                            int count G_GNUC_UNUSED) {
1053 #ifdef NEED_RESETOFS
1054     int result;
1055
1056     self->private->write_count += count;
1057     if (self->private->write_count < RESETOFS_THRESHOLD) {
1058         return;
1059     }
1060
1061     result = lseek(self->fd, 0, SEEK_SET);
1062     if (result < 0) {
1063         g_fprintf(stderr,
1064                 "Warning: lseek() failed during kernel 2GB workaround.\n");
1065     }
1066 #endif
1067 }
1068
1069 static IoResult 
1070 tape_device_robust_write (TapeDevice * self, void * buf, int count) {
1071     Device * d_self;
1072     int result;
1073
1074     g_return_val_if_fail(self != NULL, RESULT_ERROR);
1075     d_self = (Device*)self;
1076     
1077     check_resetofs(self, count);
1078
1079     for (;;) {
1080         result = write(self->fd, buf, count);
1081
1082         if (result == count) {
1083             /* Success. */
1084
1085             self->private->write_count ++;
1086             return RESULT_SUCCESS;
1087         } else if (result >= 0) {
1088             /* write() returned a short count. This should not happen. */
1089             g_fprintf(stderr,
1090                   "Mysterious short write on tape device: Tried %d, got %d.\n",
1091                     count, result);
1092             return RESULT_ERROR;
1093         } else if (0
1094 #ifdef EAGAIN
1095                    || errno == EAGAIN
1096 #endif
1097 #ifdef EWOULDBLOCK
1098                    || errno == EWOULDBLOCK
1099 #endif
1100 #ifdef EINTR
1101                    || errno == EINTR
1102 #endif
1103                    ) {
1104                 /* Interrupted system call */
1105             continue;
1106         } else if (0
1107 #ifdef ENOSPC
1108                    || errno == ENOSPC
1109 #endif
1110 #ifdef EIO
1111                    || errno == EIO
1112 #endif
1113                    ) {
1114             /* Probably EOT. Print a message if we got EIO. */
1115 #ifdef EIO
1116             if (errno == EIO) {
1117                 g_fprintf(stderr, "Got EIO on %s, assuming end of tape.\n",
1118                         d_self->device_name);
1119             }
1120 #endif
1121             return RESULT_NO_SPACE;
1122         } else {
1123             /* WTF */
1124             g_fprintf(stderr,
1125      "Kernel gave unexpected write() result of \"%s\" on device %s.\n",
1126                     strerror(errno), d_self->device_name);
1127             return RESULT_ERROR;
1128         }
1129     }
1130
1131     g_assert_not_reached();
1132 }
1133
1134 /* Reads some number of tape blocks into the bit-bucket. If the count
1135    is negative, then we read the rest of the entire file. Returns the
1136    number of blocks read, or -1 if an error occured. If we encounter
1137    EOF (as opposed to some other error) we return the number of blocks
1138    actually read. */
1139 static int drain_tape_blocks(TapeDevice * self, int count) {
1140     char * buffer;
1141     int buffer_size;
1142     int i;
1143
1144     buffer_size = self->read_block_size;
1145
1146     buffer = malloc(sizeof(buffer_size));
1147
1148     for (i = 0; i < count || count < 0;) {
1149         int result;
1150
1151         result = read(self->fd, buffer, buffer_size);
1152         if (result > 0) {
1153             i ++;
1154             continue;
1155         } else if (result == 0) {
1156             free(buffer);
1157             return i;
1158         } else {
1159             /* First check for interrupted system call. */
1160             if (0
1161 #ifdef EAGAIN
1162                 || errno == EAGAIN
1163 #endif
1164 #ifdef EWOULDBLOCK
1165                 || errno == EWOULDBLOCK
1166 #endif
1167 #ifdef EINTR
1168                 || errno == EINTR
1169 #endif
1170                 ) {
1171                 /* Interrupted system call */
1172                 continue;
1173             } else if (0
1174 #ifdef ENOSPC
1175                        || errno == ENOSPC /* bad user-space buffer */
1176 #endif
1177 #ifdef EOVERFLOW
1178                        || errno == EOVERFLOW /* bad kernel-space buffer */
1179 #endif
1180 #ifdef EINVAL
1181                        || errno == EINVAL /* ??? */
1182 #endif
1183                        ) {
1184                 /* The buffer may not be big enough. But the OS is not
1185                    100% clear. We double the buffer and try again, but
1186                    in no case allow a buffer bigger than 32 MB. */
1187                 buffer_size *= 2;
1188
1189                 if (buffer_size > 32*1024*1024) {
1190                     free(buffer);
1191                     return -1;
1192                 } else {
1193                     buffer = realloc(buffer, buffer_size);
1194                     continue;
1195                 }
1196             }
1197         }
1198     }
1199     
1200     return count;
1201 }
1202
1203 /* FIXME: Make sure that there are no cycles in reimplementation
1204    dependencies. */
1205
1206 static gboolean 
1207 tape_device_fsf (TapeDevice * self, guint count) {
1208     g_return_val_if_fail (self != NULL, (gboolean )0);
1209     g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
1210     
1211     if (self->fsf & FEATURE_STATUS_ENABLED) {
1212         return tape_fsf(self->fd, count);
1213     } else {
1214         guint i;
1215         for (i = 0; i < count; i ++) {
1216             if (drain_tape_blocks(self, -1) < 0)
1217                 return FALSE;
1218         }
1219         return TRUE;
1220     }
1221 }
1222
1223 /* Seek back over count + 1 filemarks to the start of the given file. */
1224 static gboolean 
1225 tape_device_bsf (TapeDevice * self, guint count, guint file) {
1226     g_return_val_if_fail (self != NULL, (gboolean )0);
1227     g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
1228
1229     if (self->bsf & FEATURE_STATUS_ENABLED) {
1230         /* The BSF operation is not very smart; it includes the
1231            filemark of the present file as part of the count, and seeks
1232            to the wrong (BOT) side of the filemark. We compensate for
1233            this by seeking one filemark too many, then FSFing back over
1234            it.
1235
1236            If this procedure fails for some reason, we can still try
1237            the backup plan. */
1238         if (tape_bsf(self->fd, count + 1) &&
1239             tape_device_fsf(self, 1))
1240             return TRUE;
1241     } /* Fall through to backup plan. */
1242
1243     /* We rewind the tape, then seek forward the given number of
1244        files. */
1245     if (!tape_rewind(self->fd))
1246         return FALSE;
1247
1248     return tape_device_fsf(self, file);
1249 }
1250
1251
1252 static gboolean 
1253 tape_device_fsr (TapeDevice * self, guint count) {
1254     g_return_val_if_fail (self != NULL, (gboolean )0);
1255     g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
1256
1257     if (self->fsr & FEATURE_STATUS_ENABLED) {
1258         return tape_fsr(self->fd, count);
1259     } else {
1260         int result = drain_tape_blocks(self, count);
1261         return result > 0 && (int)count == result;
1262     }
1263 }
1264
1265 /* Seek back the given number of blocks to block number block within
1266  * the current file, numbered file. */
1267
1268 static gboolean 
1269 tape_device_bsr (TapeDevice * self, guint count, guint file, guint block) {
1270     g_return_val_if_fail (self != NULL, (gboolean )0);
1271     g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
1272     
1273     g_return_val_if_fail (self != NULL, (gboolean )0);
1274     g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
1275
1276     if (self->bsr & FEATURE_STATUS_ENABLED) {
1277         return tape_bsr(self->fd, count);
1278     } else {
1279         /* We BSF, then FSR. */
1280         if (!tape_device_bsf(self, 0, file))
1281             return FALSE;
1282         
1283         return tape_device_fsr(self, block);
1284     }
1285     g_assert_not_reached();
1286 }
1287
1288 /* Go to the right place to write more data, and update the file
1289    number if possible. */
1290 static gboolean 
1291 tape_device_eod (TapeDevice * self) {
1292     Device * d_self;
1293     g_return_val_if_fail (self != NULL, (gboolean )0);
1294     g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
1295     d_self = (Device*)self;
1296
1297     if (self->eom & FEATURE_STATUS_ENABLED) {
1298         int result;
1299         result = tape_eod(self->fd); 
1300         if (result == TAPE_OP_ERROR) {
1301             return FALSE;
1302         } else if (result == TAPE_POSITION_UNKNOWN) {
1303             d_self->file = -1;
1304         } else {
1305             /* We drop by 1 because Device will increment the first
1306                time the user does start_file. */
1307             d_self->file = result - 1;
1308         }
1309         return TRUE;
1310     } else {
1311         int count = 0;
1312         if (!tape_rewind(self->fd))
1313             return FALSE;
1314         
1315         for (;;) {
1316             /* We alternately read a block and FSF. If the read is
1317                successful, then we are not there yet and should FSF
1318                again. */
1319             int result;
1320             result = drain_tape_blocks(self, 1);
1321             if (result == 1) {
1322                 /* More data, FSF. */
1323                 tape_device_fsf(self, 1);
1324                 count ++;
1325             } else if (result == 0) {
1326                 /* Finished. */
1327                 d_self->file = count;
1328                 return TRUE;
1329             } else {
1330                 return FALSE;
1331             }
1332         }
1333     }
1334 }
1335
1336 Device *
1337 tape_device_factory (char * device_type, char * device_name) {
1338     Device * rval;
1339     g_assert(0 == strcmp(device_type, "tape"));
1340     rval = DEVICE(g_object_new(TYPE_TAPE_DEVICE, NULL));
1341     if (!device_open_device(rval, device_name)) {
1342         g_object_unref(rval);
1343         return NULL;
1344     } else {
1345         return rval;
1346     }
1347 }