2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Author: James da Silva, Systems Design and Analysis Group
24 * Computer Science Department
25 * University of Maryland at College Park
28 /* NOTE: this driver is *deprecated* and should not be used. See the Device API
29 * in device-src/ for the new implementation.
33 * $Id: output-file.c,v 1.14 2006/07/06 15:04:18 martinea Exp $
35 * tapeio.c virtual tape interface for a file device.
37 * The following was based on testing with real tapes on Solaris 2.6.
38 * It is possible other OS drivers behave somewhat different in end
39 * cases, usually involving errors.
46 #include "output-file.h"
47 #include "fileheader.h"
61 #define DATA_INDICATOR "."
62 #define RECORD_INDICATOR "-"
66 char *basename; /* filename from open */
67 struct file_info *fi; /* file info array */
68 size_t fi_limit; /* length of file info array */
69 int flags; /* open flags */
70 mode_t mask; /* open mask */
71 off_t file_count; /* number of files */
72 off_t file_current; /* current file position */
73 off_t record_current; /* current record position */
74 int fd; /* data file descriptor */
75 int is_online; /* true if "tape" is "online" */
76 int at_bof; /* true if at begining of file */
77 int at_eof; /* true if at end of file */
78 int at_eom; /* true if at end of medium */
79 int last_operation_write; /* true if last op was a write */
80 off_t amount_written; /* KBytes written since open/rewind */
81 } *volume_info = NULL;
84 char *name; /* file name (tapefd_getinfo_...) */
85 struct record_info *ri; /* record info array */
86 size_t ri_count; /* number of record info entries */
87 size_t ri_limit; /* length of record info array */
88 int ri_altered; /* true if record info altered */
92 size_t record_size; /* record size */
93 off_t start_record; /* first record in range */
94 off_t end_record; /* last record in range */
97 static size_t open_count = 0;
99 static int check_online(int fd);
100 static int file_open(int fd);
101 static void file_close(int fd);
102 static void file_release(int fd);
103 static size_t get_record_size(struct file_info *fi, off_t record);
104 static void put_record_size(struct file_info *fi, off_t record, size_t size);
107 * "Open" the tape by scanning the "data" directory. "Tape files"
108 * have five leading digits indicating the position (counting from zero)
109 * followed by a '.' and optional other information (e.g. host/disk/level
112 * We allow for the following situations:
114 * + If we see the same "file" (position number) more than once, the
115 * last one seen wins. This should not normally happen.
117 * + We allow gaps in the positions. This should not normally happen.
119 * Anything in the directory that does not match a "tape file" name
120 * pattern is ignored.
122 * If the data directory does not exist, the "tape" is considered offline.
123 * It is allowed to "appear" later.
130 char *token[MAX_TOKENS];
132 struct dirent *entry;
133 struct file_info *fi;
134 struct file_info **fi_p;
139 char *qname = quote_string(volume_info[fd].basename);
142 * If we are already online, there is nothing else to do.
144 if (volume_info[fd].is_online) {
148 if ((tapedir = opendir(volume_info[fd].basename)) == NULL) {
150 * We have already opened the info file which is in the same
151 * directory as the data directory, so ENOENT has to mean the data
152 * directory is not there, which we treat as being "offline".
153 * We're already offline at this point (see the above test)
154 * and this is not an error, so just return success (no error).
157 rc = (errno != ENOENT);
158 g_fprintf(stderr,_("ERROR: %s (%s)\n"), qname, strerror(errno));
161 while ((entry = readdir(tapedir)) != NULL) {
162 if (is_dot_or_dotdot(entry->d_name)) {
165 if (isdigit((int)entry->d_name[0])
166 && isdigit((int)entry->d_name[1])
167 && isdigit((int)entry->d_name[2])
168 && isdigit((int)entry->d_name[3])
169 && isdigit((int)entry->d_name[4])
170 && entry->d_name[5] == '.') {
173 * This is a "tape file".
175 pos = OFF_T_ATOI(entry->d_name);
176 assert((pos + 1) <= (off_t)SSIZE_MAX);
177 fi_p = &volume_info[fd].fi;
178 amtable_alloc((void **)fi_p,
179 &volume_info[fd].fi_limit,
180 SIZEOF(*volume_info[fd].fi),
184 fi = &volume_info[fd].fi[pos];
185 if (fi->name != NULL) {
187 * Two files with the same position???
192 fi->name = stralloc(&entry->d_name[6]);
193 if ((pos + 1) > volume_info[fd].file_count) {
194 volume_info[fd].file_count = (pos + 1);
201 * Parse the info file. We know we are at beginning of file because
202 * the only thing that can happen to it prior to here is it being
205 for (; (line = areads(fd)) != NULL; free(line)) {
206 f = split(line, token, (int)(sizeof(token) / sizeof(token[0])), " ");
207 if (f == 2 && strcmp(token[1], "position") == 0) {
208 volume_info[fd].file_current = OFF_T_ATOI(token[2]);
209 volume_info[fd].record_current = (off_t)0;
214 * Set EOM and make sure we are not pre-BOI.
216 if (volume_info[fd].file_current >= volume_info[fd].file_count) {
217 volume_info[fd].at_eom = 1;
219 if (volume_info[fd].file_current < 0) {
220 volume_info[fd].file_current = 0;
221 volume_info[fd].record_current = (off_t)0;
224 volume_info[fd].is_online = 1;
233 * Open the tape file if not already. If we are beyond the file count
234 * (end of tape) or the file is missing and we are only reading, set
235 * up to read /dev/null which will look like EOF. If we are writing,
243 struct file_info *fi;
244 struct file_info **fi_p;
245 char *datafilename = NULL;
246 char *recordfilename = NULL;
252 char number[NUM_STR_SIZE];
257 struct record_info *ri;
258 struct record_info **ri_p;
261 size_t record_size = 0;
263 if (volume_info[fd].fd < 0) {
264 flags = volume_info[fd].flags;
265 pos = volume_info[fd].file_current;
266 assert((pos + 1) < (off_t)SSIZE_MAX);
267 fi_p = &volume_info[fd].fi;
268 amtable_alloc((void **)fi_p,
269 &volume_info[fd].fi_limit,
270 SIZEOF(*volume_info[fd].fi),
274 fi = &volume_info[fd].fi[pos];
277 * See if we are creating a new file.
279 if (pos >= volume_info[fd].file_count) {
280 volume_info[fd].file_count = pos + 1;
284 * Generate the file name to open.
286 if (fi->name == NULL) {
287 if ((volume_info[fd].flags & 3) != O_RDONLY) {
290 * This is a new file, so make sure we create/truncate
291 * it. Generate the name based on the host/disk/level
292 * information from the caller, if available, else
295 flags |= (O_CREAT | O_TRUNC);
296 host = tapefd_getinfo_host(fd);
297 disk = tapefd_getinfo_disk(fd);
298 level = tapefd_getinfo_level(fd);
299 g_snprintf(number, SIZEOF(number), "%d", level);
304 disk = sanitise_filename(disk);
308 vstrextend(&f, ".", disk, NULL);
314 f = stralloc(number);
316 vstrextend(&f, ".", number, NULL);
320 f = stralloc("unknown");
323 fi->name = stralloc(f);
329 * This is a missing file, so set up to read nothing.
331 datafilename = stralloc("/dev/null");
332 recordfilename = stralloc("/dev/null");
335 if (datafilename == NULL) {
336 g_snprintf(number, SIZEOF(number),
337 "%05lld", (long long)pos);
338 datafilename = vstralloc(volume_info[fd].basename,
341 volume_info[fd].fi[pos].name,
343 recordfilename = vstralloc(volume_info[fd].basename,
346 volume_info[fd].fi[pos].name,
351 * Do the data file open.
353 volume_info[fd].fd = open(datafilename, flags, volume_info[fd].mask);
354 amfree(datafilename);
357 * Load the record information.
359 if (volume_info[fd].fd >= 0 && fi->ri_count == 0 &&
360 (rfd = open(recordfilename, O_RDONLY)) >= 0) {
361 for (; (line = areads(rfd)) != NULL; free(line)) {
362 /* We play this game because long long is not
363 necessarily the same as off_t, and we need to cast the
364 actual value (not just the pointer. */
365 long long start_record_ = (long long)0;
366 long long end_record_ = (long long)0;
367 long record_size_ = (long)0;
368 n = sscanf(line, "%lld %lld %ld",
369 &start_record_, &end_record_, &record_size_);
370 start_record = (off_t)start_record_;
371 end_record = (off_t)end_record_;
372 record_size = (size_t)record_size_;
376 amtable_alloc((void **)ri_p,
379 (size_t)fi->ri_count + 1,
382 ri = &fi->ri[fi->ri_count];
383 ri->start_record = start_record;
384 ri->end_record = end_record;
385 ri->record_size = record_size;
391 amfree(recordfilename);
393 return volume_info[fd].fd;
397 * Close the current data file, if open. Dump the record information
398 * if it has been altered.
405 struct file_info *fi;
406 struct file_info **fi_p;
408 char number[NUM_STR_SIZE];
409 char *filename = NULL;
413 aclose(volume_info[fd].fd);
414 pos = volume_info[fd].file_current;
415 assert((pos + 1) < (off_t)SSIZE_MAX);
416 fi_p = &volume_info[fd].fi;
417 amtable_alloc((void **)fi_p,
418 &volume_info[fd].fi_limit,
419 SIZEOF(*volume_info[fd].fi),
423 fi = &volume_info[fd].fi[pos];
424 if (fi->ri_altered) {
425 g_snprintf(number, SIZEOF(number),
426 "%05lld", (long long)pos);
427 filename = vstralloc(volume_info[fd].basename,
432 if ((f = fopen(filename, "w")) == NULL) {
435 for (r = 0; r < fi->ri_count; r++) {
436 g_fprintf(f, "%lld %lld %zu\n",
437 (long long)fi->ri[r].start_record,
438 (long long)fi->ri[r].end_record,
439 fi->ri[r].record_size);
451 * Release any files beyond a given position current position and reset
452 * file_count to file_current to indicate EOM.
462 char number[NUM_STR_SIZE];
463 struct file_info **fi_p;
466 * If the current file is open, release everything beyond it.
467 * If it is not open, release everything from current.
469 if (volume_info[fd].fd >= 0) {
470 position = volume_info[fd].file_current + 1;
472 position = volume_info[fd].file_current;
474 for (pos = position; pos < volume_info[fd].file_count; pos++) {
475 assert(pos < (off_t)SSIZE_MAX);
476 fi_p = &volume_info[fd].fi;
477 amtable_alloc((void **)fi_p,
478 &volume_info[fd].fi_limit,
479 SIZEOF(*volume_info[fd].fi),
483 if (volume_info[fd].fi[pos].name != NULL) {
484 g_snprintf(number, SIZEOF(number),
485 "%05lld", (long long)pos);
486 filename = vstralloc(volume_info[fd].basename,
489 volume_info[fd].fi[pos].name,
493 filename = vstralloc(volume_info[fd].basename,
496 volume_info[fd].fi[pos].name,
500 amfree(volume_info[fd].fi[pos].name);
501 volume_info[fd].fi[pos].ri_count = 0;
504 volume_info[fd].file_count = position;
508 * Get the size of a particular record. We assume the record information is
509 * sorted, does not overlap and does not have gaps.
514 struct file_info * fi,
518 struct record_info *ri;
520 for(r = 0; r < fi->ri_count; r++) {
522 if (record <= ri->end_record) {
523 return ri->record_size;
528 * For historical reasons, the default record size is 32 KBytes.
529 * This allows us to read files written by Amanda with that block
530 * size before the record information was being kept.
536 * Update the record information. We assume the record information is
537 * sorted, does not overlap and does not have gaps.
542 struct file_info * fi,
547 struct record_info *ri;
548 struct record_info **ri_p;
551 if (record == (off_t)0) {
552 fi->ri_count = 0; /* start over */
554 for(r = 0; r < fi->ri_count; r++) {
556 if ((record - (off_t)1) <= ri->end_record) {
558 * If this record is the same size as the rest of the records
559 * in this entry, or it would replace the entire entry,
560 * reset the end record number and size, then zap the chain
563 if (record == ri->start_record || ri->record_size == size) {
564 ri->end_record = record;
565 ri->record_size = size;
566 fi->ri_count = r + 1;
570 * This record needs a new entry right after the current one.
572 ri->end_record = record - (off_t)1;
573 fi->ri_count = r + 1;
581 amtable_alloc((void **)ri_p,
584 (size_t)fi->ri_count + 1,
587 ri = &fi->ri[fi->ri_count];
588 ri->start_record = record;
589 ri->end_record = record;
590 ri->record_size = size;
595 * The normal interface routines ...
607 struct volume_info **volume_info_p = &volume_info;
610 * Use only O_RDONLY and O_RDWR.
612 if ((flags & 3) != O_RDONLY) {
618 * If the caller did not set O_CREAT (and thus, pass a mask
619 * parameter), we may still end up creating data files and need a
620 * "reasonable" value. Pick a "tight" value on the "better safe
621 * than sorry" theory.
623 if ((flags & O_CREAT) == 0) {
628 * Open/create the info file for this "tape".
630 info_file = stralloc2(filename, "/info");
631 if ((fd = open(info_file, O_RDWR|O_CREAT, 0600)) < 0) {
636 * Create the internal info structure for this "tape".
638 amtable_alloc((void **)volume_info_p,
640 SIZEOF(*volume_info),
644 volume_info[fd].flags = flags;
645 volume_info[fd].mask = mask;
646 volume_info[fd].file_count = 0;
647 volume_info[fd].file_current = 0;
648 volume_info[fd].record_current = (off_t)0;
649 volume_info[fd].fd = -1;
650 volume_info[fd].is_online = 0; /* true when .../data found */
651 volume_info[fd].at_bof = 1; /* by definition */
652 volume_info[fd].at_eof = 0; /* do not know yet */
653 volume_info[fd].at_eom = 0; /* may get reset below */
654 volume_info[fd].last_operation_write = 0;
655 volume_info[fd].amount_written = (off_t)0;
658 * Save the base directory name and see if we are "online".
660 volume_info[fd].basename = stralloc2(filename, "/data/");
661 if (check_online(fd)) {
665 amfree(volume_info[fd].basename);
675 * Return the info file descriptor as the unique descriptor for
694 * Make sure we are online.
696 if (check_online(fd) != 0) {
699 if (! volume_info[fd].is_online) {
705 * Do not allow any more reads after we find EOF.
707 if (volume_info[fd].at_eof) {
713 * If we are at EOM, set EOF and return a zero length result.
715 if (volume_info[fd].at_eom) {
716 volume_info[fd].at_eof = 1;
721 * Open the file, if needed.
723 if ((file_fd = file_open(fd)) < 0) {
728 * Make sure we do not read too much.
730 pos = volume_info[fd].file_current;
731 record_size = get_record_size(&volume_info[fd].fi[pos],
732 volume_info[fd].record_current);
733 if (record_size <= count) {
734 read_size = record_size;
740 * Read the data. If we ask for less than the record size, skip to
741 * the next record boundary.
743 result = read(file_fd, buffer, read_size);
745 volume_info[fd].at_bof = 0;
746 if ((size_t)result < record_size) {
747 if (lseek(file_fd, (off_t)(record_size-result), SEEK_CUR) == (off_t)-1) {
748 dbprintf(_("file_tapefd_read: lseek failed: <%s>\n"),
752 volume_info[fd].record_current += (off_t)1;
753 } else if (result == 0) {
754 volume_info[fd].at_eof = 1;
766 ssize_t write_count = (ssize_t)count;
773 * Make sure we are online.
775 if (check_online(fd) != 0) {
778 if (! volume_info[fd].is_online) {
784 * Check for write access first.
786 if ((volume_info[fd].flags & 3) == O_RDONLY) {
792 * Special case: allow negative buffer size.
794 if (write_count <= 0) {
795 return 0; /* special case */
799 * If we are at EOM, it takes precedence over EOF.
801 if (volume_info[fd].at_eom) {
802 volume_info[fd].at_eof = 0;
807 * Writes are only allowed at BOF and EOM.
809 if (! (volume_info[fd].at_bof || volume_info[fd].at_eom)) {
816 * Writes are only allowed if we are not at EOF.
818 if (volume_info[fd].at_eof) {
824 * Open the file, if needed.
826 if((file_fd = volume_info[fd].fd) < 0) {
828 if ((file_fd = file_open(fd)) < 0) {
834 * Truncate the write if requested and return a simulated ENOSPC.
836 if ((length = tapefd_getinfo_length(fd)) > (off_t)0) {
837 kbytes_left = length - volume_info[fd].amount_written;
838 if ((off_t)(write_count / 1024) > kbytes_left) {
839 write_count = (ssize_t)kbytes_left * 1024;
842 volume_info[fd].amount_written += (off_t)((write_count + 1023) / 1024);
843 if (write_count <= 0) {
844 volume_info[fd].at_bof = 0;
845 volume_info[fd].at_eom = 1;
851 * Do the write and truncate the file, if needed. Checking for
852 * last_operation_write is an optimization so we only truncate
855 if (! volume_info[fd].last_operation_write) {
858 if ((curpos = lseek(file_fd, (off_t)0, SEEK_CUR)) < 0) {
859 dbprintf(_(": Can not determine current file position <%s>"),
863 if (ftruncate(file_fd, curpos) != 0) {
864 dbprintf(_("ftruncate failed; Can not trim output file <%s>"),
868 volume_info[fd].at_bof = 0;
869 volume_info[fd].at_eom = 1;
871 result = fullwrite(file_fd, buffer, (size_t)write_count);
873 volume_info[fd].last_operation_write = 1;
874 pos = volume_info[fd].file_current;
875 put_record_size(&volume_info[fd].fi[pos],
876 volume_info[fd].record_current,
878 volume_info[fd].record_current += (off_t)1;
893 struct file_info **fi_p;
894 struct record_info **ri_p;
897 * If our last operation was a write, write a tapemark.
899 if (volume_info[fd].last_operation_write) {
900 if ((result = (ssize_t)file_tapefd_weof(fd, (off_t)1)) != 0) {
906 * If we are not at BOF, fsf to the next file unless we
907 * are already at end of tape.
909 if (! volume_info[fd].at_bof && ! volume_info[fd].at_eom) {
910 if ((result = (ssize_t)file_tapefd_fsf(fd, (off_t)1)) != 0) {
916 * Close the file if it is still open.
921 * Release the info structure areas.
923 for (pos = 0; pos < (off_t)volume_info[fd].fi_limit; pos++) {
924 amfree(volume_info[fd].fi[pos].name);
925 ri_p = &volume_info[fd].fi[pos].ri;
926 amtable_free((void **)ri_p,
927 &volume_info[fd].fi[pos].ri_limit);
928 volume_info[fd].fi[pos].ri_count = 0;
930 fi_p = &volume_info[fd].fi;
931 amtable_free((void **)fi_p, &volume_info[fd].fi_limit);
932 volume_info[fd].file_count = 0;
933 amfree(volume_info[fd].basename);
936 * Update the status file if we were online.
938 if (volume_info[fd].is_online) {
939 if (lseek(fd, (off_t)0, SEEK_SET) != (off_t)0) {
945 if (ftruncate(fd, (off_t)0) != 0) {
951 line = vstrallocf("position %05lld\n",
952 (long long)volume_info[fd].file_current);
954 result = write(fd, line, len);
956 if (result != (ssize_t)len) {
972 file_tapefd_resetofs(
975 (void)fd; /* Quiet unused parameter warning */
981 struct am_mt_status *stat)
986 * See if we are online.
988 if ((result = check_online(fd)) != 0) {
991 memset((void *)stat, 0, SIZEOF(*stat));
992 stat->online_valid = 1;
993 stat->online = (char)volume_info[fd].is_online;
1002 return stat(filename, buf);
1010 return access(filename, mode);
1020 * Make sure we are online.
1022 if ((result = check_online(fd)) != 0) {
1025 if (! volume_info[fd].is_online) {
1031 * If our last operation was a write, write a tapemark.
1033 if (volume_info[fd].last_operation_write) {
1034 if ((result = file_tapefd_weof(fd, (off_t)1)) != 0) {
1040 * Close the file if it is still open.
1045 * Adjust the position and reset the flags.
1047 volume_info[fd].file_current = 0;
1048 volume_info[fd].record_current = (off_t)0;
1050 volume_info[fd].at_bof = 1;
1051 volume_info[fd].at_eof = 0;
1052 volume_info[fd].at_eom
1053 = (volume_info[fd].file_current >= volume_info[fd].file_count);
1054 volume_info[fd].last_operation_write = 0;
1055 volume_info[fd].amount_written = (off_t)0;
1067 * Make sure we are online.
1069 if ((result = check_online(fd)) != 0) {
1072 if (! volume_info[fd].is_online) {
1077 (void)file_tapefd_rewind(fd);
1089 * Make sure we are online.
1091 if ((result = check_online(fd)) != 0) {
1094 if (! volume_info[fd].is_online) {
1100 * If our last operation was a write and we are going to move
1101 * backward, write a tapemark.
1103 if (volume_info[fd].last_operation_write && count < 0) {
1104 if ((result = file_tapefd_weof(fd, (off_t)1)) != 0) {
1111 * Close the file if it is still open.
1116 * If we are at EOM and moving backward, adjust the count to go
1119 if (volume_info[fd].at_eom && count < 0) {
1124 * Adjust the position and return an error if we go beyond either
1127 volume_info[fd].file_current += count;
1128 if (volume_info[fd].file_current > volume_info[fd].file_count) {
1129 volume_info[fd].file_current = volume_info[fd].file_count;
1132 } else if (volume_info[fd].file_current < 0) {
1133 volume_info[fd].file_current = 0;
1137 volume_info[fd].record_current = (off_t)0;
1140 * Set BOF to true so we can write. Set to EOF to false if the
1141 * fsf succeeded or if it failed but we were moving backward (and
1142 * thus we are at beginning of tape), otherwise set it to true so
1143 * a subsequent read will fail. Set EOM to whatever is right.
1144 * Reset amount_written if we ended up back at BOM.
1146 volume_info[fd].at_bof = 1;
1147 if (result == 0 || count < 0) {
1148 volume_info[fd].at_eof = 0;
1150 volume_info[fd].at_eof = 1;
1152 volume_info[fd].at_eom
1153 = (volume_info[fd].file_current >= volume_info[fd].file_count);
1154 volume_info[fd].last_operation_write = 0;
1155 if (volume_info[fd].file_current == 0) {
1156 volume_info[fd].amount_written = (off_t)0;
1175 * Make sure we are online.
1177 if ((result = check_online(fd)) != 0) {
1180 if (! volume_info[fd].is_online) {
1186 * Check for write access first.
1188 if ((volume_info[fd].flags & 3) == O_RDONLY) {
1194 * Special case: allow a zero count.
1197 return 0; /* special case */
1201 * Disallow negative count.
1209 * Close out the current file if open.
1211 if ((file_fd = volume_info[fd].fd) >= 0) {
1214 if ((curpos = lseek(file_fd, (off_t)0, SEEK_CUR)) < 0) {
1216 dbprintf(_(": Can not determine current file position <%s>"),
1222 if (ftruncate(file_fd, curpos) != 0) {
1224 dbprintf(_("ftruncate failed; Can not trim output file <%s>"),
1232 volume_info[fd].file_current++;
1233 volume_info[fd].record_current = (off_t)0;
1234 volume_info[fd].at_bof = 1;
1235 volume_info[fd].at_eof = 0;
1236 volume_info[fd].at_eom = 1;
1237 volume_info[fd].last_operation_write = 0;
1242 * Release any data files from current through the end.
1247 * Save any labelling information in case we clobber it.
1249 if ((save_host = tapefd_getinfo_host(fd)) != NULL) {
1250 save_host = stralloc(save_host);
1252 if ((save_disk = tapefd_getinfo_disk(fd)) != NULL) {
1253 save_disk = stralloc(save_disk);
1255 save_level = tapefd_getinfo_level(fd);
1258 * Add more tapemarks.
1260 while (--count >= 0) {
1261 if (file_open(fd) < 0) {
1265 volume_info[fd].file_current++;
1266 volume_info[fd].file_count = volume_info[fd].file_current;
1267 volume_info[fd].record_current = (off_t)0;
1268 volume_info[fd].at_bof = 1;
1269 volume_info[fd].at_eof = 0;
1270 volume_info[fd].at_eom = 1;
1271 volume_info[fd].last_operation_write = 0;
1274 * Only the first "file" terminated by an EOF gets the naming
1275 * information from the caller.
1277 tapefd_setinfo_host(fd, NULL);
1278 tapefd_setinfo_disk(fd, NULL);
1279 tapefd_setinfo_level(fd, -1);
1283 * Restore the labelling information.
1286 tapefd_setinfo_host(fd, save_host);
1288 tapefd_setinfo_disk(fd, save_disk);
1290 tapefd_setinfo_level(fd, save_level);
1297 file_tapefd_can_fork(
1300 (void)fd; /* Quiet unused parameter warning */