📄 holding.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. * * 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 + -