⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 output-file.c

📁 开源备份软件源码 AMANDA, the Advanced Maryland Automatic Network Disk Archiver, is a backup system that a
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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 + -