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-2006 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 static const int fnmode = 0;
44 * Initialize the find files "global" variables
46 FF_PKT *init_find_files()
50 ff = (FF_PKT *)bmalloc(sizeof(FF_PKT));
51 memset(ff, 0, sizeof(FF_PKT));
53 ff->sys_fname = get_pool_memory(PM_FNAME);
55 /* Get system path and filename maximum lengths */
56 path_max = pathconf(".", _PC_PATH_MAX);
57 if (path_max < 1024) {
61 name_max = pathconf(".", _PC_NAME_MAX);
62 if (name_max < 1024) {
65 path_max++; /* add for EOS */
66 name_max++; /* add for EOS */
68 Dmsg1(100, "init_find_files ff=%p\n", ff);
73 * Set find_files options. For the moment, we only
74 * provide for full/incremental saves, and setting
75 * of save_time. For additional options, see above
78 set_find_options(FF_PKT *ff, int incremental, time_t save_time)
80 Dmsg0(100, "Enter set_find_options()\n");
81 ff->incremental = incremental;
82 ff->save_time = save_time;
83 Dmsg0(100, "Leave set_find_options()\n");
87 * For VSS we need to know which windows drives
88 * are used, because we create a snapshot of all used
89 * drives before operation
91 * the function returns the number of used drives and
92 * fills "drives" with up to 26 (A..Z) drive names
96 get_win32_driveletters(FF_PKT *ff, char* szDrives)
98 /* szDrives must be at least 27 bytes long */
104 szDrives[0] = 0; /* make empty */
107 findFILESET *fileset = ff->fileset;
111 for (i=0; i<fileset->include_list.size(); i++) {
112 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
114 /* look through all files and check */
115 for (j=0; j<incexe->name_list.size(); j++) {
116 char *fname = (char *)incexe->name_list.get(j);
117 /* fname should match x:/ */
118 if (strlen(fname) >= 2 && B_ISALPHA(fname[0])
119 && fname[1] == ':') {
121 /* always add in uppercase */
122 char ch = toupper(fname[0]);
123 /* if not found in string, add drive letter */
124 if (!strchr(szDrives,ch)) {
125 szDrives[nCount] = ch;
126 szDrives[nCount+1] = 0;
137 * Find all specified files (determined by calls to name_add()
138 * This routine calls the (handle_file) subroutine with all
139 * sorts of good information for the final disposition of
142 * Call this subroutine with a callback subroutine as the first
143 * argument and a packet as the second argument, this packet
144 * will be passed back to the callback subroutine as the last
147 * The callback subroutine gets called with:
148 * arg1 -- the FF_PKT containing filename, link, stat, ftype, flags, etc
149 * arg2 -- the user supplied packet
153 find_files(JCR *jcr, FF_PKT *ff, int callback(FF_PKT *ff_pkt, void *hpkt, bool top_level),
156 ff->callback = callback;
158 /* This is the new way */
159 findFILESET *fileset = ff->fileset;
163 ff->VerifyOpts[0] = 'V';
164 ff->VerifyOpts[1] = 0;
165 for (i=0; i<fileset->include_list.size(); i++) {
166 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
167 fileset->incexe = incexe;
169 * By setting all options, we in effect or the global options
170 * which is what we want.
172 for (j=0; j<incexe->opts_list.size(); j++) {
173 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
174 ff->flags |= fo->flags;
175 ff->GZIP_level = fo->GZIP_level;
176 ff->fstypes = fo->fstype;
177 bstrncat(ff->VerifyOpts, fo->VerifyOpts, sizeof(ff->VerifyOpts));
179 for (j=0; j<incexe->name_list.size(); j++) {
180 Dmsg1(100, "F %s\n", (char *)incexe->name_list.get(j));
181 char *fname = (char *)incexe->name_list.get(j);
182 if (find_one_file(jcr, ff, our_callback, his_pkt, fname, (dev_t)-1, true) == 0) {
183 return 0; /* error return */
191 static bool accept_file(FF_PKT *ff)
195 findFILESET *fileset = ff->fileset;
196 findINCEXE *incexe = fileset->incexe;
198 for (j=0; j<incexe->opts_list.size(); j++) {
199 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
200 ff->flags = fo->flags;
201 ff->GZIP_level = fo->GZIP_level;
202 ff->reader = fo->reader;
203 ff->writer = fo->writer;
204 ff->fstypes = fo->fstype;
205 ic = (ff->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
206 if (S_ISDIR(ff->statp.st_mode)) {
207 for (k=0; k<fo->wilddir.size(); k++) {
208 if (fnmatch((char *)fo->wilddir.get(k), ff->fname, fnmode|ic) == 0) {
209 if (ff->flags & FO_EXCLUDE) {
210 Dmsg2(100, "Exclude wilddir: %s file=%s\n", (char *)fo->wilddir.get(k),
212 return false; /* reject file */
214 return true; /* accept file */
218 for (k=0; k<fo->wildfile.size(); k++) {
219 if (fnmatch((char *)fo->wildfile.get(k), ff->fname, fnmode|ic) == 0) {
220 if (ff->flags & FO_EXCLUDE) {
221 Dmsg2(100, "Exclude wildfile: %s file=%s\n", (char *)fo->wildfile.get(k),
223 return false; /* reject file */
225 return true; /* accept file */
229 for (k=0; k<fo->wild.size(); k++) {
230 if (fnmatch((char *)fo->wild.get(k), ff->fname, fnmode|ic) == 0) {
231 if (ff->flags & FO_EXCLUDE) {
232 Dmsg2(100, "Exclude wild: %s file=%s\n", (char *)fo->wild.get(k),
234 return false; /* reject file */
236 return true; /* accept file */
239 if (S_ISDIR(ff->statp.st_mode)) {
240 for (k=0; k<fo->regexdir.size(); k++) {
241 const int nmatch = 30;
242 regmatch_t pmatch[nmatch];
243 if (regexec((regex_t *)fo->regexdir.get(k), ff->fname, nmatch, pmatch, 0) == 0) {
244 if (ff->flags & FO_EXCLUDE) {
245 return false; /* reject file */
247 return true; /* accept file */
251 for (k=0; k<fo->regexfile.size(); k++) {
252 const int nmatch = 30;
253 regmatch_t pmatch[nmatch];
254 if (regexec((regex_t *)fo->regexfile.get(k), ff->fname, nmatch, pmatch, 0) == 0) {
255 if (ff->flags & FO_EXCLUDE) {
256 return false; /* reject file */
258 return true; /* accept file */
262 for (k=0; k<fo->regex.size(); k++) {
263 const int nmatch = 30;
264 regmatch_t pmatch[nmatch];
265 if (regexec((regex_t *)fo->regex.get(k), ff->fname, nmatch, pmatch, 0) == 0) {
266 if (ff->flags & FO_EXCLUDE) {
267 return false; /* reject file */
269 return true; /* accept file */
273 * If we have an empty Options clause with exclude, then
276 if (ff->flags & FO_EXCLUDE &&
277 fo->regex.size() == 0 && fo->wild.size() == 0 &&
278 fo->regexdir.size() == 0 && fo->wilddir.size() == 0 &&
279 fo->regexfile.size() == 0 && fo->wildfile.size() == 0) {
280 return false; /* reject file */
284 /* Now apply the Exclude { } directive */
285 for (i=0; i<fileset->exclude_list.size(); i++) {
286 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
287 for (j=0; j<incexe->opts_list.size(); j++) {
288 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
289 ic = (fo->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0;
290 for (k=0; k<fo->wild.size(); k++) {
291 if (fnmatch((char *)fo->wild.get(k), ff->fname, fnmode|ic) == 0) {
292 Dmsg1(100, "Reject wild1: %s\n", ff->fname);
293 return false; /* reject file */
297 ic = (incexe->current_opts != NULL && incexe->current_opts->flags & FO_IGNORECASE)
299 for (j=0; j<incexe->name_list.size(); j++) {
300 if (fnmatch((char *)incexe->name_list.get(j), ff->fname, fnmode|ic) == 0) {
301 Dmsg1(100, "Reject wild2: %s\n", ff->fname);
302 return false; /* reject file */
310 * The code comes here for each file examined.
311 * We filter the files, then call the user's callback if
312 * the file is included.
314 static int our_callback(FF_PKT *ff, void *hpkt, bool top_level)
317 return ff->callback(ff, hpkt, top_level); /* accept file */
329 // return ff->callback(ff, hpkt, top_level);
331 /* These items can be filtered */
342 if (accept_file(ff)) {
343 // Dmsg2(000, "Accept file %s; reader=%s\n", ff->fname, NPRT(ff->reader));
344 return ff->callback(ff, hpkt, top_level);
346 Dmsg1(100, "Skip file %s\n", ff->fname);
347 return -1; /* ignore this file */
351 Dmsg1(000, "Unknown FT code %d\n", ff->type);
358 * Terminate find_files() and release
359 * all allocated memory
362 term_find_files(FF_PKT *ff)
366 free_pool_memory(ff->sys_fname);
367 hard_links = term_find_one(ff);