X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Ffindlib%2Ffind.c;h=0a4599e43a7859163c423dbacd0304df0a86fb69;hb=f316834a92996bce1d360a6d7464d49bb9b9f127;hp=bbf9a14984128e4fc62711a764c74d8110b173c1;hpb=a0c9eb236637f250cc1123f3a94a1126762d882a;p=bacula%2Fbacula diff --git a/bacula/src/findlib/find.c b/bacula/src/findlib/find.c index bbf9a14984..0a4599e43a 100644 --- a/bacula/src/findlib/find.c +++ b/bacula/src/findlib/find.c @@ -1,60 +1,70 @@ /* - * Main routine for finding files on a file system. - * The heart of the work is done in find_one.c - * - * Kern E. Sibbald, MM - */ -/* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Bacula® - The Network Backup Solution + + Copyright (C) 2000-2009 Free Software Foundation Europe e.V. - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. + The main author of Bacula is Kern Sibbald, with contributions from + many others, a complete list can be found in the file AUTHORS. + This program is Free Software; you can redistribute it and/or + modify it under the terms of version two of the GNU General Public + License as published by the Free Software Foundation and included + in the file LICENSE. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ +/* + * Main routine for finding files on a file system. + * The heart of the work to find the files on the + * system is done in find_one.c. Here we have the + * higher level control as well as the matching + * routines for the new syntax Options resource. + * + * Kern E. Sibbald, MM + * + * Version $Id$ */ #include "bacula.h" #include "find.h" - int32_t name_max; /* filename max length */ int32_t path_max; /* path name max length */ - -/* ****FIXME**** debug until stable */ +#ifdef DEBUG #undef bmalloc #define bmalloc(x) sm_malloc(__FILE__, __LINE__, x) -static void set_options(FF_PKT *ff, const char *opts); -static int our_callback(FF_PKT *ff, void *hpkt); +#endif +static int our_callback(JCR *jcr, FF_PKT *ff, bool top_level); static bool accept_file(FF_PKT *ff); +static const int fnmode = 0; -/* +/* * Initialize the find files "global" variables */ FF_PKT *init_find_files() { - FF_PKT *ff; + FF_PKT *ff; ff = (FF_PKT *)bmalloc(sizeof(FF_PKT)); memset(ff, 0, sizeof(FF_PKT)); ff->sys_fname = get_pool_memory(PM_FNAME); - init_include_exclude_files(ff); /* init lists */ - /* Get system path and filename maximum lengths */ path_max = pathconf(".", _PC_PATH_MAX); if (path_max < 1024) { @@ -72,7 +82,7 @@ FF_PKT *init_find_files() return ff; } -/* +/* * Set find_files options. For the moment, we only * provide for full/incremental saves, and setting * of save_time. For additional options, see above @@ -86,32 +96,86 @@ set_find_options(FF_PKT *ff, int incremental, time_t save_time) Dmsg0(100, "Leave set_find_options()\n"); } +void +set_find_changed_function(FF_PKT *ff, bool check_fct(JCR *jcr, FF_PKT *ff)) +{ + Dmsg0(100, "Enter set_find_changed_function()\n"); + ff->check_fct = check_fct; +} -/* - * Find all specified files (determined by calls to name_add() - * This routine calls the (handle_file) subroutine with all - * sorts of good information for the final disposition of - * the file. - * +/* + * For VSS we need to know which windows drives + * are used, because we create a snapshot of all used + * drives before operation + * + * the function returns the number of used drives and + * fills "drives" with up to 26 (A..Z) drive names + * + */ +int +get_win32_driveletters(FF_PKT *ff, char* szDrives) +{ + /* szDrives must be at least 27 bytes long */ + +#if !defined(HAVE_WIN32) + return 0; +#endif + + szDrives[0] = 0; /* make empty */ + int nCount = 0; + + findFILESET *fileset = ff->fileset; + if (fileset) { + int i; + dlistString *node; + + for (i=0; iinclude_list.size(); i++) { + findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i); + + /* look through all files and check */ + foreach_dlist(node, &incexe->name_list) { + char *fname = node->c_str(); + /* fname should match x:/ */ + if (strlen(fname) >= 2 && B_ISALPHA(fname[0]) + && fname[1] == ':') { + + /* always add in uppercase */ + char ch = toupper(fname[0]); + /* if not found in string, add drive letter */ + if (!strchr(szDrives,ch)) { + szDrives[nCount] = ch; + szDrives[nCount+1] = 0; + nCount++; + } + } + } + } + } + return nCount; +} + +/* * Call this subroutine with a callback subroutine as the first * argument and a packet as the second argument, this packet * will be passed back to the callback subroutine as the last * argument. * - * The callback subroutine gets called with: - * arg1 -- the FF_PKT containing filename, link, stat, ftype, flags, etc - * arg2 -- the user supplied packet - * */ int -find_files(JCR *jcr, FF_PKT *ff, int callback(FF_PKT *ff_pkt, void *hpkt), void *his_pkt) +find_files(JCR *jcr, FF_PKT *ff, int file_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level), + int plugin_save(JCR *jcr, FF_PKT *ff_pkt, bool top_level)) { - ff->callback = callback; + ff->file_save = file_save; + ff->plugin_save = plugin_save; /* This is the new way */ findFILESET *fileset = ff->fileset; if (fileset) { int i, j; + ff->flags = 0; + ff->VerifyOpts[0] = 'V'; + ff->VerifyOpts[1] = 0; + strcpy(ff->AccurateOpts, "C:mcs"); /* mtime+ctime+size by default */ for (i=0; iinclude_list.size(); i++) { findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i); fileset->incexe = incexe; @@ -121,28 +185,31 @@ find_files(JCR *jcr, FF_PKT *ff, int callback(FF_PKT *ff_pkt, void *hpkt), void */ for (j=0; jopts_list.size(); j++) { findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j); - Dmsg1(400, "Find global options O %s\n", fo->opts); - set_options(ff, fo->opts); + ff->flags |= fo->flags; + ff->GZIP_level = fo->GZIP_level; + ff->strip_path = fo->strip_path; + ff->fstypes = fo->fstype; + ff->drivetypes = fo->drivetype; + bstrncat(ff->VerifyOpts, fo->VerifyOpts, sizeof(ff->VerifyOpts)); + bstrncat(ff->AccurateOpts, fo->AccurateOpts, sizeof(ff->AccurateOpts)); } - for (j=0; jname_list.size(); j++) { - Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j)); - char *fname = (char *)incexe->name_list.get(j); - if (!find_one_file(jcr, ff, our_callback, his_pkt, fname, (dev_t)-1, 1)) { + dlistString *node; + foreach_dlist(node, &incexe->name_list) { + char *fname = node->c_str(); + Dmsg1(100, "F %s\n", fname); + ff->top_fname = fname; + if (find_one_file(jcr, ff, our_callback, ff->top_fname, (dev_t)-1, true) == 0) { return 0; /* error return */ } } - } - } else { - struct s_included_file *inc = NULL; - - /* This is the old deprecated way */ - while (!job_canceled(jcr) && (inc = get_next_included_file(ff, inc))) { - /* Copy options for this file */ - bstrncpy(ff->VerifyOpts, inc->VerifyOpts, sizeof(ff->VerifyOpts)); - Dmsg1(50, "find_files: file=%s\n", inc->fname); - if (!file_is_excluded(ff, inc->fname)) { - if (!find_one_file(jcr, ff, callback, his_pkt, inc->fname, (dev_t)-1, 1)) { - return 0; /* error return */ + if (plugin_save) { + foreach_dlist(node, &incexe->plugin_list) { + char *fname = node->c_str(); + Dmsg1(100, "PluginCommand: %s\n", fname); + ff->top_fname = fname; + ff->cmd_plugin = true; + plugin_save(jcr, ff, true); + ff->cmd_plugin = false; } } } @@ -150,50 +217,203 @@ find_files(JCR *jcr, FF_PKT *ff, int callback(FF_PKT *ff_pkt, void *hpkt), void return 1; } +/* + * Test if the currently selected directory (in ff->fname) is + * explicitly in the Include list or explicitly in the Exclude + * list. + */ +bool is_in_fileset(FF_PKT *ff) +{ + dlistString *node; + char *fname; + int i; + findINCEXE *incexe; + findFILESET *fileset = ff->fileset; + if (fileset) { + for (i=0; iinclude_list.size(); i++) { + incexe = (findINCEXE *)fileset->include_list.get(i); + foreach_dlist(node, &incexe->name_list) { + fname = node->c_str(); + Dmsg2(100, "Inc fname=%s ff->fname=%s\n", fname, ff->fname); + if (strcmp(fname, ff->fname) == 0) { + return true; + } + } + } + for (i=0; iexclude_list.size(); i++) { + incexe = (findINCEXE *)fileset->exclude_list.get(i); + foreach_dlist(node, &incexe->name_list) { + fname = node->c_str(); + Dmsg2(100, "Exc fname=%s ff->fname=%s\n", fname, ff->fname); + if (strcmp(fname, ff->fname) == 0) { + return true; + } + } + } + } + return false; +} + + static bool accept_file(FF_PKT *ff) { int i, j, k; + int fnm_flags; findFILESET *fileset = ff->fileset; findINCEXE *incexe = fileset->incexe; + const char *basename; + int (*match_func)(const char *pattern, const char *string, int flags); + + if (ff->flags & FO_ENHANCEDWILD) { +// match_func = enh_fnmatch; + match_func = fnmatch; + if ((basename = last_path_separator(ff->fname)) != NULL) + basename++; + else + basename = ff->fname; + } else { + match_func = fnmatch; + basename = ff->fname; + } - for (j=0; jopts_list.size(); j++) { + for (j = 0; j < incexe->opts_list.size(); j++) { findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j); + ff->flags = fo->flags; + ff->GZIP_level = fo->GZIP_level; + ff->ignoredir = fo->ignoredir; + ff->fstypes = fo->fstype; + ff->drivetypes = fo->drivetype; + + fnm_flags = (ff->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0; + fnm_flags |= (ff->flags & FO_ENHANCEDWILD) ? FNM_PATHNAME : 0; + + if (S_ISDIR(ff->statp.st_mode)) { + for (k=0; kwilddir.size(); k++) { + if (match_func((char *)fo->wilddir.get(k), ff->fname, fnmode|fnm_flags) == 0) { + if (ff->flags & FO_EXCLUDE) { + Dmsg2(100, "Exclude wilddir: %s file=%s\n", (char *)fo->wilddir.get(k), + ff->fname); + return false; /* reject dir */ + } + return true; /* accept dir */ + } + } + } else { + for (k=0; kwildfile.size(); k++) { + if (match_func((char *)fo->wildfile.get(k), ff->fname, fnmode|fnm_flags) == 0) { + if (ff->flags & FO_EXCLUDE) { + Dmsg2(100, "Exclude wildfile: %s file=%s\n", (char *)fo->wildfile.get(k), + ff->fname); + return false; /* reject file */ + } + return true; /* accept file */ + } + } + + for (k=0; kwildbase.size(); k++) { + if (match_func((char *)fo->wildbase.get(k), basename, fnmode|fnm_flags) == 0) { + if (ff->flags & FO_EXCLUDE) { + Dmsg2(100, "Exclude wildbase: %s file=%s\n", (char *)fo->wildbase.get(k), + basename); + return false; /* reject file */ + } + return true; /* accept file */ + } + } + } for (k=0; kwild.size(); k++) { - + if (match_func((char *)fo->wild.get(k), ff->fname, fnmode|fnm_flags) == 0) { + if (ff->flags & FO_EXCLUDE) { + Dmsg2(100, "Exclude wild: %s file=%s\n", (char *)fo->wild.get(k), + ff->fname); + return false; /* reject file */ + } + return true; /* accept file */ + } + } + if (S_ISDIR(ff->statp.st_mode)) { + for (k=0; kregexdir.size(); k++) { + const int nmatch = 30; + regmatch_t pmatch[nmatch]; + if (regexec((regex_t *)fo->regexdir.get(k), ff->fname, nmatch, pmatch, 0) == 0) { + if (ff->flags & FO_EXCLUDE) { + return false; /* reject file */ + } + return true; /* accept file */ + } + } + } else { + for (k=0; kregexfile.size(); k++) { + const int nmatch = 30; + regmatch_t pmatch[nmatch]; + if (regexec((regex_t *)fo->regexfile.get(k), ff->fname, nmatch, pmatch, 0) == 0) { + if (ff->flags & FO_EXCLUDE) { + return false; /* reject file */ + } + return true; /* accept file */ + } + } + } + for (k=0; kregex.size(); k++) { + const int nmatch = 30; + regmatch_t pmatch[nmatch]; + if (regexec((regex_t *)fo->regex.get(k), ff->fname, nmatch, pmatch, 0) == 0) { + if (ff->flags & FO_EXCLUDE) { + return false; /* reject file */ + } + return true; /* accept file */ + } + } + /* + * If we have an empty Options clause with exclude, then + * exclude the file + */ + if (ff->flags & FO_EXCLUDE && + fo->regex.size() == 0 && fo->wild.size() == 0 && + fo->regexdir.size() == 0 && fo->wilddir.size() == 0 && + fo->regexfile.size() == 0 && fo->wildfile.size() == 0 && + fo->wildbase.size() == 0) { + return false; /* reject file */ } } + /* Now apply the Exclude { } directive */ for (i=0; iexclude_list.size(); i++) { findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i); for (j=0; jopts_list.size(); j++) { findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j); + fnm_flags = (fo->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0; for (k=0; kwild.size(); k++) { - Dmsg1(400, "W %s\n", (char *)fo->wild.get(k)); - if (fnmatch((char *)fo->wild.get(k), ff->fname, FNM_PATHNAME) == 0) { - Dmsg1(000, "Reject wild: %s\n", ff->fname); + if (fnmatch((char *)fo->wild.get(k), ff->fname, fnmode|fnm_flags) == 0) { + Dmsg1(100, "Reject wild1: %s\n", ff->fname); return false; /* reject file */ } } } - for (j=0; jname_list.size(); j++) { - Dmsg1(400, "F %s\n", (char *)incexe->name_list.get(j)); - if (fnmatch((char *)incexe->name_list.get(j), ff->fname, FNM_PATHNAME) == 0) { - Dmsg1(000, "Reject: %s\n", ff->fname); + fnm_flags = (incexe->current_opts != NULL && incexe->current_opts->flags & FO_IGNORECASE) + ? FNM_CASEFOLD : 0; + dlistString *node; + foreach_dlist(node, &incexe->name_list) { + char *fname = node->c_str(); + if (fnmatch(fname, ff->fname, fnmode|fnm_flags) == 0) { + Dmsg1(100, "Reject wild2: %s\n", ff->fname); return false; /* reject file */ } } } - Dmsg1(000, "Accept: %s\n", ff->fname); return true; } /* * The code comes here for each file examined. * We filter the files, then call the user's callback if - * the file is included. + * the file is included. */ -static int our_callback(FF_PKT *ff, void *hpkt) +static int our_callback(JCR *jcr, FF_PKT *ff, bool top_level) { + if (top_level) { + return ff->file_save(jcr, ff, top_level); /* accept file */ + } switch (ff->type) { case FT_NOACCESS: case FT_NOFOLLOW: @@ -202,9 +422,11 @@ static int our_callback(FF_PKT *ff, void *hpkt) case FT_ISARCH: case FT_NORECURSE: case FT_NOFSCHG: + case FT_INVALIDFS: + case FT_INVALIDDT: case FT_NOOPEN: - Dmsg1(000, "File=%s\n", ff->fname); - return ff->callback(ff, hpkt); + case FT_REPARSE: +// return ff->file_save(jcr, ff, top_level); /* These items can be filtered */ case FT_LNKSAVED: @@ -213,103 +435,41 @@ static int our_callback(FF_PKT *ff, void *hpkt) case FT_LNK: case FT_DIRBEGIN: case FT_DIREND: + case FT_RAW: + case FT_FIFO: case FT_SPEC: + case FT_DIRNOCHG: if (accept_file(ff)) { - return ff->callback(ff, hpkt); + return ff->file_save(jcr, ff, top_level); } else { - return 0; + Dmsg1(100, "Skip file %s\n", ff->fname); + return -1; /* ignore this file */ } - } - return 0; -} - -/* - * As an optimization, we should do this during - * "compile" time in filed/job.c, and keep only a bit mask - * and the Verify options. - */ -static void set_options(FF_PKT *ff, const char *opts) -{ - int j; - const char *p; - - for (p=opts; *p; p++) { - switch (*p) { - case 'a': /* alway replace */ - case '0': /* no option */ - break; - case 'e': - ff->flags |= FO_EXCLUDE; - break; - case 'f': - ff->flags |= FO_MULTIFS; - break; - case 'h': /* no recursion */ - ff->flags |= FO_NO_RECURSION; - break; - case 'M': /* MD5 */ - ff->flags |= FO_MD5; - break; - case 'n': - ff->flags |= FO_NOREPLACE; - break; - case 'p': /* use portable data format */ - ff->flags |= FO_PORTABLE; - break; - case 'r': /* read fifo */ - ff->flags |= FO_READFIFO; - break; - case 'S': - ff->flags |= FO_SHA1; - break; - case 's': - ff->flags |= FO_SPARSE; - break; - case 'm': - ff->flags |= FO_MTIMEONLY; - break; - case 'k': - ff->flags |= FO_KEEPATIME; - break; - case 'V': /* verify options */ - /* Copy Verify Options */ - for (j=0; *p && *p != ':'; p++) { - ff->VerifyOpts[j] = *p; - if (j < (int)sizeof(ff->VerifyOpts) - 1) { - j++; - } - } - ff->VerifyOpts[j] = 0; - break; - case 'w': - ff->flags |= FO_IF_NEWER; - break; - case 'Z': /* gzip compression */ - ff->flags |= FO_GZIP; - ff->GZIP_level = *++p - '0'; - Dmsg1(200, "Compression level=%d\n", ff->GZIP_level); - break; - default: - Emsg1(M_ERROR, 0, "Unknown include/exclude option: %c\n", *p); - break; - } + default: + Dmsg1(000, "Unknown FT code %d\n", ff->type); + return 0; } } /* * Terminate find_files() and release - * all allocated memory + * all allocated memory */ int term_find_files(FF_PKT *ff) { - int hard_links; + int hard_links; - term_include_exclude_files(ff); - free_pool_memory(ff->sys_fname); - hard_links = term_find_one(ff); - free(ff); - return hard_links; + free_pool_memory(ff->sys_fname); + if (ff->fname_save) { + free_pool_memory(ff->fname_save); + } + if (ff->link_save) { + free_pool_memory(ff->link_save); + } + hard_links = term_find_one(ff); + free(ff); + return hard_links; }