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 Kern Sibbald.
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) { }
47 extern bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code);
49 /* Global variables */
50 static int num_files = 0;
51 static int max_file_len = 0;
52 static int max_path_len = 0;
53 static int trunc_fname = 0;
54 static int trunc_path = 0;
56 static CONFIG *config;
60 static int print_file(JCR *jcr, FF_PKT *ff, bool);
61 static void count_files(FF_PKT *ff);
62 static bool copy_fileset(FF_PKT *ff, JCR *jcr);
63 static void set_options(findFOPTS *fo, const char *opts);
69 "Usage: testfind [-d debug_level] [-] [pattern1 ...]\n"
70 " -a print extended attributes (Win32 debug)\n"
71 " -d <nn> set debug level to <nn>\n"
72 " -dt print timestamp in debug output\n"
73 " -c specify config file containing FileSet resources\n"
74 " -f specify which FileSet to use\n"
75 " -? print this message.\n"
77 "Patterns are used for file inclusion -- normally directories.\n"
78 "Debug level >= 1 prints each file found.\n"
79 "Debug level >= 10 prints path/file for catalog.\n"
80 "Errors are always printed.\n"
81 "Files/paths truncated is the number of files/paths with len > 255.\n"
82 "Truncation is only in the catalog.\n"
90 main (int argc, char *const *argv)
93 const char *configfile = "bacula-dir.conf";
94 const char *fileset_name = "Windows-Full-Set";
99 setlocale(LC_ALL, "");
100 bindtextdomain("bacula", LOCALEDIR);
101 textdomain("bacula");
103 while ((ch = getopt(argc, argv, "ac:d:f:?")) != -1) {
105 case 'a': /* print extended attributes *debug* */
109 case 'c': /* set debug level */
113 case 'd': /* set debug level */
114 if (*optarg == 't') {
115 dbg_timestamp = true;
117 debug_level = atoi(optarg);
118 if (debug_level <= 0) {
124 case 'f': /* exclude patterns */
125 fileset_name = optarg;
138 config = new_config_parser();
139 parse_dir_config(config, configfile, M_ERROR_TERM);
143 foreach_res(msg, R_MSGS)
148 jcr = new_jcr(sizeof(JCR), NULL);
149 jcr->fileset = (FILESET *)GetResWithName(R_FILESET, fileset_name);
151 if (jcr->fileset == NULL) {
152 fprintf(stderr, "%s: Fileset not found\n", fileset_name);
156 fprintf(stderr, "Valid FileSets:\n");
158 foreach_res(var, R_FILESET) {
159 fprintf(stderr, " %s\n", var->hdr.name);
165 ff = init_find_files();
167 copy_fileset(ff, jcr);
169 find_files(jcr, ff, print_file, NULL);
173 config->free_resources();
178 term_last_jobs_list();
180 /* Clean up fileset */
181 findFILESET *fileset = ff->fileset;
185 /* Delete FileSet Include lists */
186 for (i=0; i<fileset->include_list.size(); i++) {
187 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
188 for (j=0; j<incexe->opts_list.size(); j++) {
189 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
190 for (k=0; k<fo->regex.size(); k++) {
191 regfree((regex_t *)fo->regex.get(k));
194 fo->regexdir.destroy();
195 fo->regexfile.destroy();
197 fo->wilddir.destroy();
198 fo->wildfile.destroy();
199 fo->wildbase.destroy();
200 fo->fstype.destroy();
201 fo->drivetype.destroy();
203 incexe->opts_list.destroy();
204 incexe->name_list.destroy();
206 fileset->include_list.destroy();
208 /* Delete FileSet Exclude lists */
209 for (i=0; i<fileset->exclude_list.size(); i++) {
210 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
211 for (j=0; j<incexe->opts_list.size(); j++) {
212 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
214 fo->regexdir.destroy();
215 fo->regexfile.destroy();
217 fo->wilddir.destroy();
218 fo->wildfile.destroy();
219 fo->wildbase.destroy();
220 fo->fstype.destroy();
221 fo->drivetype.destroy();
223 incexe->opts_list.destroy();
224 incexe->name_list.destroy();
226 fileset->exclude_list.destroy();
230 hard_links = term_find_files(ff);
234 "Max file length: %d\n"
235 "Max path length: %d\n"
236 "Files truncated: %d\n"
237 "Paths truncated: %d\n"
238 "Hard links : %d\n"),
239 num_files, max_file_len, max_path_len,
240 trunc_fname, trunc_path, hard_links);
249 static int print_file(JCR *jcr, FF_PKT *ff, bool top_level)
254 if (debug_level == 1) {
255 printf("%s\n", ff->fname);
256 } else if (debug_level > 1) {
257 printf("Lnka: %s -> %s\n", ff->fname, ff->link);
261 if (debug_level == 1) {
262 printf("%s\n", ff->fname);
263 } else if (debug_level > 1) {
264 printf("Empty: %s\n", ff->fname);
269 if (debug_level == 1) {
270 printf("%s\n", ff->fname);
271 } else if (debug_level > 1) {
272 printf(_("Reg: %s\n"), ff->fname);
277 if (debug_level == 1) {
278 printf("%s\n", ff->fname);
279 } else if (debug_level > 1) {
280 printf("Lnk: %s -> %s\n", ff->fname, ff->link);
292 char errmsg[100] = "";
293 if (ff->type == FT_NORECURSE) {
294 bstrncpy(errmsg, _("\t[will not descend: recursion turned off]"), sizeof(errmsg));
295 } else if (ff->type == FT_NOFSCHG) {
296 bstrncpy(errmsg, _("\t[will not descend: file system change not allowed]"), sizeof(errmsg));
297 } else if (ff->type == FT_INVALIDFS) {
298 bstrncpy(errmsg, _("\t[will not descend: disallowed file system]"), sizeof(errmsg));
299 } else if (ff->type == FT_INVALIDDT) {
300 bstrncpy(errmsg, _("\t[will not descend: disallowed drive type]"), sizeof(errmsg));
302 printf("%s%s%s\n", (debug_level > 1 ? "Dir: " : ""), ff->fname, errmsg);
304 ff->type = FT_DIREND;
308 if (debug_level == 1) {
309 printf("%s\n", ff->fname);
310 } else if (debug_level > 1) {
311 printf("Spec: %s\n", ff->fname);
316 printf(_("Err: Could not access %s: %s\n"), ff->fname, strerror(errno));
319 printf(_("Err: Could not follow ff->link %s: %s\n"), ff->fname, strerror(errno));
322 printf(_("Err: Could not stat %s: %s\n"), ff->fname, strerror(errno));
325 printf(_("Skip: File not saved. No change. %s\n"), ff->fname);
328 printf(_("Err: Attempt to backup archive. Not saved. %s\n"), ff->fname);
331 printf(_("Err: Could not open directory %s: %s\n"), ff->fname, strerror(errno));
334 printf(_("Err: Unknown file ff->type %d: %s\n"), ff->type, ff->fname);
339 encode_attribsEx(NULL, attr, ff);
341 printf("AttrEx=%s\n", attr);
343 // set_attribsEx(NULL, ff->fname, NULL, NULL, ff->type, attr);
348 static void count_files(FF_PKT *ar)
352 char file[MAXSTRING];
353 char spath[MAXSTRING];
357 /* Find path without the filename.
358 * I.e. everything after the last / is a "filename".
359 * OK, maybe it is a directory name, but we treat it like
360 * a filename. If we don't find a / then the whole name
361 * must be a path name (e.g. c:).
363 for (p=l=ar->fname; *p; p++) {
364 if (IsPathSeparator(*p)) {
365 l = p; /* set pos of last slash */
368 if (IsPathSeparator(*l)) { /* did we find a slash? */
369 l++; /* yes, point to filename */
370 } else { /* no, whole thing must be path name */
374 /* If filename doesn't exist (i.e. root directory), we
375 * simply create a blank name consisting of a single
376 * space. This makes handling zero length filenames
380 if (fnl > max_file_len) {
384 printf(_("===== Filename truncated to 255 chars: %s\n"), l);
389 strncpy(file, l, fnl); /* copy filename */
392 file[0] = ' '; /* blank filename */
397 if (pnl > max_path_len) {
401 printf(_("========== Path name truncated to 255 chars: %s\n"), ar->fname);
405 strncpy(spath, ar->fname, pnl);
410 printf(_("========== Path length is zero. File=%s\n"), ar->fname);
412 if (debug_level >= 10) {
413 printf(_("Path: %s\n"), spath);
414 printf(_("File: %s\n"), file);
419 bool python_set_prog(JCR*, char const*) { return false; }
421 static bool copy_fileset(FF_PKT *ff, JCR *jcr)
423 FILESET *jcr_fileset = jcr->fileset;
427 findFILESET *fileset;
428 findFOPTS *current_opts;
430 fileset = (findFILESET *)malloc(sizeof(findFILESET));
431 memset(fileset, 0, sizeof(findFILESET));
432 ff->fileset = fileset;
434 fileset->state = state_none;
435 fileset->include_list.init(1, true);
436 fileset->exclude_list.init(1, true);
440 num = jcr_fileset->num_includes;
442 num = jcr_fileset->num_excludes;
444 for (int i=0; i<num; i++) {
449 ie = jcr_fileset->include_items[i];
452 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
453 memset(fileset->incexe, 0, sizeof(findINCEXE));
454 fileset->incexe->opts_list.init(1, true);
455 fileset->incexe->name_list.init(0, 0);
456 fileset->include_list.append(fileset->incexe);
458 ie = jcr_fileset->exclude_items[i];
461 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
462 memset(fileset->incexe, 0, sizeof(findINCEXE));
463 fileset->incexe->opts_list.init(1, true);
464 fileset->incexe->name_list.init(0, 0);
465 fileset->exclude_list.append(fileset->incexe);
468 for (j=0; j<ie->num_opts; j++) {
469 FOPTS *fo = ie->opts_list[j];
471 current_opts = (findFOPTS *)malloc(sizeof(findFOPTS));
472 memset(current_opts, 0, sizeof(findFOPTS));
473 fileset->incexe->current_opts = current_opts;
474 fileset->incexe->opts_list.append(current_opts);
476 current_opts->regex.init(1, true);
477 current_opts->regexdir.init(1, true);
478 current_opts->regexfile.init(1, true);
479 current_opts->wild.init(1, true);
480 current_opts->wilddir.init(1, true);
481 current_opts->wildfile.init(1, true);
482 current_opts->wildbase.init(1, true);
483 current_opts->fstype.init(1, true);
484 current_opts->drivetype.init(1, true);
486 set_options(current_opts, fo->opts);
488 for (k=0; k<fo->regex.size(); k++) {
489 // bnet_fsend(fd, "R %s\n", fo->regex.get(k));
490 current_opts->regex.append(bstrdup((const char *)fo->regex.get(k)));
492 for (k=0; k<fo->regexdir.size(); k++) {
493 // bnet_fsend(fd, "RD %s\n", fo->regexdir.get(k));
494 current_opts->regexdir.append(bstrdup((const char *)fo->regexdir.get(k)));
496 for (k=0; k<fo->regexfile.size(); k++) {
497 // bnet_fsend(fd, "RF %s\n", fo->regexfile.get(k));
498 current_opts->regexfile.append(bstrdup((const char *)fo->regexfile.get(k)));
500 for (k=0; k<fo->wild.size(); k++) {
501 current_opts->wild.append(bstrdup((const char *)fo->wild.get(k)));
503 for (k=0; k<fo->wilddir.size(); k++) {
504 current_opts->wilddir.append(bstrdup((const char *)fo->wilddir.get(k)));
506 for (k=0; k<fo->wildfile.size(); k++) {
507 current_opts->wildfile.append(bstrdup((const char *)fo->wildfile.get(k)));
509 for (k=0; k<fo->wildbase.size(); k++) {
510 current_opts->wildbase.append(bstrdup((const char *)fo->wildbase.get(k)));
512 for (k=0; k<fo->fstype.size(); k++) {
513 current_opts->fstype.append(bstrdup((const char *)fo->fstype.get(k)));
515 for (k=0; k<fo->drivetype.size(); k++) {
516 current_opts->drivetype.append(bstrdup((const char *)fo->drivetype.get(k)));
520 for (j=0; j<ie->name_list.size(); j++) {
521 fileset->incexe->name_list.append(bstrdup((const char *)ie->name_list.get(j)));
525 if (!include) { /* If we just did excludes */
526 break; /* all done */
529 include = false; /* Now do excludes */
535 static void set_options(findFOPTS *fo, const char *opts)
540 for (p=opts; *p; p++) {
542 case 'a': /* alway replace */
543 case '0': /* no option */
546 fo->flags |= FO_EXCLUDE;
549 fo->flags |= FO_MULTIFS;
551 case 'h': /* no recursion */
552 fo->flags |= FO_NO_RECURSION;
554 case 'H': /* no hard link handling */
555 fo->flags |= FO_NO_HARDLINK;
558 fo->flags |= FO_IGNORECASE;
564 fo->flags |= FO_NOREPLACE;
566 case 'p': /* use portable data format */
567 fo->flags |= FO_PORTABLE;
569 case 'R': /* Resource forks and Finder Info */
570 fo->flags |= FO_HFSPLUS;
571 case 'r': /* read fifo */
572 fo->flags |= FO_READFIFO;
577 /* Old director did not specify SHA variant */
578 fo->flags |= FO_SHA1;
581 fo->flags |= FO_SHA1;
586 fo->flags |= FO_SHA256;
590 fo->flags |= FO_SHA512;
595 /* Automatically downgrade to SHA-1 if an unsupported
596 * SHA variant is specified */
597 fo->flags |= FO_SHA1;
603 fo->flags |= FO_SPARSE;
606 fo->flags |= FO_MTIMEONLY;
609 fo->flags |= FO_KEEPATIME;
614 case 'V': /* verify options */
615 /* Copy Verify Options */
616 for (j=0; *p && *p != ':'; p++) {
617 fo->VerifyOpts[j] = *p;
618 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
622 fo->VerifyOpts[j] = 0;
625 fo->flags |= FO_IF_NEWER;
628 fo->flags |= FO_ENHANCEDWILD;
630 case 'Z': /* gzip compression */
631 fo->flags |= FO_GZIP;
632 fo->GZIP_level = *++p - '0';
633 Dmsg1(200, "Compression level=%d\n", fo->GZIP_level);
636 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);