2 * Copyright (c) 2005 Zmanda, Inc. All Rights Reserved.
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.
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.
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.
17 * Contact information: Zmanda Inc., 505 N Mathlida Ave, Suite 120
18 * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
21 #include <string.h> /* memset() */
23 #include "tape-device.h"
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)
30 /* Largest possible block size on SCSI systems. */
31 #define LARGEST_BLOCK_ESTIMATE (16 * 1024 * 1024)
33 struct TapeDevicePrivate_s {
34 /* This holds the total number of bytes written to the device,
35 modulus RESETOFS_THRESHOLD. */
39 /* Possible (abstracted) results from a system I/O operation. */
42 RESULT_ERROR, /* Undefined error. */
43 RESULT_SMALL_BUFFER, /* Tried to read with a buffer that is too
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. */
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,
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,
68 static gboolean tape_device_property_set (Device * self, DevicePropertyId id,
70 static gboolean tape_device_finish (Device * self);
71 static IoResult tape_device_robust_read (TapeDevice * self, void * buf,
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);
80 /* pointer to the class of our parent */
81 static DeviceClass *parent_class = NULL;
83 GType tape_device_get_type (void)
85 static GType type = 0;
87 if G_UNLIKELY(type == 0) {
88 static const GTypeInfo info = {
89 sizeof (TapeDeviceClass),
91 (GBaseFinalizeFunc) NULL,
92 (GClassInitFunc) tape_device_class_init,
93 (GClassFinalizeFunc) NULL,
94 NULL /* class_data */,
97 (GInstanceInitFunc) tape_device_init,
101 type = g_type_register_static (TYPE_DEVICE, "TapeDevice",
102 &info, (GTypeFlags)0);
109 tape_device_init (TapeDevice * self) {
110 Device * device_self;
114 device_self = (Device*)self;
115 bzero(&response, sizeof(response));
117 self->private = malloc(sizeof(TapeDevicePrivate));
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;
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;
129 self->private->write_count = 0;
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);
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);
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);
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);
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);
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);
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);
187 prop.access = PROPERTY_ACCESS_GET_MASK;
188 prop.base = &device_property_canonical_name;
189 device_add_property(device_self, &prop, NULL);
192 static void tape_device_finalize(GObject * obj_self) {
193 TapeDevice * self = TAPE_DEVICE(obj_self);
195 if(G_OBJECT_CLASS(parent_class)->finalize) \
196 (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
198 robust_close(self->fd);
200 amfree(self->private);
204 tape_device_class_init (TapeDeviceClass * c)
206 DeviceClass *device_class = (DeviceClass *)c;
207 GObjectClass *g_object_class = (GObjectClass *)c;
209 parent_class = g_type_class_ref (TYPE_DEVICE);
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;
223 g_object_class->finalize = tape_device_finalize;
226 void tape_device_register(void) {
227 static const char * device_prefix_list[] = { "tape", NULL };
228 register_device(tape_device_factory, device_prefix_list);
232 /* Open the tape device, trying various combinations of O_RDWR and
234 static int try_open_tape_device(TapeDevice * self, char * device_name) {
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);
242 self->write_open_errno = 0;
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);
253 /* Clear O_NONBLOCK for operations from now on. */
254 fcntl(rval, F_SETFL, fcntl(rval, F_GETFL, 0) & ~O_NONBLOCK);
257 #else /* !defined(O_NONBLOCK) */
258 static int try_open_tape_device(TapeDevice * self, char * device_name) {
260 rval = robust_open(device_name, O_RDWR);
262 self->write_open_errno = 0;
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);
272 #endif /* O_NONBLOCK */
275 tape_device_open_device (Device * d_self, char * device_name) {
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);
282 self->fd = try_open_tape_device(self, device_name);
285 g_fprintf(stderr, "Can't open tape device %s: %s\n",
286 device_name, strerror(errno));
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",
294 robust_close(self->fd);
298 if (tape_is_ready(self->fd) == TAPE_CHECK_FAILURE) {
300 "Tape device %s is not ready or is empty.\n",
302 robust_close(self->fd);
307 if (!tape_rewind(self->fd)) {
308 g_fprintf(stderr, "Error rewinding device %s\n",
310 robust_close(self->fd);
314 /* Get tape drive/OS info */
315 tape_device_discover_capabilities(self);
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);
328 if (parent_class->open_device) {
329 if (!(parent_class->open_device)(d_self, device_name)) {
330 robust_close(self->fd);
338 static ReadLabelStatusFlags tape_device_read_label(Device * dself) {
340 char * header_buffer;
345 self = TAPE_DEVICE(dself);
346 g_return_val_if_fail(self != NULL, FALSE);
348 if (!tape_rewind(self->fd)) {
349 g_fprintf(stderr, "Error rewinding device %s\n",
351 return (READ_LABEL_STATUS_DEVICE_ERROR |
352 READ_LABEL_STATUS_VOLUME_ERROR);
355 buffer_len = self->read_block_size;
356 header_buffer = malloc(buffer_len);
357 result = tape_device_robust_read(self, header_buffer, &buffer_len);
359 if (result != RESULT_SUCCESS) {
361 tape_rewind(self->fd);
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);
368 return (READ_LABEL_STATUS_DEVICE_ERROR |
369 READ_LABEL_STATUS_VOLUME_ERROR |
370 READ_LABEL_STATUS_VOLUME_UNLABELED);
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;
380 dself->volume_label = g_strdup(header.name);
381 dself->volume_time = g_strdup(header.datestamp);
383 if (parent_class->read_label) {
384 return parent_class->read_label(dself);
386 return READ_LABEL_STATUS_SUCCESS;
391 tape_device_write_block(Device * pself, guint size,
392 gpointer data, gboolean short_block) {
394 char *replacement_buffer = NULL;
397 self = TAPE_DEVICE(pself);
398 g_return_val_if_fail (self != NULL, FALSE);
399 g_return_val_if_fail (self->fd >= 0, FALSE);
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);
406 data = replacement_buffer;
407 size = self->min_block_size;
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);
415 amfree(replacement_buffer);
418 amfree(replacement_buffer);
422 g_assert_not_reached();
425 static int tape_device_read_block (Device * pself, gpointer buf,
431 self = TAPE_DEVICE(pself);
432 g_return_val_if_fail (self != NULL, -1);
434 if (buf == NULL || *size_req < (int)self->read_block_size) {
435 /* Just a size query. */
436 *size_req = self->read_block_size;
441 result = tape_device_robust_read(self, buf, &size);
446 case RESULT_SMALL_BUFFER: {
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;
458 if (new_size <= *size_req) {
461 *size_req = new_size;
466 pself->is_eof = TRUE;
472 g_assert_not_reached();
475 /* Just a helper function for tape_device_start(). */
476 static gboolean write_tapestart_header(TapeDevice * self, char * label,
482 gboolean header_fits;
483 Device * d_self = (Device*)self;
484 tape_rewind(self->fd);
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,
491 g_assert(header_buf != NULL);
495 g_fprintf(stderr, "Tapestart header won't fit in a single block!\n");
499 g_assert(header_size >= (int)self->min_block_size);
500 result = tape_device_robust_write(self, header_buf, header_size);
502 return (result == RESULT_SUCCESS);
506 tape_device_start (Device * d_self, DeviceAccessMode mode, char * label,
510 self = TAPE_DEVICE(d_self);
511 g_return_val_if_fail(self != NULL, FALSE);
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));
519 } else if (!tape_rewind(self->fd)) {
520 g_fprintf(stderr, "Couldn't rewind device: %s\n",
525 /* Position the tape */
528 if (!tape_device_eod(self))
530 self->first_file = TRUE;
534 if (!tape_rewind(self->fd)) {
535 g_fprintf(stderr, "Error rewinding device %s\n",
536 d_self->device_name);
543 if (!write_tapestart_header(self, label, timestamp)) {
546 self->first_file = TRUE;
550 g_assert_not_reached();
553 if (parent_class->start) {
554 return parent_class->start(d_self, mode, label, timestamp);
560 static gboolean tape_device_start_file(Device * d_self,
561 const dumpfile_t * info) {
564 char * amanda_header;
566 gboolean header_fits;
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);
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));
579 self->first_file = FALSE;
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) {
591 if (parent_class->start_file) {
592 parent_class->start_file(d_self, info);
601 tape_device_seek_file (Device * d_self, guint file) {
604 char * header_buffer;
609 self = TAPE_DEVICE(d_self);
610 g_return_val_if_fail(d_self != NULL, NULL);
612 d_self->in_file = FALSE;
614 difference = file - d_self->file;
616 /* Check if we already read a filemark. */
617 if (d_self->is_eof) {
621 if (difference > 0) {
622 /* Seeking forwards */
623 if (!tape_device_fsf(self, difference)) {
624 tape_rewind(self->fd);
627 } else if (difference < 0) {
628 /* Seeking backwards */
629 if (!tape_device_bsf(self, -difference, d_self->file)) {
630 tape_rewind(self->fd);
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);
640 if (result != RESULT_SUCCESS) {
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
648 return make_tapeend_header();
651 g_fprintf(stderr, "Error reading Amanda header.\n");
655 rval = malloc(sizeof(*rval));
656 parse_file_header(header_buffer, rval, buffer_len);
657 amfree(header_buffer);
658 switch (rval->type) {
660 case F_CONT_DUMPFILE:
661 case F_SPLIT_DUMPFILE:
662 d_self->in_file = TRUE;
666 tape_rewind(self->fd);
673 tape_device_seek_block (Device * d_self, guint64 block) {
677 self = TAPE_DEVICE(d_self);
678 g_return_val_if_fail(d_self != NULL, FALSE);
680 difference = block - d_self->block;
682 if (difference > 0) {
683 if (!tape_device_fsr(self, difference))
685 } else if (difference < 0) {
686 if (!tape_device_bsr(self, difference, d_self->file, d_self->block))
690 if (parent_class->seek_block) {
691 return (parent_class->seek_block)(d_self, block);
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);
708 tape_device_property_get (Device * d_self, DevicePropertyId id, GValue * val) {
710 const DevicePropertyBase * base;
712 self = TAPE_DEVICE(d_self);
713 g_return_val_if_fail(self != NULL, FALSE);
715 base = device_property_get_by_id(id);
716 g_return_val_if_fail(self != NULL, FALSE);
718 g_value_unset_init(val, base->type);
720 if (id == PROPERTY_COMPRESSION) {
721 g_value_set_boolean(val, self->compression);
723 } else if (id == PROPERTY_MIN_BLOCK_SIZE) {
724 g_value_set_uint(val, self->min_block_size);
726 } else if (id == PROPERTY_MAX_BLOCK_SIZE) {
727 g_value_set_uint(val, self->max_block_size);
729 } else if (id == PROPERTY_BLOCK_SIZE) {
730 if (self->fixed_block_size == 0) {
731 g_value_set_int(val, -1);
733 g_value_set_int(val, self->fixed_block_size);
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);
753 if (parent_class->property_get) {
754 return (parent_class->property_get)(d_self, id, val);
760 g_assert_not_reached();
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))
770 else if (!feature_support_flags_is_valid(existing))
772 else if (request == existing)
774 else if (existing & FEATURE_SURETY_GOOD)
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) {
787 } else if (flags_settable(request, *existing)) {
796 tape_device_property_set (Device * d_self, DevicePropertyId id, GValue * val) {
798 FeatureSupportFlags feature_request_flags = 0;
799 const DevicePropertyBase * base;
801 self = TAPE_DEVICE(d_self);
802 g_return_val_if_fail(self != NULL, FALSE);
804 base = device_property_get_by_id(id);
805 g_return_val_if_fail(self != NULL, FALSE);
807 g_return_val_if_fail(G_VALUE_HOLDS(val, base->type), FALSE);
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);
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);
831 } else if (id == PROPERTY_MIN_BLOCK_SIZE) {
832 if (d_self->access_mode != ACCESS_NULL)
834 self->min_block_size = g_value_get_uint(val);
835 device_clear_volume_details(d_self);
837 } else if (id == PROPERTY_MAX_BLOCK_SIZE) {
838 if (d_self->access_mode != ACCESS_NULL)
840 self->max_block_size = g_value_get_uint(val);
841 device_clear_volume_details(d_self);
843 } else if (id == PROPERTY_BLOCK_SIZE) {
844 if (d_self->access_mode != ACCESS_NULL)
847 self->fixed_block_size = g_value_get_int(val);
848 device_clear_volume_details(d_self);
850 } else if (id == PROPERTY_READ_BUFFER_SIZE) {
851 if (d_self->access_mode != ACCESS_NULL)
853 self->read_block_size = g_value_get_uint(val);
854 device_clear_volume_details(d_self);
856 } else if (id == PROPERTY_FSF) {
857 return try_set_feature(d_self->access_mode,
858 feature_request_flags,
860 } else if (id == PROPERTY_BSF) {
861 return try_set_feature(d_self->access_mode,
862 feature_request_flags,
864 } else if (id == PROPERTY_FSR) {
865 return try_set_feature(d_self->access_mode,
866 feature_request_flags,
868 } else if (id == PROPERTY_BSR) {
869 return try_set_feature(d_self->access_mode,
870 feature_request_flags,
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,
877 feature_request_flags &= ~FEATURE_SUPPORT_FLAGS_STATUS_MASK;
878 feature_request_flags |= FEATURE_STATUS_DISABLED;
879 self->bsf_after_eom = feature_request_flags;
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)
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;
902 if (parent_class->property_set) {
903 return (parent_class->property_set)(d_self, id, val);
909 g_assert_not_reached();
913 tape_device_finish (Device * d_self) {
916 self = TAPE_DEVICE(d_self);
917 g_return_val_if_fail(self != NULL, FALSE);
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))
925 /* Write an extra filemark, if needed. The OS will give us one for
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",
937 if (!tape_rewind(self->fd)) {
938 g_fprintf(stderr, "Error rewinding tape: %s\n", strerror(errno));
942 d_self->access_mode = ACCESS_NULL;
944 if (parent_class->finish) {
945 return (parent_class->finish)(d_self);
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. */
957 tape_device_robust_read (TapeDevice * self, void * buf, int * count) {
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);
968 result = read(self->fd, buf, *count);
970 /* Success. By definition, we read a full block. */
972 return RESULT_SUCCESS;
973 } else if (result == 0) {
974 return RESULT_NO_DATA;
981 || errno == EWOULDBLOCK
987 /* Interrupted system call */
989 } else if ((self->fixed_block_size == 0) &&
992 || errno == ENOMEM /* bad user-space buffer */
995 || errno == EOVERFLOW /* bad kernel-space buffer */
998 || errno == EINVAL /* ??? */
1001 /* Buffer too small. */
1002 return RESULT_SMALL_BUFFER;
1004 g_fprintf(stderr, "Error reading %d bytes from %s: %s\n",
1005 *count, d_self->device_name, strerror(errno));
1006 return RESULT_ERROR;
1012 g_assert_not_reached();
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
1018 static void check_resetofs(TapeDevice * self G_GNUC_UNUSED,
1019 int count G_GNUC_UNUSED) {
1020 #ifdef NEED_RESETOFS
1023 self->private->write_count += count;
1024 if (self->private->write_count < RESETOFS_THRESHOLD) {
1028 result = lseek(self->fd, 0, SEEK_SET);
1031 "Warning: lseek() failed during kernel 2GB workaround.\n");
1037 tape_device_robust_write (TapeDevice * self, void * buf, int count) {
1041 g_return_val_if_fail(self != NULL, RESULT_ERROR);
1042 d_self = (Device*)self;
1044 check_resetofs(self, count);
1047 result = write(self->fd, buf, count);
1049 if (result == count) {
1052 self->private->write_count ++;
1053 return RESULT_SUCCESS;
1054 } else if (result >= 0) {
1055 /* write() returned a short count. This should not happen. */
1057 "Mysterious short write on tape device: Tried %d, got %d.\n",
1059 return RESULT_ERROR;
1065 || errno == EWOULDBLOCK
1071 /* Interrupted system call */
1081 /* Probably EOT. Print a message if we got EIO. */
1084 g_fprintf(stderr, "Got EIO on %s, assuming end of tape.\n",
1085 d_self->device_name);
1088 return RESULT_NO_SPACE;
1092 "Kernel gave unexpected write() result of \"%s\" on device %s.\n",
1093 strerror(errno), d_self->device_name);
1094 return RESULT_ERROR;
1098 g_assert_not_reached();
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
1106 static int drain_tape_blocks(TapeDevice * self, int count) {
1111 buffer_size = self->read_block_size;
1113 buffer = malloc(sizeof(buffer_size));
1115 for (i = 0; i < count || count < 0;) {
1118 result = read(self->fd, buffer, buffer_size);
1122 } else if (result == 0) {
1126 /* First check for interrupted system call. */
1132 || errno == EWOULDBLOCK
1138 /* Interrupted system call */
1142 || errno == ENOSPC /* bad user-space buffer */
1145 || errno == EOVERFLOW /* bad kernel-space buffer */
1148 || errno == EINVAL /* ??? */
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. */
1156 if (buffer_size > 32*1024*1024) {
1160 buffer = realloc(buffer, buffer_size);
1170 /* FIXME: Make sure that there are no cycles in reimplementation
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);
1178 if (self->fsf & FEATURE_STATUS_ENABLED) {
1179 return tape_fsf(self->fd, count);
1182 for (i = 0; i < count; i ++) {
1183 if (drain_tape_blocks(self, -1) < 0)
1190 /* Seek back over count + 1 filemarks to the start of the given file. */
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);
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
1203 If this procedure fails for some reason, we can still try
1205 if (tape_bsf(self->fd, count + 1) &&
1206 tape_device_fsf(self, 1))
1208 } /* Fall through to backup plan. */
1210 /* We rewind the tape, then seek forward the given number of
1212 if (!tape_rewind(self->fd))
1215 return tape_device_fsf(self, file);
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);
1224 if (self->fsr & FEATURE_STATUS_ENABLED) {
1225 return tape_fsr(self->fd, count);
1227 int result = drain_tape_blocks(self, count);
1228 return result > 0 && (int)count == result;
1232 /* Seek back the given number of blocks to block number block within
1233 * the current file, numbered file. */
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);
1240 g_return_val_if_fail (self != NULL, (gboolean )0);
1241 g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
1243 if (self->bsr & FEATURE_STATUS_ENABLED) {
1244 return tape_bsr(self->fd, count);
1246 /* We BSF, then FSR. */
1247 if (!tape_device_bsf(self, 0, file))
1250 return tape_device_fsr(self, block);
1252 g_assert_not_reached();
1255 /* Go to the right place to write more data, and update the file
1256 number if possible. */
1258 tape_device_eod (TapeDevice * 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;
1264 if (self->eom & FEATURE_STATUS_ENABLED) {
1266 result = tape_eod(self->fd);
1267 if (result == TAPE_OP_ERROR) {
1269 } else if (result == TAPE_POSITION_UNKNOWN) {
1272 /* We drop by 1 because Device will increment the first
1273 time the user does start_file. */
1274 d_self->file = result - 1;
1279 if (!tape_rewind(self->fd))
1283 /* We alternately read a block and FSF. If the read is
1284 successful, then we are not there yet and should FSF
1287 result = drain_tape_blocks(self, 1);
1289 /* More data, FSF. */
1290 tape_device_fsf(self, 1);
1292 } else if (result == 0) {
1294 d_self->file = count;
1304 tape_device_factory (char * device_type, char * device_name) {
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);