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");
104 while ((ch = getopt(argc, argv, "ac:d:f:?")) != -1) {
106 case 'a': /* print extended attributes *debug* */
110 case 'c': /* set debug level */
114 case 'd': /* set debug level */
115 if (*optarg == 't') {
116 dbg_timestamp = true;
118 debug_level = atoi(optarg);
119 if (debug_level <= 0) {
125 case 'f': /* exclude patterns */
126 fileset_name = optarg;
139 config = new_config_parser();
140 parse_dir_config(config, configfile, M_ERROR_TERM);
144 foreach_res(msg, R_MSGS)
149 jcr = new_jcr(sizeof(JCR), NULL);
150 jcr->fileset = (FILESET *)GetResWithName(R_FILESET, fileset_name);
152 if (jcr->fileset == NULL) {
153 fprintf(stderr, "%s: Fileset not found\n", fileset_name);
157 fprintf(stderr, "Valid FileSets:\n");
159 foreach_res(var, R_FILESET) {
160 fprintf(stderr, " %s\n", var->hdr.name);
166 ff = init_find_files();
168 copy_fileset(ff, jcr);
170 find_files(jcr, ff, print_file, NULL);
174 config->free_resources();
179 term_last_jobs_list();
181 /* Clean up fileset */
182 findFILESET *fileset = ff->fileset;
186 /* Delete FileSet Include lists */
187 for (i=0; i<fileset->include_list.size(); i++) {
188 findINCEXE *incexe = (findINCEXE *)fileset->include_list.get(i);
189 for (j=0; j<incexe->opts_list.size(); j++) {
190 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
191 for (k=0; k<fo->regex.size(); k++) {
192 regfree((regex_t *)fo->regex.get(k));
195 fo->regexdir.destroy();
196 fo->regexfile.destroy();
198 fo->wilddir.destroy();
199 fo->wildfile.destroy();
200 fo->wildbase.destroy();
201 fo->fstype.destroy();
202 fo->drivetype.destroy();
204 incexe->opts_list.destroy();
205 incexe->name_list.destroy();
207 fileset->include_list.destroy();
209 /* Delete FileSet Exclude lists */
210 for (i=0; i<fileset->exclude_list.size(); i++) {
211 findINCEXE *incexe = (findINCEXE *)fileset->exclude_list.get(i);
212 for (j=0; j<incexe->opts_list.size(); j++) {
213 findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
215 fo->regexdir.destroy();
216 fo->regexfile.destroy();
218 fo->wilddir.destroy();
219 fo->wildfile.destroy();
220 fo->wildbase.destroy();
221 fo->fstype.destroy();
222 fo->drivetype.destroy();
224 incexe->opts_list.destroy();
225 incexe->name_list.destroy();
227 fileset->exclude_list.destroy();
231 hard_links = term_find_files(ff);
235 "Max file length: %d\n"
236 "Max path length: %d\n"
237 "Files truncated: %d\n"
238 "Paths truncated: %d\n"
239 "Hard links : %d\n"),
240 num_files, max_file_len, max_path_len,
241 trunc_fname, trunc_path, hard_links);
250 static int print_file(JCR *jcr, FF_PKT *ff, bool top_level)
255 if (debug_level == 1) {
256 printf("%s\n", ff->fname);
257 } else if (debug_level > 1) {
258 printf("Lnka: %s -> %s\n", ff->fname, ff->link);
262 if (debug_level == 1) {
263 printf("%s\n", ff->fname);
264 } else if (debug_level > 1) {
265 printf("Empty: %s\n", ff->fname);
270 if (debug_level == 1) {
271 printf("%s\n", ff->fname);
272 } else if (debug_level > 1) {
273 printf(_("Reg: %s\n"), ff->fname);
278 if (debug_level == 1) {
279 printf("%s\n", ff->fname);
280 } else if (debug_level > 1) {
281 printf("Lnk: %s -> %s\n", ff->fname, ff->link);
293 char errmsg[100] = "";
294 if (ff->type == FT_NORECURSE) {
295 bstrncpy(errmsg, _("\t[will not descend: recursion turned off]"), sizeof(errmsg));
296 } else if (ff->type == FT_NOFSCHG) {
297 bstrncpy(errmsg, _("\t[will not descend: file system change not allowed]"), sizeof(errmsg));
298 } else if (ff->type == FT_INVALIDFS) {
299 bstrncpy(errmsg, _("\t[will not descend: disallowed file system]"), sizeof(errmsg));
300 } else if (ff->type == FT_INVALIDDT) {
301 bstrncpy(errmsg, _("\t[will not descend: disallowed drive type]"), sizeof(errmsg));
303 printf("%s%s%s\n", (debug_level > 1 ? "Dir: " : ""), ff->fname, errmsg);
305 ff->type = FT_DIREND;
309 if (debug_level == 1) {
310 printf("%s\n", ff->fname);
311 } else if (debug_level > 1) {
312 printf("Spec: %s\n", ff->fname);
317 printf(_("Err: Could not access %s: %s\n"), ff->fname, strerror(errno));
320 printf(_("Err: Could not follow ff->link %s: %s\n"), ff->fname, strerror(errno));
323 printf(_("Err: Could not stat %s: %s\n"), ff->fname, strerror(errno));
326 printf(_("Skip: File not saved. No change. %s\n"), ff->fname);
329 printf(_("Err: Attempt to backup archive. Not saved. %s\n"), ff->fname);
332 printf(_("Err: Could not open directory %s: %s\n"), ff->fname, strerror(errno));
335 printf(_("Err: Unknown file ff->type %d: %s\n"), ff->type, ff->fname);
340 encode_attribsEx(NULL, attr, ff);
342 printf("AttrEx=%s\n", attr);
344 // set_attribsEx(NULL, ff->fname, NULL, NULL, ff->type, attr);
349 static void count_files(FF_PKT *ar)
353 char file[MAXSTRING];
354 char spath[MAXSTRING];
358 /* Find path without the filename.
359 * I.e. everything after the last / is a "filename".
360 * OK, maybe it is a directory name, but we treat it like
361 * a filename. If we don't find a / then the whole name
362 * must be a path name (e.g. c:).
364 for (p=l=ar->fname; *p; p++) {
365 if (IsPathSeparator(*p)) {
366 l = p; /* set pos of last slash */
369 if (IsPathSeparator(*l)) { /* did we find a slash? */
370 l++; /* yes, point to filename */
371 } else { /* no, whole thing must be path name */
375 /* If filename doesn't exist (i.e. root directory), we
376 * simply create a blank name consisting of a single
377 * space. This makes handling zero length filenames
381 if (fnl > max_file_len) {
385 printf(_("===== Filename truncated to 255 chars: %s\n"), l);
390 strncpy(file, l, fnl); /* copy filename */
393 file[0] = ' '; /* blank filename */
398 if (pnl > max_path_len) {
402 printf(_("========== Path name truncated to 255 chars: %s\n"), ar->fname);
406 strncpy(spath, ar->fname, pnl);
411 printf(_("========== Path length is zero. File=%s\n"), ar->fname);
413 if (debug_level >= 10) {
414 printf(_("Path: %s\n"), spath);
415 printf(_("File: %s\n"), file);
420 bool python_set_prog(JCR*, char const*) { return false; }
422 static bool copy_fileset(FF_PKT *ff, JCR *jcr)
424 FILESET *jcr_fileset = jcr->fileset;
428 findFILESET *fileset;
429 findFOPTS *current_opts;
431 fileset = (findFILESET *)malloc(sizeof(findFILESET));
432 memset(fileset, 0, sizeof(findFILESET));
433 ff->fileset = fileset;
435 fileset->state = state_none;
436 fileset->include_list.init(1, true);
437 fileset->exclude_list.init(1, true);
441 num = jcr_fileset->num_includes;
443 num = jcr_fileset->num_excludes;
445 for (int i=0; i<num; i++) {
450 ie = jcr_fileset->include_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->include_list.append(fileset->incexe);
459 ie = jcr_fileset->exclude_items[i];
462 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
463 memset(fileset->incexe, 0, sizeof(findINCEXE));
464 fileset->incexe->opts_list.init(1, true);
465 fileset->incexe->name_list.init(0, 0);
466 fileset->exclude_list.append(fileset->incexe);
469 for (j=0; j<ie->num_opts; j++) {
470 FOPTS *fo = ie->opts_list[j];
472 current_opts = (findFOPTS *)malloc(sizeof(findFOPTS));
473 memset(current_opts, 0, sizeof(findFOPTS));
474 fileset->incexe->current_opts = current_opts;
475 fileset->incexe->opts_list.append(current_opts);
477 current_opts->regex.init(1, true);
478 current_opts->regexdir.init(1, true);
479 current_opts->regexfile.init(1, true);
480 current_opts->wild.init(1, true);
481 current_opts->wilddir.init(1, true);
482 current_opts->wildfile.init(1, true);
483 current_opts->wildbase.init(1, true);
484 current_opts->fstype.init(1, true);
485 current_opts->drivetype.init(1, true);
487 set_options(current_opts, fo->opts);
489 for (k=0; k<fo->regex.size(); k++) {
490 // bnet_fsend(fd, "R %s\n", fo->regex.get(k));
491 current_opts->regex.append(bstrdup((const char *)fo->regex.get(k)));
493 for (k=0; k<fo->regexdir.size(); k++) {
494 // bnet_fsend(fd, "RD %s\n", fo->regexdir.get(k));
495 current_opts->regexdir.append(bstrdup((const char *)fo->regexdir.get(k)));
497 for (k=0; k<fo->regexfile.size(); k++) {
498 // bnet_fsend(fd, "RF %s\n", fo->regexfile.get(k));
499 current_opts->regexfile.append(bstrdup((const char *)fo->regexfile.get(k)));
501 for (k=0; k<fo->wild.size(); k++) {
502 current_opts->wild.append(bstrdup((const char *)fo->wild.get(k)));
504 for (k=0; k<fo->wilddir.size(); k++) {
505 current_opts->wilddir.append(bstrdup((const char *)fo->wilddir.get(k)));
507 for (k=0; k<fo->wildfile.size(); k++) {
508 current_opts->wildfile.append(bstrdup((const char *)fo->wildfile.get(k)));
510 for (k=0; k<fo->wildbase.size(); k++) {
511 current_opts->wildbase.append(bstrdup((const char *)fo->wildbase.get(k)));
513 for (k=0; k<fo->fstype.size(); k++) {
514 current_opts->fstype.append(bstrdup((const char *)fo->fstype.get(k)));
516 for (k=0; k<fo->drivetype.size(); k++) {
517 current_opts->drivetype.append(bstrdup((const char *)fo->drivetype.get(k)));
521 for (j=0; j<ie->name_list.size(); j++) {
522 fileset->incexe->name_list.append(bstrdup((const char *)ie->name_list.get(j)));
526 if (!include) { /* If we just did excludes */
527 break; /* all done */
530 include = false; /* Now do excludes */
536 static void set_options(findFOPTS *fo, const char *opts)
541 for (p=opts; *p; p++) {
543 case 'a': /* alway replace */
544 case '0': /* no option */
547 fo->flags |= FO_EXCLUDE;
550 fo->flags |= FO_MULTIFS;
552 case 'h': /* no recursion */
553 fo->flags |= FO_NO_RECURSION;
555 case 'H': /* no hard link handling */
556 fo->flags |= FO_NO_HARDLINK;
559 fo->flags |= FO_IGNORECASE;
565 fo->flags |= FO_NOREPLACE;
567 case 'p': /* use portable data format */
568 fo->flags |= FO_PORTABLE;
570 case 'R': /* Resource forks and Finder Info */
571 fo->flags |= FO_HFSPLUS;
572 case 'r': /* read fifo */
573 fo->flags |= FO_READFIFO;
578 /* Old director did not specify SHA variant */
579 fo->flags |= FO_SHA1;
582 fo->flags |= FO_SHA1;
587 fo->flags |= FO_SHA256;
591 fo->flags |= FO_SHA512;
596 /* Automatically downgrade to SHA-1 if an unsupported
597 * SHA variant is specified */
598 fo->flags |= FO_SHA1;
604 fo->flags |= FO_SPARSE;
607 fo->flags |= FO_MTIMEONLY;
610 fo->flags |= FO_KEEPATIME;
615 case 'V': /* verify options */
616 /* Copy Verify Options */
617 for (j=0; *p && *p != ':'; p++) {
618 fo->VerifyOpts[j] = *p;
619 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
623 fo->VerifyOpts[j] = 0;
626 fo->flags |= FO_IF_NEWER;
629 fo->flags |= FO_ENHANCEDWILD;
631 case 'Z': /* gzip compression */
632 fo->flags |= FO_GZIP;
633 fo->GZIP_level = *++p - '0';
634 Dmsg1(200, "Compression level=%d\n", fo->GZIP_level);
637 fo->flags |= FO_XATTR;
640 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);