2 * Main routine for finding files on a file system.
3 * The heart of the work to find the files on the
4 * system is done in find_one.c. Here we have the
5 * higher level control as well as the matching
6 * routines for the new syntax Options resource.
13 Copyright (C) 2000-2005 Kern Sibbald
15 This program is free software; you can redistribute it and/or
16 modify it under the terms of the GNU General Public License
17 version 2 as amended with additional clauses defined in the
18 file LICENSE in the main source directory.
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 the file LICENSE for additional details.
31 int32_t name_max; /* filename max length */
32 int32_t path_max; /* path name max length */
36 #define bmalloc(x) sm_malloc(__FILE__, __LINE__, x)
38 static int our_callback(FF_PKT *ff, void *hpkt, bool top_level);
39 static bool accept_file(FF_PKT *ff);
41 /* Fold case in fnmatch() on Win32 */
43 static const int fnmode = FNM_CASEFOLD;
45 static const int fnmode = 0;
50 * Initialize the find files "global" variables
52 FF_PKT *init_find_files()
56 ff = (FF_PKT *)bmalloc(sizeof(FF_PKT));
57 memset(ff, 0, sizeof(FF_PKT));
59 ff->sys_fname = get_pool_memory(PM_FNAME);
61 /* Get system path and filename maximum lengths */
62 path_max = pathconf(".", _PC_PATH_MAX);
63 if (path_max < 1024) {
67 name_max = pathconf(".", _PC_NAME_MAX);
68 if (name_max < 1024) {
71 path_max++; /* add for EOS */
72 name_max++; /* add for EOS */
74 Dmsg1(100, "init_find_files ff=%p\n", ff);
79 * Set find_files options. For the moment, we only
80 * provide for full/incremental saves, and setting
81 * of save_time. For additional options, see above
84 set_find_options(FF_PKT *ff, int incremental, time_t save_time)
86 Dmsg0(100, "Enter set_find_options()\n");
87 ff->incremental = incremental;
88 ff->save_time = save_time;
89 Dmsg0(100, "Leave set_find_options()\n");
93 * For VSS we need to know which windows drives
94 * are used, because we create a snapshot of all used
95 * drives before operation
97 * the function returns the number of used drives and
98 * fills "drives" with up to 26 (A..Z) drive names
102 get_win32_driveletters(FF_PKT *ff, char* szDrives)
104 /* szDrives must be at least 27 bytes long */
110 szDrives[0] = 0; /* make empty */
113 findFILESET *fileset = ff->fileset;
117 for (i=0; i<fileset->include_list.size(); i++) {
118 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
120 /* look through all files and check */
121 for (j=0; j<incexe->name_list.size(); j++) {
122 char *fname = (char *)incexe->name_list.get(j);
123 /* fname should match x:/ */
124 if (strlen(fname) >= 2 && B_ISALPHA(fname[0])
125 && fname[1] == ':') {
127 /* always add in uppercase */
128 char ch = toupper(fname[0]);
129 /* if not found in string, add drive letter */
130 if (!strchr(szDrives,ch)) {
131 szDrives[nCount] = ch;
132 szDrives[nCount+1] = 0;
143 * Find all specified files (determined by calls to name_add()
144 * This routine calls the (handle_file) subroutine with all
145 * sorts of good information for the final disposition of
148 * Call this subroutine with a callback subroutine as the first
149 * argument and a packet as the second argument, this packet
150 * will be passed back to the callback subroutine as the last
153 * The callback subroutine gets called with:
154 * arg1 -- the FF_PKT containing filename, link, stat, ftype, flags, etc
155 * arg2 -- the user supplied packet
159 find_files(JCR *jcr, FF_PKT *ff, int callback(FF_PKT *ff_pkt, void *hpkt, bool top_level),
162 ff->callback = callback;
164 /* This is the new way */
165 findFILESET *fileset = ff->fileset;
169 ff->VerifyOpts[0] = 'V';
170 ff->VerifyOpts[1] = 0;
171 for (i=0; i<fileset->include_list.size(); i++) {
172 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
173 fileset->incexe = incexe;
175 * By setting all options, we in effect or the global options
176 * which is what we want.
178 for (j=0; j<incexe->opts_list.size(); j++) {
179 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
180 ff->flags |= fo->flags;
181 ff->GZIP_level = fo->GZIP_level;
182 ff->fstypes = fo->fstype;
183 bstrncat(ff->VerifyOpts, fo->VerifyOpts, sizeof(ff->VerifyOpts));
185 for (j=0; j<incexe->name_list.size(); j++) {
186 Dmsg1(100, "F %s\n", (char *)incexe->name_list.get(j));
187 char *fname = (char *)incexe->name_list.get(j);
188 if (find_one_file(jcr, ff, our_callback, his_pkt, fname, (dev_t)-1, true) == 0) {
189 return 0; /* error return */
197 static bool accept_file(FF_PKT *ff)
201 findFILESET *fileset = ff->fileset;
202 findINCEXE *incexe = fileset->incexe;
204 for (j=0; j<incexe->opts_list.size(); j++) {
205 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
206 ff->flags = fo->flags;
207 ff->GZIP_level = fo->GZIP_level;
208 ff->reader = fo->reader;
209 ff->writer = fo->writer;
210 ff->fstypes = fo->fstype;
211 ic = (ff->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
212 if (S_ISDIR(ff->statp.st_mode)) {
213 for (k=0; k<fo->wilddir.size(); k++) {
214 if (fnmatch((char *)fo->wilddir.get(k), ff->fname, fnmode|ic) == 0) {
215 if (ff->flags & FO_EXCLUDE) {
216 Dmsg2(100, "Exclude wilddir: %s file=%s\n", (char *)fo->wilddir.get(k),
218 return false; /* reject file */
220 return true; /* accept file */
224 for (k=0; k<fo->wildfile.size(); k++) {
225 if (fnmatch((char *)fo->wildfile.get(k), ff->fname, fnmode|ic) == 0) {
226 if (ff->flags & FO_EXCLUDE) {
227 Dmsg2(100, "Exclude wildfile: %s file=%s\n", (char *)fo->wildfile.get(k),
229 return false; /* reject file */
231 return true; /* accept file */
235 for (k=0; k<fo->wild.size(); k++) {
236 if (fnmatch((char *)fo->wild.get(k), ff->fname, fnmode|ic) == 0) {
237 if (ff->flags & FO_EXCLUDE) {
238 Dmsg2(100, "Exclude wild: %s file=%s\n", (char *)fo->wild.get(k),
240 return false; /* reject file */
242 return true; /* accept file */
246 if (S_ISDIR(ff->statp.st_mode)) {
247 for (k=0; k<fo->regexdir.size(); k++) {
248 const int nmatch = 30;
249 regmatch_t pmatch[nmatch];
250 if (regexec((regex_t *)fo->regexdir.get(k), ff->fname, nmatch, pmatch, 0) == 0) {
251 if (ff->flags & FO_EXCLUDE) {
252 return false; /* reject file */
254 return true; /* accept file */
258 for (k=0; k<fo->regexfile.size(); k++) {
259 const int nmatch = 30;
260 regmatch_t pmatch[nmatch];
261 if (regexec((regex_t *)fo->regexfile.get(k), ff->fname, nmatch, pmatch, 0) == 0) {
262 if (ff->flags & FO_EXCLUDE) {
263 return false; /* reject file */
265 return true; /* accept file */
269 for (k=0; k<fo->regex.size(); k++) {
270 const int nmatch = 30;
271 regmatch_t pmatch[nmatch];
272 if (regexec((regex_t *)fo->regex.get(k), ff->fname, nmatch, pmatch, 0) == 0) {
273 if (ff->flags & FO_EXCLUDE) {
274 return false; /* reject file */
276 return true; /* accept file */
281 * If we have an empty Options clause with exclude, then
284 if (ff->flags & FO_EXCLUDE &&
285 fo->regex.size() == 0 && fo->wild.size() == 0 &&
286 fo->regexdir.size() == 0 && fo->wilddir.size() == 0 &&
287 fo->regexfile.size() == 0 && fo->wildfile.size() == 0) {
288 return false; /* reject file */
292 /* Now apply the Exclude { } directive */
293 for (i=0; i<fileset->exclude_list.size(); i++) {
294 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
295 for (j=0; j<incexe->opts_list.size(); j++) {
296 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
297 ic = (fo->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
298 for (k=0; k<fo->wild.size(); k++) {
299 if (fnmatch((char *)fo->wild.get(k), ff->fname, fnmode|ic) == 0) {
300 Dmsg1(100, "Reject wild1: %s\n", ff->fname);
301 return false; /* reject file */
305 ic = (incexe->current_opts != NULL && incexe->current_opts->flags & FO_IGNORECASE)
307 for (j=0; j<incexe->name_list.size(); j++) {
308 if (fnmatch((char *)incexe->name_list.get(j), ff->fname, fnmode|ic) == 0) {
309 Dmsg1(100, "Reject wild2: %s\n", ff->fname);
310 return false; /* reject file */
318 * The code comes here for each file examined.
319 * We filter the files, then call the user's callback if
320 * the file is included.
322 static int our_callback(FF_PKT *ff, void *hpkt, bool top_level)
325 return ff->callback(ff, hpkt, top_level); /* accept file */
337 // return ff->callback(ff, hpkt, top_level);
339 /* These items can be filtered */
350 if (accept_file(ff)) {
351 // Dmsg2(000, "Accept file %s; reader=%s\n", ff->fname, NPRT(ff->reader));
352 return ff->callback(ff, hpkt, top_level);
354 Dmsg1(100, "Skip file %s\n", ff->fname);
355 return -1; /* ignore this file */
359 Dmsg1(000, "Unknown FT code %d\n", ff->type);
366 * Terminate find_files() and release
367 * all allocated memory
370 term_find_files(FF_PKT *ff)
374 free_pool_memory(ff->sys_fname);
375 hard_links = term_find_one(ff);