📄 output-file.c
字号:
/* * Amanda, The Advanced Maryland Automatic Network Disk Archiver * Copyright (c) 1991-1998 University of Maryland at College Park * All Rights Reserved. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of U.M. not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. U.M. makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: James da Silva, Systems Design and Analysis Group * Computer Science Department * University of Maryland at College Park *//* NOTE: this driver is *deprecated* and should not be used. See the Device API * in device-src/ for the new implementation. *//* * $Id: output-file.c,v 1.14 2006/07/06 15:04:18 martinea Exp $ * * tapeio.c virtual tape interface for a file device. * * The following was based on testing with real tapes on Solaris 2.6. * It is possible other OS drivers behave somewhat different in end * cases, usually involving errors. */#include "amanda.h"#include "token.h"#include "tapeio.h"#include "output-file.h"#include "fileheader.h"#ifndef SEEK_SET#define SEEK_SET 0#endif#ifndef SEEK_CUR#define SEEK_CUR 1#endif#ifndef SEEK_END#define SEEK_END 2#endif#define MAX_TOKENS 10#define DATA_INDICATOR "."#define RECORD_INDICATOR "-"staticstruct volume_info { char *basename; /* filename from open */ struct file_info *fi; /* file info array */ size_t fi_limit; /* length of file info array */ int flags; /* open flags */ mode_t mask; /* open mask */ off_t file_count; /* number of files */ off_t file_current; /* current file position */ off_t record_current; /* current record position */ int fd; /* data file descriptor */ int is_online; /* true if "tape" is "online" */ int at_bof; /* true if at begining of file */ int at_eof; /* true if at end of file */ int at_eom; /* true if at end of medium */ int last_operation_write; /* true if last op was a write */ off_t amount_written; /* KBytes written since open/rewind */} *volume_info = NULL;struct file_info { char *name; /* file name (tapefd_getinfo_...) */ struct record_info *ri; /* record info array */ size_t ri_count; /* number of record info entries */ size_t ri_limit; /* length of record info array */ int ri_altered; /* true if record info altered */};struct record_info { size_t record_size; /* record size */ off_t start_record; /* first record in range */ off_t end_record; /* last record in range */ };static size_t open_count = 0;static int check_online(int fd);static int file_open(int fd);static void file_close(int fd);static void file_release(int fd);static size_t get_record_size(struct file_info *fi, off_t record);static void put_record_size(struct file_info *fi, off_t record, size_t size);/* * "Open" the tape by scanning the "data" directory. "Tape files" * have five leading digits indicating the position (counting from zero) * followed by a '.' and optional other information (e.g. host/disk/level * image name). * * We allow for the following situations: * * + If we see the same "file" (position number) more than once, the * last one seen wins. This should not normally happen. * * + We allow gaps in the positions. This should not normally happen. * * Anything in the directory that does not match a "tape file" name * pattern is ignored. * * If the data directory does not exist, the "tape" is considered offline. * It is allowed to "appear" later. */static intcheck_online( int fd){ char *token[MAX_TOKENS]; DIR *tapedir; struct dirent *entry; struct file_info *fi; struct file_info **fi_p; char *line; int f; off_t pos; int rc = 0; char *qname = quote_string(volume_info[fd].basename); /* * If we are already online, there is nothing else to do. */ if (volume_info[fd].is_online) { goto common_exit; } if ((tapedir = opendir(volume_info[fd].basename)) == NULL) { /* * We have already opened the info file which is in the same * directory as the data directory, so ENOENT has to mean the data * directory is not there, which we treat as being "offline". * We're already offline at this point (see the above test) * and this is not an error, so just return success (no error). */ rc = (errno != ENOENT); g_fprintf(stderr,_("ERROR: %s (%s)\n"), qname, strerror(errno)); goto common_exit; } while ((entry = readdir(tapedir)) != NULL) { if (is_dot_or_dotdot(entry->d_name)) { continue; } if (isdigit((int)entry->d_name[0]) && isdigit((int)entry->d_name[1]) && isdigit((int)entry->d_name[2]) && isdigit((int)entry->d_name[3]) && isdigit((int)entry->d_name[4]) && entry->d_name[5] == '.') { /* * This is a "tape file". */ pos = OFF_T_ATOI(entry->d_name); assert((pos + 1) <= (off_t)SSIZE_MAX); fi_p = &volume_info[fd].fi; amtable_alloc((void **)fi_p, &volume_info[fd].fi_limit, SIZEOF(*volume_info[fd].fi), (size_t)(pos + 1), 10, NULL); fi = &volume_info[fd].fi[pos]; if (fi->name != NULL) { /* * Two files with the same position??? */ amfree(fi->name); fi->ri_count = 0; } fi->name = stralloc(&entry->d_name[6]); if ((pos + 1) > volume_info[fd].file_count) { volume_info[fd].file_count = (pos + 1); } } } closedir(tapedir); /* * Parse the info file. We know we are at beginning of file because * the only thing that can happen to it prior to here is it being * opened. */ for (; (line = areads(fd)) != NULL; free(line)) { f = split(line, token, (int)(sizeof(token) / sizeof(token[0])), " "); if (f == 2 && strcmp(token[1], "position") == 0) { volume_info[fd].file_current = OFF_T_ATOI(token[2]); volume_info[fd].record_current = (off_t)0; } } /* * Set EOM and make sure we are not pre-BOI. */ if (volume_info[fd].file_current >= volume_info[fd].file_count) { volume_info[fd].at_eom = 1; } if (volume_info[fd].file_current < 0) { volume_info[fd].file_current = 0; volume_info[fd].record_current = (off_t)0; } volume_info[fd].is_online = 1;common_exit: amfree(qname); return rc;}/* * Open the tape file if not already. If we are beyond the file count * (end of tape) or the file is missing and we are only reading, set * up to read /dev/null which will look like EOF. If we are writing, * create the file. */static intfile_open( int fd){ struct file_info *fi; struct file_info **fi_p; char *datafilename = NULL; char *recordfilename = NULL; char *f = NULL; off_t pos; char *host; char *disk; int level; char number[NUM_STR_SIZE]; int flags; int rfd; int n; char *line; struct record_info *ri; struct record_info **ri_p; off_t start_record; off_t end_record; size_t record_size = 0; if (volume_info[fd].fd < 0) { flags = volume_info[fd].flags; pos = volume_info[fd].file_current; assert((pos + 1) < (off_t)SSIZE_MAX); fi_p = &volume_info[fd].fi; amtable_alloc((void **)fi_p, &volume_info[fd].fi_limit, SIZEOF(*volume_info[fd].fi), (size_t)(pos + 1), 10, NULL); fi = &volume_info[fd].fi[pos]; /* * See if we are creating a new file. */ if (pos >= volume_info[fd].file_count) { volume_info[fd].file_count = pos + 1; } /* * Generate the file name to open. */ if (fi->name == NULL) { if ((volume_info[fd].flags & 3) != O_RDONLY) { /* * This is a new file, so make sure we create/truncate * it. Generate the name based on the host/disk/level * information from the caller, if available, else * a constant. */ flags |= (O_CREAT | O_TRUNC); host = tapefd_getinfo_host(fd); disk = tapefd_getinfo_disk(fd); level = tapefd_getinfo_level(fd); g_snprintf(number, SIZEOF(number), "%d", level); if (host != NULL) { f = stralloc(host); } if (disk != NULL) { disk = sanitise_filename(disk); if (f == NULL) { f = stralloc(disk); } else { vstrextend(&f, ".", disk, NULL); } amfree(disk); } if (level >= 0) { if (f == NULL) { f = stralloc(number); } else { vstrextend(&f, ".", number, NULL); } } if (f == NULL) { f = stralloc("unknown"); } amfree(fi->name); fi->name = stralloc(f); fi->ri_count = 0; amfree(f); } else { /* * This is a missing file, so set up to read nothing. */ datafilename = stralloc("/dev/null"); recordfilename = stralloc("/dev/null"); } } if (datafilename == NULL) { g_snprintf(number, SIZEOF(number), "%05lld", (long long)pos); datafilename = vstralloc(volume_info[fd].basename, number, DATA_INDICATOR, volume_info[fd].fi[pos].name, NULL); recordfilename = vstralloc(volume_info[fd].basename, number, RECORD_INDICATOR, volume_info[fd].fi[pos].name, NULL); } /* * Do the data file open. */ volume_info[fd].fd = open(datafilename, flags, volume_info[fd].mask); amfree(datafilename); /* * Load the record information. */ if (volume_info[fd].fd >= 0 && fi->ri_count == 0 && (rfd = open(recordfilename, O_RDONLY)) >= 0) { for (; (line = areads(rfd)) != NULL; free(line)) { /* We play this game because long long is not necessarily the same as off_t, and we need to cast the actual value (not just the pointer. */ long long start_record_ = (long long)0; long long end_record_ = (long long)0; long record_size_ = (long)0; n = sscanf(line, "%lld %lld %ld", &start_record_, &end_record_, &record_size_); start_record = (off_t)start_record_; end_record = (off_t)end_record_; record_size = (size_t)record_size_; if (n == 3) { ri_p = &fi->ri; amtable_alloc((void **)ri_p, &fi->ri_limit, SIZEOF(*fi->ri), (size_t)fi->ri_count + 1, 10, NULL); ri = &fi->ri[fi->ri_count]; ri->start_record = start_record; ri->end_record = end_record; ri->record_size = record_size; fi->ri_count++; } } aclose(rfd); } amfree(recordfilename); } return volume_info[fd].fd;}/* * Close the current data file, if open. Dump the record information * if it has been altered. */static voidfile_close( int fd){ struct file_info *fi; struct file_info **fi_p; off_t pos; char number[NUM_STR_SIZE]; char *filename = NULL; size_t r; FILE *f; aclose(volume_info[fd].fd); pos = volume_info[fd].file_current; assert((pos + 1) < (off_t)SSIZE_MAX); fi_p = &volume_info[fd].fi; amtable_alloc((void **)fi_p, &volume_info[fd].fi_limit, SIZEOF(*volume_info[fd].fi), (size_t)(pos + 1), 10, NULL); fi = &volume_info[fd].fi[pos]; if (fi->ri_altered) { g_snprintf(number, SIZEOF(number), "%05lld", (long long)pos); filename = vstralloc(volume_info[fd].basename, number, RECORD_INDICATOR, fi->name, NULL); if ((f = fopen(filename, "w")) == NULL) { goto common_exit; } for (r = 0; r < fi->ri_count; r++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -