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_FSF) {
851 return try_set_feature(d_self->access_mode,
852 feature_request_flags,
854 } else if (id == PROPERTY_BSF) {
855 return try_set_feature(d_self->access_mode,
856 feature_request_flags,
858 } else if (id == PROPERTY_FSR) {
859 return try_set_feature(d_self->access_mode,
860 feature_request_flags,
862 } else if (id == PROPERTY_BSR) {
863 return try_set_feature(d_self->access_mode,
864 feature_request_flags,
866 } else if (id == PROPERTY_EOM) {
867 /* Setting this to disabled also clears BSF after EOM. */
868 if (try_set_feature(d_self->access_mode,
869 feature_request_flags,
871 feature_request_flags &= ~FEATURE_SUPPORT_FLAGS_STATUS_MASK;
872 feature_request_flags |= FEATURE_STATUS_DISABLED;
873 self->bsf_after_eom = feature_request_flags;
878 } else if (id == PROPERTY_BSF_AFTER_EOM) {
879 /* You can only set this if EOM is enabled. */
880 if (self->bsf | FEATURE_STATUS_DISABLED)
883 return try_set_feature(d_self->access_mode,
884 feature_request_flags,
885 &(self->bsf_after_eom));
886 } else if (id == PROPERTY_FINAL_FILEMARKS) {
887 guint request = g_value_get_uint(val);
888 if (request == 1 || request == 2) {
889 self->final_filemarks = request;
896 if (parent_class->property_set) {
897 return (parent_class->property_set)(d_self, id, val);
903 g_assert_not_reached();
907 tape_device_finish (Device * d_self) {
910 self = TAPE_DEVICE(d_self);
911 g_return_val_if_fail(self != NULL, FALSE);
913 /* Polish off this file, if relevant. */
914 if (d_self->in_file && IS_WRITABLE_ACCESS_MODE(d_self->access_mode)) {
915 if (!device_finish_file(d_self))
919 /* Write an extra filemark, if needed. The OS will give us one for
921 if (self->final_filemarks > 1 &&
922 IS_WRITABLE_ACCESS_MODE(d_self->access_mode)) {
923 if (!tape_weof(self->fd, 1)) {
924 g_fprintf(stderr, "Error writing final filemark: %s\n",
931 if (!tape_rewind(self->fd)) {
932 g_fprintf(stderr, "Error rewinding tape: %s\n", strerror(errno));
936 d_self->access_mode = ACCESS_NULL;
938 if (parent_class->finish) {
939 return (parent_class->finish)(d_self);
946 /* Works just like read(), except for the following:
947 * 1) Retries on EINTR & friends.
948 * 2) Stores count in parameter, not return value.
949 * 3) Provides explicit return result. */
951 tape_device_robust_read (TapeDevice * self, void * buf, int * count) {
955 d_self = (Device*)self;
956 g_return_val_if_fail(self != NULL, RESULT_ERROR);
957 g_return_val_if_fail(*count >= 0, RESULT_ERROR);
958 /* Callers should ensure this. */
959 g_assert((guint)(*count) <= self->read_block_size);
962 result = read(self->fd, buf, *count);
964 /* Success. By definition, we read a full block. */
966 return RESULT_SUCCESS;
967 } else if (result == 0) {
968 return RESULT_NO_DATA;
975 || errno == EWOULDBLOCK
981 /* Interrupted system call */
983 } else if ((self->fixed_block_size == 0) &&
986 || errno == ENOMEM /* bad user-space buffer */
989 || errno == EOVERFLOW /* bad kernel-space buffer */
992 || errno == EINVAL /* ??? */
995 /* Buffer too small. */
996 return RESULT_SMALL_BUFFER;
998 g_fprintf(stderr, "Error reading %d bytes from %s: %s\n",
999 *count, d_self->device_name, strerror(errno));
1000 return RESULT_ERROR;
1006 g_assert_not_reached();
1009 /* Kernel workaround: If needed, poke the kernel so it doesn't fail.
1010 at the 2GB boundry. Parameters are G_GNUC_UNUSED in case NEED_RESETOFS
1012 static void check_resetofs(TapeDevice * self G_GNUC_UNUSED,
1013 int count G_GNUC_UNUSED) {
1014 #ifdef NEED_RESETOFS
1017 self->private->write_count += count;
1018 if (self->private->write_count < RESETOFS_THRESHOLD) {
1022 result = lseek(self->fd, 0, SEEK_SET);
1025 "Warning: lseek() failed during kernel 2GB workaround.\n");
1031 tape_device_robust_write (TapeDevice * self, void * buf, int count) {
1035 g_return_val_if_fail(self != NULL, RESULT_ERROR);
1036 d_self = (Device*)self;
1038 check_resetofs(self, count);
1041 result = write(self->fd, buf, count);
1043 if (result == count) {
1046 self->private->write_count ++;
1047 return RESULT_SUCCESS;
1048 } else if (result >= 0) {
1049 /* write() returned a short count. This should not happen. */
1051 "Mysterious short write on tape device: Tried %d, got %d.\n",
1053 return RESULT_ERROR;
1059 || errno == EWOULDBLOCK
1065 /* Interrupted system call */
1075 /* Probably EOT. Print a message if we got EIO. */
1078 g_fprintf(stderr, "Got EIO on %s, assuming end of tape.\n",
1079 d_self->device_name);
1082 return RESULT_NO_SPACE;
1086 "Kernel gave unexpected write() result of \"%s\" on device %s.\n",
1087 strerror(errno), d_self->device_name);
1088 return RESULT_ERROR;
1092 g_assert_not_reached();
1095 /* Reads some number of tape blocks into the bit-bucket. If the count
1096 is negative, then we read the rest of the entire file. Returns the
1097 number of blocks read, or -1 if an error occured. If we encounter
1098 EOF (as opposed to some other error) we return the number of blocks
1100 static int drain_tape_blocks(TapeDevice * self, int count) {
1105 buffer_size = self->read_block_size;
1107 buffer = malloc(sizeof(buffer_size));
1109 for (i = 0; i < count || count < 0;) {
1112 result = read(self->fd, buffer, buffer_size);
1116 } else if (result == 0) {
1120 /* First check for interrupted system call. */
1126 || errno == EWOULDBLOCK
1132 /* Interrupted system call */
1136 || errno == ENOSPC /* bad user-space buffer */
1139 || errno == EOVERFLOW /* bad kernel-space buffer */
1142 || errno == EINVAL /* ??? */
1145 /* The buffer may not be big enough. But the OS is not
1146 100% clear. We double the buffer and try again, but
1147 in no case allow a buffer bigger than 32 MB. */
1150 if (buffer_size > 32*1024*1024) {
1154 buffer = realloc(buffer, buffer_size);
1164 /* FIXME: Make sure that there are no cycles in reimplementation
1168 tape_device_fsf (TapeDevice * self, guint count) {
1169 g_return_val_if_fail (self != NULL, (gboolean )0);
1170 g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
1172 if (self->fsf & FEATURE_STATUS_ENABLED) {
1173 return tape_fsf(self->fd, count);
1176 for (i = 0; i < count; i ++) {
1177 if (drain_tape_blocks(self, -1) < 0)
1184 /* Seek back over count + 1 filemarks to the start of the given file. */
1186 tape_device_bsf (TapeDevice * self, guint count, guint file) {
1187 g_return_val_if_fail (self != NULL, (gboolean )0);
1188 g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
1190 if (self->bsf & FEATURE_STATUS_ENABLED) {
1191 /* The BSF operation is not very smart; it includes the
1192 filemark of the present file as part of the count, and seeks
1193 to the wrong (BOT) side of the filemark. We compensate for
1194 this by seeking one filemark too many, then FSFing back over
1197 If this procedure fails for some reason, we can still try
1199 if (tape_bsf(self->fd, count + 1) &&
1200 tape_device_fsf(self, 1))
1202 } /* Fall through to backup plan. */
1204 /* We rewind the tape, then seek forward the given number of
1206 if (!tape_rewind(self->fd))
1209 return tape_device_fsf(self, file);
1214 tape_device_fsr (TapeDevice * self, guint count) {
1215 g_return_val_if_fail (self != NULL, (gboolean )0);
1216 g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
1218 if (self->fsr & FEATURE_STATUS_ENABLED) {
1219 return tape_fsr(self->fd, count);
1221 int result = drain_tape_blocks(self, count);
1222 return result > 0 && (int)count == result;
1226 /* Seek back the given number of blocks to block number block within
1227 * the current file, numbered file. */
1230 tape_device_bsr (TapeDevice * self, guint count, guint file, guint block) {
1231 g_return_val_if_fail (self != NULL, (gboolean )0);
1232 g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
1234 g_return_val_if_fail (self != NULL, (gboolean )0);
1235 g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
1237 if (self->bsr & FEATURE_STATUS_ENABLED) {
1238 return tape_bsr(self->fd, count);
1240 /* We BSF, then FSR. */
1241 if (!tape_device_bsf(self, 0, file))
1244 return tape_device_fsr(self, block);
1246 g_assert_not_reached();
1249 /* Go to the right place to write more data, and update the file
1250 number if possible. */
1252 tape_device_eod (TapeDevice * self) {
1254 g_return_val_if_fail (self != NULL, (gboolean )0);
1255 g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
1256 d_self = (Device*)self;
1258 if (self->eom & FEATURE_STATUS_ENABLED) {
1260 result = tape_eod(self->fd);
1261 if (result == TAPE_OP_ERROR) {
1263 } else if (result == TAPE_POSITION_UNKNOWN) {
1266 /* We drop by 1 because Device will increment the first
1267 time the user does start_file. */
1268 d_self->file = result - 1;
1273 if (!tape_rewind(self->fd))
1277 /* We alternately read a block and FSF. If the read is
1278 successful, then we are not there yet and should FSF
1281 result = drain_tape_blocks(self, 1);
1283 /* More data, FSF. */
1284 tape_device_fsf(self, 1);
1286 } else if (result == 0) {
1288 d_self->file = count;
1298 tape_device_factory (char * device_type, char * device_name) {
1300 g_assert(0 == strcmp(device_type, "tape"));
1301 rval = DEVICE(g_object_new(TYPE_TAPE_DEVICE, NULL));
1302 if (!device_open_device(rval, device_name)) {
1303 g_object_unref(rval);