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);
251 static int print_file(JCR *jcr, FF_PKT *ff, bool top_level)
256 if (debug_level == 1) {
257 printf("%s\n", ff->fname);
258 } else if (debug_level > 1) {
259 printf("Lnka: %s -> %s\n", ff->fname, ff->link);
263 if (debug_level == 1) {
264 printf("%s\n", ff->fname);
265 } else if (debug_level > 1) {
266 printf("Empty: %s\n", ff->fname);
271 if (debug_level == 1) {
272 printf("%s\n", ff->fname);
273 } else if (debug_level > 1) {
274 printf(_("Reg: %s\n"), ff->fname);
279 if (debug_level == 1) {
280 printf("%s\n", ff->fname);
281 } else if (debug_level > 1) {
282 printf("Lnk: %s -> %s\n", ff->fname, ff->link);
294 char errmsg[100] = "";
295 if (ff->type == FT_NORECURSE) {
296 bstrncpy(errmsg, _("\t[will not descend: recursion turned off]"), sizeof(errmsg));
297 } else if (ff->type == FT_NOFSCHG) {
298 bstrncpy(errmsg, _("\t[will not descend: file system change not allowed]"), sizeof(errmsg));
299 } else if (ff->type == FT_INVALIDFS) {
300 bstrncpy(errmsg, _("\t[will not descend: disallowed file system]"), sizeof(errmsg));
301 } else if (ff->type == FT_INVALIDDT) {
302 bstrncpy(errmsg, _("\t[will not descend: disallowed drive type]"), sizeof(errmsg));
304 printf("%s%s%s\n", (debug_level > 1 ? "Dir: " : ""), ff->fname, errmsg);
306 ff->type = FT_DIREND;
310 if (debug_level == 1) {
311 printf("%s\n", ff->fname);
312 } else if (debug_level > 1) {
313 printf("Spec: %s\n", ff->fname);
318 printf(_("Err: Could not access %s: %s\n"), ff->fname, strerror(errno));
321 printf(_("Err: Could not follow ff->link %s: %s\n"), ff->fname, strerror(errno));
324 printf(_("Err: Could not stat %s: %s\n"), ff->fname, strerror(errno));
327 printf(_("Skip: File not saved. No change. %s\n"), ff->fname);
330 printf(_("Err: Attempt to backup archive. Not saved. %s\n"), ff->fname);
333 printf(_("Err: Could not open directory %s: %s\n"), ff->fname, strerror(errno));
336 printf(_("Err: Unknown file ff->type %d: %s\n"), ff->type, ff->fname);
341 encode_attribsEx(NULL, attr, ff);
343 printf("AttrEx=%s\n", attr);
345 // set_attribsEx(NULL, ff->fname, NULL, NULL, ff->type, attr);
350 static void count_files(FF_PKT *ar)
354 char file[MAXSTRING];
355 char spath[MAXSTRING];
359 /* Find path without the filename.
360 * I.e. everything after the last / is a "filename".
361 * OK, maybe it is a directory name, but we treat it like
362 * a filename. If we don't find a / then the whole name
363 * must be a path name (e.g. c:).
365 for (p=l=ar->fname; *p; p++) {
366 if (IsPathSeparator(*p)) {
367 l = p; /* set pos of last slash */
370 if (IsPathSeparator(*l)) { /* did we find a slash? */
371 l++; /* yes, point to filename */
372 } else { /* no, whole thing must be path name */
376 /* If filename doesn't exist (i.e. root directory), we
377 * simply create a blank name consisting of a single
378 * space. This makes handling zero length filenames
382 if (fnl > max_file_len) {
386 printf(_("===== Filename truncated to 255 chars: %s\n"), l);
391 strncpy(file, l, fnl); /* copy filename */
394 file[0] = ' '; /* blank filename */
399 if (pnl > max_path_len) {
403 printf(_("========== Path name truncated to 255 chars: %s\n"), ar->fname);
407 strncpy(spath, ar->fname, pnl);
412 printf(_("========== Path length is zero. File=%s\n"), ar->fname);
414 if (debug_level >= 10) {
415 printf(_("Path: %s\n"), spath);
416 printf(_("File: %s\n"), file);
421 bool python_set_prog(JCR*, char const*) { return false; }
423 static bool copy_fileset(FF_PKT *ff, JCR *jcr)
425 FILESET *jcr_fileset = jcr->fileset;
429 findFILESET *fileset;
430 findFOPTS *current_opts;
432 fileset = (findFILESET *)malloc(sizeof(findFILESET));
433 memset(fileset, 0, sizeof(findFILESET));
434 ff->fileset = fileset;
436 fileset->state = state_none;
437 fileset->include_list.init(1, true);
438 fileset->exclude_list.init(1, true);
442 num = jcr_fileset->num_includes;
444 num = jcr_fileset->num_excludes;
446 for (int i=0; i<num; i++) {
451 ie = jcr_fileset->include_items[i];
454 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
455 memset(fileset->incexe, 0, sizeof(findINCEXE));
456 fileset->incexe->opts_list.init(1, true);
457 fileset->incexe->name_list.init(0, 0);
458 fileset->include_list.append(fileset->incexe);
460 ie = jcr_fileset->exclude_items[i];
463 fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
464 memset(fileset->incexe, 0, sizeof(findINCEXE));
465 fileset->incexe->opts_list.init(1, true);
466 fileset->incexe->name_list.init(0, 0);
467 fileset->exclude_list.append(fileset->incexe);
470 for (j=0; j<ie->num_opts; j++) {
471 FOPTS *fo = ie->opts_list[j];
473 current_opts = (findFOPTS *)malloc(sizeof(findFOPTS));
474 memset(current_opts, 0, sizeof(findFOPTS));
475 fileset->incexe->current_opts = current_opts;
476 fileset->incexe->opts_list.append(current_opts);
478 current_opts->regex.init(1, true);
479 current_opts->regexdir.init(1, true);
480 current_opts->regexfile.init(1, true);
481 current_opts->wild.init(1, true);
482 current_opts->wilddir.init(1, true);
483 current_opts->wildfile.init(1, true);
484 current_opts->wildbase.init(1, true);
485 current_opts->fstype.init(1, true);
486 current_opts->drivetype.init(1, true);
488 set_options(current_opts, fo->opts);
490 for (k=0; k<fo->regex.size(); k++) {
491 // bnet_fsend(fd, "R %s\n", fo->regex.get(k));
492 current_opts->regex.append(bstrdup((const char *)fo->regex.get(k)));
494 for (k=0; k<fo->regexdir.size(); k++) {
495 // bnet_fsend(fd, "RD %s\n", fo->regexdir.get(k));
496 current_opts->regexdir.append(bstrdup((const char *)fo->regexdir.get(k)));
498 for (k=0; k<fo->regexfile.size(); k++) {
499 // bnet_fsend(fd, "RF %s\n", fo->regexfile.get(k));
500 current_opts->regexfile.append(bstrdup((const char *)fo->regexfile.get(k)));
502 for (k=0; k<fo->wild.size(); k++) {
503 current_opts->wild.append(bstrdup((const char *)fo->wild.get(k)));
505 for (k=0; k<fo->wilddir.size(); k++) {
506 current_opts->wilddir.append(bstrdup((const char *)fo->wilddir.get(k)));
508 for (k=0; k<fo->wildfile.size(); k++) {
509 current_opts->wildfile.append(bstrdup((const char *)fo->wildfile.get(k)));
511 for (k=0; k<fo->wildbase.size(); k++) {
512 current_opts->wildbase.append(bstrdup((const char *)fo->wildbase.get(k)));
514 for (k=0; k<fo->fstype.size(); k++) {
515 current_opts->fstype.append(bstrdup((const char *)fo->fstype.get(k)));
517 for (k=0; k<fo->drivetype.size(); k++) {
518 current_opts->drivetype.append(bstrdup((const char *)fo->drivetype.get(k)));
522 for (j=0; j<ie->name_list.size(); j++) {
523 fileset->incexe->name_list.append(bstrdup((const char *)ie->name_list.get(j)));
527 if (!include) { /* If we just did excludes */
528 break; /* all done */
531 include = false; /* Now do excludes */
537 static void set_options(findFOPTS *fo, const char *opts)
542 for (p=opts; *p; p++) {
544 case 'a': /* alway replace */
545 case '0': /* no option */
548 fo->flags |= FO_EXCLUDE;
551 fo->flags |= FO_MULTIFS;
553 case 'h': /* no recursion */
554 fo->flags |= FO_NO_RECURSION;
556 case 'H': /* no hard link handling */
557 fo->flags |= FO_NO_HARDLINK;
560 fo->flags |= FO_IGNORECASE;
566 fo->flags |= FO_NOREPLACE;
568 case 'p': /* use portable data format */
569 fo->flags |= FO_PORTABLE;
571 case 'R': /* Resource forks and Finder Info */
572 fo->flags |= FO_HFSPLUS;
573 case 'r': /* read fifo */
574 fo->flags |= FO_READFIFO;
579 /* Old director did not specify SHA variant */
580 fo->flags |= FO_SHA1;
583 fo->flags |= FO_SHA1;
588 fo->flags |= FO_SHA256;
592 fo->flags |= FO_SHA512;
597 /* Automatically downgrade to SHA-1 if an unsupported
598 * SHA variant is specified */
599 fo->flags |= FO_SHA1;
605 fo->flags |= FO_SPARSE;
608 fo->flags |= FO_MTIMEONLY;
611 fo->flags |= FO_KEEPATIME;
616 case 'V': /* verify options */
617 /* Copy Verify Options */
618 for (j=0; *p && *p != ':'; p++) {
619 fo->VerifyOpts[j] = *p;
620 if (j < (int)sizeof(fo->VerifyOpts) - 1) {
624 fo->VerifyOpts[j] = 0;
627 fo->flags |= FO_IF_NEWER;
630 fo->flags |= FO_ENHANCEDWILD;
632 case 'Z': /* gzip compression */
633 fo->flags |= FO_GZIP;
634 fo->GZIP_level = *++p - '0';
635 Dmsg1(200, "Compression level=%d\n", fo->GZIP_level);
638 fo->flags |= FO_XATTR;
641 Emsg1(M_ERROR, 0, _("Unknown include/exclude option: %c\n"), *p);