2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of John Walker.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Test program for find files
36 #include "dird/dird.h"
37 #include "findlib/find.h"
39 #if defined(HAVE_WIN32)
40 #define isatty(fd) (fd==0)
44 int generate_daemon_event(JCR *jcr, const char *event) { return 1; }
45 int generate_job_event(JCR *jcr, const char *event) { return 1; }
46 void generate_plugin_event(JCR *jcr, bEventType eventType, void *value) { }
48 /* Global variables */
49 static int num_files = 0;
50 static int max_file_len = 0;
51 static int max_path_len = 0;
52 static int trunc_fname = 0;
53 static int trunc_path = 0;
58 static int print_file(JCR *jcr, FF_PKT *ff, bool);
59 static void count_files(FF_PKT *ff);
60 static bool copy_fileset(FF_PKT *ff, JCR *jcr);
61 static void set_options(findFOPTS *fo, const char *opts);
67 "Usage: testfind [-d debug_level] [-] [pattern1 ...]\n"
68 " -a print extended attributes (Win32 debug)\n"
69 " -d <nn> set debug level to <nn>\n"
70 " -dt print timestamp in debug output\n"
71 " -c specify config file containing FileSet resources\n"
72 " -f specify which FileSet to use\n"
73 " -? print this message.\n"
75 "Patterns are used for file inclusion -- normally directories.\n"
76 "Debug level >= 1 prints each file found.\n"
77 "Debug level >= 10 prints path/file for catalog.\n"
78 "Errors are always printed.\n"
79 "Files/paths truncated is the number of files/paths with len > 255.\n"
80 "Truncation is only in the catalog.\n"
88 main (int argc, char *const *argv)
91 const char *configfile = "bacula-dir.conf";
92 const char *fileset_name = "Windows-Full-Set";
97 setlocale(LC_ALL, "");
98 bindtextdomain("bacula", LOCALEDIR);
101 while ((ch = getopt(argc, argv, "ac:d:f:?")) != -1) {
103 case 'a': /* print extended attributes *debug* */
107 case 'c': /* set debug level */
111 case 'd': /* set debug level */
112 if (*optarg == 't') {
113 dbg_timestamp = true;
115 debug_level = atoi(optarg);
116 if (debug_level <= 0) {
122 case 'f': /* exclude patterns */
123 fileset_name = optarg;
136 parse_config(configfile);
140 foreach_res(msg, R_MSGS)
145 jcr = new_jcr(sizeof(JCR), NULL);
146 jcr->fileset = (FILESET *)GetResWithName(R_FILESET, fileset_name);
148 if (jcr->fileset == NULL) {
149 fprintf(stderr, "%s: Fileset not found\n", fileset_name);
153 fprintf(stderr, "Valid FileSets:\n");
155 foreach_res(var, R_FILESET) {
156 fprintf(stderr, " %s\n", var->hdr.name);
162 ff = init_find_files();
164 copy_fileset(ff, jcr);
166 find_files(jcr, ff, print_file, NULL);
169 free_config_resources();
170 term_last_jobs_list();
172 /* Clean up fileset */
173 findFILESET *fileset = ff->fileset;
177 /* Delete FileSet Include lists */
178 for (i=0; i<fileset->include_list.size(); i++) {
179 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
180 for (j=0; j<incexe->opts_list.size(); j++) {
181 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
182 for (k=0; k<fo->regex.size(); k++) {
183 regfree((regex_t *)fo->regex.get(k));
186 fo->regexdir.destroy();
187 fo->regexfile.destroy();
189 fo->wilddir.destroy();
190 fo->wildfile.destroy();
191 fo->wildbase.destroy();
192 fo->fstype.destroy();
193 fo->drivetype.destroy();
195 incexe->opts_list.destroy();
196 incexe->name_list.destroy();
198 fileset->include_list.destroy();
200 /* Delete FileSet Exclude lists */
201 for (i=0; i<fileset->exclude_list.size(); i++) {
202 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
203 for (j=0; j<incexe->opts_list.size(); j++) {
204 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
206 fo->regexdir.destroy();
207 fo->regexfile.destroy();
209 fo->wilddir.destroy();
210 fo->wildfile.destroy();
211 fo->wildbase.destroy();
212 fo->fstype.destroy();
213 fo->drivetype.destroy();
215 incexe->opts_list.destroy();
216 incexe->name_list.destroy();
218 fileset->exclude_list.destroy();
222 hard_links = term_find_files(ff);
226 "Max file length: %d\n"
227 "Max path length: %d\n"
228 "Files truncated: %d\n"
229 "Paths truncated: %d\n"
230 "Hard links : %d\n"),
231 num_files, max_file_len, max_path_len,
232 trunc_fname, trunc_path, hard_links);
241 static int print_file(JCR *jcr, FF_PKT *ff, bool top_level)
246 if (debug_level == 1) {
247 printf("%s\n", ff->fname);
248 } else if (debug_level > 1) {
249 printf("Lnka: %s -> %s\n", ff->fname, ff->link);
253 if (debug_level == 1) {
254 printf("%s\n", ff->fname);
255 } else if (debug_level > 1) {
256 printf("Empty: %s\n", ff->fname);
261 if (debug_level == 1) {
262 printf("%s\n", ff->fname);
263 } else if (debug_level > 1) {
264 printf(_("Reg: %s\n"), ff->fname);
269 if (debug_level == 1) {
270 printf("%s\n", ff->fname);
271 } else if (debug_level > 1) {
272 printf("Lnk: %s -> %s\n", ff->fname, ff->link);
284 char errmsg[100] = "";
285 if (ff->type == FT_NORECURSE) {
286 bstrncpy(errmsg, _("\t[will not descend: recursion turned off]"), sizeof(errmsg));
287 } else if (ff->type == FT_NOFSCHG) {
288 bstrncpy(errmsg, _("\t[will not descend: file system change not allowed]"), sizeof(errmsg));
289 } else if (ff->type == FT_INVALIDFS) {
290 bstrncpy(errmsg, _("\t[will not descend: disallowed file system]"), sizeof(errmsg));
291 } else if (ff->type == FT_INVALIDDT) {
292 bstrncpy(errmsg, _("\t[will not descend: disallowed drive type]"), sizeof(errmsg));
294 printf("%s%s%s\n", (debug_level > 1 ? "Dir: " : ""), ff->fname, errmsg);
296 ff->type = FT_DIREND;
300 if (debug_level == 1) {
301 printf("%s\n", ff->fname);
302 } else if (debug_level > 1) {
303 printf("Spec: %s\n", ff->fname);
308 printf(_("Err: Could not access %s: %s\n"), ff->fname, strerror(errno));
311 printf(_("Err: Could not follow ff->link %s: %s\n"), ff->fname, strerror(errno));
314 printf(_("Err: Could not stat %s: %s\n"), ff->fname, strerror(errno));
317 printf(_("Skip: File not saved. No change. %s\n"), ff->fname);
320 printf(_("Err: Attempt to backup archive. Not saved. %s\n"), ff->fname);
323 printf(_("Err: Could not open directory %s: %s\n"), ff->fname, strerror(errno));
326 printf(_("Err: Unknown file ff->type %d: %s\n"), ff->type, ff->fname);
331 encode_attribsEx(NULL, attr, ff);
333 printf("AttrEx=%s\n", attr);
335 // set_attribsEx(NULL, ff->fname, NULL, NULL, ff->type, attr);
340 static void count_files(FF_PKT *ar)
344 char file[MAXSTRING];
345 char spath[MAXSTRING];
349 /* Find path without the filename.
350 * I.e. everything after the last / is a "filename".
351 * OK, maybe it is a directory name, but we treat it like
352 * a filename. If we don't find a / then the whole name
353 * must be a path name (e.g. c:).
355 for (p=l=ar->fname; *p; p++) {
356 if (IsPathSeparator(*p)) {
357 l = p; /* set pos of last slash */
360 if (IsPathSeparator(*l)) { /* did we find a slash? */
361 l++; /* yes, point to filename */
362 } else { /* no, whole thing must be path name */
366 /* If filename doesn't exist (i.e. root directory), we
367 * simply create a blank name consisting of a single
368 * space. This makes handling zero length filenames
372 if (fnl > max_file_len) {
376 printf(_("===== Filename truncated to 255 chars: %s\n"), l);
381 strncpy(file, l, fnl); /* copy filename */
384 file[0] = ' '; /* blank filename */
389 if (pnl > max_path_len) {
393 printf(_("========== Path name truncated to 255 chars: %s\n"), ar->fname);
397 strncpy(spath, ar->fname, pnl);
402 printf(_("========== Path length is zero. File=%s\n"), ar->fname);
404 if (debug_level >= 10) {
405 printf(_("Path: %s\n"), spath);
406 printf(_("File: %s\n"), file);
411 bool python_set_prog(JCR*, char const*) { return false; }
413 static bool copy_fileset(FF_PKT *ff, JCR *jcr)
415 FILESET *jcr_fileset = jcr->fileset;
419 findFILESET *fileset;
420 findFOPTS *current_opts;
422 fileset = (findFILESET *)malloc(sizeof(findFILESET));
423 memset(fileset, 0, sizeof(findFILESET));
424 ff->fileset = fileset;
426 fileset->state = state_none;
427 fileset->include_list.init(1, true);
428 fileset->exclude_list.init(1, true);
432 num = jcr_fileset->num_includes;
434 num = jcr_fileset->num_excludes;
436 for (int i=0; i<num; i++) {
441 ie = jcr_fileset->include_items[i];
444 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
445 memset(fileset->incexe, 0, sizeof(findINCEXE));
446 fileset->incexe->opts_list.init(1, true);
447 fileset->incexe->name_list.init(0, 0);
448 fileset->include_list.append(fileset->incexe);
450 ie = jcr_fileset->exclude_items[i];
453 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
454 memset(fileset->incexe, 0, sizeof(findINCEXE));
455 fileset->incexe->opts_list.init(1, true);
456 fileset->incexe->name_list.init(0, 0);
457 fileset->exclude_list.append(fileset->incexe);
460 for (j=0; j<ie->num_opts; j++) {
461 FOPTS *fo = ie->opts_list[j];
463 current_opts = (findFOPTS *)malloc(sizeof(findFOPTS));
464 memset(current_opts, 0, sizeof(findFOPTS));
465 fileset->incexe->current_opts = current_opts;
466 fileset->incexe->opts_list.append(current_opts);
468 current_opts->regex.init(1, true);
469 current_opts->regexdir.init(1, true);
470 current_opts->regexfile.init(1, true);
471 current_opts->wild.init(1, true);
472 current_opts->wilddir.init(1, true);
473 current_opts->wildfile.init(1, true);
474 current_opts->wildbase.init(1, true);
475 current_opts->fstype.init(1, true);
476 current_opts->drivetype.init(1, true);
478 set_options(current_opts, fo->opts);
480 for (k=0; k<fo->regex.size(); k++) {
481 // bnet_fsend(fd, "R %s\n", fo->regex.get(k));
482 current_opts->regex.append(bstrdup((const char *)fo->regex.get(k)));
484 for (k=0; k<fo->regexdir.size(); k++) {
485 // bnet_fsend(fd, "RD %s\n", fo->regexdir.get(k));
486 current_opts->regexdir.append(bstrdup((const char *)fo->regexdir.get(k)));
488 for (k=0; k<fo->regexfile.size(); k++) {
489 // bnet_fsend(fd, "RF %s\n", fo->regexfile.get(k));
490 current_opts->regexfile.append(bstrdup((const char *)fo->regexfile.get(k)));
492 for (k=0; k<fo->wild.size(); k++) {
493 current_opts->wild.append(bstrdup((const char *)fo->wild.get(k)));
495 for (k=0; k<fo->wilddir.size(); k++) {
496 current_opts->wilddir.append(bstrdup((const char *)fo->wilddir.get(k)));
498 for (k=0; k<fo->wildfile.size(); k++) {
499 current_opts->wildfile.append(bstrdup((const char *)fo->wildfile.get(k)));
501 for (k=0; k<fo->wildbase.size(); k++) {
502 current_opts->wildbase.append(bstrdup((const char *)fo->wildbase.get(k)));
504 for (k=0; k<fo->fstype.size(); k++) {
505 current_opts->fstype.append(bstrdup((const char *)fo->fstype.get(k)));
507 for (k=0; k<fo->drivetype.size(); k++) {
508 current_opts->drivetype.append(bstrdup((const char *)fo->drivetype.get(k)));
512 for (j=0; j<ie->name_list.size(); j++) {
513 fileset->incexe->name_list.append(bstrdup((const char *)ie->name_list.get(j)));
517 if (!include) { /* If we just did excludes */
518 break; /* all done */
521 include = false; /* Now do excludes */
527 static void set_options(findFOPTS *fo, const char *opts)
532 for (p=opts; *p; p++) {
534 case 'a': /* alway replace */
535 case '0': /* no option */
538 fo->flags |= FO_EXCLUDE;
541 fo->flags |= FO_MULTIFS;
543 case 'h': /* no recursion */
544 fo->flags |= FO_NO_RECURSION;
546 case 'H': /* no hard link handling */
547 fo->flags |= FO_NO_HARDLINK;
550 fo->flags |= FO_IGNORECASE;
556 fo->flags |= FO_NOREPLACE;
558 case 'p': /* use portable data format */
559 fo->flags |= FO_PORTABLE;
561 case 'R': /* Resource forks and Finder Info */
562 fo->flags |= FO_HFSPLUS;
563 case 'r': /* read fifo */
564 fo->flags |= FO_READFIFO;
569 /* Old director did not specify SHA variant */
570 fo->flags |= FO_SHA1;
573 fo->flags |= FO_SHA1;
578 fo->flags |= FO_SHA256;
582 fo->flags |= FO_SHA512;
587 /* Automatically downgrade to SHA-1 if an unsupported
588 * SHA variant is specified */
589 fo->flags |= FO_SHA1;
595 fo->flags |= FO_SPARSE;
598 fo->flags |= FO_MTIMEONLY;
601 fo->flags |= FO_KEEPATIME;
606 case 'V': /* verify options */
607 /* Copy Verify Options */
608 for (j=0; *p && *p != ':'; p++) {
609 fo->VerifyOpts[j] = *p;
610 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
614 fo->VerifyOpts[j] = 0;
617 fo->flags |= FO_IF_NEWER;
620 fo->flags |= FO_ENHANCEDWILD;
622 case 'Z': /* gzip compression */
623 fo->flags |= FO_GZIP;
624 fo->GZIP_level = *++p - '0';
625 Dmsg1(200, "Compression level=%d\n", fo->GZIP_level);
628 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);