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.2.1 2006/11/20 22:34:39 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)) {
358 /* We play this game because OFF_T_FMT_TYPE is not
359 necessarily the same as off_t, and we need to cast the
360 actual value (not just the pointer. */
361 OFF_T_FMT_TYPE start_record_ = (OFF_T_FMT_TYPE)0;
362 OFF_T_FMT_TYPE end_record_ = (OFF_T_FMT_TYPE)0;
363 n = sscanf(line, OFF_T_FMT " " OFF_T_FMT " " SIZE_T_FMT,
364 &start_record_, &end_record_, &record_size);
365 start_record = start_record_;
366 end_record = end_record_;
370 amtable_alloc((void **)ri_p,
373 (size_t)fi->ri_count + 1,
376 ri = &fi->ri[fi->ri_count];
377 ri->start_record = start_record;
378 ri->end_record = end_record;
379 ri->record_size = record_size;
385 amfree(recordfilename);
387 return volume_info[fd].fd;
391 * Close the current data file, if open. Dump the record information
392 * if it has been altered.
399 struct file_info *fi;
400 struct file_info **fi_p;
402 char number[NUM_STR_SIZE];
403 char *filename = NULL;
407 aclose(volume_info[fd].fd);
408 pos = volume_info[fd].file_current;
409 assert((pos + 1) < (off_t)SSIZE_MAX);
410 fi_p = &volume_info[fd].fi;
411 amtable_alloc((void **)fi_p,
412 &volume_info[fd].fi_limit,
413 SIZEOF(*volume_info[fd].fi),
417 fi = &volume_info[fd].fi[pos];
418 if (fi->ri_altered) {
419 snprintf(number, SIZEOF(number),
420 "%05" OFF_T_RFMT, (OFF_T_FMT_TYPE)pos);
421 filename = vstralloc(volume_info[fd].basename,
426 if ((f = fopen(filename, "w")) == NULL) {
429 for (r = 0; r < fi->ri_count; r++) {
430 fprintf(f, OFF_T_FMT " " OFF_T_FMT " " SIZE_T_FMT "\n",
431 (OFF_T_FMT_TYPE)fi->ri[r].start_record,
432 (OFF_T_FMT_TYPE)fi->ri[r].end_record,
433 (SIZE_T_FMT_TYPE)fi->ri[r].record_size);
445 * Release any files beyond a given position current position and reset
446 * file_count to file_current to indicate EOM.
456 char number[NUM_STR_SIZE];
457 struct file_info **fi_p;
460 * If the current file is open, release everything beyond it.
461 * If it is not open, release everything from current.
463 if (volume_info[fd].fd >= 0) {
464 position = volume_info[fd].file_current + 1;
466 position = volume_info[fd].file_current;
468 for (pos = position; pos < volume_info[fd].file_count; pos++) {
469 assert(pos < (off_t)SSIZE_MAX);
470 fi_p = &volume_info[fd].fi;
471 amtable_alloc((void **)fi_p,
472 &volume_info[fd].fi_limit,
473 SIZEOF(*volume_info[fd].fi),
477 if (volume_info[fd].fi[pos].name != NULL) {
478 snprintf(number, SIZEOF(number),
479 "%05" OFF_T_RFMT, (OFF_T_FMT_TYPE)pos);
480 filename = vstralloc(volume_info[fd].basename,
483 volume_info[fd].fi[pos].name,
487 filename = vstralloc(volume_info[fd].basename,
490 volume_info[fd].fi[pos].name,
494 amfree(volume_info[fd].fi[pos].name);
495 volume_info[fd].fi[pos].ri_count = 0;
498 volume_info[fd].file_count = position;
502 * Get the size of a particular record. We assume the record information is
503 * sorted, does not overlap and does not have gaps.
508 struct file_info * fi,
512 struct record_info *ri;
514 for(r = 0; r < fi->ri_count; r++) {
516 if (record <= ri->end_record) {
517 return ri->record_size;
522 * For historical reasons, the default record size is 32 KBytes.
523 * This allows us to read files written by Amanda with that block
524 * size before the record information was being kept.
530 * Update the record information. We assume the record information is
531 * sorted, does not overlap and does not have gaps.
536 struct file_info * fi,
541 struct record_info *ri;
542 struct record_info **ri_p;
545 if (record == (off_t)0) {
546 fi->ri_count = 0; /* start over */
548 for(r = 0; r < fi->ri_count; r++) {
550 if ((record - (off_t)1) <= ri->end_record) {
552 * If this record is the same size as the rest of the records
553 * in this entry, or it would replace the entire entry,
554 * reset the end record number and size, then zap the chain
557 if (record == ri->start_record || ri->record_size == size) {
558 ri->end_record = record;
559 ri->record_size = size;
560 fi->ri_count = r + 1;
564 * This record needs a new entry right after the current one.
566 ri->end_record = record - (off_t)1;
567 fi->ri_count = r + 1;
575 amtable_alloc((void **)ri_p,
578 (size_t)fi->ri_count + 1,
581 ri = &fi->ri[fi->ri_count];
582 ri->start_record = record;
583 ri->end_record = record;
584 ri->record_size = size;
589 * The normal interface routines ...
601 struct volume_info **volume_info_p = &volume_info;
604 * Use only O_RDONLY and O_RDWR.
606 if ((flags & 3) != O_RDONLY) {
612 * If the caller did not set O_CREAT (and thus, pass a mask
613 * parameter), we may still end up creating data files and need a
614 * "reasonable" value. Pick a "tight" value on the "better safe
615 * than sorry" theory.
617 if ((flags & O_CREAT) == 0) {
622 * Open/create the info file for this "tape".
624 info_file = stralloc2(filename, "/info");
625 if ((fd = open(info_file, O_RDWR|O_CREAT, 0600)) < 0) {
630 * Create the internal info structure for this "tape".
632 amtable_alloc((void **)volume_info_p,
634 SIZEOF(*volume_info),
638 volume_info[fd].flags = flags;
639 volume_info[fd].mask = mask;
640 volume_info[fd].file_count = 0;
641 volume_info[fd].file_current = 0;
642 volume_info[fd].record_current = (off_t)0;
643 volume_info[fd].fd = -1;
644 volume_info[fd].is_online = 0; /* true when .../data found */
645 volume_info[fd].at_bof = 1; /* by definition */
646 volume_info[fd].at_eof = 0; /* do not know yet */
647 volume_info[fd].at_eom = 0; /* may get reset below */
648 volume_info[fd].last_operation_write = 0;
649 volume_info[fd].amount_written = (off_t)0;
652 * Save the base directory name and see if we are "online".
654 volume_info[fd].basename = stralloc2(filename, "/data/");
655 if (check_online(fd)) {
659 amfree(volume_info[fd].basename);
669 * Return the info file descriptor as the unique descriptor for
688 * Make sure we are online.
690 if (check_online(fd) != 0) {
693 if (! volume_info[fd].is_online) {
699 * Do not allow any more reads after we find EOF.
701 if (volume_info[fd].at_eof) {
707 * If we are at EOM, set EOF and return a zero length result.
709 if (volume_info[fd].at_eom) {
710 volume_info[fd].at_eof = 1;
715 * Open the file, if needed.
717 if ((file_fd = file_open(fd)) < 0) {
722 * Make sure we do not read too much.
724 pos = volume_info[fd].file_current;
725 record_size = get_record_size(&volume_info[fd].fi[pos],
726 volume_info[fd].record_current);
727 if (record_size <= count) {
728 read_size = record_size;
734 * Read the data. If we ask for less than the record size, skip to
735 * the next record boundary.
737 result = read(file_fd, buffer, read_size);
739 volume_info[fd].at_bof = 0;
740 if ((size_t)result < record_size) {
741 if (lseek(file_fd, (off_t)(record_size-result), SEEK_CUR) == (off_t)-1) {
742 dbprintf(("file_tapefd_read: lseek failed: <%s>\n",
746 volume_info[fd].record_current += (off_t)1;
747 } else if (result == 0) {
748 volume_info[fd].at_eof = 1;
760 ssize_t write_count = (ssize_t)count;
767 * Make sure we are online.
769 if (check_online(fd) != 0) {
772 if (! volume_info[fd].is_online) {
778 * Check for write access first.
780 if ((volume_info[fd].flags & 3) == O_RDONLY) {
786 * Special case: allow negative buffer size.
788 if (write_count <= 0) {
789 return 0; /* special case */
793 * If we are at EOM, it takes precedence over EOF.
795 if (volume_info[fd].at_eom) {
796 volume_info[fd].at_eof = 0;
801 * Writes are only allowed at BOF and EOM.
803 if (! (volume_info[fd].at_bof || volume_info[fd].at_eom)) {
810 * Writes are only allowed if we are not at EOF.
812 if (volume_info[fd].at_eof) {
818 * Open the file, if needed.
820 if((file_fd = volume_info[fd].fd) < 0) {
822 if ((file_fd = file_open(fd)) < 0) {
828 * Truncate the write if requested and return a simulated ENOSPC.
830 if ((length = tapefd_getinfo_length(fd)) > (off_t)0) {
831 kbytes_left = length - volume_info[fd].amount_written;
832 if ((off_t)(write_count / 1024) > kbytes_left) {
833 write_count = (ssize_t)kbytes_left * 1024;
836 volume_info[fd].amount_written += (off_t)((write_count + 1023) / 1024);
837 if (write_count <= 0) {
838 volume_info[fd].at_bof = 0;
839 volume_info[fd].at_eom = 1;
845 * Do the write and truncate the file, if needed. Checking for
846 * last_operation_write is an optimization so we only truncate
849 if (! volume_info[fd].last_operation_write) {
852 if ((curpos = lseek(file_fd, (off_t)0, SEEK_CUR)) < 0) {
853 dbprintf((": Can not determine current file position <%s>",
857 if (ftruncate(file_fd, curpos) != 0) {
858 dbprintf(("ftruncate failed; Can not trim output file <%s>",
862 volume_info[fd].at_bof = 0;
863 volume_info[fd].at_eom = 1;
865 result = fullwrite(file_fd, buffer, (size_t)write_count);
867 volume_info[fd].last_operation_write = 1;
868 pos = volume_info[fd].file_current;
869 put_record_size(&volume_info[fd].fi[pos],
870 volume_info[fd].record_current,
872 volume_info[fd].record_current += (off_t)1;
886 char number[NUM_STR_SIZE];
888 struct file_info **fi_p;
889 struct record_info **ri_p;
892 * If our last operation was a write, write a tapemark.
894 if (volume_info[fd].last_operation_write) {
895 if ((result = (ssize_t)file_tapefd_weof(fd, (off_t)1)) != 0) {
901 * If we are not at BOF, fsf to the next file unless we
902 * are already at end of tape.
904 if (! volume_info[fd].at_bof && ! volume_info[fd].at_eom) {
905 if ((result = (ssize_t)file_tapefd_fsf(fd, (off_t)1)) != 0) {
911 * Close the file if it is still open.
916 * Release the info structure areas.
918 for (pos = 0; pos < (off_t)volume_info[fd].fi_limit; pos++) {
919 amfree(volume_info[fd].fi[pos].name);
920 ri_p = &volume_info[fd].fi[pos].ri;
921 amtable_free((void **)ri_p,
922 &volume_info[fd].fi[pos].ri_limit);
923 volume_info[fd].fi[pos].ri_count = 0;
925 fi_p = &volume_info[fd].fi;
926 amtable_free((void **)fi_p, &volume_info[fd].fi_limit);
927 volume_info[fd].file_count = 0;
928 amfree(volume_info[fd].basename);
931 * Update the status file if we were online.
933 if (volume_info[fd].is_online) {
934 if (lseek(fd, (off_t)0, SEEK_SET) != (off_t)0) {
940 if (ftruncate(fd, (off_t)0) != 0) {
946 snprintf(number, SIZEOF(number), "%05" OFF_T_RFMT,
947 (OFF_T_FMT_TYPE)volume_info[fd].file_current);
948 line = vstralloc("position ", number, "\n", NULL);
950 result = write(fd, line, len);
952 if (result != (ssize_t)len) {
968 file_tapefd_resetofs(
971 (void)fd; /* Quiet unused parameter warning */
977 struct am_mt_status *stat)
982 * See if we are online.
984 if ((result = check_online(fd)) != 0) {
987 memset((void *)stat, 0, SIZEOF(*stat));
988 stat->online_valid = 1;
989 stat->online = (char)volume_info[fd].is_online;
998 return stat(filename, buf);
1006 return access(filename, mode);
1016 * Make sure we are online.
1018 if ((result = check_online(fd)) != 0) {
1021 if (! volume_info[fd].is_online) {
1027 * If our last operation was a write, write a tapemark.
1029 if (volume_info[fd].last_operation_write) {
1030 if ((result = file_tapefd_weof(fd, (off_t)1)) != 0) {
1036 * Close the file if it is still open.
1041 * Adjust the position and reset the flags.
1043 volume_info[fd].file_current = 0;
1044 volume_info[fd].record_current = (off_t)0;
1046 volume_info[fd].at_bof = 1;
1047 volume_info[fd].at_eof = 0;
1048 volume_info[fd].at_eom
1049 = (volume_info[fd].file_current >= volume_info[fd].file_count);
1050 volume_info[fd].last_operation_write = 0;
1051 volume_info[fd].amount_written = (off_t)0;
1063 * Make sure we are online.
1065 if ((result = check_online(fd)) != 0) {
1068 if (! volume_info[fd].is_online) {
1073 (void)file_tapefd_rewind(fd);
1085 * Make sure we are online.
1087 if ((result = check_online(fd)) != 0) {
1090 if (! volume_info[fd].is_online) {
1096 * If our last operation was a write and we are going to move
1097 * backward, write a tapemark.
1099 if (volume_info[fd].last_operation_write && count < 0) {
1100 if ((result = file_tapefd_weof(fd, (off_t)1)) != 0) {
1107 * Close the file if it is still open.
1112 * If we are at EOM and moving backward, adjust the count to go
1115 if (volume_info[fd].at_eom && count < 0) {
1120 * Adjust the position and return an error if we go beyond either
1123 volume_info[fd].file_current += count;
1124 if (volume_info[fd].file_current > volume_info[fd].file_count) {
1125 volume_info[fd].file_current = volume_info[fd].file_count;
1128 } else if (volume_info[fd].file_current < 0) {
1129 volume_info[fd].file_current = 0;
1133 volume_info[fd].record_current = (off_t)0;
1136 * Set BOF to true so we can write. Set to EOF to false if the
1137 * fsf succeeded or if it failed but we were moving backward (and
1138 * thus we are at beginning of tape), otherwise set it to true so
1139 * a subsequent read will fail. Set EOM to whatever is right.
1140 * Reset amount_written if we ended up back at BOM.
1142 volume_info[fd].at_bof = 1;
1143 if (result == 0 || count < 0) {
1144 volume_info[fd].at_eof = 0;
1146 volume_info[fd].at_eof = 1;
1148 volume_info[fd].at_eom
1149 = (volume_info[fd].file_current >= volume_info[fd].file_count);
1150 volume_info[fd].last_operation_write = 0;
1151 if (volume_info[fd].file_current == 0) {
1152 volume_info[fd].amount_written = (off_t)0;
1171 * Make sure we are online.
1173 if ((result = check_online(fd)) != 0) {
1176 if (! volume_info[fd].is_online) {
1182 * Check for write access first.
1184 if ((volume_info[fd].flags & 3) == O_RDONLY) {
1190 * Special case: allow a zero count.
1193 return 0; /* special case */
1197 * Disallow negative count.
1205 * Close out the current file if open.
1207 if ((file_fd = volume_info[fd].fd) >= 0) {
1210 if ((curpos = lseek(file_fd, (off_t)0, SEEK_CUR)) < 0) {
1212 dbprintf((": Can not determine current file position <%s>",
1218 if (ftruncate(file_fd, curpos) != 0) {
1220 dbprintf(("ftruncate failed; Can not trim output file <%s>",
1228 volume_info[fd].file_current++;
1229 volume_info[fd].record_current = (off_t)0;
1230 volume_info[fd].at_bof = 1;
1231 volume_info[fd].at_eof = 0;
1232 volume_info[fd].at_eom = 1;
1233 volume_info[fd].last_operation_write = 0;
1238 * Release any data files from current through the end.
1243 * Save any labelling information in case we clobber it.
1245 if ((save_host = tapefd_getinfo_host(fd)) != NULL) {
1246 save_host = stralloc(save_host);
1248 if ((save_disk = tapefd_getinfo_disk(fd)) != NULL) {
1249 save_disk = stralloc(save_disk);
1251 save_level = tapefd_getinfo_level(fd);
1254 * Add more tapemarks.
1256 while (--count >= 0) {
1257 if (file_open(fd) < 0) {
1261 volume_info[fd].file_current++;
1262 volume_info[fd].file_count = volume_info[fd].file_current;
1263 volume_info[fd].record_current = (off_t)0;
1264 volume_info[fd].at_bof = 1;
1265 volume_info[fd].at_eof = 0;
1266 volume_info[fd].at_eom = 1;
1267 volume_info[fd].last_operation_write = 0;
1270 * Only the first "file" terminated by an EOF gets the naming
1271 * information from the caller.
1273 tapefd_setinfo_host(fd, NULL);
1274 tapefd_setinfo_disk(fd, NULL);
1275 tapefd_setinfo_level(fd, -1);
1279 * Restore the labelling information.
1282 tapefd_setinfo_host(fd, save_host);
1284 tapefd_setinfo_disk(fd, save_disk);
1286 tapefd_setinfo_level(fd, save_level);
1293 file_tapefd_can_fork(
1296 (void)fd; /* Quiet unused parameter warning */