2 * Copyright (c) 2005-2008 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., 465 S Mathlida Ave, Suite 300
18 * Sunnyvale, CA 94086, 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. */
37 char * device_filename;
38 gsize read_buffer_size;
41 /* Possible (abstracted) results from a system I/O operation. */
44 RESULT_ERROR, /* Undefined error. */
45 RESULT_SMALL_BUFFER, /* Tried to read with a buffer that is too
47 RESULT_NO_DATA, /* End of File, while reading */
48 RESULT_NO_SPACE, /* Out of space. Sometimes we don't know if
49 it was this or I/O error, but this is the
50 preferred explanation. */
55 * Our device-specific properties. These are not static because they are
56 * accessed from the OS-specific tape-*.c files.
58 DevicePropertyBase device_property_broken_gmt_online;
59 DevicePropertyBase device_property_fsf;
60 DevicePropertyBase device_property_fsf_after_filemark;
61 DevicePropertyBase device_property_bsf;
62 DevicePropertyBase device_property_fsr;
63 DevicePropertyBase device_property_bsr;
64 DevicePropertyBase device_property_eom;
65 DevicePropertyBase device_property_bsf_after_eom;
66 DevicePropertyBase device_property_nonblocking_open;
67 DevicePropertyBase device_property_final_filemarks;
69 void tape_device_register(void);
71 #define tape_device_read_size(self) \
72 (((TapeDevice *)(self))->private->read_buffer_size? \
73 ((TapeDevice *)(self))->private->read_buffer_size : ((Device *)(self))->block_size)
75 /* here are local prototypes */
76 static void tape_device_init (TapeDevice * o);
77 static void tape_device_class_init (TapeDeviceClass * c);
78 static void tape_device_base_init (TapeDeviceClass * c);
79 static gboolean tape_device_set_feature_property_fn(Device *p_self, DevicePropertyBase *base,
80 GValue *val, PropertySurety surety, PropertySource source);
81 static gboolean tape_device_set_final_filemarks_fn(Device *p_self, DevicePropertyBase *base,
82 GValue *val, PropertySurety surety, PropertySource source);
83 static gboolean tape_device_set_compression_fn(Device *p_self, DevicePropertyBase *base,
84 GValue *val, PropertySurety surety, PropertySource source);
85 static gboolean tape_device_set_read_buffer_size_fn(Device *p_self, DevicePropertyBase *base,
86 GValue *val, PropertySurety surety, PropertySource source);
87 static void tape_device_open_device (Device * self, char * device_name, char * device_type, char * device_node);
88 static Device * tape_device_factory (char * device_name, char * device_type, char * device_node);
89 static DeviceStatusFlags tape_device_read_label(Device * self);
90 static gboolean tape_device_write_block(Device * self, guint size, gpointer data);
91 static int tape_device_read_block(Device * self, gpointer buf,
93 static gboolean tape_device_start (Device * self, DeviceAccessMode mode,
94 char * label, char * timestamp);
95 static gboolean tape_device_start_file (Device * self, dumpfile_t * ji);
96 static gboolean tape_device_finish_file (Device * self);
97 static dumpfile_t * tape_device_seek_file (Device * self, guint file);
98 static gboolean tape_device_seek_block (Device * self, guint64 block);
99 static gboolean tape_device_finish (Device * self);
100 static IoResult tape_device_robust_read (TapeDevice * self, void * buf,
102 static IoResult tape_device_robust_write (TapeDevice * self, void * buf, int count);
103 static gboolean tape_device_fsf (TapeDevice * self, guint count);
104 static gboolean tape_device_bsf (TapeDevice * self, guint count, guint file);
105 static gboolean tape_device_fsr (TapeDevice * self, guint count);
106 static gboolean tape_device_bsr (TapeDevice * self, guint count, guint file, guint block);
107 static gboolean tape_device_eod (TapeDevice * self);
109 /* pointer to the class of our parent */
110 static DeviceClass *parent_class = NULL;
112 GType tape_device_get_type (void)
114 static GType type = 0;
116 if G_UNLIKELY(type == 0) {
117 static const GTypeInfo info = {
118 sizeof (TapeDeviceClass),
119 (GBaseInitFunc) tape_device_base_init,
120 (GBaseFinalizeFunc) NULL,
121 (GClassInitFunc) tape_device_class_init,
122 (GClassFinalizeFunc) NULL,
123 NULL /* class_data */,
126 (GInstanceInitFunc) tape_device_init,
130 type = g_type_register_static (TYPE_DEVICE, "TapeDevice",
131 &info, (GTypeFlags)0);
138 tape_device_init (TapeDevice * self) {
142 d_self = DEVICE(self);
143 bzero(&response, sizeof(response));
145 self->private = g_new0(TapeDevicePrivate, 1);
147 /* Clear all fields. */
148 d_self->block_size = 32768;
149 d_self->min_block_size = 32768;
150 d_self->max_block_size = LARGEST_BLOCK_ESTIMATE;
151 self->broken_gmt_online = FALSE;
155 /* set all of the feature properties to an unsure default of FALSE */
156 self->broken_gmt_online = FALSE;
162 self->bsf_after_eom = FALSE;
164 g_value_init(&response, G_TYPE_BOOLEAN);
165 g_value_set_boolean(&response, FALSE);
166 device_set_simple_property(d_self, PROPERTY_BROKEN_GMT_ONLINE,
167 &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
168 device_set_simple_property(d_self, PROPERTY_FSF,
169 &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
170 device_set_simple_property(d_self, PROPERTY_FSF_AFTER_FILEMARK,
171 &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
172 device_set_simple_property(d_self, PROPERTY_BSF,
173 &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
174 device_set_simple_property(d_self, PROPERTY_FSR,
175 &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
176 device_set_simple_property(d_self, PROPERTY_BSR,
177 &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
178 device_set_simple_property(d_self, PROPERTY_EOM,
179 &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
180 device_set_simple_property(d_self, PROPERTY_BSF_AFTER_EOM,
181 &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
183 #ifdef DEFAULT_TAPE_NON_BLOCKING_OPEN
184 self->nonblocking_open = TRUE;
186 self->nonblocking_open = FALSE;
188 g_value_set_boolean(&response, self->nonblocking_open);
189 device_set_simple_property(d_self, PROPERTY_NONBLOCKING_OPEN,
190 &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
191 g_value_unset(&response);
193 self->final_filemarks = 2;
194 g_value_init(&response, G_TYPE_UINT);
195 g_value_set_uint(&response, self->final_filemarks);
196 device_set_simple_property(d_self, PROPERTY_FINAL_FILEMARKS,
197 &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
198 g_value_unset(&response);
200 self->private->read_buffer_size = 0;
201 g_value_init(&response, G_TYPE_UINT);
202 g_value_set_uint(&response, self->private->read_buffer_size);
203 device_set_simple_property(d_self, PROPERTY_READ_BUFFER_SIZE,
204 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DEFAULT);
205 g_value_unset(&response);
207 self->private->write_count = 0;
208 self->private->device_filename = NULL;
210 /* Static properites */
211 g_value_init(&response, CONCURRENCY_PARADIGM_TYPE);
212 g_value_set_enum(&response, CONCURRENCY_PARADIGM_EXCLUSIVE);
213 device_set_simple_property(d_self, PROPERTY_CONCURRENCY,
214 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
215 g_value_unset(&response);
217 g_value_init(&response, STREAMING_REQUIREMENT_TYPE);
218 g_value_set_enum(&response, STREAMING_REQUIREMENT_DESIRED);
219 device_set_simple_property(d_self, PROPERTY_STREAMING,
220 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
221 g_value_unset(&response);
223 g_value_init(&response, G_TYPE_BOOLEAN);
224 g_value_set_boolean(&response, FALSE);
225 device_set_simple_property(d_self, PROPERTY_APPENDABLE,
226 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
227 g_value_unset(&response);
229 g_value_init(&response, G_TYPE_BOOLEAN);
230 g_value_set_boolean(&response, FALSE);
231 device_set_simple_property(d_self, PROPERTY_PARTIAL_DELETION,
232 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
233 g_value_unset(&response);
235 g_value_init(&response, MEDIA_ACCESS_MODE_TYPE);
236 g_value_set_enum(&response, MEDIA_ACCESS_MODE_READ_WRITE);
237 device_set_simple_property(d_self, PROPERTY_MEDIUM_ACCESS_TYPE,
238 &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
239 g_value_unset(&response);
242 static void tape_device_finalize(GObject * obj_self) {
243 TapeDevice * self = TAPE_DEVICE(obj_self);
245 if(G_OBJECT_CLASS(parent_class)->finalize) \
246 (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
248 robust_close(self->fd);
250 amfree(self->private->device_filename);
251 amfree(self->private);
255 tape_device_class_init (TapeDeviceClass * c)
257 DeviceClass *device_class = (DeviceClass *)c;
258 GObjectClass *g_object_class = (GObjectClass *)c;
260 parent_class = g_type_class_ref (TYPE_DEVICE);
262 device_class->open_device = tape_device_open_device;
263 device_class->read_label = tape_device_read_label;
264 device_class->write_block = tape_device_write_block;
265 device_class->read_block = tape_device_read_block;
266 device_class->start = tape_device_start;
267 device_class->start_file = tape_device_start_file;
268 device_class->finish_file = tape_device_finish_file;
269 device_class->seek_file = tape_device_seek_file;
270 device_class->seek_block = tape_device_seek_block;
271 device_class->finish = tape_device_finish;
273 g_object_class->finalize = tape_device_finalize;
277 tape_device_base_init (TapeDeviceClass * c)
279 DeviceClass *device_class = (DeviceClass *)c;
281 device_class_register_property(device_class, PROPERTY_BROKEN_GMT_ONLINE,
282 PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
283 device_simple_property_get_fn,
284 tape_device_set_feature_property_fn);
286 device_class_register_property(device_class, PROPERTY_FSF,
287 PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
288 device_simple_property_get_fn,
289 tape_device_set_feature_property_fn);
291 device_class_register_property(device_class, PROPERTY_FSF_AFTER_FILEMARK,
292 PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
293 device_simple_property_get_fn,
294 tape_device_set_feature_property_fn);
296 device_class_register_property(device_class, PROPERTY_BSF,
297 PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
298 device_simple_property_get_fn,
299 tape_device_set_feature_property_fn);
301 device_class_register_property(device_class, PROPERTY_FSR,
302 PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
303 device_simple_property_get_fn,
304 tape_device_set_feature_property_fn);
306 device_class_register_property(device_class, PROPERTY_BSR,
307 PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
308 device_simple_property_get_fn,
309 tape_device_set_feature_property_fn);
311 device_class_register_property(device_class, PROPERTY_EOM,
312 PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
313 device_simple_property_get_fn,
314 tape_device_set_feature_property_fn);
316 device_class_register_property(device_class, PROPERTY_BSF_AFTER_EOM,
317 PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
318 device_simple_property_get_fn,
319 tape_device_set_feature_property_fn);
321 device_class_register_property(device_class, PROPERTY_NONBLOCKING_OPEN,
322 PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
323 device_simple_property_get_fn,
324 tape_device_set_feature_property_fn);
326 device_class_register_property(device_class, PROPERTY_FINAL_FILEMARKS,
327 PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
328 device_simple_property_get_fn,
329 tape_device_set_final_filemarks_fn);
331 /* We don't (yet?) support reading the device's compression state, so not
333 device_class_register_property(device_class, PROPERTY_COMPRESSION,
334 PROPERTY_ACCESS_SET_MASK,
336 tape_device_set_compression_fn);
338 device_class_register_property(device_class, PROPERTY_READ_BUFFER_SIZE,
339 PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
340 device_simple_property_get_fn,
341 tape_device_set_read_buffer_size_fn);
345 tape_device_set_feature_property_fn(Device *p_self, DevicePropertyBase *base,
346 GValue *val, PropertySurety surety, PropertySource source)
348 TapeDevice *self = TAPE_DEVICE(p_self);
350 gboolean old_bool, new_bool;
351 PropertySurety old_surety;
352 PropertySource old_source;
354 new_bool = g_value_get_boolean(val);
356 /* get the old source and surety and see if we're willing to make this change */
357 bzero(&old_val, sizeof(old_val));
358 if (device_get_simple_property(p_self, base->ID, &old_val, &old_surety, &old_source)) {
359 old_bool = g_value_get_boolean(&old_val);
361 if (old_surety == PROPERTY_SURETY_GOOD && old_source == PROPERTY_SOURCE_DETECTED) {
362 if (new_bool != old_bool) {
363 device_set_error(p_self, vstrallocf(_(
364 "Value for property '%s' was autodetected and cannot be changed"),
366 DEVICE_STATUS_DEVICE_ERROR);
369 /* pretend we set it, but don't change surety/source */
375 /* (note: PROPERTY_* are not constants, so we can't use switch) */
376 if (base->ID == PROPERTY_BROKEN_GMT_ONLINE)
377 self->broken_gmt_online = new_bool;
378 else if (base->ID == PROPERTY_FSF)
379 self->fsf = new_bool;
380 else if (base->ID == PROPERTY_FSF_AFTER_FILEMARK)
381 self->fsf_after_filemark = new_bool;
382 else if (base->ID == PROPERTY_BSF)
383 self->bsf = new_bool;
384 else if (base->ID == PROPERTY_FSR)
385 self->fsr = new_bool;
386 else if (base->ID == PROPERTY_BSR)
387 self->bsr = new_bool;
388 else if (base->ID == PROPERTY_EOM)
389 self->eom = new_bool;
390 else if (base->ID == PROPERTY_BSF_AFTER_EOM)
391 self->bsf_after_eom = new_bool;
392 else if (base->ID == PROPERTY_NONBLOCKING_OPEN)
393 self->nonblocking_open = new_bool;
395 return FALSE; /* shouldn't happen */
397 return device_simple_property_set_fn(p_self, base, val, surety, source);
401 tape_device_set_final_filemarks_fn(Device *p_self, DevicePropertyBase *base,
402 GValue *val, PropertySurety surety, PropertySource source)
404 TapeDevice *self = TAPE_DEVICE(p_self);
406 gboolean old_int, new_int;
407 PropertySurety old_surety;
408 PropertySource old_source;
410 new_int = g_value_get_uint(val);
412 /* get the old source and surety and see if we're willing to make this change */
413 bzero(&old_val, sizeof(old_val));
414 if (device_get_simple_property(p_self, base->ID, &old_val, &old_surety, &old_source)) {
415 old_int = g_value_get_uint(&old_val);
417 if (old_surety == PROPERTY_SURETY_GOOD && old_source == PROPERTY_SOURCE_DETECTED) {
418 if (new_int != old_int) {
419 device_set_error(p_self, vstrallocf(_(
420 "Value for property '%s' was autodetected and cannot be changed"),
422 DEVICE_STATUS_DEVICE_ERROR);
425 /* pretend we set it, but don't change surety/source */
431 self->final_filemarks = new_int;
433 return device_simple_property_set_fn(p_self, base, val, surety, source);
437 tape_device_set_compression_fn(Device *p_self, DevicePropertyBase *base,
438 GValue *val, PropertySurety surety, PropertySource source)
440 TapeDevice *self = TAPE_DEVICE(p_self);
441 gboolean request = g_value_get_boolean(val);
443 /* We allow this property to be set at any time. This is mostly
444 * because setting compression is a hit-and-miss proposition
445 * at any time; some drives accept the mode setting but don't
446 * actually support compression, while others do support
447 * compression but do it via density settings or some other
448 * way. Set this property whenever you want, but all we'll do
449 * is report whether or not the ioctl succeeded. */
450 if (tape_setcompression(self->fd, request)) {
451 /* looks good .. let's start the device over, though */
452 device_clear_volume_details(p_self);
457 return device_simple_property_set_fn(p_self, base, val, surety, source);
461 tape_device_set_read_buffer_size_fn(Device *p_self, DevicePropertyBase *base,
462 GValue *val, PropertySurety surety, PropertySource source)
464 TapeDevice *self = TAPE_DEVICE(p_self);
465 guint buffer_size = g_value_get_uint(val);
467 if (buffer_size != 0 &&
468 ((gsize)buffer_size < p_self->block_size ||
469 (gsize)buffer_size > p_self->max_block_size))
472 self->private->read_buffer_size = buffer_size;
474 return device_simple_property_set_fn(p_self, base, val, surety, source);
477 void tape_device_register(void) {
478 static const char * device_prefix_list[] = { "tape", NULL };
480 /* First register tape-specific properties */
481 device_property_fill_and_register(&device_property_broken_gmt_online,
482 G_TYPE_BOOLEAN, "broken_gmt_online",
483 "Does this drive support the GMT_ONLINE macro?");
485 device_property_fill_and_register(&device_property_fsf,
486 G_TYPE_BOOLEAN, "fsf",
487 "Does this drive support the MTFSF command?");
489 device_property_fill_and_register(&device_property_fsf_after_filemark,
490 G_TYPE_BOOLEAN, "fsf_after_filemark",
491 "Does this drive needs a FSF if a filemark is already read?");
493 device_property_fill_and_register(&device_property_bsf,
494 G_TYPE_BOOLEAN, "bsf",
495 "Does this drive support the MTBSF command?" );
497 device_property_fill_and_register(&device_property_fsr,
498 G_TYPE_BOOLEAN, "fsr",
499 "Does this drive support the MTFSR command?");
501 device_property_fill_and_register(&device_property_bsr,
502 G_TYPE_BOOLEAN, "bsr",
503 "Does this drive support the MTBSR command?");
505 /* FIXME: Is this feature even useful? */
506 device_property_fill_and_register(&device_property_eom,
507 G_TYPE_BOOLEAN, "eom",
508 "Does this drive support the MTEOM command?");
510 device_property_fill_and_register(&device_property_bsf_after_eom,
513 "Does this drive require an MTBSF after MTEOM in order to append?" );
515 device_property_fill_and_register(&device_property_nonblocking_open,
518 "Does this drive require a open with O_NONBLOCK?" );
520 device_property_fill_and_register(&device_property_final_filemarks,
521 G_TYPE_UINT, "final_filemarks",
522 "How many filemarks to write after the last tape file?" );
524 /* Then the device itself */
525 register_device(tape_device_factory, device_prefix_list);
528 /* Open the tape device, trying various combinations of O_RDWR and
529 O_NONBLOCK. Returns -1 and calls device_set_error for errors
530 On Linux, with O_NONBLOCK, the kernel just checks the state once,
531 whereas it checks it every second for ST_BLOCK_SECONDS if O_NONBLOCK is
532 not given. Amanda already have the code to poll, we want open to check
533 the state only once. */
535 static int try_open_tape_device(TapeDevice * self, char * device_filename) {
538 DeviceStatusFlags new_status;
543 if (self->nonblocking_open) {
544 nonblocking = O_NONBLOCK;
549 fd = robust_open(device_filename, O_RDWR | nonblocking, 0);
551 if (fd < 0 && nonblocking && (save_errno == EWOULDBLOCK || save_errno == EINVAL)) {
552 /* Maybe we don't support O_NONBLOCK for tape devices. */
553 fd = robust_open(device_filename, O_RDWR, 0);
557 fd = robust_open(device_filename, O_RDWR, 0);
561 self->write_open_errno = 0;
563 if (errno == EACCES || errno == EPERM
568 /* Device is write-protected. */
569 self->write_open_errno = errno;
571 fd = robust_open(device_filename, O_RDONLY | nonblocking, 0);
573 if (fd < 0 && nonblocking && (save_errno == EWOULDBLOCK || save_errno == EINVAL)) {
574 fd = robust_open(device_filename, O_RDONLY, 0);
578 fd = robust_open(device_filename, O_RDONLY, 0);
584 /* Clear O_NONBLOCK for operations from now on. */
585 if (fd >= 0 && nonblocking)
586 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
588 /* function continues after #endif */
590 #endif /* O_NONBLOCK */
593 DeviceStatusFlags status_flag = 0;
595 status_flag = DEVICE_STATUS_DEVICE_BUSY;
597 status_flag = DEVICE_STATUS_DEVICE_ERROR;
598 device_set_error(DEVICE(self),
599 vstrallocf(_("Can't open tape device %s: %s"), self->private->device_filename, strerror(errno)),
604 /* Check that this is actually a tape device. */
605 new_status = tape_is_tape_device(fd);
606 if (new_status & DEVICE_STATUS_DEVICE_ERROR) {
607 device_set_error(DEVICE(self),
608 vstrallocf(_("File %s is not a tape device"), self->private->device_filename),
613 if (new_status & DEVICE_STATUS_VOLUME_MISSING) {
614 device_set_error(DEVICE(self),
615 vstrallocf(_("Tape device %s is not ready or is empty"), self->private->device_filename),
621 new_status = tape_is_ready(fd, self);
622 if (new_status & DEVICE_STATUS_VOLUME_MISSING) {
623 device_set_error(DEVICE(self),
624 vstrallocf(_("Tape device %s is empty"), self->private->device_filename),
629 if (new_status != DEVICE_STATUS_SUCCESS) {
630 device_set_error(DEVICE(self),
631 vstrallocf(_("Tape device %s is not ready or is empty"), self->private->device_filename),
641 tape_device_open_device (Device * d_self, char * device_name G_GNUC_UNUSED,
642 char * device_type G_GNUC_UNUSED, char * device_node) {
645 self = TAPE_DEVICE(d_self);
648 self->private->device_filename = stralloc(device_node);
650 /* Get tape drive/OS info */
651 tape_device_detect_capabilities(self);
654 if (parent_class->open_device) {
655 parent_class->open_device(d_self, device_node, device_type, device_node);
660 tape_device_set_capabilities(TapeDevice *self,
661 gboolean fsf, PropertySurety fsf_surety, PropertySource fsf_source,
662 gboolean fsf_after_filemark, PropertySurety faf_surety, PropertySource faf_source,
663 gboolean bsf, PropertySurety bsf_surety, PropertySource bsf_source,
664 gboolean fsr, PropertySurety fsr_surety, PropertySource fsr_source,
665 gboolean bsr, PropertySurety bsr_surety, PropertySource bsr_source,
666 gboolean eom, PropertySurety eom_surety, PropertySource eom_source,
667 gboolean bsf_after_eom, PropertySurety bae_surety, PropertySource bae_source,
668 guint final_filemarks, PropertySurety ff_surety, PropertySource ff_source)
670 Device *dself = DEVICE(self);
673 /* this function is called by tape_device_detect_capabilities, and basically
674 * exists to take care of the GValue mechanics in one place */
676 g_assert(final_filemarks == 1 || final_filemarks == 2);
678 bzero(&val, sizeof(val));
679 g_value_init(&val, G_TYPE_BOOLEAN);
682 g_value_set_boolean(&val, fsf);
683 device_set_simple_property(dself, PROPERTY_FSF, &val, fsf_surety, fsf_source);
685 self->fsf_after_filemark = fsf_after_filemark;
686 g_value_set_boolean(&val, fsf_after_filemark);
687 device_set_simple_property(dself, PROPERTY_FSF_AFTER_FILEMARK, &val, faf_surety, faf_source);
690 g_value_set_boolean(&val, bsf);
691 device_set_simple_property(dself, PROPERTY_BSF, &val, bsf_surety, bsf_source);
694 g_value_set_boolean(&val, fsr);
695 device_set_simple_property(dself, PROPERTY_FSR, &val, fsr_surety, fsr_source);
698 g_value_set_boolean(&val, bsr);
699 device_set_simple_property(dself, PROPERTY_BSR, &val, bsr_surety, bsr_source);
702 g_value_set_boolean(&val, eom);
703 device_set_simple_property(dself, PROPERTY_EOM, &val, eom_surety, eom_source);
705 self->bsf_after_eom = bsf_after_eom;
706 g_value_set_boolean(&val, bsf_after_eom);
707 device_set_simple_property(dself, PROPERTY_BSF_AFTER_EOM, &val, bae_surety, bae_source);
710 g_value_init(&val, G_TYPE_UINT);
712 self->final_filemarks = final_filemarks;
713 g_value_set_uint(&val, final_filemarks);
714 device_set_simple_property(dself, PROPERTY_FINAL_FILEMARKS, &val, ff_surety, ff_source);
719 static DeviceStatusFlags tape_device_read_label(Device * dself) {
721 char * header_buffer;
725 DeviceStatusFlags new_status;
727 self = TAPE_DEVICE(dself);
729 amfree(dself->volume_label);
730 amfree(dself->volume_time);
731 amfree(dself->volume_header);
733 if (device_in_error(self)) return dself->status;
735 header = dself->volume_header = g_new(dumpfile_t, 1);
738 if (self->fd == -1) {
739 self->fd = try_open_tape_device(self, self->private->device_filename);
740 /* if the open failed, then try_open_tape_device already set the
741 * approppriate error status */
743 return dself->status;
747 if (!tape_rewind(self->fd)) {
748 device_set_error(dself,
749 vstrallocf(_("Error rewinding device %s"), self->private->device_filename),
750 DEVICE_STATUS_DEVICE_ERROR
751 | DEVICE_STATUS_VOLUME_ERROR);
752 robust_close(self->fd);
753 return dself->status;
756 buffer_len = tape_device_read_size(self);
757 header_buffer = malloc(buffer_len);
758 result = tape_device_robust_read(self, header_buffer, &buffer_len);
760 if (result != RESULT_SUCCESS) {
762 tape_rewind(self->fd);
764 if (result == RESULT_NO_DATA) {
765 new_status = (DEVICE_STATUS_VOLUME_ERROR |
766 DEVICE_STATUS_VOLUME_UNLABELED);
768 new_status = (DEVICE_STATUS_DEVICE_ERROR |
769 DEVICE_STATUS_VOLUME_ERROR |
770 DEVICE_STATUS_VOLUME_UNLABELED);
772 device_set_error(dself, stralloc(_("Error reading Amanda header")), new_status);
773 return dself->status;
776 parse_file_header(header_buffer, header, buffer_len);
777 amfree(header_buffer);
778 if (header->type != F_TAPESTART) {
779 device_set_error(dself,
780 stralloc(_("No tapestart header -- unlabeled device?")),
781 DEVICE_STATUS_VOLUME_UNLABELED);
782 return dself->status;
785 dself->volume_label = g_strdup(header->name);
786 dself->volume_time = g_strdup(header->datestamp);
787 /* dself->volume_header is already set */
789 device_set_error(dself, NULL, DEVICE_STATUS_SUCCESS);
791 return dself->status;
795 tape_device_write_block(Device * pself, guint size, gpointer data) {
797 char *replacement_buffer = NULL;
800 self = TAPE_DEVICE(pself);
802 g_assert(self->fd >= 0);
803 if (device_in_error(self)) return FALSE;
805 /* zero out to the end of a short block -- tape devices only write
807 if (size < pself->block_size) {
808 replacement_buffer = malloc(pself->block_size);
809 memcpy(replacement_buffer, data, size);
810 bzero(replacement_buffer+size, pself->block_size-size);
812 data = replacement_buffer;
813 size = pself->block_size;
816 result = tape_device_robust_write(self, data, size);
817 amfree(replacement_buffer);
823 case RESULT_NO_SPACE:
824 device_set_error(pself,
825 stralloc(_("No space left on device")),
826 DEVICE_STATUS_VOLUME_ERROR);
827 pself->is_eof = TRUE;
832 device_set_error(pself,
833 vstrallocf(_("Error writing block: %s"), strerror(errno)),
834 DEVICE_STATUS_DEVICE_ERROR);
843 static int tape_device_read_block (Device * pself, gpointer buf,
848 gssize read_block_size = tape_device_read_size(pself);
850 self = TAPE_DEVICE(pself);
852 g_assert(self->fd >= 0);
853 if (device_in_error(self)) return -1;
855 g_assert(read_block_size < INT_MAX); /* data type mismatch */
856 if (buf == NULL || *size_req < (int)read_block_size) {
857 /* Just a size query. */
858 *size_req = (int)read_block_size;
863 result = tape_device_robust_read(self, buf, &size);
869 case RESULT_SMALL_BUFFER: {
873 /* If this happens, it means that we have:
874 * (next block size) > (buffer size) >= (read_block_size)
875 * The solution is to ask for an even bigger buffer. We also play
876 * some games to refrain from reading above the SCSI limit or from
877 * integer overflow. Note that not all devices will tell us about
878 * this problem -- some will just discard the "extra" data. */
879 new_size = MIN(INT_MAX/2 - 1, *size_req) * 2;
880 if (new_size > LARGEST_BLOCK_ESTIMATE &&
881 *size_req < LARGEST_BLOCK_ESTIMATE) {
882 new_size = LARGEST_BLOCK_ESTIMATE;
884 g_assert (new_size > (gsize)*size_req);
886 g_warning("Device %s indicated blocksize %zd was too small; using %zd.",
887 pself->device_name, (gsize)*size_req, new_size);
888 *size_req = (int)new_size;
889 self->private->read_buffer_size = new_size;
891 bzero(&newval, sizeof(newval));
892 g_value_init(&newval, G_TYPE_UINT);
893 g_value_set_uint(&newval, self->private->read_buffer_size);
894 device_set_simple_property(pself, PROPERTY_READ_BUFFER_SIZE,
895 &newval, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
896 g_value_unset(&newval);
901 pself->is_eof = TRUE;
902 pself->in_file = FALSE;
903 device_set_error(pself,
905 DEVICE_STATUS_SUCCESS);
909 device_set_error(pself,
910 vstrallocf(_("Error reading from tape device: %s"), strerror(errno)),
911 DEVICE_STATUS_VOLUME_ERROR | DEVICE_STATUS_DEVICE_ERROR);
915 g_assert_not_reached();
918 /* Just a helper function for tape_device_start(). */
919 static gboolean write_tapestart_header(TapeDevice * self, char * label,
925 gboolean header_fits;
926 Device * d_self = (Device*)self;
927 tape_rewind(self->fd);
929 header = make_tapestart_header(d_self, label, timestamp);
930 g_assert(header != NULL);
931 header_buf = device_build_amanda_header(d_self, header, &header_size,
934 g_assert(header_buf != NULL);
938 device_set_error(d_self,
939 stralloc(_("Tapestart header won't fit in a single block!")),
940 DEVICE_STATUS_DEVICE_ERROR);
944 g_assert(header_size >= (int)d_self->min_block_size);
945 result = tape_device_robust_write(self, header_buf, header_size);
946 if (result != RESULT_SUCCESS) {
947 device_set_error(d_self,
948 vstrallocf(_("Error writing tapestart header: %s"), strerror(errno)),
949 DEVICE_STATUS_DEVICE_ERROR);
956 if (!tape_weof(self->fd, 1)) {
957 device_set_error(d_self,
958 vstrallocf(_("Error writing filemark: %s"),
960 DEVICE_STATUS_DEVICE_ERROR|DEVICE_STATUS_VOLUME_ERROR);
969 tape_device_start (Device * d_self, DeviceAccessMode mode, char * label,
973 self = TAPE_DEVICE(d_self);
975 if (device_in_error(self)) return FALSE;
977 if (self->fd == -1) {
978 self->fd = try_open_tape_device(self, self->private->device_filename);
979 /* if the open failed, then try_open_tape_device already set the
980 * approppriate error status */
985 if (mode != ACCESS_WRITE && d_self->volume_label == NULL) {
986 /* we need a labeled volume for APPEND and READ */
987 if (tape_device_read_label(d_self) != DEVICE_STATUS_SUCCESS)
991 d_self->access_mode = mode;
992 d_self->in_file = FALSE;
994 if (IS_WRITABLE_ACCESS_MODE(mode)) {
995 if (self->write_open_errno != 0) {
996 /* We tried and failed to open the device in write mode. */
997 device_set_error(d_self,
998 vstrallocf(_("Can't open tape device %s for writing: %s"),
999 self->private->device_filename, strerror(self->write_open_errno)),
1000 DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
1002 } else if (!tape_rewind(self->fd)) {
1003 device_set_error(d_self,
1004 vstrallocf(_("Couldn't rewind device: %s"), strerror(errno)),
1005 DEVICE_STATUS_DEVICE_ERROR);
1010 /* Position the tape */
1013 if (d_self->volume_label == NULL && device_read_label(d_self) != DEVICE_STATUS_SUCCESS) {
1014 /* device_read_label already set our error message */
1018 if (!tape_device_eod(self)) {
1019 device_set_error(d_self,
1020 vstrallocf(_("Couldn't seek to end of tape: %s"), strerror(errno)),
1021 DEVICE_STATUS_DEVICE_ERROR);
1027 if (d_self->volume_label == NULL && device_read_label(d_self) != DEVICE_STATUS_SUCCESS) {
1028 /* device_read_label already set our error message */
1032 if (!tape_rewind(self->fd)) {
1033 device_set_error(d_self,
1034 vstrallocf(_("Couldn't rewind device: %s"), strerror(errno)),
1035 DEVICE_STATUS_DEVICE_ERROR);
1042 if (!write_tapestart_header(self, label, timestamp)) {
1043 /* write_tapestart_header already set the error status */
1047 d_self->volume_label = newstralloc(d_self->volume_label, label);
1048 d_self->volume_time = newstralloc(d_self->volume_time, timestamp);
1050 /* unset the VOLUME_UNLABELED flag, if it was set */
1051 device_set_error(d_self, NULL, DEVICE_STATUS_SUCCESS);
1056 g_assert_not_reached();
1062 static gboolean tape_device_start_file(Device * d_self,
1063 dumpfile_t * info) {
1066 char * amanda_header;
1068 gboolean header_fits;
1070 self = TAPE_DEVICE(d_self);
1072 g_assert(self->fd >= 0);
1073 if (device_in_error(self)) return FALSE;
1075 /* set the blocksize in the header properly */
1076 info->blocksize = d_self->block_size;
1078 /* Make the Amanda header suitable for writing to the device. */
1079 /* Then write the damn thing. */
1080 amanda_header = device_build_amanda_header(d_self, info,
1081 &header_size, &header_fits);
1083 device_set_error(d_self,
1084 stralloc(_("Amanda file header won't fit in a single block!")),
1085 DEVICE_STATUS_DEVICE_ERROR);
1088 result = tape_device_robust_write(self, amanda_header, header_size);
1089 if (result != RESULT_SUCCESS) {
1090 device_set_error(d_self,
1091 vstrallocf(_("Error writing file header: %s"), strerror(errno)),
1092 DEVICE_STATUS_DEVICE_ERROR);
1093 amfree(amanda_header);
1096 amfree(amanda_header);
1098 /* arrange the file numbers correctly */
1099 d_self->in_file = TRUE;
1101 if (d_self->file >= 0)
1107 tape_device_finish_file (Device * d_self) {
1110 self = TAPE_DEVICE(d_self);
1111 if (device_in_error(d_self)) return FALSE;
1113 if (!tape_weof(self->fd, 1)) {
1114 device_set_error(d_self,
1115 vstrallocf(_("Error writing filemark: %s"), strerror(errno)),
1116 DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
1120 d_self->in_file = FALSE;
1125 tape_device_seek_file (Device * d_self, guint file) {
1128 char * header_buffer;
1133 self = TAPE_DEVICE(d_self);
1135 if (device_in_error(self)) return NULL;
1137 difference = file - d_self->file;
1139 /* Check if we already read a filemark. */
1140 /* If we already read a filemark and the drive automaticaly goes to the
1141 next file, then we must reduce the difference by one. */
1142 if (d_self->is_eof && !self->fsf_after_filemark) {
1146 d_self->in_file = FALSE;
1147 d_self->is_eof = FALSE;
1150 if (difference > 0) {
1151 /* Seeking forwards */
1152 if (!tape_device_fsf(self, difference)) {
1153 tape_rewind(self->fd);
1154 device_set_error(d_self,
1155 vstrallocf(_("Could not seek forward to file %d"), file),
1156 DEVICE_STATUS_VOLUME_ERROR | DEVICE_STATUS_DEVICE_ERROR);
1159 } else if (difference < 0) {
1160 /* Seeking backwards */
1161 if (!tape_device_bsf(self, -difference, d_self->file)) {
1162 tape_rewind(self->fd);
1163 device_set_error(d_self,
1164 vstrallocf(_("Could not seek backward to file %d"), file),
1165 DEVICE_STATUS_VOLUME_ERROR | DEVICE_STATUS_DEVICE_ERROR);
1170 buffer_len = tape_device_read_size(d_self);
1171 header_buffer = malloc(buffer_len);
1172 d_self->is_eof = FALSE;
1173 result = tape_device_robust_read(self, header_buffer, &buffer_len);
1175 if (result != RESULT_SUCCESS) {
1176 free(header_buffer);
1177 tape_rewind(self->fd);
1178 if (result == RESULT_NO_DATA) {
1179 /* If we read 0 bytes, that means we encountered a double
1180 * filemark, which indicates end of tape. This should
1181 * work even with QIC tapes on operating systems with
1182 * proper support. */
1183 d_self->file = file; /* other attributes are already correct */
1184 return make_tapeend_header();
1187 device_set_error(d_self,
1188 stralloc(_("Error reading Amanda header")),
1189 DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
1193 rval = g_new(dumpfile_t, 1);
1194 parse_file_header(header_buffer, rval, buffer_len);
1195 amfree(header_buffer);
1196 switch (rval->type) {
1198 case F_CONT_DUMPFILE:
1199 case F_SPLIT_DUMPFILE:
1203 tape_rewind(self->fd);
1204 device_set_error(d_self,
1205 stralloc(_("Invalid amanda header while reading file header")),
1206 DEVICE_STATUS_VOLUME_ERROR);
1211 d_self->in_file = TRUE;
1212 d_self->file = file;
1218 tape_device_seek_block (Device * d_self, guint64 block) {
1222 self = TAPE_DEVICE(d_self);
1224 if (device_in_error(self)) return FALSE;
1226 difference = block - d_self->block;
1228 if (difference > 0) {
1229 if (!tape_device_fsr(self, difference)) {
1230 device_set_error(d_self,
1231 vstrallocf(_("Could not seek forward to block %ju"), (uintmax_t)block),
1232 DEVICE_STATUS_VOLUME_ERROR | DEVICE_STATUS_DEVICE_ERROR);
1235 } else if (difference < 0) {
1236 if (!tape_device_bsr(self, difference, d_self->file, d_self->block)) {
1237 device_set_error(d_self,
1238 vstrallocf(_("Could not seek backward to block %ju"), (uintmax_t)block),
1239 DEVICE_STATUS_VOLUME_ERROR | DEVICE_STATUS_DEVICE_ERROR);
1244 d_self->block = block;
1249 tape_device_finish (Device * d_self) {
1252 self = TAPE_DEVICE(d_self);
1254 if (device_in_error(self)) return FALSE;
1256 if (d_self->access_mode == ACCESS_NULL)
1259 /* Polish off this file, if relevant. */
1260 if (d_self->in_file && IS_WRITABLE_ACCESS_MODE(d_self->access_mode)) {
1261 if (!device_finish_file(d_self))
1265 /* Write an extra filemark, if needed. The OS will give us one for
1267 /* device_finish_file already wrote one for us */
1269 if (self->final_filemarks > 1 &&
1270 IS_WRITABLE_ACCESS_MODE(d_self->access_mode)) {
1271 if (!tape_weof(self->fd, 1)) {
1272 device_set_error(d_self,
1273 vstrallocf(_("Error writing final filemark: %s"), strerror(errno)),
1274 DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
1281 if (!tape_rewind(self->fd)) {
1282 device_set_error(d_self,
1283 vstrallocf(_("Couldn't rewind device: %s"), strerror(errno)),
1284 DEVICE_STATUS_DEVICE_ERROR);
1288 d_self->is_eof = FALSE;
1289 d_self->access_mode = ACCESS_NULL;
1294 /* Works just like read(), except for the following:
1295 * 1) Retries on EINTR & friends.
1296 * 2) Stores count in parameter, not return value.
1297 * 3) Provides explicit return result. */
1299 tape_device_robust_read (TapeDevice * self, void * buf, int * count) {
1303 d_self = (Device*)self;
1305 /* Callers should ensure this. */
1306 g_assert(*count >= 0);
1309 result = read(self->fd, buf, *count);
1311 /* Success. By definition, we read a full block. */
1312 d_self->is_eof = FALSE;
1314 return RESULT_SUCCESS;
1315 } else if (result == 0) {
1316 d_self->is_eof = TRUE;
1317 return RESULT_NO_DATA;
1324 || errno == EWOULDBLOCK
1330 /* Interrupted system call */
1334 || errno == ENOMEM /* bad user-space buffer */
1337 || errno == EOVERFLOW /* bad kernel-space buffer */
1340 || errno == EINVAL /* ??? */
1343 /* Buffer too small. */
1344 return RESULT_SMALL_BUFFER;
1346 device_set_error(d_self,
1347 vstrallocf(_("Error reading %d bytes from %s: %s"),
1348 *count, self->private->device_filename, strerror(errno)),
1349 DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
1350 return RESULT_ERROR;
1356 g_assert_not_reached();
1359 /* Kernel workaround: If needed, poke the kernel so it doesn't fail.
1360 at the 2GB boundry. Parameters are G_GNUC_UNUSED in case NEED_RESETOFS
1362 static void check_resetofs(TapeDevice * self G_GNUC_UNUSED,
1363 int count G_GNUC_UNUSED) {
1364 #ifdef NEED_RESETOFS
1368 d_self = (Device*)self;
1370 self->private->write_count += count;
1371 if (self->private->write_count < RESETOFS_THRESHOLD) {
1375 result = lseek(self->fd, 0, SEEK_SET);
1377 g_warning(_("lseek() failed during kernel 2GB workaround: %s"),
1384 tape_device_robust_write (TapeDevice * self, void * buf, int count) {
1388 d_self = (Device*)self;
1390 check_resetofs(self, count);
1393 result = write(self->fd, buf, count);
1395 if (result == count) {
1398 self->private->write_count ++;
1399 return RESULT_SUCCESS;
1400 } else if (result >= 0) {
1401 /* write() returned a short count. This should not happen. */
1402 device_set_error(d_self,
1403 vstrallocf(_("Mysterious short write on tape device: Tried %d, got %d"),
1405 DEVICE_STATUS_DEVICE_ERROR);
1406 return RESULT_ERROR;
1412 || errno == EWOULDBLOCK
1418 /* Interrupted system call */
1428 /* Probably EOT. Print a message if we got EIO. */
1431 g_warning(_("Got EIO on %s, assuming end of tape"),
1432 self->private->device_filename);
1435 return RESULT_NO_SPACE;
1438 device_set_error(d_self,
1439 vstrallocf(_("Kernel gave unexpected write() result of \"%s\" on device %s"),
1440 strerror(errno), self->private->device_filename),
1441 DEVICE_STATUS_DEVICE_ERROR);
1442 return RESULT_ERROR;
1446 g_assert_not_reached();
1449 /* Reads some number of tape blocks into the bit-bucket. If the count
1450 is negative, then we read the rest of the entire file. Returns the
1451 number of blocks read, or -1 if an error occured. If we encounter
1452 EOF (as opposed to some other error) we return the number of blocks
1454 static int drain_tape_blocks(TapeDevice * self, int count) {
1459 buffer_size = tape_device_read_size(self);
1461 buffer = malloc(sizeof(buffer_size));
1463 for (i = 0; i < count || count < 0;) {
1466 result = read(self->fd, buffer, buffer_size);
1470 } else if (result == 0) {
1474 /* First check for interrupted system call. */
1480 || errno == EWOULDBLOCK
1486 /* Interrupted system call */
1490 || errno == ENOSPC /* bad user-space buffer */
1493 || errno == EOVERFLOW /* bad kernel-space buffer */
1496 || errno == EINVAL /* ??? */
1499 /* The buffer may not be big enough. But the OS is not
1500 100% clear. We double the buffer and try again, but
1501 in no case allow a buffer bigger than 32 MB. */
1504 if (buffer_size > 32*1024*1024) {
1508 buffer = realloc(buffer, buffer_size);
1519 /* FIXME: Make sure that there are no cycles in reimplementation
1523 tape_device_fsf (TapeDevice * self, guint count) {
1525 return tape_fsf(self->fd, count);
1528 for (i = 0; i < count; i ++) {
1529 if (drain_tape_blocks(self, -1) < 0)
1536 /* Seek back over count + 1 filemarks to the start of the given file. */
1538 tape_device_bsf (TapeDevice * self, guint count, guint file) {
1540 /* The BSF operation is not very smart; it includes the
1541 filemark of the present file as part of the count, and seeks
1542 to the wrong (BOT) side of the filemark. We compensate for
1543 this by seeking one filemark too many, then FSFing back over
1546 If this procedure fails for some reason, we can still try
1548 if (tape_bsf(self->fd, count + 1) &&
1549 tape_device_fsf(self, 1))
1551 } /* Fall through to backup plan. */
1553 /* We rewind the tape, then seek forward the given number of
1555 if (!tape_rewind(self->fd))
1558 return tape_device_fsf(self, file);
1563 tape_device_fsr (TapeDevice * self, guint count) {
1565 return tape_fsr(self->fd, count);
1567 int result = drain_tape_blocks(self, count);
1568 return result > 0 && (int)count == result;
1572 /* Seek back the given number of blocks to block number block within
1573 * the current file, numbered file. */
1576 tape_device_bsr (TapeDevice * self, guint count, guint file, guint block) {
1578 return tape_bsr(self->fd, count);
1580 /* We BSF, then FSR. */
1581 if (!tape_device_bsf(self, 0, file))
1584 return tape_device_fsr(self, block);
1586 g_assert_not_reached();
1589 /* Go to the right place to write more data, and update the file
1590 number if possible. */
1592 tape_device_eod (TapeDevice * self) {
1594 d_self = (Device*)self;
1598 result = tape_eod(self->fd);
1599 if (result == TAPE_OP_ERROR) {
1601 } else if (result == TAPE_POSITION_UNKNOWN) {
1604 /* We drop by 1 because Device will increment the first
1605 time the user does start_file. */
1606 d_self->file = result - 1;
1611 if (!tape_rewind(self->fd))
1615 /* We alternately read a block and FSF. If the read is
1616 successful, then we are not there yet and should FSF
1619 result = drain_tape_blocks(self, 1);
1621 /* More data, FSF. */
1622 tape_device_fsf(self, 1);
1624 } else if (result == 0) {
1626 d_self->file = count;
1636 tape_device_factory (char * device_name, char * device_type, char * device_node) {
1638 g_assert(0 == strcmp(device_type, "tape"));
1639 rval = DEVICE(g_object_new(TYPE_TAPE_DEVICE, NULL));
1640 device_open_device(rval, device_name, device_type, device_node);