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 int 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);
231 /* Open the tape device, trying various combinations of O_RDWR and
232 O_NONBLOCK. Returns -1 and sets status_result for errors */
233 static int try_open_tape_device(TapeDevice * self, char * device_filename,
234 ReadLabelStatusFlags *status_result) {
237 ReadLabelStatusFlags new_status;
239 *status_result = READ_LABEL_STATUS_SUCCESS;
242 fd = robust_open(device_filename, O_RDWR | O_NONBLOCK, 0);
244 if (fd < 0 && (save_errno == EWOULDBLOCK || save_errno == EINVAL)) {
245 /* Maybe we don't support O_NONBLOCK for tape devices. */
246 fd = robust_open(device_filename, O_RDWR, 0);
250 fd = robust_open(device_filename, O_RDWR);
254 self->write_open_errno = 0;
256 if (errno == EACCES || errno == EPERM) {
257 /* Device is write-protected. */
258 self->write_open_errno = errno;
260 fd = robust_open(device_filename, O_RDONLY | O_NONBLOCK, 0);
262 if (fd < 0 && (save_errno == EWOULDBLOCK || save_errno == EINVAL)) {
263 fd = robust_open(device_filename, O_RDONLY, 0);
267 fd = robust_open(device_filename, O_RDONLY);
273 /* Clear O_NONBLOCK for operations from now on. */
275 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
277 /* function continues after #endif */
279 #endif /* O_NONBLOCK */
282 g_fprintf(stderr, _("Can't open tape device %s: %s\n"),
283 DEVICE(self)->device_name, strerror(errno));
284 *status_result = READ_LABEL_STATUS_DEVICE_ERROR;
288 /* Check that this is actually a tape device. */
289 new_status = tape_is_tape_device(fd);
290 if (new_status & (READ_LABEL_STATUS_DEVICE_ERROR | READ_LABEL_STATUS_VOLUME_MISSING)) {
291 g_fprintf(stderr, _("File %s is not a tape device\n"),
292 DEVICE(self)->device_name);
294 *status_result = new_status;
298 tcr = tape_is_ready(fd);
299 if (new_status == TAPE_CHECK_FAILURE) {
300 g_fprintf(stderr, _("Tape device %s is not ready or is empty\n"),
301 DEVICE(self)->device_name);
303 *status_result = READ_LABEL_STATUS_DEVICE_ERROR;
311 tape_device_open_device (Device * d_self, char * device_name) {
314 self = TAPE_DEVICE(d_self);
315 g_return_val_if_fail (self != NULL, FALSE);
316 g_return_val_if_fail (device_name != NULL, FALSE);
318 /* Get tape drive/OS info */
319 tape_device_discover_capabilities(self);
321 /* And verify the above. */
322 g_assert(feature_support_flags_is_valid(self->fsf));
323 g_assert(feature_support_flags_is_valid(self->bsf));
324 g_assert(feature_support_flags_is_valid(self->fsr));
325 g_assert(feature_support_flags_is_valid(self->bsr));
326 g_assert(feature_support_flags_is_valid(self->eom));
327 g_assert(feature_support_flags_is_valid(self->bsf_after_eom));
328 g_assert(self->final_filemarks == 1 ||
329 self->final_filemarks == 2);
332 if (parent_class->open_device) {
333 if (!(parent_class->open_device)(d_self, device_name)) {
334 robust_close(self->fd);
342 static ReadLabelStatusFlags tape_device_read_label(Device * dself) {
344 char * header_buffer;
349 self = TAPE_DEVICE(dself);
350 g_return_val_if_fail(self != NULL, FALSE);
352 amfree(dself->volume_label);
353 amfree(dself->volume_time);
355 if (self->fd == -1) {
356 ReadLabelStatusFlags status;
357 self->fd = try_open_tape_device(self, dself->device_name, &status);
363 if (!tape_rewind(self->fd)) {
364 g_fprintf(stderr, "Error rewinding device %s\n",
366 return (READ_LABEL_STATUS_DEVICE_ERROR |
367 READ_LABEL_STATUS_VOLUME_ERROR);
370 buffer_len = self->read_block_size;
371 header_buffer = malloc(buffer_len);
372 result = tape_device_robust_read(self, header_buffer, &buffer_len);
374 if (result != RESULT_SUCCESS) {
376 tape_rewind(self->fd);
378 g_fprintf(stderr, "Error reading Amanda header.\n");
379 if (result == RESULT_NO_DATA) {
380 return (READ_LABEL_STATUS_VOLUME_ERROR |
381 READ_LABEL_STATUS_VOLUME_UNLABELED);
383 return (READ_LABEL_STATUS_DEVICE_ERROR |
384 READ_LABEL_STATUS_VOLUME_ERROR |
385 READ_LABEL_STATUS_VOLUME_UNLABELED);
389 parse_file_header(header_buffer, &header, buffer_len);
390 amfree(header_buffer);
391 if (header.type != F_TAPESTART) {
392 return READ_LABEL_STATUS_VOLUME_UNLABELED;
395 dself->volume_label = g_strdup(header.name);
396 dself->volume_time = g_strdup(header.datestamp);
398 if (parent_class->read_label) {
399 return parent_class->read_label(dself);
401 return READ_LABEL_STATUS_SUCCESS;
406 tape_device_write_block(Device * pself, guint size,
407 gpointer data, gboolean short_block) {
409 char *replacement_buffer = NULL;
412 self = TAPE_DEVICE(pself);
413 g_return_val_if_fail (self != NULL, FALSE);
414 g_return_val_if_fail (self->fd >= 0, FALSE);
416 if (short_block && self->min_block_size > size) {
417 replacement_buffer = malloc(self->min_block_size);
418 memcpy(replacement_buffer, data, size);
419 bzero(replacement_buffer+size, self->min_block_size-size);
421 data = replacement_buffer;
422 size = self->min_block_size;
425 result = tape_device_robust_write(self, data, size);
426 if (result == RESULT_SUCCESS) {
427 if (parent_class->write_block) {
428 (parent_class->write_block)(pself, size, data, short_block);
430 amfree(replacement_buffer);
433 amfree(replacement_buffer);
437 g_assert_not_reached();
440 static int tape_device_read_block (Device * pself, gpointer buf,
446 self = TAPE_DEVICE(pself);
447 g_return_val_if_fail (self != NULL, -1);
449 if (buf == NULL || *size_req < (int)self->read_block_size) {
450 /* Just a size query. */
451 *size_req = self->read_block_size;
456 result = tape_device_robust_read(self, buf, &size);
461 case RESULT_SMALL_BUFFER: {
463 /* If this happens, it means that we have:
464 * (next block size) > (buffer size) >= (read_block_size)
465 * The solution is to ask for an even bigger buffer. We also play
466 * some games to refrain from reading above the SCSI limit or from
467 * integer overflow. */
468 new_size = MIN(INT_MAX/2 - 1, *size_req) * 2;
469 if (new_size > LARGEST_BLOCK_ESTIMATE &&
470 *size_req < LARGEST_BLOCK_ESTIMATE) {
471 new_size = LARGEST_BLOCK_ESTIMATE;
473 if (new_size <= *size_req) {
476 *size_req = new_size;
481 pself->is_eof = TRUE;
482 pself->in_file = FALSE;
489 g_assert_not_reached();
492 /* Just a helper function for tape_device_start(). */
493 static gboolean write_tapestart_header(TapeDevice * self, char * label,
499 gboolean header_fits;
500 Device * d_self = (Device*)self;
501 tape_rewind(self->fd);
503 header = make_tapestart_header(d_self, label, timestamp);
504 g_assert(header != NULL);
505 header_buf = device_build_amanda_header(d_self, header, &header_size,
508 g_assert(header_buf != NULL);
512 g_fprintf(stderr, "Tapestart header won't fit in a single block!\n");
516 g_assert(header_size >= (int)self->min_block_size);
517 result = tape_device_robust_write(self, header_buf, header_size);
519 return (result == RESULT_SUCCESS);
523 tape_device_start (Device * d_self, DeviceAccessMode mode, char * label,
527 self = TAPE_DEVICE(d_self);
528 g_return_val_if_fail(self != NULL, FALSE);
530 if (self->fd == -1) {
531 ReadLabelStatusFlags status;
532 self->fd = try_open_tape_device(self, d_self->device_name, &status);
534 return FALSE; /* can't do anything with status here */
537 if (mode != ACCESS_WRITE && d_self->volume_label == NULL) {
538 /* we need a labeled volume for APPEND and READ */
539 if (tape_device_read_label(d_self) != READ_LABEL_STATUS_SUCCESS)
543 d_self->access_mode = mode;
544 d_self->in_file = FALSE;
546 if (IS_WRITABLE_ACCESS_MODE(mode)) {
547 if (self->write_open_errno != 0) {
548 /* We tried and failed to open the device in write mode. */
549 g_fprintf(stderr, "Can't open tape device %s for writing: %s\n",
550 d_self->device_name, strerror(self->write_open_errno));
552 } else if (!tape_rewind(self->fd)) {
553 g_fprintf(stderr, "Couldn't rewind device: %s\n",
558 /* Position the tape */
561 if (!tape_device_eod(self))
563 self->first_file = TRUE;
567 if (!tape_rewind(self->fd)) {
568 g_fprintf(stderr, "Error rewinding device %s\n",
569 d_self->device_name);
576 if (!write_tapestart_header(self, label, timestamp)) {
579 self->first_file = TRUE;
583 g_assert_not_reached();
586 if (parent_class->start) {
587 return parent_class->start(d_self, mode, label, timestamp);
593 static gboolean tape_device_start_file(Device * d_self,
594 const dumpfile_t * info) {
597 char * amanda_header;
599 gboolean header_fits;
601 self = TAPE_DEVICE(d_self);
602 g_return_val_if_fail(self != NULL, FALSE);
603 g_return_val_if_fail (self->fd >= 0, FALSE);
605 if (!(d_self->access_mode == ACCESS_APPEND && self->first_file)) {
606 if (!tape_weof(self->fd, 1)) {
607 g_fprintf(stderr, "Error writing filemark: %s\n", strerror(errno));
612 self->first_file = FALSE;
614 /* Make the Amanda header suitable for writing to the device. */
615 /* Then write the damn thing. */
616 amanda_header = device_build_amanda_header(d_self, info,
617 &header_size, &header_fits);
618 g_return_val_if_fail(amanda_header != NULL, FALSE);
619 g_return_val_if_fail(header_fits, FALSE);
620 result = tape_device_robust_write(self, amanda_header, header_size);
621 amfree(amanda_header);
622 if (result == RESULT_SUCCESS) {
624 if (parent_class->start_file) {
625 parent_class->start_file(d_self, info);
634 tape_device_seek_file (Device * d_self, guint file) {
637 char * header_buffer;
642 self = TAPE_DEVICE(d_self);
643 g_return_val_if_fail(d_self != NULL, NULL);
645 d_self->in_file = FALSE;
647 difference = file - d_self->file;
649 /* Check if we already read a filemark. */
650 if (d_self->is_eof) {
654 if (difference > 0) {
655 /* Seeking forwards */
656 if (!tape_device_fsf(self, difference)) {
657 tape_rewind(self->fd);
660 } else if (difference < 0) {
661 /* Seeking backwards */
662 if (!tape_device_bsf(self, -difference, d_self->file)) {
663 tape_rewind(self->fd);
668 buffer_len = self->read_block_size;
669 header_buffer = malloc(buffer_len);
670 d_self->is_eof = FALSE;
671 result = tape_device_robust_read(self, header_buffer, &buffer_len);
673 if (result != RESULT_SUCCESS) {
675 tape_rewind(self->fd);
676 if (result == RESULT_NO_DATA) {
677 /* If we read 0 bytes, that means we encountered a double
678 * filemark, which indicates end of tape. This should
679 * work even with QIC tapes on operating systems with
681 return make_tapeend_header();
684 g_fprintf(stderr, "Error reading Amanda header.\n");
688 rval = malloc(sizeof(*rval));
689 parse_file_header(header_buffer, rval, buffer_len);
690 amfree(header_buffer);
691 switch (rval->type) {
693 case F_CONT_DUMPFILE:
694 case F_SPLIT_DUMPFILE:
695 d_self->in_file = TRUE;
699 tape_rewind(self->fd);
706 tape_device_seek_block (Device * d_self, guint64 block) {
710 self = TAPE_DEVICE(d_self);
711 g_return_val_if_fail(d_self != NULL, FALSE);
713 difference = block - d_self->block;
715 if (difference > 0) {
716 if (!tape_device_fsr(self, difference))
718 } else if (difference < 0) {
719 if (!tape_device_bsr(self, difference, d_self->file, d_self->block))
723 if (parent_class->seek_block) {
724 return (parent_class->seek_block)(d_self, block);
730 /* Just checks that the flag is valid before setting it. */
731 static gboolean get_feature_flag(GValue * val, FeatureSupportFlags f) {
732 if (feature_support_flags_is_valid(f)) {
733 g_value_set_flags(val, f);
741 tape_device_property_get (Device * d_self, DevicePropertyId id, GValue * val) {
743 const DevicePropertyBase * base;
745 self = TAPE_DEVICE(d_self);
746 g_return_val_if_fail(self != NULL, FALSE);
748 base = device_property_get_by_id(id);
749 g_return_val_if_fail(self != NULL, FALSE);
751 g_value_unset_init(val, base->type);
753 if (id == PROPERTY_COMPRESSION) {
754 g_value_set_boolean(val, self->compression);
756 } else if (id == PROPERTY_MIN_BLOCK_SIZE) {
757 g_value_set_uint(val, self->min_block_size);
759 } else if (id == PROPERTY_MAX_BLOCK_SIZE) {
760 g_value_set_uint(val, self->max_block_size);
762 } else if (id == PROPERTY_BLOCK_SIZE) {
763 if (self->fixed_block_size == 0) {
764 g_value_set_int(val, -1);
766 g_value_set_int(val, self->fixed_block_size);
769 } else if (id == PROPERTY_FSF) {
770 return get_feature_flag(val, self->fsf);
771 } else if (id == PROPERTY_BSF) {
772 return get_feature_flag(val, self->bsf);
773 } else if (id == PROPERTY_FSR) {
774 return get_feature_flag(val, self->fsr);
775 } else if (id == PROPERTY_BSR) {
776 return get_feature_flag(val, self->bsr);
777 } else if (id == PROPERTY_EOM) {
778 return get_feature_flag(val, self->eom);
779 } else if (id == PROPERTY_BSF_AFTER_EOM) {
780 return get_feature_flag(val, self->bsf_after_eom);
781 } else if (id == PROPERTY_FINAL_FILEMARKS) {
782 g_value_set_uint(val, self->final_filemarks);
786 if (parent_class->property_get) {
787 return (parent_class->property_get)(d_self, id, val);
793 g_assert_not_reached();
796 /* We don't allow overriding of flags with _GOOD surety. That way, if
797 e.g., a feature has no matching IOCTL on a given platform, we don't
798 ever try to set it. */
799 static gboolean flags_settable(FeatureSupportFlags request,
800 FeatureSupportFlags existing) {
801 if (!feature_support_flags_is_valid(request))
803 else if (!feature_support_flags_is_valid(existing))
805 else if (request == existing)
807 else if (existing & FEATURE_SURETY_GOOD)
813 /* If the access listed is NULL, and the provided flags can override the
814 existing ones, then do it and return TRUE. */
815 static gboolean try_set_feature(DeviceAccessMode mode,
816 FeatureSupportFlags request,
817 FeatureSupportFlags * existing) {
818 if (mode != ACCESS_NULL) {
820 } else if (flags_settable(request, *existing)) {
829 tape_device_property_set (Device * d_self, DevicePropertyId id, GValue * val) {
831 FeatureSupportFlags feature_request_flags = 0;
832 const DevicePropertyBase * base;
834 self = TAPE_DEVICE(d_self);
835 g_return_val_if_fail(self != NULL, FALSE);
837 base = device_property_get_by_id(id);
838 g_return_val_if_fail(self != NULL, FALSE);
840 g_return_val_if_fail(G_VALUE_HOLDS(val, base->type), FALSE);
842 if (base->type == FEATURE_SUPPORT_FLAGS_TYPE) {
843 feature_request_flags = g_value_get_flags(val);
844 g_return_val_if_fail(
845 feature_support_flags_is_valid(feature_request_flags), FALSE);
848 if (id == PROPERTY_COMPRESSION) {
849 /* We allow this property to be set at any time. This is mostly
850 * because setting compression is a hit-and-miss proposition
851 * at any time; some drives accept the mode setting but don't
852 * actually support compression, while others do support
853 * compression but do it via density settings or some other
854 * way. Set this property whenever you want, but all we'll do
855 * is report whether or not the ioctl succeeded. */
856 gboolean request = g_value_get_boolean(val);
857 if (tape_setcompression(self->fd, request)) {
858 self->compression = request;
859 device_clear_volume_details(d_self);
864 } else if (id == PROPERTY_MIN_BLOCK_SIZE) {
865 if (d_self->access_mode != ACCESS_NULL)
867 self->min_block_size = g_value_get_uint(val);
868 device_clear_volume_details(d_self);
870 } else if (id == PROPERTY_MAX_BLOCK_SIZE) {
871 if (d_self->access_mode != ACCESS_NULL)
873 self->max_block_size = g_value_get_uint(val);
874 device_clear_volume_details(d_self);
876 } else if (id == PROPERTY_BLOCK_SIZE) {
877 if (d_self->access_mode != ACCESS_NULL)
880 self->fixed_block_size = g_value_get_int(val);
881 device_clear_volume_details(d_self);
883 } else if (id == PROPERTY_READ_BUFFER_SIZE) {
884 if (d_self->access_mode != ACCESS_NULL)
886 self->read_block_size = g_value_get_uint(val);
887 device_clear_volume_details(d_self);
889 } else if (id == PROPERTY_FSF) {
890 return try_set_feature(d_self->access_mode,
891 feature_request_flags,
893 } else if (id == PROPERTY_BSF) {
894 return try_set_feature(d_self->access_mode,
895 feature_request_flags,
897 } else if (id == PROPERTY_FSR) {
898 return try_set_feature(d_self->access_mode,
899 feature_request_flags,
901 } else if (id == PROPERTY_BSR) {
902 return try_set_feature(d_self->access_mode,
903 feature_request_flags,
905 } else if (id == PROPERTY_EOM) {
906 /* Setting this to disabled also clears BSF after EOM. */
907 if (try_set_feature(d_self->access_mode,
908 feature_request_flags,
910 feature_request_flags &= ~FEATURE_SUPPORT_FLAGS_STATUS_MASK;
911 feature_request_flags |= FEATURE_STATUS_DISABLED;
912 self->bsf_after_eom = feature_request_flags;
917 } else if (id == PROPERTY_BSF_AFTER_EOM) {
918 /* You can only set this if EOM is enabled. */
919 if (self->bsf | FEATURE_STATUS_DISABLED)
922 return try_set_feature(d_self->access_mode,
923 feature_request_flags,
924 &(self->bsf_after_eom));
925 } else if (id == PROPERTY_FINAL_FILEMARKS) {
926 guint request = g_value_get_uint(val);
927 if (request == 1 || request == 2) {
928 self->final_filemarks = request;
935 if (parent_class->property_set) {
936 return (parent_class->property_set)(d_self, id, val);
942 g_assert_not_reached();
946 tape_device_finish (Device * d_self) {
949 self = TAPE_DEVICE(d_self);
950 g_return_val_if_fail(self != NULL, FALSE);
952 /* Polish off this file, if relevant. */
953 if (d_self->in_file && IS_WRITABLE_ACCESS_MODE(d_self->access_mode)) {
954 if (!device_finish_file(d_self))
958 /* Write an extra filemark, if needed. The OS will give us one for
960 if (self->final_filemarks > 1 &&
961 IS_WRITABLE_ACCESS_MODE(d_self->access_mode)) {
962 if (!tape_weof(self->fd, 1)) {
963 g_fprintf(stderr, "Error writing final filemark: %s\n",
970 if (!tape_rewind(self->fd)) {
971 g_fprintf(stderr, "Error rewinding tape: %s\n", strerror(errno));
975 d_self->access_mode = ACCESS_NULL;
977 if (parent_class->finish) {
978 return (parent_class->finish)(d_self);
985 /* Works just like read(), except for the following:
986 * 1) Retries on EINTR & friends.
987 * 2) Stores count in parameter, not return value.
988 * 3) Provides explicit return result. */
990 tape_device_robust_read (TapeDevice * self, void * buf, int * count) {
994 d_self = (Device*)self;
995 g_return_val_if_fail(self != NULL, RESULT_ERROR);
996 g_return_val_if_fail(*count >= 0, RESULT_ERROR);
997 /* Callers should ensure this. */
998 g_assert((guint)(*count) <= self->read_block_size);
1001 result = read(self->fd, buf, *count);
1003 /* Success. By definition, we read a full block. */
1005 return RESULT_SUCCESS;
1006 } else if (result == 0) {
1007 return RESULT_NO_DATA;
1014 || errno == EWOULDBLOCK
1020 /* Interrupted system call */
1022 } else if ((self->fixed_block_size == 0) &&
1025 || errno == ENOMEM /* bad user-space buffer */
1028 || errno == EOVERFLOW /* bad kernel-space buffer */
1031 || errno == EINVAL /* ??? */
1034 /* Buffer too small. */
1035 return RESULT_SMALL_BUFFER;
1037 g_fprintf(stderr, "Error reading %d bytes from %s: %s\n",
1038 *count, d_self->device_name, strerror(errno));
1039 return RESULT_ERROR;
1045 g_assert_not_reached();
1048 /* Kernel workaround: If needed, poke the kernel so it doesn't fail.
1049 at the 2GB boundry. Parameters are G_GNUC_UNUSED in case NEED_RESETOFS
1051 static void check_resetofs(TapeDevice * self G_GNUC_UNUSED,
1052 int count G_GNUC_UNUSED) {
1053 #ifdef NEED_RESETOFS
1056 self->private->write_count += count;
1057 if (self->private->write_count < RESETOFS_THRESHOLD) {
1061 result = lseek(self->fd, 0, SEEK_SET);
1064 "Warning: lseek() failed during kernel 2GB workaround.\n");
1070 tape_device_robust_write (TapeDevice * self, void * buf, int count) {
1074 g_return_val_if_fail(self != NULL, RESULT_ERROR);
1075 d_self = (Device*)self;
1077 check_resetofs(self, count);
1080 result = write(self->fd, buf, count);
1082 if (result == count) {
1085 self->private->write_count ++;
1086 return RESULT_SUCCESS;
1087 } else if (result >= 0) {
1088 /* write() returned a short count. This should not happen. */
1090 "Mysterious short write on tape device: Tried %d, got %d.\n",
1092 return RESULT_ERROR;
1098 || errno == EWOULDBLOCK
1104 /* Interrupted system call */
1114 /* Probably EOT. Print a message if we got EIO. */
1117 g_fprintf(stderr, "Got EIO on %s, assuming end of tape.\n",
1118 d_self->device_name);
1121 return RESULT_NO_SPACE;
1125 "Kernel gave unexpected write() result of \"%s\" on device %s.\n",
1126 strerror(errno), d_self->device_name);
1127 return RESULT_ERROR;
1131 g_assert_not_reached();
1134 /* Reads some number of tape blocks into the bit-bucket. If the count
1135 is negative, then we read the rest of the entire file. Returns the
1136 number of blocks read, or -1 if an error occured. If we encounter
1137 EOF (as opposed to some other error) we return the number of blocks
1139 static int drain_tape_blocks(TapeDevice * self, int count) {
1144 buffer_size = self->read_block_size;
1146 buffer = malloc(sizeof(buffer_size));
1148 for (i = 0; i < count || count < 0;) {
1151 result = read(self->fd, buffer, buffer_size);
1155 } else if (result == 0) {
1159 /* First check for interrupted system call. */
1165 || errno == EWOULDBLOCK
1171 /* Interrupted system call */
1175 || errno == ENOSPC /* bad user-space buffer */
1178 || errno == EOVERFLOW /* bad kernel-space buffer */
1181 || errno == EINVAL /* ??? */
1184 /* The buffer may not be big enough. But the OS is not
1185 100% clear. We double the buffer and try again, but
1186 in no case allow a buffer bigger than 32 MB. */
1189 if (buffer_size > 32*1024*1024) {
1193 buffer = realloc(buffer, buffer_size);
1203 /* FIXME: Make sure that there are no cycles in reimplementation
1207 tape_device_fsf (TapeDevice * self, guint count) {
1208 g_return_val_if_fail (self != NULL, (gboolean )0);
1209 g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
1211 if (self->fsf & FEATURE_STATUS_ENABLED) {
1212 return tape_fsf(self->fd, count);
1215 for (i = 0; i < count; i ++) {
1216 if (drain_tape_blocks(self, -1) < 0)
1223 /* Seek back over count + 1 filemarks to the start of the given file. */
1225 tape_device_bsf (TapeDevice * self, guint count, guint file) {
1226 g_return_val_if_fail (self != NULL, (gboolean )0);
1227 g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
1229 if (self->bsf & FEATURE_STATUS_ENABLED) {
1230 /* The BSF operation is not very smart; it includes the
1231 filemark of the present file as part of the count, and seeks
1232 to the wrong (BOT) side of the filemark. We compensate for
1233 this by seeking one filemark too many, then FSFing back over
1236 If this procedure fails for some reason, we can still try
1238 if (tape_bsf(self->fd, count + 1) &&
1239 tape_device_fsf(self, 1))
1241 } /* Fall through to backup plan. */
1243 /* We rewind the tape, then seek forward the given number of
1245 if (!tape_rewind(self->fd))
1248 return tape_device_fsf(self, file);
1253 tape_device_fsr (TapeDevice * self, guint count) {
1254 g_return_val_if_fail (self != NULL, (gboolean )0);
1255 g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
1257 if (self->fsr & FEATURE_STATUS_ENABLED) {
1258 return tape_fsr(self->fd, count);
1260 int result = drain_tape_blocks(self, count);
1261 return result > 0 && (int)count == result;
1265 /* Seek back the given number of blocks to block number block within
1266 * the current file, numbered file. */
1269 tape_device_bsr (TapeDevice * self, guint count, guint file, guint block) {
1270 g_return_val_if_fail (self != NULL, (gboolean )0);
1271 g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
1273 g_return_val_if_fail (self != NULL, (gboolean )0);
1274 g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
1276 if (self->bsr & FEATURE_STATUS_ENABLED) {
1277 return tape_bsr(self->fd, count);
1279 /* We BSF, then FSR. */
1280 if (!tape_device_bsf(self, 0, file))
1283 return tape_device_fsr(self, block);
1285 g_assert_not_reached();
1288 /* Go to the right place to write more data, and update the file
1289 number if possible. */
1291 tape_device_eod (TapeDevice * self) {
1293 g_return_val_if_fail (self != NULL, (gboolean )0);
1294 g_return_val_if_fail (IS_TAPE_DEVICE (self), (gboolean )0);
1295 d_self = (Device*)self;
1297 if (self->eom & FEATURE_STATUS_ENABLED) {
1299 result = tape_eod(self->fd);
1300 if (result == TAPE_OP_ERROR) {
1302 } else if (result == TAPE_POSITION_UNKNOWN) {
1305 /* We drop by 1 because Device will increment the first
1306 time the user does start_file. */
1307 d_self->file = result - 1;
1312 if (!tape_rewind(self->fd))
1316 /* We alternately read a block and FSF. If the read is
1317 successful, then we are not there yet and should FSF
1320 result = drain_tape_blocks(self, 1);
1322 /* More data, FSF. */
1323 tape_device_fsf(self, 1);
1325 } else if (result == 0) {
1327 d_self->file = count;
1337 tape_device_factory (char * device_type, char * device_name) {
1339 g_assert(0 == strcmp(device_type, "tape"));
1340 rval = DEVICE(g_object_new(TYPE_TAPE_DEVICE, NULL));
1341 if (!device_open_device(rval, device_name)) {
1342 g_object_unref(rval);