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

📄 holding.c

📁 开源备份软件源码 AMANDA, the Advanced Maryland Automatic Network Disk Archiver, is a backup system that a
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * 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. * * Authors: the Amanda Development Team.  Its members are listed in a * file named AUTHORS, in the root directory of this distribution. *//* * $Id: holding.c,v 1.56 2006/06/09 23:07:26 martinea Exp $ * * Functions to access holding disk */#include "amanda.h"#include "util.h"#include "holding.h"#include "fileheader.h"#include "logfile.h"/* * utilities *//* Is fname a directory? * * @param fname: filename (fully qualified) * @returns: boolean */static int is_dir(char *fname);/* Is fname an empty file? * * @param fname: filename (fully qualified) * @returns: boolean */static int is_emptyfile(char *fname);/* sanity check that datestamp is of the form YYYYMMDD or  * YYYYMMDDhhmmss * * @param fname: a filename (without directory) * @returns: boolean */static int is_datestr(char *fname);/* * Static functions */static intis_dir(    char *fname){    struct stat statbuf;    if(stat(fname, &statbuf) == -1) return 0;    return (statbuf.st_mode & S_IFDIR) == S_IFDIR;}static intis_emptyfile(    char *fname){    struct stat statbuf;    if(stat(fname, &statbuf) == -1) return 0;    return ((statbuf.st_mode & S_IFDIR) != S_IFDIR) &&		(statbuf.st_size == (off_t)0);}static intis_datestr(    char *fname){    char *cp;    int ch, num, date, year, month, hour, minute, second;    char ymd[9], hms[7];    /* must be 8 digits */    for(cp = fname; (ch = *cp) != '\0'; cp++) {	if(!isdigit(ch)) {	    break;	}    }    if(ch != '\0' || (cp-fname != 8 && cp-fname != 14)) {	return 0;    }    /* sanity check year, month, and day */    strncpy(ymd, fname, 8);    ymd[8] = '\0';    num = atoi(ymd);    year = num / 10000;    month = (num / 100) % 100;    date = num % 100;    if(year<1990 || year>2100 || month<1 || month>12 || date<1 || date>31)	return 0;    if(cp-fname == 8)	return 1;    /* sanity check hour, minute, and second */    strncpy(hms, fname+8, 6);    hms[6] = '\0';    num = atoi(hms);    hour = num / 10000;    minute = (num / 100) % 100;    second = num % 100;    if(hour> 23 || minute>59 || second>59)	return 0;    /* yes, we passed all the checks */    return 1;}/* * Recursion functions * * These implement a general-purpose walk down the holding-* hierarchy. *//* Perform a custom action for this holding element (disk, dir, file, chunk). * * If the element is not cruft, the next step into the tree will only take place  * if this function returns a nonzero value. * * The walk is depth-first, with the callback for an element invoked * before entering that element.  Callbacks may depend on this behavior. * * @param datap: generic user-data pointer * @param base: the parent of the element being examined, or NULL for  * holding disks * @param element: the name of the element being examined * @param fqpath: fully qualified path to 'element' * @param is_cruft: nonzero if this element doesn't belong here * @returns: nonzero if the walk should descend into this element. */typedef int (*holding_walk_fn)(    gpointer datap,    char *base,    char *element,    char *fqpath,    int is_cruft);typedef enum {    STOP_AT_DISK,    STOP_AT_DIR,    STOP_AT_FILE,    STOP_AT_CHUNK} stop_at_t;/* Recurse over all holding chunks in a holding file. * * Call per_chunk_fn for each chunk of the given file * * datap is passed, unchanged, to all holding_walk_fns. * * @param hfile: holding file to examine (fully qualified path) * @param datap: generic user-data pointer * @param per_chunk_fn: function to call for each holding chunk */static void holding_walk_file(    char *hfile,    gpointer datap,    holding_walk_fn per_chunk_fn){    dumpfile_t file;    char *filename = NULL;    /* Loop through all cont_filenames (subsequent chunks) */    filename = stralloc(hfile);    while (filename != NULL && filename[0] != '\0') {	int is_cruft = 0;        /* get the header to look for cont_filename */        if (!holding_file_get_dumpfile(filename, &file)) {	    is_cruft = 1;        }	if (per_chunk_fn) 	    per_chunk_fn(datap, 			hfile, 			filename, 			filename, 			is_cruft);	amfree(filename);        /* and go on to the next chunk if this wasn't cruft */	if (!is_cruft)	    filename = stralloc(file.cont_filename);    }    amfree(filename);}/* Recurse over all holding files in a holding directory. * * Call per_file_fn for each file, and so on, stopping at the level given by  * stop_at. * * datap is passed, unchanged, to all holding_walk_fns. * * @param hdir: holding directory to examine (fully qualified path) * @param datap: generic user-data pointer * @param stop_at: do not proceed beyond this level of the hierarchy * @param per_file_fn: function to call for each holding file * @param per_chunk_fn: function to call for each holding chunk */static void holding_walk_dir(    char *hdir,    gpointer datap,    stop_at_t stop_at,    holding_walk_fn per_file_fn,    holding_walk_fn per_chunk_fn){    DIR *dir;    struct dirent *workdir;    char *hfile = NULL;    dumpfile_t dumpf;    int dumpf_ok;    int proceed = 1;    if ((dir = opendir(hdir)) == NULL) {        if (errno != ENOENT)           dbprintf(_("Warning: could not open holding dir %s: %s\n"),                  hdir, strerror(errno));        return;    }    while ((workdir = readdir(dir)) != NULL) {	int is_cruft = 0;        if (is_dot_or_dotdot(workdir->d_name))            continue; /* expected cruft */        hfile = newvstralloc(hfile,                     hdir, "/", workdir->d_name,                     NULL);        /* filter out various undesirables */        if (is_emptyfile(hfile))            is_cruft = 1;        if (is_dir(hfile)) {            is_cruft= 1;        }        if (!(dumpf_ok=holding_file_get_dumpfile(hfile, &dumpf)) ||            dumpf.type != F_DUMPFILE) {            if (dumpf_ok && dumpf.type == F_CONT_DUMPFILE)                continue; /* silently skip expected file */            is_cruft = 1;        }	if (dumpf.dumplevel < 0 || dumpf.dumplevel > 9) {	    is_cruft = 1;	}	if (per_file_fn) 	    proceed = per_file_fn(datap, 			hdir, 			workdir->d_name, 			hfile, 			is_cruft);	if (!is_cruft && proceed && stop_at != STOP_AT_FILE)	    holding_walk_file(hfile,		    datap,		    per_chunk_fn);    }    closedir(dir);    amfree(hfile);}/* Recurse over all holding directories in a holding disk. * * Call per_dir_fn for each dir, and so on, stopping at the level given by  * stop_at. * * datap is passed, unchanged, to all holding_walk_fns. * * @param hdisk: holding disk to examine (fully qualified path) * @param datap: generic user-data pointer * @param stop_at: do not proceed beyond this level of the hierarchy * @param per_dir_fn: function to call for each holding dir * @param per_file_fn: function to call for each holding file * @param per_chunk_fn: function to call for each holding chunk */static void holding_walk_disk(    char *hdisk,    gpointer datap,    stop_at_t stop_at,    holding_walk_fn per_dir_fn,    holding_walk_fn per_file_fn,    holding_walk_fn per_chunk_fn){    DIR *dir;    struct dirent *workdir;    char *hdir = NULL;    int proceed = 1;    if ((dir = opendir(hdisk)) == NULL) {        if (errno != ENOENT)           dbprintf(_("Warning: could not open holding disk %s: %s\n"),                  hdisk, strerror(errno));        return;    }    while ((workdir = readdir(dir)) != NULL) {	int is_cruft = 0;        if (is_dot_or_dotdot(workdir->d_name))            continue; /* expected cruft */        hdir = newvstralloc(hdir,                     hdisk, "/", workdir->d_name,                     NULL);        /* detect cruft */        if (!is_dir(hdir)) {	    is_cruft = 1;        } else if (!is_datestr(workdir->d_name)) {            /* EXT2/3 leave these in the root of each volume */            if (strcmp(workdir->d_name, "lost+found") == 0)		continue; /* expected cruft */	    else		is_cruft = 1; /* unexpected */        }	if (per_dir_fn) 	    proceed = per_dir_fn(datap, 			hdisk, 			workdir->d_name, 			hdir, 			is_cruft);	if (!is_cruft && proceed && stop_at != STOP_AT_DIR)	    holding_walk_dir(hdir,		    datap,		    stop_at,		    per_file_fn,		    per_chunk_fn);    }    closedir(dir);    amfree(hdir);}/* Recurse over all holding disks. * * Call per_disk_fn for each disk, per_dir_fn for each dir, and so on, stopping * at the level given by stop_at. * * datap is passed, unchanged, to all holding_walk_fns. * * @param datap: generic user-data pointer * @param stop_at: do not proceed beyond this level of the hierarchy * @param per_disk_fn: function to call for each holding disk * @param per_dir_fn: function to call for each holding dir * @param per_file_fn: function to call for each holding file * @param per_chunk_fn: function to call for each holding chunk */static void holding_walk(    gpointer datap,    stop_at_t stop_at,    holding_walk_fn per_disk_fn,    holding_walk_fn per_dir_fn,    holding_walk_fn per_file_fn,    holding_walk_fn per_chunk_fn){    holdingdisk_t *hdisk_conf;    char *hdisk;    int proceed = 1;    for (hdisk_conf = getconf_holdingdisks(); 		hdisk_conf != NULL;		hdisk_conf = holdingdisk_next(hdisk_conf)) {	int is_cruft = 0;	hdisk = holdingdisk_get_diskdir(hdisk_conf);	if (!is_dir(hdisk))	    is_cruft = 1;	if (per_disk_fn) 	    proceed = per_disk_fn(datap, 			NULL, 			hdisk, 			hdisk, 			0);	if (proceed && stop_at != STOP_AT_DISK)	    holding_walk_disk(hdisk,		    datap,		    stop_at,		    per_dir_fn,		    per_file_fn,		    per_chunk_fn);    }}/* * holding_get_* functions */typedef struct {    GSList *result;    int fullpaths;} holding_get_datap_t;/* Functor for holding_get_*; adds 'element' or 'fqpath' to * the result. */static intholding_get_walk_fn(    gpointer datap,    G_GNUC_UNUSED char *base,    char *element,    char *fqpath,    int is_cruft){    holding_get_datap_t *data = (holding_get_datap_t *)datap;    /* ignore cruft */    if (is_cruft) return 0;    if (data->fullpaths)	data->result = g_slist_insert_sorted(data->result,		stralloc(fqpath), 		g_compare_strings);    else	data->result = g_slist_insert_sorted(data->result, 		stralloc(element), 		g_compare_strings);    /* don't proceed any deeper */    return 0;}GSList *holding_get_disks(void){    holding_get_datap_t data;    data.result = NULL;    data.fullpaths = 1; /* ignored anyway */    holding_walk((gpointer)&data,	STOP_AT_DISK,	holding_get_walk_fn, NULL, NULL, NULL);    return data.result;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -