Imported Upstream version 2.6.0p1
[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 gboolean 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 #ifdef O_NONBLOCK
232 /* Open the tape device, trying various combinations of O_RDWR and
233    O_NONBLOCK. */
234 static int try_open_tape_device(TapeDevice * self, char * device_name) {
235     int rval;
236     rval  = robust_open(device_name, O_RDWR | O_NONBLOCK, 0);
237     if (rval < 0 && (errno == EWOULDBLOCK || errno == EINVAL)) {
238         /* Maybe we don't support O_NONBLOCK for tape devices. */
239         rval = robust_open(device_name, O_RDWR, 0);
240     }
241     if (rval >= 0) {
242         self->write_open_errno = 0;
243     } else {
244         if (errno == EACCES || errno == EPERM) {
245             /* Device is write-protected. */
246             self->write_open_errno = errno;
247             rval = robust_open(device_name, O_RDONLY | O_NONBLOCK, 0);
248             if (rval < 0 && (errno == EWOULDBLOCK || errno == EINVAL)) {
249                 rval = robust_open(device_name, O_RDONLY, 0);
250             }
251         }
252     }
253     /* Clear O_NONBLOCK for operations from now on. */
254     fcntl(rval, F_SETFL, fcntl(rval, F_GETFL, 0) & ~O_NONBLOCK);
255     return rval;
256 }
257 #else /* !defined(O_NONBLOCK) */
258 static int try_open_tape_device(TapeDevice * self, char * device_name) {
259     int rval;
260     rval = robust_open(device_name, O_RDWR);
261     if (rval >= 0) {
262         self->write_open_errno = 0;
263     } else {
264         if (errno == EACCES || errno == EPERM) {
265             /* Device is write-protected. */
266             self->write_open_errno = errno;
267             rval = robust_open(device_name, O_RDONLY);
268         }
269     }
270     return rval;
271 }
272 #endif /* O_NONBLOCK */
273
274 static gboolean 
275 tape_device_open_device (Device * d_self, char * device_name) {
276     TapeDevice * self;
277
278     self = TAPE_DEVICE(d_self);
279     g_return_val_if_fail (self != NULL, FALSE);
280     g_return_val_if_fail (device_name != NULL, FALSE);
281
282     self->fd = try_open_tape_device(self, device_name);
283
284     if (self->fd < 0) {
285         g_fprintf(stderr, "Can't open tape device %s: %s\n",
286                 device_name, strerror(errno));
287         return FALSE;
288     }
289
290     /* Check that this is actually a tape device. */
291     if (tape_is_tape_device(self->fd) == TAPE_CHECK_FAILURE) {
292         g_fprintf(stderr, "File %s is not a tape device.\n",
293                 device_name);
294         robust_close(self->fd);
295         return FALSE;
296     }
297
298     if (tape_is_ready(self->fd) == TAPE_CHECK_FAILURE) {
299         g_fprintf(stderr,
300                   "Tape device %s is not ready or is empty.\n",
301                   device_name);
302         robust_close(self->fd);
303         return FALSE;
304     }
305
306     /* Rewind it. */
307     if (!tape_rewind(self->fd)) {
308         g_fprintf(stderr, "Error rewinding device %s\n",
309                 device_name);
310         robust_close(self->fd);
311         return FALSE;
312     }
313
314     /* Get tape drive/OS info */
315     tape_device_discover_capabilities(self);
316
317     /* And verify the above. */
318     g_assert(feature_support_flags_is_valid(self->fsf));
319     g_assert(feature_support_flags_is_valid(self->bsf));
320     g_assert(feature_support_flags_is_valid(self->fsr));
321     g_assert(feature_support_flags_is_valid(self->bsr));
322     g_assert(feature_support_flags_is_valid(self->eom));
323     g_assert(feature_support_flags_is_valid(self->bsf_after_eom));
324     g_assert(self->final_filemarks == 1 ||
325              self->final_filemarks == 2);
326
327     /* Chain up */
328     if (parent_class->open_device) {
329         if (!(parent_class->open_device)(d_self, device_name)) {
330             robust_close(self->fd);
331             return FALSE;
332         }
333     }
334
335     return TRUE;
336 }
337
338 static ReadLabelStatusFlags tape_device_read_label(Device * dself) {
339     TapeDevice * self;
340     char * header_buffer;
341     int buffer_len;
342     IoResult result;
343     dumpfile_t header;
344
345     self = TAPE_DEVICE(dself);
346     g_return_val_if_fail(self != NULL, FALSE);
347
348     if (!tape_rewind(self->fd)) {
349         g_fprintf(stderr, "Error rewinding device %s\n",
350                 dself->device_name);
351         return (READ_LABEL_STATUS_DEVICE_ERROR |
352                 READ_LABEL_STATUS_VOLUME_ERROR);
353     }   
354
355     buffer_len = self->read_block_size;
356     header_buffer = malloc(buffer_len);
357     result = tape_device_robust_read(self, header_buffer, &buffer_len);
358
359     if (result != RESULT_SUCCESS) {
360         free(header_buffer);
361         tape_rewind(self->fd);
362         /* I/O error. */
363         g_fprintf(stderr, "Error reading Amanda header.\n");
364         if (result == RESULT_NO_DATA) {
365             return (READ_LABEL_STATUS_VOLUME_ERROR |
366                     READ_LABEL_STATUS_VOLUME_UNLABELED);
367         } else {
368             return (READ_LABEL_STATUS_DEVICE_ERROR |
369                     READ_LABEL_STATUS_VOLUME_ERROR |
370                     READ_LABEL_STATUS_VOLUME_UNLABELED);
371         }
372     }
373
374     parse_file_header(header_buffer, &header, buffer_len);
375     amfree(header_buffer);
376     if (header.type != F_TAPESTART) {
377         return READ_LABEL_STATUS_VOLUME_UNLABELED;
378     }
379      
380     dself->volume_label = g_strdup(header.name);
381     dself->volume_time = g_strdup(header.datestamp);
382    
383     if (parent_class->read_label) {
384         return parent_class->read_label(dself);
385     } else {
386         return READ_LABEL_STATUS_SUCCESS;
387     }
388 }
389
390 static gboolean
391 tape_device_write_block(Device * pself, guint size,
392                         gpointer data, gboolean short_block) {
393     TapeDevice * self;
394     char *replacement_buffer = NULL;
395     IoResult result;
396
397     self = TAPE_DEVICE(pself);
398     g_return_val_if_fail (self != NULL, FALSE);
399     g_return_val_if_fail (self->fd >= 0, FALSE);
400    
401     if (short_block && self->min_block_size > size) {
402         replacement_buffer = malloc(self->min_block_size);
403         memcpy(replacement_buffer, data, size);
404         bzero(replacement_buffer+size, self->min_block_size-size);
405         
406         data = replacement_buffer;
407         size = self->min_block_size;
408     }
409
410     result = tape_device_robust_write(self, data, size);
411     if (result == RESULT_SUCCESS) {
412         if (parent_class->write_block) {
413             (parent_class->write_block)(pself, size, data, short_block);
414         }
415         amfree(replacement_buffer);
416         return TRUE;
417     } else {
418         amfree(replacement_buffer);
419         return FALSE;
420     }
421     
422     g_assert_not_reached();
423 }
424
425 static int tape_device_read_block (Device * pself, gpointer buf,
426                                    int * size_req) {
427     TapeDevice * self;
428     int size;
429     IoResult result;
430     
431     self = TAPE_DEVICE(pself);
432     g_return_val_if_fail (self != NULL, -1);
433
434     if (buf == NULL || *size_req < (int)self->read_block_size) {
435         /* Just a size query. */
436         *size_req = self->read_block_size;
437         return 0;
438     }
439
440     size = *size_req;
441     result = tape_device_robust_read(self, buf, &size);
442     switch (result) {
443     case RESULT_SUCCESS:
444         *size_req = size;
445         return size;
446     case RESULT_SMALL_BUFFER: {
447         int new_size;
448         /* If this happens, it means that we have:
449          *     (next block size) > (buffer size) >= (read_block_size)
450          * The solution is to ask for an even bigger buffer. We also play
451          * some games to refrain from reading above the SCSI limit or from
452          * integer overflow. */
453         new_size = MIN(INT_MAX/2 - 1, *size_req) * 2;
454         if (new_size > LARGEST_BLOCK_ESTIMATE &&
455             *size_req < LARGEST_BLOCK_ESTIMATE) {
456             new_size = LARGEST_BLOCK_ESTIMATE;
457         }
458         if (new_size <= *size_req) {
459             return -1;
460         } else {
461             *size_req = new_size;
462             return 0;
463         }
464     }
465     case RESULT_NO_DATA:
466         pself->is_eof = TRUE;
467         /* FALLTHROUGH */
468     default:
469         return -1;
470     }
471
472     g_assert_not_reached();
473 }
474
475 /* Just a helper function for tape_device_start(). */
476 static gboolean write_tapestart_header(TapeDevice * self, char * label,
477                                        char * timestamp) {
478      IoResult result;
479      dumpfile_t * header;
480      char * header_buf;
481      int header_size;
482      gboolean header_fits;
483      Device * d_self = (Device*)self;
484      tape_rewind(self->fd);
485     
486      header = make_tapestart_header(d_self, label, timestamp);
487      g_assert(header != NULL);
488      header_buf = device_build_amanda_header(d_self, header, &header_size,
489                                              &header_fits);
490      amfree(header);
491      g_assert(header_buf != NULL);
492                                              
493      if (!header_fits) {
494          amfree(header_buf);
495          g_fprintf(stderr, "Tapestart header won't fit in a single block!\n");
496          return FALSE;
497      }
498
499      g_assert(header_size >= (int)self->min_block_size);
500      result = tape_device_robust_write(self, header_buf, header_size);
501      amfree(header_buf);
502      return (result == RESULT_SUCCESS);
503 }
504
505 static gboolean 
506 tape_device_start (Device * d_self, DeviceAccessMode mode, char * label,
507                    char * timestamp) {
508     TapeDevice * self;
509
510     self = TAPE_DEVICE(d_self);
511     g_return_val_if_fail(self != NULL, FALSE);
512     
513     if (IS_WRITABLE_ACCESS_MODE(mode)) {
514         if (self->write_open_errno != 0) {
515             /* We tried and failed to open the device in write mode. */
516             g_fprintf(stderr, "Can't open tape device %s for writing: %s\n",
517                     d_self->device_name, strerror(self->write_open_errno));
518             return FALSE;
519         } else if (!tape_rewind(self->fd)) {
520             g_fprintf(stderr, "Couldn't rewind device: %s\n",
521                     strerror(errno));
522         }
523     }
524
525     /* Position the tape */
526     switch (mode) {
527     case ACCESS_APPEND:
528         if (!tape_device_eod(self))
529             return FALSE;
530         self->first_file = TRUE;
531         break;
532         
533     case ACCESS_READ:
534         if (!tape_rewind(self->fd)) {
535             g_fprintf(stderr, "Error rewinding device %s\n",
536                     d_self->device_name);
537             return FALSE;
538         }
539         d_self->file = 0;
540         break;
541
542     case ACCESS_WRITE:
543         if (!write_tapestart_header(self, label, timestamp)) {
544             return FALSE;
545         }
546         self->first_file = TRUE;
547         break;
548
549     default:
550         g_assert_not_reached();
551     }
552
553     if (parent_class->start) {
554         return parent_class->start(d_self, mode, label, timestamp);
555     } else {
556         return TRUE;
557     }
558 }
559
560 static gboolean tape_device_start_file(Device * d_self,
561                                        const dumpfile_t * info) {
562     TapeDevice * self;
563     IoResult result;
564     char * amanda_header;
565     int header_size;
566     gboolean header_fits;
567
568     self = TAPE_DEVICE(d_self);
569     g_return_val_if_fail(self != NULL, FALSE);
570     g_return_val_if_fail (self->fd >= 0, FALSE);
571
572     if (!(d_self->access_mode == ACCESS_APPEND && self->first_file)) {
573         if (!tape_weof(self->fd, 1)) {
574             g_fprintf(stderr, "Error writing filemark: %s\n", strerror(errno));
575             return FALSE;
576         }
577     }
578
579     self->first_file = FALSE;
580
581     /* Make the Amanda header suitable for writing to the device. */
582     /* Then write the damn thing. */
583     amanda_header = device_build_amanda_header(d_self, info,
584                                                &header_size, &header_fits);
585     g_return_val_if_fail(amanda_header != NULL, FALSE);
586     g_return_val_if_fail(header_fits, FALSE);
587     result = tape_device_robust_write(self, amanda_header, header_size);
588     amfree(amanda_header);
589     if (result == RESULT_SUCCESS) {
590         /* Chain up. */
591         if (parent_class->start_file) {
592             parent_class->start_file(d_self, info);
593         }
594         return TRUE;
595     } else {
596         return FALSE;
597     }
598 }
599
600 static dumpfile_t * 
601 tape_device_seek_file (Device * d_self, guint file) {
602     TapeDevice * self;
603     int difference;
604     char * header_buffer;
605     dumpfile_t * rval;
606     int buffer_len;
607     IoResult result;
608
609     self = TAPE_DEVICE(d_self);
610     g_return_val_if_fail(d_self != NULL, NULL);
611
612     d_self->in_file = FALSE;
613
614     difference = file - d_self->file;
615
616     /* Check if we already read a filemark. */
617     if (d_self->is_eof) {
618         difference --;
619     }
620
621     if (difference > 0) {
622         /* Seeking forwards */
623         if (!tape_device_fsf(self, difference)) {
624             tape_rewind(self->fd);
625             return NULL;
626         }
627     } else if (difference < 0) {
628         /* Seeking backwards */
629         if (!tape_device_bsf(self, -difference, d_self->file)) {
630             tape_rewind(self->fd);
631             return NULL;
632         }
633     }
634
635     buffer_len = self->read_block_size;
636     header_buffer = malloc(buffer_len);
637     d_self->is_eof = FALSE;
638     result = tape_device_robust_read(self, header_buffer, &buffer_len);
639
640     if (result != RESULT_SUCCESS) {
641         free(header_buffer);
642         tape_rewind(self->fd);
643         if (result == RESULT_NO_DATA) {
644             /* If we read 0 bytes, that means we encountered a double
645              * filemark, which indicates end of tape. This should
646              * work even with QIC tapes on operating systems with
647              * proper support. */
648             return make_tapeend_header();
649         }
650         /* I/O error. */
651         g_fprintf(stderr, "Error reading Amanda header.\n");
652         return FALSE;
653     }
654         
655     rval = malloc(sizeof(*rval));
656     parse_file_header(header_buffer, rval, buffer_len);
657     amfree(header_buffer);
658     switch (rval->type) {
659     case F_DUMPFILE:
660     case F_CONT_DUMPFILE:
661     case F_SPLIT_DUMPFILE:
662         d_self->in_file = TRUE;
663         d_self->file = file;
664         return rval;
665     default:
666         tape_rewind(self->fd);
667         amfree(rval);
668         return NULL;
669     }
670 }
671
672 static gboolean 
673 tape_device_seek_block (Device * d_self, guint64 block) {
674     TapeDevice * self;
675     int difference;
676
677     self = TAPE_DEVICE(d_self);
678     g_return_val_if_fail(d_self != NULL, FALSE);
679
680     difference = block - d_self->block;
681     
682     if (difference > 0) {
683         if (!tape_device_fsr(self, difference))
684             return FALSE;
685     } else if (difference < 0) {
686         if (!tape_device_bsr(self, difference, d_self->file, d_self->block))
687             return FALSE;
688     }
689
690     if (parent_class->seek_block) {
691         return (parent_class->seek_block)(d_self, block);
692     } else {
693         return TRUE;
694     }
695 }
696
697 /* Just checks that the flag is valid before setting it. */
698 static gboolean get_feature_flag(GValue * val, FeatureSupportFlags f) {
699     if (feature_support_flags_is_valid(f)) {
700         g_value_set_flags(val, f);
701         return TRUE;
702     } else {
703         return FALSE;
704     }
705 }
706
707 static gboolean 
708 tape_device_property_get (Device * d_self, DevicePropertyId id, GValue * val) {
709     TapeDevice * self;
710     const DevicePropertyBase * base;
711
712     self = TAPE_DEVICE(d_self);
713     g_return_val_if_fail(self != NULL, FALSE);
714
715     base = device_property_get_by_id(id);
716     g_return_val_if_fail(self != NULL, FALSE);
717
718     g_value_unset_init(val, base->type);
719
720     if (id == PROPERTY_COMPRESSION) {
721         g_value_set_boolean(val, self->compression);
722         return TRUE;
723     } else if (id == PROPERTY_MIN_BLOCK_SIZE) {
724         g_value_set_uint(val, self->min_block_size);
725         return TRUE;
726     } else if (id == PROPERTY_MAX_BLOCK_SIZE) {
727         g_value_set_uint(val, self->max_block_size);
728         return TRUE;
729     } else if (id == PROPERTY_BLOCK_SIZE) {
730         if (self->fixed_block_size == 0) {
731             g_value_set_int(val, -1);
732         } else {
733             g_value_set_int(val, self->fixed_block_size);
734         }
735         return TRUE;
736     } else if (id == PROPERTY_FSF) {
737         return get_feature_flag(val, self->fsf);
738     } else if (id == PROPERTY_BSF) {
739         return get_feature_flag(val, self->bsf);
740     } else if (id == PROPERTY_FSR) {
741         return get_feature_flag(val, self->fsr);
742     } else if (id == PROPERTY_BSR) {
743         return get_feature_flag(val, self->bsr);
744     } else if (id == PROPERTY_EOM) {
745         return get_feature_flag(val, self->eom);
746     } else if (id == PROPERTY_BSF_AFTER_EOM) {
747         return get_feature_flag(val, self->bsf_after_eom);
748     } else if (id == PROPERTY_FINAL_FILEMARKS) {
749         g_value_set_uint(val, self->final_filemarks);
750         return TRUE;
751     } else {
752         /* Chain up */
753         if (parent_class->property_get) {
754             return (parent_class->property_get)(d_self, id, val);
755         } else {
756             return FALSE;
757         }
758     }
759
760     g_assert_not_reached();
761 }
762
763 /* We don't allow overriding of flags with _GOOD surety. That way, if
764    e.g., a feature has no matching IOCTL on a given platform, we don't
765    ever try to set it. */
766 static gboolean flags_settable(FeatureSupportFlags request,
767                                FeatureSupportFlags existing) {
768     if (!feature_support_flags_is_valid(request))
769         return FALSE;
770     else if (!feature_support_flags_is_valid(existing))
771         return TRUE;
772     else if (request == existing)
773         return TRUE;
774     else if (existing & FEATURE_SURETY_GOOD)
775         return FALSE;
776     else
777         return TRUE;
778 }
779
780 /* If the access listed is NULL, and the provided flags can override the
781    existing ones, then do it and return TRUE. */
782 static gboolean try_set_feature(DeviceAccessMode mode,
783                                 FeatureSupportFlags request,
784                                 FeatureSupportFlags * existing) {
785     if (mode != ACCESS_NULL) {
786         return FALSE;
787     } else if (flags_settable(request, *existing)) {
788         *existing = request;
789         return TRUE;
790     } else {
791         return FALSE;
792     }
793 }
794  
795 static gboolean 
796 tape_device_property_set (Device * d_self, DevicePropertyId id, GValue * val) {
797     TapeDevice * self;
798     FeatureSupportFlags feature_request_flags = 0;
799     const DevicePropertyBase * base;
800
801     self = TAPE_DEVICE(d_self);
802     g_return_val_if_fail(self != NULL, FALSE);
803
804     base = device_property_get_by_id(id);
805     g_return_val_if_fail(self != NULL, FALSE);
806
807     g_return_val_if_fail(G_VALUE_HOLDS(val, base->type), FALSE);
808
809     if (base->type == FEATURE_SUPPORT_FLAGS_TYPE) {
810         feature_request_flags = g_value_get_flags(val);
811         g_return_val_if_fail(
812             feature_support_flags_is_valid(feature_request_flags), FALSE);
813     }
814
815     if (id == PROPERTY_COMPRESSION) {
816         /* We allow this property to be set at any time. This is mostly
817          * because setting compression is a hit-and-miss proposition
818          * at any time; some drives accept the mode setting but don't
819          * actually support compression, while others do support
820          * compression but do it via density settings or some other
821          * way. Set this property whenever you want, but all we'll do
822          * is report whether or not the ioctl succeeded. */
823         gboolean request = g_value_get_boolean(val);
824         if (tape_setcompression(self->fd, request)) {
825             self->compression = request;
826             device_clear_volume_details(d_self);
827             return TRUE;
828         } else {
829             return FALSE;
830         }
831     } else if (id == PROPERTY_MIN_BLOCK_SIZE) {
832         if (d_self->access_mode != ACCESS_NULL)
833             return FALSE;
834         self->min_block_size = g_value_get_uint(val);
835         device_clear_volume_details(d_self);
836         return TRUE;
837     } else if (id == PROPERTY_MAX_BLOCK_SIZE) {
838         if (d_self->access_mode != ACCESS_NULL)
839             return FALSE;
840         self->max_block_size = g_value_get_uint(val);
841         device_clear_volume_details(d_self);
842         return TRUE;
843     } else if (id == PROPERTY_BLOCK_SIZE) {
844         if (d_self->access_mode != ACCESS_NULL)
845             return FALSE;
846
847         self->fixed_block_size = g_value_get_int(val);
848         device_clear_volume_details(d_self);
849         return TRUE;
850     } else if (id == PROPERTY_READ_BUFFER_SIZE) {
851         if (d_self->access_mode != ACCESS_NULL)
852             return FALSE;
853         self->read_block_size = g_value_get_uint(val);
854         device_clear_volume_details(d_self);
855         return TRUE;
856     } else if (id == PROPERTY_FSF) {
857         return try_set_feature(d_self->access_mode,
858                                feature_request_flags,
859                                &(self->fsf));
860     } else if (id == PROPERTY_BSF) {
861         return try_set_feature(d_self->access_mode,
862                                feature_request_flags,
863                                &(self->bsf));
864     } else if (id == PROPERTY_FSR) {
865         return try_set_feature(d_self->access_mode,
866                                feature_request_flags,
867                                &(self->fsr));
868     } else if (id == PROPERTY_BSR) {
869         return try_set_feature(d_self->access_mode,
870                                feature_request_flags,
871                                &(self->bsr));
872     } else if (id == PROPERTY_EOM) {
873         /* Setting this to disabled also clears BSF after EOM. */
874         if (try_set_feature(d_self->access_mode,
875                             feature_request_flags,
876                             &(self->eom))) {
877             feature_request_flags &= ~FEATURE_SUPPORT_FLAGS_STATUS_MASK;
878             feature_request_flags |= FEATURE_STATUS_DISABLED;
879             self->bsf_after_eom = feature_request_flags;
880             return TRUE;
881         } else {
882             return FALSE;
883         }
884     } else if (id == PROPERTY_BSF_AFTER_EOM) {
885         /* You can only set this if EOM is enabled. */
886         if (self->bsf | FEATURE_STATUS_DISABLED)
887             return FALSE;
888         else
889             return try_set_feature(d_self->access_mode,
890                                    feature_request_flags,
891                                    &(self->bsf_after_eom));
892     } else if (id == PROPERTY_FINAL_FILEMARKS) {
893         guint request = g_value_get_uint(val);
894         if (request == 1 || request == 2) {
895             self->final_filemarks = request;
896             return TRUE;
897         } else {
898             return FALSE;
899         }
900     } else {
901         /* Chain up */
902         if (parent_class->property_set) {
903             return (parent_class->property_set)(d_self, id, val);
904         } else {
905             return FALSE;
906         }
907     }
908
909     g_assert_not_reached();
910 }
911
912 static gboolean 
913 tape_device_finish (Device * d_self) {
914     TapeDevice * self;
915
916     self = TAPE_DEVICE(d_self);
917     g_return_val_if_fail(self != NULL, FALSE);
918
919     /* Polish off this file, if relevant. */
920     if (d_self->in_file && IS_WRITABLE_ACCESS_MODE(d_self->access_mode)) {
921         if (!device_finish_file(d_self))
922             return FALSE;
923     }
924
925     /* Write an extra filemark, if needed. The OS will give us one for
926        sure. */
927     if (self->final_filemarks > 1 &&
928         IS_WRITABLE_ACCESS_MODE(d_self->access_mode)) {
929         if (!tape_weof(self->fd, 1)) {
930             g_fprintf(stderr, "Error writing final filemark: %s\n",
931                     strerror(errno));
932             return FALSE;
933         }
934     }
935
936     /* Rewind. */
937     if (!tape_rewind(self->fd)) {
938         g_fprintf(stderr, "Error rewinding tape: %s\n", strerror(errno));
939         return FALSE;
940     }
941
942     d_self->access_mode = ACCESS_NULL;
943
944     if (parent_class->finish) {
945         return (parent_class->finish)(d_self);
946     } else {
947         return TRUE;
948     }
949
950 }
951
952 /* Works just like read(), except for the following:
953  * 1) Retries on EINTR & friends.
954  * 2) Stores count in parameter, not return value.
955  * 3) Provides explicit return result. */
956 static IoResult
957 tape_device_robust_read (TapeDevice * self, void * buf, int * count) {
958     Device * d_self;
959     int result;
960
961     d_self = (Device*)self;
962     g_return_val_if_fail(self != NULL, RESULT_ERROR);
963     g_return_val_if_fail(*count >= 0, RESULT_ERROR);
964     /* Callers should ensure this. */
965     g_assert((guint)(*count) <= self->read_block_size);
966
967     for (;;) {
968         result = read(self->fd, buf, *count);
969         if (result > 0) {
970             /* Success. By definition, we read a full block. */
971             *count = result;
972             return RESULT_SUCCESS;
973         } else if (result == 0) {
974             return RESULT_NO_DATA;
975         } else {
976             if (0
977 #ifdef EAGAIN
978                 || errno == EAGAIN
979 #endif
980 #ifdef EWOULDBLOCK
981                 || errno == EWOULDBLOCK
982 #endif
983 #ifdef EINTR
984                 || errno == EINTR
985 #endif
986                 ) {
987                 /* Interrupted system call */
988                 continue;
989             } else if ((self->fixed_block_size == 0) &&
990                        (0
991 #ifdef ENOMEM
992                         || errno == ENOMEM /* bad user-space buffer */
993 #endif
994 #ifdef EOVERFLOW
995                         || errno == EOVERFLOW /* bad kernel-space buffer */
996 #endif
997 #ifdef EINVAL
998                         || errno == EINVAL /* ??? */
999 #endif
1000                         )) {
1001                 /* Buffer too small. */
1002                 return RESULT_SMALL_BUFFER;
1003             } else {
1004                 g_fprintf(stderr, "Error reading %d bytes from %s: %s\n",
1005                         *count, d_self->device_name, strerror(errno));
1006                 return RESULT_ERROR;
1007             }
1008         }
1009
1010     }
1011
1012     g_assert_not_reached();
1013 }
1014
1015 /* Kernel workaround: If needed, poke the kernel so it doesn't fail.
1016    at the 2GB boundry. Parameters are G_GNUC_UNUSED in case NEED_RESETOFS
1017    is not defined. */
1018 static void check_resetofs(TapeDevice * self G_GNUC_UNUSED,
1019                            int count G_GNUC_UNUSED) {
1020 #ifdef NEED_RESETOFS
1021     int result;
1022
1023     self->private->write_count += count;
1024     if (self->private->write_count < RESETOFS_THRESHOLD) {
1025         return;
1026     }
1027
1028     result = lseek(self->fd, 0, SEEK_SET);
1029     if (result < 0) {
1030         g_fprintf(stderr,
1031                 "Warning: lseek() failed during kernel 2GB workaround.\n");
1032     }
1033 #endif
1034 }
1035
1036 static IoResult 
1037 tape_device_robust_write (TapeDevice * self, void * buf, int count) {
1038     Device * d_self;
1039     int result;
1040
1041     g_return_val_if_fail(self != NULL, RESULT_ERROR);
1042     d_self = (Device*)self;
1043     
1044     check_resetofs(self, count);
1045
1046     for (;;) {
1047         result = write(self->fd, buf, count);
1048
1049         if (result == count) {
1050             /* Success. */
1051
1052             self->private->write_count ++;
1053             return RESULT_SUCCESS;
1054         } else if (result >= 0) {
1055             /* write() returned a short count. This should not happen. */
1056             g_fprintf(stderr,
1057                   "Mysterious short write on tape device: Tried %d, got %d.\n",
1058                     count, result);
1059             return RESULT_ERROR;
1060         } else if (0
1061 #ifdef EAGAIN
1062                    || errno == EAGAIN
1063 #endif
1064 #ifdef EWOULDBLOCK
1065                    || errno == EWOULDBLOCK
1066 #endif
1067 #ifdef EINTR
1068                    || errno == EINTR
1069 #endif
1070                    ) {
1071                 /* Interrupted system call */
1072             continue;
1073         } else if (0
1074 #ifdef ENOSPC
1075                    || errno == ENOSPC
1076 #endif
1077 #ifdef EIO
1078                    || errno == EIO
1079 #endif
1080                    ) {
1081             /* Probably EOT. Print a message if we got EIO. */
1082 #ifdef EIO
1083             if (errno == EIO) {
1084                 g_fprintf(stderr, "Got EIO on %s, assuming end of tape.\n",
1085                         d_self->device_name);
1086             }
1087 #endif
1088             return RESULT_NO_SPACE;
1089         } else {
1090             /* WTF */
1091             g_fprintf(stderr,
1092      "Kernel gave unexpected write() result of \"%s\" on device %s.\n",
1093                     strerror(errno), d_self->device_name);
1094             return RESULT_ERROR;
1095         }
1096     }
1097
1098     g_assert_not_reached();
1099 }
1100
1101 /* Reads some number of tape blocks into the bit-bucket. If the count
1102    is negative, then we read the rest of the entire file. Returns the
1103    number of blocks read, or -1 if an error occured. If we encounter
1104    EOF (as opposed to some other error) we return the number of blocks
1105    actually read. */
1106 static int drain_tape_blocks(TapeDevice * self, int count) {
1107     char * buffer;
1108     int buffer_size;
1109     int i;
1110
1111     buffer_size = self->read_block_size;
1112
1113     buffer = malloc(sizeof(buffer_size));
1114
1115     for (i = 0; i < count || count < 0;) {
1116         int result;
1117
1118         result = read(self->fd, buffer, buffer_size);
1119         if (result > 0) {
1120             i ++;
1121             continue;
1122         } else if (result == 0) {
1123             free(buffer);
1124             return i;
1125         } else {
1126             /* First check for interrupted system call. */
1127             if (0
1128 #ifdef EAGAIN
1129                 || errno == EAGAIN
1130 #endif
1131 #ifdef EWOULDBLOCK
1132                 || errno == EWOULDBLOCK
1133 #endif
1134 #ifdef EINTR
1135                 || errno == EINTR
1136 #endif
1137                 ) {
1138                 /* Interrupted system call */
1139                 continue;
1140             } else if (0
1141 #ifdef ENOSPC
1142                        || errno == ENOSPC /* bad user-space buffer */
1143 #endif
1144 #ifdef EOVERFLOW
1145                        || errno == EOVERFLOW /* bad kernel-space buffer */
1146 #endif
1147 #ifdef EINVAL
1148                        || errno == EINVAL /* ??? */
1149 #endif
1150                        ) {
1151                 /* The buffer may not be big enough. But the OS is not
1152                    100% clear. We double the buffer and try again, but
1153                    in no case allow a buffer bigger than 32 MB. */
1154                 buffer_size *= 2;
1155
1156                 if (buffer_size > 32*1024*1024) {
1157                     free(buffer);
1158                     return -1;
1159                 } else {
1160                     buffer = realloc(buffer, buffer_size);
1161                     continue;
1162                 }
1163             }
1164         }
1165     }
1166     
1167     return count;
1168 }
1169
1170 /* FIXME: Make sure that there are no cycles in reimplementation
1171    dependencies. */
1172
1173 static gboolean 
1174 tape_device_fsf (TapeDevice * self, guint count) {
1175     g_return_val_if_fail (self != NULL, (gboolean )0);
1176     g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
1177     
1178     if (self->fsf & FEATURE_STATUS_ENABLED) {
1179         return tape_fsf(self->fd, count);
1180     } else {
1181         guint i;
1182         for (i = 0; i < count; i ++) {
1183             if (drain_tape_blocks(self, -1) < 0)
1184                 return FALSE;
1185         }
1186         return TRUE;
1187     }
1188 }
1189
1190 /* Seek back over count + 1 filemarks to the start of the given file. */
1191 static gboolean 
1192 tape_device_bsf (TapeDevice * self, guint count, guint file) {
1193     g_return_val_if_fail (self != NULL, (gboolean )0);
1194     g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
1195
1196     if (self->bsf & FEATURE_STATUS_ENABLED) {
1197         /* The BSF operation is not very smart; it includes the
1198            filemark of the present file as part of the count, and seeks
1199            to the wrong (BOT) side of the filemark. We compensate for
1200            this by seeking one filemark too many, then FSFing back over
1201            it.
1202
1203            If this procedure fails for some reason, we can still try
1204            the backup plan. */
1205         if (tape_bsf(self->fd, count + 1) &&
1206             tape_device_fsf(self, 1))
1207             return TRUE;
1208     } /* Fall through to backup plan. */
1209
1210     /* We rewind the tape, then seek forward the given number of
1211        files. */
1212     if (!tape_rewind(self->fd))
1213         return FALSE;
1214
1215     return tape_device_fsf(self, file);
1216 }
1217
1218
1219 static gboolean 
1220 tape_device_fsr (TapeDevice * self, guint count) {
1221     g_return_val_if_fail (self != NULL, (gboolean )0);
1222     g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
1223
1224     if (self->fsr & FEATURE_STATUS_ENABLED) {
1225         return tape_fsr(self->fd, count);
1226     } else {
1227         int result = drain_tape_blocks(self, count);
1228         return result > 0 && (int)count == result;
1229     }
1230 }
1231
1232 /* Seek back the given number of blocks to block number block within
1233  * the current file, numbered file. */
1234
1235 static gboolean 
1236 tape_device_bsr (TapeDevice * self, guint count, guint file, guint block) {
1237     g_return_val_if_fail (self != NULL, (gboolean )0);
1238     g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
1239     
1240     g_return_val_if_fail (self != NULL, (gboolean )0);
1241     g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
1242
1243     if (self->bsr & FEATURE_STATUS_ENABLED) {
1244         return tape_bsr(self->fd, count);
1245     } else {
1246         /* We BSF, then FSR. */
1247         if (!tape_device_bsf(self, 0, file))
1248             return FALSE;
1249         
1250         return tape_device_fsr(self, block);
1251     }
1252     g_assert_not_reached();
1253 }
1254
1255 /* Go to the right place to write more data, and update the file
1256    number if possible. */
1257 static gboolean 
1258 tape_device_eod (TapeDevice * self) {
1259     Device * d_self;
1260     g_return_val_if_fail (self != NULL, (gboolean )0);
1261     g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
1262     d_self = (Device*)self;
1263
1264     if (self->eom & FEATURE_STATUS_ENABLED) {
1265         int result;
1266         result = tape_eod(self->fd); 
1267         if (result == TAPE_OP_ERROR) {
1268             return FALSE;
1269         } else if (result == TAPE_POSITION_UNKNOWN) {
1270             d_self->file = -1;
1271         } else {
1272             /* We drop by 1 because Device will increment the first
1273                time the user does start_file. */
1274             d_self->file = result - 1;
1275         }
1276         return TRUE;
1277     } else {
1278         int count = 0;
1279         if (!tape_rewind(self->fd))
1280             return FALSE;
1281         
1282         for (;;) {
1283             /* We alternately read a block and FSF. If the read is
1284                successful, then we are not there yet and should FSF
1285                again. */
1286             int result;
1287             result = drain_tape_blocks(self, 1);
1288             if (result == 1) {
1289                 /* More data, FSF. */
1290                 tape_device_fsf(self, 1);
1291                 count ++;
1292             } else if (result == 0) {
1293                 /* Finished. */
1294                 d_self->file = count;
1295                 return TRUE;
1296             } else {
1297                 return FALSE;
1298             }
1299         }
1300     }
1301 }
1302
1303 Device *
1304 tape_device_factory (char * device_type, char * device_name) {
1305     Device * rval;
1306     g_assert(0 == strcmp(device_type, "tape"));
1307     rval = DEVICE(g_object_new(TYPE_TAPE_DEVICE, NULL));
1308     if (!device_open_device(rval, device_name)) {
1309         g_object_unref(rval);
1310         return NULL;
1311     } else {
1312         return rval;
1313     }
1314 }