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
29 * $Id: output-file.c,v 1.14 2006/07/06 15:04:18 martinea Exp $
31 * tapeio.c virtual tape interface for a file device.
33 * The following was based on testing with real tapes on Solaris 2.6.
34 * It is possible other OS drivers behave somewhat different in end
35 * cases, usually involving errors.
42 #include "output-file.h"
43 #include "fileheader.h"
57 #define DATA_INDICATOR "."
58 #define RECORD_INDICATOR "-"
62 char *basename; /* filename from open */
63 struct file_info *fi; /* file info array */
64 size_t fi_limit; /* length of file info array */
65 int flags; /* open flags */
66 mode_t mask; /* open mask */
67 off_t file_count; /* number of files */
68 off_t file_current; /* current file position */
69 off_t record_current; /* current record position */
70 int fd; /* data file descriptor */
71 int is_online; /* true if "tape" is "online" */
72 int at_bof; /* true if at begining of file */
73 int at_eof; /* true if at end of file */
74 int at_eom; /* true if at end of medium */
75 int last_operation_write; /* true if last op was a write */
76 off_t amount_written; /* KBytes written since open/rewind */
77 } *volume_info = NULL;
80 char *name; /* file name (tapefd_getinfo_...) */
81 struct record_info *ri; /* record info array */
82 size_t ri_count; /* number of record info entries */
83 size_t ri_limit; /* length of record info array */
84 int ri_altered; /* true if record info altered */
88 size_t record_size; /* record size */
89 off_t start_record; /* first record in range */
90 off_t end_record; /* last record in range */
93 static size_t open_count = 0;
95 static int check_online(int fd);
96 static int file_open(int fd);
97 static void file_close(int fd);
98 static void file_release(int fd);
99 static size_t get_record_size(struct file_info *fi, off_t record);
100 static void put_record_size(struct file_info *fi, off_t record, size_t size);
103 * "Open" the tape by scanning the "data" directory. "Tape files"
104 * have five leading digits indicating the position (counting from zero)
105 * followed by a '.' and optional other information (e.g. host/disk/level
108 * We allow for the following situations:
110 * + If we see the same "file" (position number) more than once, the
111 * last one seen wins. This should not normally happen.
113 * + We allow gaps in the positions. This should not normally happen.
115 * Anything in the directory that does not match a "tape file" name
116 * pattern is ignored.
118 * If the data directory does not exist, the "tape" is considered offline.
119 * It is allowed to "appear" later.
126 char *token[MAX_TOKENS];
128 struct dirent *entry;
129 struct file_info *fi;
130 struct file_info **fi_p;
135 char *qname = quote_string(volume_info[fd].basename);
138 * If we are already online, there is nothing else to do.
140 if (volume_info[fd].is_online) {
144 if ((tapedir = opendir(volume_info[fd].basename)) == NULL) {
146 * We have already opened the info file which is in the same
147 * directory as the data directory, so ENOENT has to mean the data
148 * directory is not there, which we treat as being "offline".
149 * We're already offline at this point (see the above test)
150 * and this is not an error, so just return success (no error).
153 rc = (errno != ENOENT);
154 fprintf(stderr,"ERROR: %s (%s)\n", qname, strerror(errno));
157 while ((entry = readdir(tapedir)) != NULL) {
158 if (is_dot_or_dotdot(entry->d_name)) {
161 if (isdigit((int)entry->d_name[0])
162 && isdigit((int)entry->d_name[1])
163 && isdigit((int)entry->d_name[2])
164 && isdigit((int)entry->d_name[3])
165 && isdigit((int)entry->d_name[4])
166 && entry->d_name[5] == '.') {
169 * This is a "tape file".
171 pos = OFF_T_ATOI(entry->d_name);
172 assert((pos + 1) <= (off_t)SSIZE_MAX);
173 fi_p = &volume_info[fd].fi;
174 amtable_alloc((void **)fi_p,
175 &volume_info[fd].fi_limit,
176 SIZEOF(*volume_info[fd].fi),
180 fi = &volume_info[fd].fi[pos];
181 if (fi->name != NULL) {
183 * Two files with the same position???
188 fi->name = stralloc(&entry->d_name[6]);
189 if ((pos + 1) > volume_info[fd].file_count) {
190 volume_info[fd].file_count = (pos + 1);
197 * Parse the info file. We know we are at beginning of file because
198 * the only thing that can happen to it prior to here is it being
201 for (; (line = areads(fd)) != NULL; free(line)) {
202 f = split(line, token, (int)(sizeof(token) / sizeof(token[0])), " ");
203 if (f == 2 && strcmp(token[1], "position") == 0) {
204 volume_info[fd].file_current = OFF_T_ATOI(token[2]);
205 volume_info[fd].record_current = (off_t)0;
210 * Set EOM and make sure we are not pre-BOI.
212 if (volume_info[fd].file_current >= volume_info[fd].file_count) {
213 volume_info[fd].at_eom = 1;
215 if (volume_info[fd].file_current < 0) {
216 volume_info[fd].file_current = 0;
217 volume_info[fd].record_current = (off_t)0;
220 volume_info[fd].is_online = 1;
229 * Open the tape file if not already. If we are beyond the file count
230 * (end of tape) or the file is missing and we are only reading, set
231 * up to read /dev/null which will look like EOF. If we are writing,
239 struct file_info *fi;
240 struct file_info **fi_p;
241 char *datafilename = NULL;
242 char *recordfilename = NULL;
248 char number[NUM_STR_SIZE];
253 struct record_info *ri;
254 struct record_info **ri_p;
257 size_t record_size = 0;
259 if (volume_info[fd].fd < 0) {
260 flags = volume_info[fd].flags;
261 pos = volume_info[fd].file_current;
262 assert((pos + 1) < (off_t)SSIZE_MAX);
263 fi_p = &volume_info[fd].fi;
264 amtable_alloc((void **)fi_p,
265 &volume_info[fd].fi_limit,
266 SIZEOF(*volume_info[fd].fi),
270 fi = &volume_info[fd].fi[pos];
273 * See if we are creating a new file.
275 if (pos >= volume_info[fd].file_count) {
276 volume_info[fd].file_count = pos + 1;
280 * Generate the file name to open.
282 if (fi->name == NULL) {
283 if ((volume_info[fd].flags & 3) != O_RDONLY) {
286 * This is a new file, so make sure we create/truncate
287 * it. Generate the name based on the host/disk/level
288 * information from the caller, if available, else
291 flags |= (O_CREAT | O_TRUNC);
292 host = tapefd_getinfo_host(fd);
293 disk = tapefd_getinfo_disk(fd);
294 level = tapefd_getinfo_level(fd);
295 snprintf(number, SIZEOF(number), "%d", level);
300 disk = sanitise_filename(disk);
304 vstrextend(&f, ".", disk, NULL);
310 f = stralloc(number);
312 vstrextend(&f, ".", number, NULL);
316 f = stralloc("unknown");
319 fi->name = stralloc(f);
325 * This is a missing file, so set up to read nothing.
327 datafilename = stralloc("/dev/null");
328 recordfilename = stralloc("/dev/null");
331 if (datafilename == NULL) {
332 snprintf(number, SIZEOF(number),
333 "%05" OFF_T_RFMT, (OFF_T_FMT_TYPE)pos);
334 datafilename = vstralloc(volume_info[fd].basename,
337 volume_info[fd].fi[pos].name,
339 recordfilename = vstralloc(volume_info[fd].basename,
342 volume_info[fd].fi[pos].name,
347 * Do the data file open.
349 volume_info[fd].fd = open(datafilename, flags, volume_info[fd].mask);
350 amfree(datafilename);
353 * Load the record information.
355 if (volume_info[fd].fd >= 0 && fi->ri_count == 0 &&
356 (rfd = open(recordfilename, O_RDONLY)) >= 0) {
357 for (; (line = areads(rfd)) != NULL; free(line)) {
359 OFF_T_FMT " " OFF_T_FMT " " SIZE_T_FMT,
360 (OFF_T_FMT_TYPE *)&start_record,
361 (OFF_T_FMT_TYPE *)&end_record,
362 (SIZE_T_FMT_TYPE *)&record_size);
365 amtable_alloc((void **)ri_p,
368 (size_t)fi->ri_count + 1,
371 ri = &fi->ri[fi->ri_count];
372 ri->start_record = start_record;
373 ri->end_record = end_record;
374 ri->record_size = record_size;
380 amfree(recordfilename);
382 return volume_info[fd].fd;
386 * Close the current data file, if open. Dump the record information
387 * if it has been altered.
394 struct file_info *fi;
395 struct file_info **fi_p;
397 char number[NUM_STR_SIZE];
398 char *filename = NULL;
402 aclose(volume_info[fd].fd);
403 pos = volume_info[fd].file_current;
404 assert((pos + 1) < (off_t)SSIZE_MAX);
405 fi_p = &volume_info[fd].fi;
406 amtable_alloc((void **)fi_p,
407 &volume_info[fd].fi_limit,
408 SIZEOF(*volume_info[fd].fi),
412 fi = &volume_info[fd].fi[pos];
413 if (fi->ri_altered) {
414 snprintf(number, SIZEOF(number),
415 "%05" OFF_T_RFMT, (OFF_T_FMT_TYPE)pos);
416 filename = vstralloc(volume_info[fd].basename,
421 if ((f = fopen(filename, "w")) == NULL) {
424 for (r = 0; r < fi->ri_count; r++) {
425 fprintf(f, OFF_T_FMT " " OFF_T_FMT " " SIZE_T_FMT "\n",
426 (OFF_T_FMT_TYPE)fi->ri[r].start_record,
427 (OFF_T_FMT_TYPE)fi->ri[r].end_record,
428 (SIZE_T_FMT_TYPE)fi->ri[r].record_size);
440 * Release any files beyond a given position current position and reset
441 * file_count to file_current to indicate EOM.
451 char number[NUM_STR_SIZE];
452 struct file_info **fi_p;
455 * If the current file is open, release everything beyond it.
456 * If it is not open, release everything from current.
458 if (volume_info[fd].fd >= 0) {
459 position = volume_info[fd].file_current + 1;
461 position = volume_info[fd].file_current;
463 for (pos = position; pos < volume_info[fd].file_count; pos++) {
464 assert(pos < (off_t)SSIZE_MAX);
465 fi_p = &volume_info[fd].fi;
466 amtable_alloc((void **)fi_p,
467 &volume_info[fd].fi_limit,
468 SIZEOF(*volume_info[fd].fi),
472 if (volume_info[fd].fi[pos].name != NULL) {
473 snprintf(number, SIZEOF(number),
474 "%05" OFF_T_RFMT, (OFF_T_FMT_TYPE)pos);
475 filename = vstralloc(volume_info[fd].basename,
478 volume_info[fd].fi[pos].name,
482 filename = vstralloc(volume_info[fd].basename,
485 volume_info[fd].fi[pos].name,
489 amfree(volume_info[fd].fi[pos].name);
490 volume_info[fd].fi[pos].ri_count = 0;
493 volume_info[fd].file_count = position;
497 * Get the size of a particular record. We assume the record information is
498 * sorted, does not overlap and does not have gaps.
503 struct file_info * fi,
507 struct record_info *ri;
509 for(r = 0; r < fi->ri_count; r++) {
511 if (record <= ri->end_record) {
512 return ri->record_size;
517 * For historical reasons, the default record size is 32 KBytes.
518 * This allows us to read files written by Amanda with that block
519 * size before the record information was being kept.
525 * Update the record information. We assume the record information is
526 * sorted, does not overlap and does not have gaps.
531 struct file_info * fi,
536 struct record_info *ri;
537 struct record_info **ri_p;
540 if (record == (off_t)0) {
541 fi->ri_count = 0; /* start over */
543 for(r = 0; r < fi->ri_count; r++) {
545 if ((record - (off_t)1) <= ri->end_record) {
547 * If this record is the same size as the rest of the records
548 * in this entry, or it would replace the entire entry,
549 * reset the end record number and size, then zap the chain
552 if (record == ri->start_record || ri->record_size == size) {
553 ri->end_record = record;
554 ri->record_size = size;
555 fi->ri_count = r + 1;
559 * This record needs a new entry right after the current one.
561 ri->end_record = record - (off_t)1;
562 fi->ri_count = r + 1;
570 amtable_alloc((void **)ri_p,
573 (size_t)fi->ri_count + 1,
576 ri = &fi->ri[fi->ri_count];
577 ri->start_record = record;
578 ri->end_record = record;
579 ri->record_size = size;
584 * The normal interface routines ...
596 struct volume_info **volume_info_p = &volume_info;
599 * Use only O_RDONLY and O_RDWR.
601 if ((flags & 3) != O_RDONLY) {
607 * If the caller did not set O_CREAT (and thus, pass a mask
608 * parameter), we may still end up creating data files and need a
609 * "reasonable" value. Pick a "tight" value on the "better safe
610 * than sorry" theory.
612 if ((flags & O_CREAT) == 0) {
617 * Open/create the info file for this "tape".
619 info_file = stralloc2(filename, "/info");
620 if ((fd = open(info_file, O_RDWR|O_CREAT, 0600)) < 0) {
625 * Create the internal info structure for this "tape".
627 amtable_alloc((void **)volume_info_p,
629 SIZEOF(*volume_info),
633 volume_info[fd].flags = flags;
634 volume_info[fd].mask = mask;
635 volume_info[fd].file_count = 0;
636 volume_info[fd].file_current = 0;
637 volume_info[fd].record_current = (off_t)0;
638 volume_info[fd].fd = -1;
639 volume_info[fd].is_online = 0; /* true when .../data found */
640 volume_info[fd].at_bof = 1; /* by definition */
641 volume_info[fd].at_eof = 0; /* do not know yet */
642 volume_info[fd].at_eom = 0; /* may get reset below */
643 volume_info[fd].last_operation_write = 0;
644 volume_info[fd].amount_written = (off_t)0;
647 * Save the base directory name and see if we are "online".
649 volume_info[fd].basename = stralloc2(filename, "/data/");
650 if (check_online(fd)) {
654 amfree(volume_info[fd].basename);
664 * Return the info file descriptor as the unique descriptor for
683 * Make sure we are online.
685 if (check_online(fd) != 0) {
688 if (! volume_info[fd].is_online) {
694 * Do not allow any more reads after we find EOF.
696 if (volume_info[fd].at_eof) {
702 * If we are at EOM, set EOF and return a zero length result.
704 if (volume_info[fd].at_eom) {
705 volume_info[fd].at_eof = 1;
710 * Open the file, if needed.
712 if ((file_fd = file_open(fd)) < 0) {
717 * Make sure we do not read too much.
719 pos = volume_info[fd].file_current;
720 record_size = get_record_size(&volume_info[fd].fi[pos],
721 volume_info[fd].record_current);
722 if (record_size <= count) {
723 read_size = record_size;
729 * Read the data. If we ask for less than the record size, skip to
730 * the next record boundary.
732 result = read(file_fd, buffer, read_size);
734 volume_info[fd].at_bof = 0;
735 if ((size_t)result < record_size) {
736 if (lseek(file_fd, (off_t)(record_size-result), SEEK_CUR) == (off_t)-1) {
737 dbprintf(("file_tapefd_read: lseek failed: <%s>\n",
741 volume_info[fd].record_current += (off_t)1;
742 } else if (result == 0) {
743 volume_info[fd].at_eof = 1;
755 ssize_t write_count = (ssize_t)count;
762 * Make sure we are online.
764 if (check_online(fd) != 0) {
767 if (! volume_info[fd].is_online) {
773 * Check for write access first.
775 if ((volume_info[fd].flags & 3) == O_RDONLY) {
781 * Special case: allow negative buffer size.
783 if (write_count <= 0) {
784 return 0; /* special case */
788 * If we are at EOM, it takes precedence over EOF.
790 if (volume_info[fd].at_eom) {
791 volume_info[fd].at_eof = 0;
796 * Writes are only allowed at BOF and EOM.
798 if (! (volume_info[fd].at_bof || volume_info[fd].at_eom)) {
805 * Writes are only allowed if we are not at EOF.
807 if (volume_info[fd].at_eof) {
813 * Open the file, if needed.
815 if((file_fd = volume_info[fd].fd) < 0) {
817 if ((file_fd = file_open(fd)) < 0) {
823 * Truncate the write if requested and return a simulated ENOSPC.
825 if ((length = tapefd_getinfo_length(fd)) > (off_t)0) {
826 kbytes_left = length - volume_info[fd].amount_written;
827 if ((off_t)(write_count / 1024) > kbytes_left) {
828 write_count = (ssize_t)kbytes_left * 1024;
831 volume_info[fd].amount_written += (off_t)((write_count + 1023) / 1024);
832 if (write_count <= 0) {
833 volume_info[fd].at_bof = 0;
834 volume_info[fd].at_eom = 1;
840 * Do the write and truncate the file, if needed. Checking for
841 * last_operation_write is an optimization so we only truncate
844 if (! volume_info[fd].last_operation_write) {
847 if ((curpos = lseek(file_fd, (off_t)0, SEEK_CUR)) < 0) {
848 dbprintf((": Can not determine current file position <%s>",
852 if (ftruncate(file_fd, curpos) != 0) {
853 dbprintf(("ftruncate failed; Can not trim output file <%s>",
857 volume_info[fd].at_bof = 0;
858 volume_info[fd].at_eom = 1;
860 result = fullwrite(file_fd, buffer, (size_t)write_count);
862 volume_info[fd].last_operation_write = 1;
863 pos = volume_info[fd].file_current;
864 put_record_size(&volume_info[fd].fi[pos],
865 volume_info[fd].record_current,
867 volume_info[fd].record_current += (off_t)1;
881 char number[NUM_STR_SIZE];
883 struct file_info **fi_p;
884 struct record_info **ri_p;
887 * If our last operation was a write, write a tapemark.
889 if (volume_info[fd].last_operation_write) {
890 if ((result = (ssize_t)file_tapefd_weof(fd, (off_t)1)) != 0) {
896 * If we are not at BOF, fsf to the next file unless we
897 * are already at end of tape.
899 if (! volume_info[fd].at_bof && ! volume_info[fd].at_eom) {
900 if ((result = (ssize_t)file_tapefd_fsf(fd, (off_t)1)) != 0) {
906 * Close the file if it is still open.
911 * Release the info structure areas.
913 for (pos = 0; pos < (off_t)volume_info[fd].fi_limit; pos++) {
914 amfree(volume_info[fd].fi[pos].name);
915 ri_p = &volume_info[fd].fi[pos].ri;
916 amtable_free((void **)ri_p,
917 &volume_info[fd].fi[pos].ri_limit);
918 volume_info[fd].fi[pos].ri_count = 0;
920 fi_p = &volume_info[fd].fi;
921 amtable_free((void **)fi_p, &volume_info[fd].fi_limit);
922 volume_info[fd].file_count = 0;
923 amfree(volume_info[fd].basename);
926 * Update the status file if we were online.
928 if (volume_info[fd].is_online) {
929 if (lseek(fd, (off_t)0, SEEK_SET) != (off_t)0) {
935 if (ftruncate(fd, (off_t)0) != 0) {
941 snprintf(number, SIZEOF(number), "%05" OFF_T_RFMT,
942 (OFF_T_FMT_TYPE)volume_info[fd].file_current);
943 line = vstralloc("position ", number, "\n", NULL);
945 result = write(fd, line, len);
947 if (result != (ssize_t)len) {
963 file_tapefd_resetofs(
966 (void)fd; /* Quiet unused parameter warning */
972 struct am_mt_status *stat)
977 * See if we are online.
979 if ((result = check_online(fd)) != 0) {
982 memset((void *)stat, 0, SIZEOF(*stat));
983 stat->online_valid = 1;
984 stat->online = (char)volume_info[fd].is_online;
993 return stat(filename, buf);
1001 return access(filename, mode);
1011 * Make sure we are online.
1013 if ((result = check_online(fd)) != 0) {
1016 if (! volume_info[fd].is_online) {
1022 * If our last operation was a write, write a tapemark.
1024 if (volume_info[fd].last_operation_write) {
1025 if ((result = file_tapefd_weof(fd, (off_t)1)) != 0) {
1031 * Close the file if it is still open.
1036 * Adjust the position and reset the flags.
1038 volume_info[fd].file_current = 0;
1039 volume_info[fd].record_current = (off_t)0;
1041 volume_info[fd].at_bof = 1;
1042 volume_info[fd].at_eof = 0;
1043 volume_info[fd].at_eom
1044 = (volume_info[fd].file_current >= volume_info[fd].file_count);
1045 volume_info[fd].last_operation_write = 0;
1046 volume_info[fd].amount_written = (off_t)0;
1058 * Make sure we are online.
1060 if ((result = check_online(fd)) != 0) {
1063 if (! volume_info[fd].is_online) {
1068 (void)file_tapefd_rewind(fd);
1080 * Make sure we are online.
1082 if ((result = check_online(fd)) != 0) {
1085 if (! volume_info[fd].is_online) {
1091 * If our last operation was a write and we are going to move
1092 * backward, write a tapemark.
1094 if (volume_info[fd].last_operation_write && count < 0) {
1095 if ((result = file_tapefd_weof(fd, (off_t)1)) != 0) {
1102 * Close the file if it is still open.
1107 * If we are at EOM and moving backward, adjust the count to go
1110 if (volume_info[fd].at_eom && count < 0) {
1115 * Adjust the position and return an error if we go beyond either
1118 volume_info[fd].file_current += count;
1119 if (volume_info[fd].file_current > volume_info[fd].file_count) {
1120 volume_info[fd].file_current = volume_info[fd].file_count;
1123 } else if (volume_info[fd].file_current < 0) {
1124 volume_info[fd].file_current = 0;
1128 volume_info[fd].record_current = (off_t)0;
1131 * Set BOF to true so we can write. Set to EOF to false if the
1132 * fsf succeeded or if it failed but we were moving backward (and
1133 * thus we are at beginning of tape), otherwise set it to true so
1134 * a subsequent read will fail. Set EOM to whatever is right.
1135 * Reset amount_written if we ended up back at BOM.
1137 volume_info[fd].at_bof = 1;
1138 if (result == 0 || count < 0) {
1139 volume_info[fd].at_eof = 0;
1141 volume_info[fd].at_eof = 1;
1143 volume_info[fd].at_eom
1144 = (volume_info[fd].file_current >= volume_info[fd].file_count);
1145 volume_info[fd].last_operation_write = 0;
1146 if (volume_info[fd].file_current == 0) {
1147 volume_info[fd].amount_written = (off_t)0;
1166 * Make sure we are online.
1168 if ((result = check_online(fd)) != 0) {
1171 if (! volume_info[fd].is_online) {
1177 * Check for write access first.
1179 if ((volume_info[fd].flags & 3) == O_RDONLY) {
1185 * Special case: allow a zero count.
1188 return 0; /* special case */
1192 * Disallow negative count.
1200 * Close out the current file if open.
1202 if ((file_fd = volume_info[fd].fd) >= 0) {
1205 if ((curpos = lseek(file_fd, (off_t)0, SEEK_CUR)) < 0) {
1207 dbprintf((": Can not determine current file position <%s>",
1213 if (ftruncate(file_fd, curpos) != 0) {
1215 dbprintf(("ftruncate failed; Can not trim output file <%s>",
1223 volume_info[fd].file_current++;
1224 volume_info[fd].record_current = (off_t)0;
1225 volume_info[fd].at_bof = 1;
1226 volume_info[fd].at_eof = 0;
1227 volume_info[fd].at_eom = 1;
1228 volume_info[fd].last_operation_write = 0;
1233 * Release any data files from current through the end.
1238 * Save any labelling information in case we clobber it.
1240 if ((save_host = tapefd_getinfo_host(fd)) != NULL) {
1241 save_host = stralloc(save_host);
1243 if ((save_disk = tapefd_getinfo_disk(fd)) != NULL) {
1244 save_disk = stralloc(save_disk);
1246 save_level = tapefd_getinfo_level(fd);
1249 * Add more tapemarks.
1251 while (--count >= 0) {
1252 if (file_open(fd) < 0) {
1256 volume_info[fd].file_current++;
1257 volume_info[fd].file_count = volume_info[fd].file_current;
1258 volume_info[fd].record_current = (off_t)0;
1259 volume_info[fd].at_bof = 1;
1260 volume_info[fd].at_eof = 0;
1261 volume_info[fd].at_eom = 1;
1262 volume_info[fd].last_operation_write = 0;
1265 * Only the first "file" terminated by an EOF gets the naming
1266 * information from the caller.
1268 tapefd_setinfo_host(fd, NULL);
1269 tapefd_setinfo_disk(fd, NULL);
1270 tapefd_setinfo_level(fd, -1);
1274 * Restore the labelling information.
1277 tapefd_setinfo_host(fd, save_host);
1279 tapefd_setinfo_disk(fd, save_disk);
1281 tapefd_setinfo_level(fd, save_level);
1288 file_tapefd_can_fork(
1291 (void)fd; /* Quiet unused parameter warning */