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.10 2006/01/14 04:37:20 paddy_s 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 int fi_limit; /* length of file info array */
65 int flags; /* open flags */
66 int mask; /* open mask */
67 int file_count; /* number of files */
68 int file_current; /* current file position */
69 int 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 long 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 int ri_count; /* number of record info entries */
83 int ri_limit; /* length of record info array */
84 int ri_altered; /* true if record info altered */
88 int record_size; /* record size */
89 int start_record; /* first record in range */
90 int end_record; /* last record in range */
93 static int open_count = 0;
96 * "Open" the tape by scanning the "data" directory. "Tape files"
97 * have five leading digits indicating the position (counting from zero)
98 * followed by a '.' and optional other information (e.g. host/disk/level
101 * We allow for the following situations:
103 * + If we see the same "file" (position number) more than once, the
104 * last one seen wins. This should not normally happen.
106 * + We allow gaps in the positions. This should not normally happen.
108 * Anything in the directory that does not match a "tape file" name
109 * pattern is ignored.
111 * If the data directory does not exist, the "tape" is considered offline.
112 * It is allowed to "appear" later.
119 char *token[MAX_TOKENS];
121 struct dirent *entry;
122 struct file_info *fi;
129 * If we are already online, there is nothing else to do.
131 if (volume_info[fd].is_online) {
135 if ((tapedir = opendir(volume_info[fd].basename)) == NULL) {
137 * We have already opened the info file which is in the same
138 * directory as the data directory, so ENOENT has to mean the data
139 * directory is not there, which we treat as being "offline".
140 * We're already offline at this point (see the above test)
141 * and this is not an error, so just return success (no error).
144 rc = (errno != ENOENT);
145 fprintf(stderr,"ERROR: %s: %s\n", volume_info[fd].basename, strerror(errno));
148 while ((entry = readdir(tapedir)) != NULL) {
149 if (is_dot_or_dotdot(entry->d_name)) {
152 if (isdigit((int)entry->d_name[0])
153 && isdigit((int)entry->d_name[1])
154 && isdigit((int)entry->d_name[2])
155 && isdigit((int)entry->d_name[3])
156 && isdigit((int)entry->d_name[4])
157 && entry->d_name[5] == '.') {
160 * This is a "tape file".
162 pos = atoi(entry->d_name);
163 amtable_alloc((void **)&volume_info[fd].fi,
164 &volume_info[fd].fi_limit,
165 sizeof(*volume_info[fd].fi),
169 fi = &volume_info[fd].fi[pos];
170 if (fi->name != NULL) {
172 * Two files with the same position???
177 fi->name = stralloc(&entry->d_name[6]);
178 if (pos + 1 > volume_info[fd].file_count) {
179 volume_info[fd].file_count = pos + 1;
186 * Parse the info file. We know we are at beginning of file because
187 * the only thing that can happen to it prior to here is it being
190 for (; (line = areads(fd)) != NULL; free(line)) {
191 f = split(line, token, sizeof(token) / sizeof(token[0]), " ");
192 if (f == 2 && strcmp(token[1], "position") == 0) {
193 volume_info[fd].file_current = atoi(token[2]);
194 volume_info[fd].record_current = 0;
199 * Set EOM and make sure we are not pre-BOI.
201 if (volume_info[fd].file_current >= volume_info[fd].file_count) {
202 volume_info[fd].at_eom = 1;
204 if (volume_info[fd].file_current < 0) {
205 volume_info[fd].file_current = 0;
206 volume_info[fd].record_current = 0;
209 volume_info[fd].is_online = 1;
217 * Open the tape file if not already. If we are beyond the file count
218 * (end of tape) or the file is missing and we are only reading, set
219 * up to read /dev/null which will look like EOF. If we are writing,
227 struct file_info *fi;
228 char *datafilename = NULL;
229 char *recordfilename = NULL;
235 char number[NUM_STR_SIZE];
240 struct record_info *ri;
245 if (volume_info[fd].fd < 0) {
246 flags = volume_info[fd].flags;
247 pos = volume_info[fd].file_current;
248 amtable_alloc((void **)&volume_info[fd].fi,
249 &volume_info[fd].fi_limit,
250 sizeof(*volume_info[fd].fi),
254 fi = &volume_info[fd].fi[pos];
257 * See if we are creating a new file.
259 if (pos >= volume_info[fd].file_count) {
260 volume_info[fd].file_count = pos + 1;
264 * Generate the file name to open.
266 if (fi->name == NULL) {
267 if ((volume_info[fd].flags & 3) != O_RDONLY) {
270 * This is a new file, so make sure we create/truncate
271 * it. Generate the name based on the host/disk/level
272 * information from the caller, if available, else
275 flags |= (O_CREAT | O_TRUNC);
276 host = tapefd_getinfo_host(fd);
277 disk = tapefd_getinfo_disk(fd);
278 level = tapefd_getinfo_level(fd);
279 snprintf(number, sizeof(number), "%d", level);
284 disk = sanitise_filename(disk);
288 f = newvstralloc(f, f, ".", disk, NULL);
294 f = stralloc(number);
296 f = newvstralloc(f, f, ".", number, NULL);
300 f = stralloc("unknown");
303 fi->name = stralloc(f);
309 * This is a missing file, so set up to read nothing.
311 datafilename = stralloc("/dev/null");
312 recordfilename = stralloc("/dev/null");
315 if (datafilename == NULL) {
316 snprintf(number, sizeof(number), "%05d", pos);
317 datafilename = vstralloc(volume_info[fd].basename,
320 volume_info[fd].fi[pos].name,
322 recordfilename = vstralloc(volume_info[fd].basename,
325 volume_info[fd].fi[pos].name,
330 * Do the data file open.
332 volume_info[fd].fd = open(datafilename, flags, volume_info[fd].mask);
333 amfree(datafilename);
336 * Load the record information.
338 if (volume_info[fd].fd >= 0
340 && (rfd = open(recordfilename, O_RDONLY)) >= 0) {
341 for (; (line = areads(rfd)) != NULL; free(line)) {
348 amtable_alloc((void **)&fi->ri,
354 ri = &fi->ri[fi->ri_count];
355 ri->start_record = start_record;
356 ri->end_record = end_record;
357 ri->record_size = record_size;
363 amfree(recordfilename);
365 return volume_info[fd].fd;
369 * Close the current data file, if open. Dump the record information
370 * if it has been altered.
377 struct file_info *fi;
379 char number[NUM_STR_SIZE];
380 char *filename = NULL;
384 aclose(volume_info[fd].fd);
385 pos = volume_info[fd].file_current;
386 amtable_alloc((void **)&volume_info[fd].fi,
387 &volume_info[fd].fi_limit,
388 sizeof(*volume_info[fd].fi),
392 fi = &volume_info[fd].fi[pos];
393 if (fi->ri_altered) {
394 snprintf(number, sizeof(number), "%05d", pos);
395 filename = vstralloc(volume_info[fd].basename,
400 if ((f = fopen(filename, "w")) == NULL) {
403 for (r = 0; r < fi->ri_count; r++) {
406 fi->ri[r].start_record,
407 fi->ri[r].end_record,
408 fi->ri[r].record_size);
420 * Release any files beyond a given position current position and reset
421 * file_count to file_current to indicate EOM.
431 char number[NUM_STR_SIZE];
434 * If the current file is open, release everything beyond it.
435 * If it is not open, release everything from current.
437 if (volume_info[fd].fd >= 0) {
438 position = volume_info[fd].file_current + 1;
440 position = volume_info[fd].file_current;
442 for (pos = position; pos < volume_info[fd].file_count; pos++) {
443 amtable_alloc((void **)&volume_info[fd].fi,
444 &volume_info[fd].fi_limit,
445 sizeof(*volume_info[fd].fi),
449 if (volume_info[fd].fi[pos].name != NULL) {
450 snprintf(number, sizeof(number), "%05d", pos);
451 filename = vstralloc(volume_info[fd].basename,
454 volume_info[fd].fi[pos].name,
458 filename = vstralloc(volume_info[fd].basename,
461 volume_info[fd].fi[pos].name,
465 amfree(volume_info[fd].fi[pos].name);
466 volume_info[fd].fi[pos].ri_count = 0;
469 volume_info[fd].file_count = position;
473 * Get the size of a particular record. We assume the record information is
474 * sorted, does not overlap and does not have gaps.
478 get_record_size(fi, record)
479 struct file_info *fi;
483 struct record_info *ri;
485 for(r = 0; r < fi->ri_count; r++) {
487 if (record <= ri->end_record) {
488 return ri->record_size;
493 * For historical reasons, the default record size is 32 KBytes.
494 * This allows us to read files written by Amanda with that block
495 * size before the record information was being kept.
501 * Update the record information. We assume the record information is
502 * sorted, does not overlap and does not have gaps.
506 put_record_size(fi, record, size)
507 struct file_info *fi;
512 struct record_info *ri;
516 fi->ri_count = 0; /* start over */
518 for(r = 0; r < fi->ri_count; r++) {
520 if (record - 1 <= ri->end_record) {
522 * If this record is the same size as the rest of the records
523 * in this entry, or it would replace the entire entry,
524 * reset the end record number and size, then zap the chain
527 if (record == ri->start_record || ri->record_size == size) {
528 ri->end_record = record;
529 ri->record_size = size;
530 fi->ri_count = r + 1;
534 * This record needs a new entry right after the current one.
536 ri->end_record = record - 1;
537 fi->ri_count = r + 1;
544 amtable_alloc((void **)&fi->ri,
550 ri = &fi->ri[fi->ri_count];
551 ri->start_record = record;
552 ri->end_record = record;
553 ri->record_size = size;
558 * The normal interface routines ...
562 file_tape_open(filename, flags, mask)
569 char *info_file = NULL;
572 * Use only O_RDONLY and O_RDWR.
574 if ((flags & 3) != O_RDONLY) {
580 * If the caller did not set O_CREAT (and thus, pass a mask
581 * parameter), we may still end up creating data files and need a
582 * "reasonable" value. Pick a "tight" value on the "better safe
583 * than sorry" theory.
585 if ((flags & O_CREAT) == 0) {
590 * Open/create the info file for this "tape".
592 info_file = stralloc2(filename, "/info");
593 if ((fd = open(info_file, O_RDWR|O_CREAT, 0600)) < 0) {
598 * Create the internal info structure for this "tape".
600 amtable_alloc((void **)&volume_info,
602 sizeof(*volume_info),
606 volume_info[fd].flags = flags;
607 volume_info[fd].mask = mask;
608 volume_info[fd].file_count = 0;
609 volume_info[fd].file_current = 0;
610 volume_info[fd].record_current = 0;
611 volume_info[fd].fd = -1;
612 volume_info[fd].is_online = 0; /* true when .../data found */
613 volume_info[fd].at_bof = 1; /* by definition */
614 volume_info[fd].at_eof = 0; /* do not know yet */
615 volume_info[fd].at_eom = 0; /* may get reset below */
616 volume_info[fd].last_operation_write = 0;
617 volume_info[fd].amount_written = 0;
620 * Save the base directory name and see if we are "online".
622 volume_info[fd].basename = stralloc2(filename, "/data/");
623 if (check_online(fd)) {
627 amfree(volume_info[fd].basename);
637 * Return the info file descriptor as the unique descriptor for
644 file_tapefd_read(fd, buffer, count)
656 * Make sure we are online.
658 if ((result = check_online(fd)) != 0) {
661 if (! volume_info[fd].is_online) {
667 * Do not allow any more reads after we find EOF.
669 if (volume_info[fd].at_eof) {
675 * If we are at EOM, set EOF and return a zero length result.
677 if (volume_info[fd].at_eom) {
678 volume_info[fd].at_eof = 1;
683 * Open the file, if needed.
685 if ((file_fd = file_open(fd)) < 0) {
690 * Make sure we do not read too much.
692 pos = volume_info[fd].file_current;
693 record_size = get_record_size(&volume_info[fd].fi[pos],
694 volume_info[fd].record_current);
695 if (record_size <= count) {
696 read_size = record_size;
702 * Read the data. If we ask for less than the record size, skip to
703 * the next record boundary.
705 result = read(file_fd, buffer, read_size);
707 volume_info[fd].at_bof = 0;
708 if (result < record_size) {
709 (void)lseek(file_fd, record_size - result, SEEK_CUR);
711 volume_info[fd].record_current++;
712 } else if (result == 0) {
713 volume_info[fd].at_eof = 1;
719 file_tapefd_write(fd, buffer, count)
725 int write_count = count;
732 * Make sure we are online.
734 if ((result = check_online(fd)) != 0) {
737 if (! volume_info[fd].is_online) {
743 * Check for write access first.
745 if ((volume_info[fd].flags & 3) == O_RDONLY) {
751 * Special case: allow negative buffer size.
753 if (write_count <= 0) {
754 return 0; /* special case */
758 * If we are at EOM, it takes precedence over EOF.
760 if (volume_info[fd].at_eom) {
761 volume_info[fd].at_eof = 0;
766 * Writes are only allowed at BOF and EOM.
768 if (! (volume_info[fd].at_bof || volume_info[fd].at_eom)) {
775 * Writes are only allowed if we are not at EOF.
777 if (volume_info[fd].at_eof) {
783 * Open the file, if needed.
785 if((file_fd = volume_info[fd].fd) < 0) {
787 if ((file_fd = file_open(fd)) < 0) {
793 * Truncate the write if requested and return a simulated ENOSPC.
795 if ((length = tapefd_getinfo_length(fd)) > 0) {
796 kbytes_left = length - volume_info[fd].amount_written;
797 if (write_count / 1024 > kbytes_left) {
798 write_count = kbytes_left * 1024;
801 volume_info[fd].amount_written += (write_count + 1023) / 1024;
802 if (write_count <= 0) {
803 volume_info[fd].at_bof = 0;
804 volume_info[fd].at_eom = 1;
810 * Do the write and truncate the file, if needed. Checking for
811 * last_operation_write is an optimization so we only truncate
814 if (! volume_info[fd].last_operation_write) {
815 (void)ftruncate(file_fd, lseek(file_fd, 0, SEEK_CUR));
816 volume_info[fd].at_bof = 0;
817 volume_info[fd].at_eom = 1;
819 result = fullwrite(file_fd, buffer, write_count);
821 volume_info[fd].last_operation_write = 1;
822 pos = volume_info[fd].file_current;
823 put_record_size(&volume_info[fd].fi[pos],
824 volume_info[fd].record_current,
826 volume_info[fd].record_current++;
833 file_tapefd_close(fd)
840 char number[NUM_STR_SIZE];
844 * If our last operation was a write, write a tapemark.
846 if (volume_info[fd].last_operation_write) {
847 if ((result = file_tapefd_weof(fd, 1)) != 0) {
853 * If we are not at BOF, fsf to the next file unless we
854 * are already at end of tape.
856 if (! volume_info[fd].at_bof && ! volume_info[fd].at_eom) {
857 if ((result = file_tapefd_fsf(fd, 1)) != 0) {
863 * Close the file if it is still open.
868 * Release the info structure areas.
870 for (pos = 0; pos < volume_info[fd].fi_limit; pos++) {
871 amfree(volume_info[fd].fi[pos].name);
872 amtable_free((void **)&volume_info[fd].fi[pos].ri,
873 &volume_info[fd].fi[pos].ri_limit);
874 volume_info[fd].fi[pos].ri_count = 0;
876 amtable_free((void **)&volume_info[fd].fi, &volume_info[fd].fi_limit);
877 volume_info[fd].file_count = 0;
878 amfree(volume_info[fd].basename);
881 * Update the status file if we were online.
883 if (volume_info[fd].is_online) {
884 if (lseek(fd, 0, SEEK_SET) != 0) {
890 if (ftruncate(fd, 0) != 0) {
896 snprintf(number, sizeof(number),
897 "%d", volume_info[fd].file_current);
898 line = vstralloc("position ", number, "\n", NULL);
900 result = write(fd, line, len);
918 file_tapefd_resetofs(fd)
924 file_tapefd_status(fd, stat)
926 struct am_mt_status *stat;
931 * See if we are online.
933 if ((result = check_online(fd)) != 0) {
936 memset((void *)stat, 0, sizeof(*stat));
937 stat->online_valid = 1;
938 stat->online = volume_info[fd].is_online;
943 file_tape_stat(filename, buf)
947 return stat(filename, buf);
951 file_tape_access(filename, mode)
955 return access(filename, mode);
959 file_tapefd_rewind(fd)
965 * Make sure we are online.
967 if ((result = check_online(fd)) != 0) {
970 if (! volume_info[fd].is_online) {
976 * If our last operation was a write, write a tapemark.
978 if (volume_info[fd].last_operation_write) {
979 if ((result = file_tapefd_weof(fd, 1)) != 0) {
985 * Close the file if it is still open.
990 * Adjust the position and reset the flags.
992 volume_info[fd].file_current = 0;
993 volume_info[fd].record_current = 0;
995 volume_info[fd].at_bof = 1;
996 volume_info[fd].at_eof = 0;
997 volume_info[fd].at_eom
998 = (volume_info[fd].file_current >= volume_info[fd].file_count);
999 volume_info[fd].last_operation_write = 0;
1000 volume_info[fd].amount_written = 0;
1006 file_tapefd_unload(fd)
1012 * Make sure we are online.
1014 if ((result = check_online(fd)) != 0) {
1017 if (! volume_info[fd].is_online) {
1022 file_tapefd_rewind(fd);
1027 file_tapefd_fsf(fd, count)
1033 * Make sure we are online.
1035 if ((result = check_online(fd)) != 0) {
1038 if (! volume_info[fd].is_online) {
1044 * If our last operation was a write and we are going to move
1045 * backward, write a tapemark.
1047 if (volume_info[fd].last_operation_write && count < 0) {
1048 if ((result = file_tapefd_weof(fd, 1)) != 0) {
1055 * Close the file if it is still open.
1060 * If we are at EOM and moving backward, adjust the count to go
1063 if (volume_info[fd].at_eom && count < 0) {
1068 * Adjust the position and return an error if we go beyond either
1071 volume_info[fd].file_current += count;
1072 if (volume_info[fd].file_current > volume_info[fd].file_count) {
1073 volume_info[fd].file_current = volume_info[fd].file_count;
1076 } else if (volume_info[fd].file_current < 0) {
1077 volume_info[fd].file_current = 0;
1081 volume_info[fd].record_current = 0;
1084 * Set BOF to true so we can write. Set to EOF to false if the
1085 * fsf succeeded or if it failed but we were moving backward (and
1086 * thus we are at beginning of tape), otherwise set it to true so
1087 * a subsequent read will fail. Set EOM to whatever is right.
1088 * Reset amount_written if we ended up back at BOM.
1090 volume_info[fd].at_bof = 1;
1091 if (result == 0 || count < 0) {
1092 volume_info[fd].at_eof = 0;
1094 volume_info[fd].at_eof = 1;
1096 volume_info[fd].at_eom
1097 = (volume_info[fd].file_current >= volume_info[fd].file_count);
1098 volume_info[fd].last_operation_write = 0;
1099 if (volume_info[fd].file_current == 0) {
1100 volume_info[fd].amount_written = 0;
1107 file_tapefd_weof(fd, count)
1118 * Make sure we are online.
1120 if ((result = check_online(fd)) != 0) {
1123 if (! volume_info[fd].is_online) {
1129 * Check for write access first.
1131 if ((volume_info[fd].flags & 3) == O_RDONLY) {
1137 * Special case: allow a zero count.
1140 return 0; /* special case */
1144 * Disallow negative count.
1152 * Close out the current file if open.
1154 if ((file_fd = volume_info[fd].fd) >= 0) {
1155 (void)ftruncate(file_fd, lseek(file_fd, 0, SEEK_CUR));
1157 volume_info[fd].file_current++;
1158 volume_info[fd].record_current = 0;
1159 volume_info[fd].at_bof = 1;
1160 volume_info[fd].at_eof = 0;
1161 volume_info[fd].at_eom = 1;
1162 volume_info[fd].last_operation_write = 0;
1167 * Release any data files from current through the end.
1172 * Save any labelling information in case we clobber it.
1174 if ((save_host = tapefd_getinfo_host(fd)) != NULL) {
1175 save_host = stralloc(save_host);
1177 if ((save_disk = tapefd_getinfo_disk(fd)) != NULL) {
1178 save_disk = stralloc(save_disk);
1180 save_level = tapefd_getinfo_level(fd);
1183 * Add more tapemarks.
1185 while (--count >= 0) {
1186 if (file_open(fd) < 0) {
1190 volume_info[fd].file_current++;
1191 volume_info[fd].file_count = volume_info[fd].file_current;
1192 volume_info[fd].record_current = 0;
1193 volume_info[fd].at_bof = 1;
1194 volume_info[fd].at_eof = 0;
1195 volume_info[fd].at_eom = 1;
1196 volume_info[fd].last_operation_write = 0;
1199 * Only the first "file" terminated by an EOF gets the naming
1200 * information from the caller.
1202 tapefd_setinfo_host(fd, NULL);
1203 tapefd_setinfo_disk(fd, NULL);
1204 tapefd_setinfo_level(fd, -1);
1208 * Restore the labelling information.
1211 tapefd_setinfo_host(fd, save_host);
1213 tapefd_setinfo_disk(fd, save_disk);
1215 tapefd_setinfo_level(fd, save_level);
1222 file_tapefd_can_fork(fd)