1 /*
2 Bacula(R) - The Network Backup Solution
3
4 Copyright (C) 2000-2018 Kern Sibbald
5
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
8
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
13
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
16
17 Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20
21 This file was derived from GNU TAR source code. Except for a few key
22 ideas, it has been entirely rewritten for Bacula.
23
24 Kern Sibbald, MM
25
26 Thanks to the TAR programmers.
27
28 */
29
30 #include "bacula.h"
31 #include "find.h"
32 #ifdef HAVE_DARWIN_OS
33 #include <sys/param.h>
34 #include <sys/mount.h>
35 #include <sys/attr.h>
36 #endif
37
38 int breaddir(DIR *dirp, POOLMEM *&d_name);
39
40 extern int32_t name_max; /* filename max length */
41 extern int32_t path_max; /* path name max length */
42
43 /*
44 * Structure for keeping track of hard linked files, we
45 * keep an entry for each hardlinked file that we save,
46 * which is the first one found. For all the other files that
47 * are linked to this one, we save only the directory
48 * entry so we can link it.
49 */
50 struct f_link {
51 struct f_link *next;
52 dev_t dev; /* device */
53 ino_t ino; /* inode with device is unique */
54 int32_t FileIndex; /* Bacula FileIndex of this file */
55 int32_t digest_stream; /* Digest type if needed */
56 uint32_t digest_len; /* Digest len if needed */
57 char *digest; /* Checksum of the file if needed */
58 char name[1]; /* The name */
59 };
60
61 typedef struct f_link link_t;
62 #define LINK_HASHTABLE_BITS 16
63 #define LINK_HASHTABLE_SIZE (1<<LINK_HASHTABLE_BITS)
64 #define LINK_HASHTABLE_MASK (LINK_HASHTABLE_SIZE-1)
65
LINKHASH(const struct stat & info)66 static inline int LINKHASH(const struct stat &info)
67 {
68 int hash = info.st_dev;
69 unsigned long long i = info.st_ino;
70 hash ^= i;
71 i >>= 16;
72 hash ^= i;
73 i >>= 16;
74 hash ^= i;
75 i >>= 16;
76 hash ^= i;
77 return hash & LINK_HASHTABLE_MASK;
78 }
79
80 /*
81 * Create a new directory Find File packet, but copy
82 * some of the essential info from the current packet.
83 * However, be careful to zero out the rest of the
84 * packet.
85 */
new_dir_ff_pkt(FF_PKT * ff_pkt)86 static FF_PKT *new_dir_ff_pkt(FF_PKT *ff_pkt)
87 {
88 FF_PKT *dir_ff_pkt = (FF_PKT *)bmalloc(sizeof(FF_PKT));
89 memcpy((void *)dir_ff_pkt, (void *)ff_pkt, sizeof(FF_PKT));
90 dir_ff_pkt->fname = bstrdup(ff_pkt->fname);
91 dir_ff_pkt->link = bstrdup(ff_pkt->link);
92 dir_ff_pkt->sys_fname = get_pool_memory(PM_FNAME);
93
94 if (ff_pkt->strip_snap_path) {
95 dir_ff_pkt->fname_save = get_pool_memory(PM_FNAME);
96 dir_ff_pkt->link_save = get_pool_memory(PM_FNAME);
97 pm_strcpy(dir_ff_pkt->fname_save, ff_pkt->fname_save);
98 pm_strcpy(dir_ff_pkt->link_save, ff_pkt->link_save);
99
100 // need its own "working" buffers, some pm_strcat or pm_strcopy
101 // will realloc these ones, no need to copy the current values
102 dir_ff_pkt->snap_top_fname = get_pool_memory(PM_FNAME);
103 dir_ff_pkt->snap_fname = get_pool_memory(PM_FNAME);
104 } else {
105 dir_ff_pkt->fname_save = NULL;
106 dir_ff_pkt->link_save = NULL;
107 }
108
109 dir_ff_pkt->included_files_list = NULL;
110 dir_ff_pkt->excluded_files_list = NULL;
111 dir_ff_pkt->excluded_paths_list = NULL;
112 dir_ff_pkt->linkhash = NULL;
113 dir_ff_pkt->ignoredir_fname = NULL;
114 return dir_ff_pkt;
115 }
116
117 /*
118 * Free the temp directory ff_pkt
119 */
free_dir_ff_pkt(FF_PKT * dir_ff_pkt)120 static void free_dir_ff_pkt(FF_PKT *dir_ff_pkt)
121 {
122 free(dir_ff_pkt->fname);
123 free(dir_ff_pkt->link);
124 free_pool_memory(dir_ff_pkt->sys_fname);
125 if (dir_ff_pkt->fname_save) {
126 free_pool_memory(dir_ff_pkt->fname_save);
127 }
128 if (dir_ff_pkt->link_save) {
129 free_pool_memory(dir_ff_pkt->link_save);
130 }
131 if (dir_ff_pkt->snap_top_fname) {
132 free_pool_memory(dir_ff_pkt->snap_top_fname);
133 free_pool_memory(dir_ff_pkt->snap_fname);
134 }
135 free(dir_ff_pkt);
136 }
137
138 /*
139 * Check to see if we allow the file system type of a file or directory.
140 * If we do not have a list of file system types, we accept anything.
141 */
accept_fstype(FF_PKT * ff,void * dummy)142 static int accept_fstype(FF_PKT *ff, void *dummy) {
143 int i;
144 char fs[1000];
145 bool accept = true;
146
147 if (ff->fstypes.size()) {
148 accept = false;
149 if (!fstype(ff, fs, sizeof(fs))) {
150 Dmsg1(50, "Cannot determine file system type for \"%s\"\n", ff->fname);
151 } else {
152 for (i = 0; i < ff->fstypes.size(); ++i) {
153 if (strcmp(fs, (char *)ff->fstypes.get(i)) == 0) {
154 Dmsg2(100, "Accepting fstype %s for \"%s\"\n", fs, ff->fname);
155 accept = true;
156 break;
157 }
158 Dmsg3(200, "fstype %s for \"%s\" does not match %s\n", fs,
159 ff->fname, ff->fstypes.get(i));
160 }
161 }
162 }
163 return accept;
164 }
165
166 /*
167 * Check to see if we allow the drive type of a file or directory.
168 * If we do not have a list of drive types, we accept anything.
169 */
accept_drivetype(FF_PKT * ff,void * dummy)170 static int accept_drivetype(FF_PKT *ff, void *dummy) {
171 int i;
172 char dt[100];
173 bool accept = true;
174
175 if (ff->drivetypes.size()) {
176 accept = false;
177 if (!drivetype(ff->fname, dt, sizeof(dt))) {
178 Dmsg1(50, "Cannot determine drive type for \"%s\"\n", ff->fname);
179 } else {
180 for (i = 0; i < ff->drivetypes.size(); ++i) {
181 if (strcmp(dt, (char *)ff->drivetypes.get(i)) == 0) {
182 Dmsg2(100, "Accepting drive type %s for \"%s\"\n", dt, ff->fname);
183 accept = true;
184 break;
185 }
186 Dmsg3(200, "drive type %s for \"%s\" does not match %s\n", dt,
187 ff->fname, ff->drivetypes.get(i));
188 }
189 }
190 }
191 return accept;
192 }
193
194 /*
195 * This function determines whether we can use getattrlist()
196 * It's odd, but we have to use the function to determine that...
197 * Also, the man pages talk about things as if they were implemented.
198 *
199 * On Mac OS X, this succesfully differentiates between HFS+ and UFS
200 * volumes, which makes me trust it is OK for others, too.
201 */
volume_has_attrlist(const char * fname)202 static bool volume_has_attrlist(const char *fname)
203 {
204 #ifdef HAVE_DARWIN_OS
205 struct statfs st;
206 struct volinfo_struct {
207 unsigned long length; /* Mandatory field */
208 vol_capabilities_attr_t info; /* Volume capabilities */
209 } vol;
210 struct attrlist attrList;
211
212 memset(&attrList, 0, sizeof(attrList));
213 attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
214 attrList.volattr = ATTR_VOL_INFO | ATTR_VOL_CAPABILITIES;
215 if (statfs(fname, &st) == 0) {
216 /* We need to check on the mount point */
217 if (getattrlist(st.f_mntonname, &attrList, &vol, sizeof(vol), FSOPT_NOFOLLOW) == 0
218 && (vol.info.capabilities[VOL_CAPABILITIES_INTERFACES] & VOL_CAP_INT_ATTRLIST)
219 && (vol.info.valid[VOL_CAPABILITIES_INTERFACES] & VOL_CAP_INT_ATTRLIST)) {
220 return true;
221 }
222 }
223 #endif
224 return false;
225 }
226
227 /*
228 * check for BSD nodump flag
229 */
no_dump(JCR * jcr,FF_PKT * ff_pkt)230 static bool no_dump(JCR *jcr, FF_PKT *ff_pkt)
231 {
232 #if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
233 if ( (ff_pkt->flags & FO_HONOR_NODUMP) &&
234 (ff_pkt->statp.st_flags & UF_NODUMP) ) {
235 Jmsg(jcr, M_INFO, 1, _(" NODUMP flag set - will not process %s\n"),
236 ff_pkt->fname);
237 return true; /* do not backup this file */
238 }
239 #endif
240 return false; /* do backup */
241 }
242
243 /* check if a file have changed during backup and display an error */
has_file_changed(JCR * jcr,FF_PKT * ff_pkt)244 bool has_file_changed(JCR *jcr, FF_PKT *ff_pkt)
245 {
246 struct stat statp;
247 Dmsg1(500, "has_file_changed fname=%s\n",ff_pkt->fname);
248
249 if (ff_pkt->type != FT_REG) { /* not a regular file */
250 return false;
251 }
252
253 if (lstat(ff_pkt->fname, &statp) != 0) {
254 berrno be;
255 Jmsg(jcr, M_WARNING, 0,
256 _("Cannot stat file %s: ERR=%s\n"),ff_pkt->fname,be.bstrerror());
257 return true;
258 }
259
260 if (statp.st_mtime != ff_pkt->statp.st_mtime) {
261 Jmsg(jcr, M_ERROR, 0, _("%s mtime changed during backup.\n"), ff_pkt->fname);
262 Dmsg3(50, "%s mtime (%lld) changed during backup (%lld).\n", ff_pkt->fname,
263 (int64_t)ff_pkt->statp.st_mtime, (int64_t)statp.st_mtime);
264 return true;
265 }
266
267 if (statp.st_ctime != ff_pkt->statp.st_ctime) {
268 Jmsg(jcr, M_ERROR, 0, _("%s ctime changed during backup.\n"), ff_pkt->fname);
269 Dmsg3(50, "%s ctime (%lld) changed during backup (%lld).\n", ff_pkt->fname,
270 (int64_t)ff_pkt->statp.st_ctime, (int64_t)statp.st_ctime);
271 return true;
272 }
273
274 if ((int64_t)statp.st_size != (int64_t)ff_pkt->statp.st_size) {
275 Jmsg(jcr, M_ERROR, 0, _("%s size of %lld changed during backup to %lld.n"),ff_pkt->fname,
276 (int64_t)ff_pkt->statp.st_size, (int64_t)statp.st_size);
277 Dmsg3(50, "%s size (%lld) changed during backup (%lld).\n", ff_pkt->fname,
278 (int64_t)ff_pkt->statp.st_size, (int64_t)statp.st_size);
279 return true;
280 }
281
282 return false;
283 }
284
285 /*
286 * For incremental/diffential or accurate backups, we
287 * determine if the current file has changed.
288 */
check_changes(JCR * jcr,FF_PKT * ff_pkt)289 bool check_changes(JCR *jcr, FF_PKT *ff_pkt)
290 {
291 /* in special mode (like accurate backup), the programmer can
292 * choose his comparison function.
293 */
294 if (ff_pkt->check_fct) {
295 return ff_pkt->check_fct(jcr, ff_pkt);
296 }
297
298 /* For normal backups (incr/diff), we use this default
299 * behaviour
300 */
301 if (ff_pkt->incremental &&
302 (ff_pkt->statp.st_mtime < ff_pkt->save_time &&
303 ((ff_pkt->flags & FO_MTIMEONLY) ||
304 ff_pkt->statp.st_ctime < ff_pkt->save_time)))
305 {
306 return false;
307 }
308
309 return true;
310 }
311
have_ignoredir(FF_PKT * ff_pkt)312 static bool have_ignoredir(FF_PKT *ff_pkt)
313 {
314 struct stat sb;
315 char *ignoredir;
316
317 /* Ensure that pointers are defined */
318 if (!ff_pkt->fileset || !ff_pkt->fileset->incexe) {
319 return false;
320 }
321 ignoredir = ff_pkt->fileset->incexe->ignoredir;
322
323 if (ignoredir) {
324 if (!ff_pkt->ignoredir_fname) {
325 ff_pkt->ignoredir_fname = get_pool_memory(PM_FNAME);
326 }
327 Mmsg(ff_pkt->ignoredir_fname, "%s/%s", ff_pkt->fname, ignoredir);
328 if (stat(ff_pkt->ignoredir_fname, &sb) == 0) {
329 Dmsg2(100, "Directory '%s' ignored (found %s)\n",
330 ff_pkt->fname, ignoredir);
331 return true; /* Just ignore this directory */
332 }
333 }
334 return false;
335 }
336
337 /*
338 * When the current file is a hardlink, the backup code can compute
339 * the checksum and store it into the link_t structure.
340 */
341 void
ff_pkt_set_link_digest(FF_PKT * ff_pkt,int32_t digest_stream,const char * digest,uint32_t len)342 ff_pkt_set_link_digest(FF_PKT *ff_pkt,
343 int32_t digest_stream, const char *digest, uint32_t len)
344 {
345 if (ff_pkt->linked && !ff_pkt->linked->digest) { /* is a hardlink */
346 ff_pkt->linked->digest = (char *) bmalloc(len);
347 memcpy(ff_pkt->linked->digest, digest, len);
348 ff_pkt->linked->digest_len = len;
349 ff_pkt->linked->digest_stream = digest_stream;
350 }
351 }
352
353 /*
354 * Find a single file.
355 * handle_file is the callback for handling the file.
356 * p is the filename
357 * parent_device is the device we are currently on
358 * top_level is 1 when not recursing or 0 when
359 * descending into a directory.
360 */
361 int
find_one_file(JCR * jcr,FF_PKT * ff_pkt,int handle_file (JCR * jcr,FF_PKT * ff,bool top_level),char * fname,dev_t parent_device,bool top_level)362 find_one_file(JCR *jcr, FF_PKT *ff_pkt,
363 int handle_file(JCR *jcr, FF_PKT *ff, bool top_level),
364 char *fname, dev_t parent_device, bool top_level)
365 {
366 struct utimbuf restore_times;
367 int rtn_stat;
368 int len;
369
370 ff_pkt->fname = ff_pkt->link = fname;
371
372 if (lstat(fname, &ff_pkt->statp) != 0) {
373 /* Cannot stat file */
374 ff_pkt->type = FT_NOSTAT;
375 ff_pkt->ff_errno = errno;
376 return handle_file(jcr, ff_pkt, top_level);
377 }
378
379 Dmsg1(300, "File ----: %s\n", fname);
380
381 /* Save current times of this directory in case we need to
382 * reset them because the user doesn't want them changed.
383 */
384 restore_times.actime = ff_pkt->statp.st_atime;
385 restore_times.modtime = ff_pkt->statp.st_mtime;
386
387 /*
388 * We check for allowed fstypes and drivetypes at top_level and fstype change (below).
389 */
390 if (top_level) {
391 if (!accept_fstype(ff_pkt, NULL)) {
392 ff_pkt->type = FT_INVALIDFS;
393 if (ff_pkt->flags & FO_KEEPATIME) {
394 utime(fname, &restore_times);
395 }
396
397 char fs[100];
398
399 if (!fstype(ff_pkt, fs, sizeof(fs))) {
400 bstrncpy(fs, "unknown", sizeof(fs));
401 }
402
403 Jmsg(jcr, M_INFO, 0, _("Top level directory \"%s\" has unlisted fstype \"%s\"\n"), fname, fs);
404 return 1; /* Just ignore this error - or the whole backup is cancelled */
405 }
406 if (!accept_drivetype(ff_pkt, NULL)) {
407 ff_pkt->type = FT_INVALIDDT;
408 if (ff_pkt->flags & FO_KEEPATIME) {
409 utime(fname, &restore_times);
410 }
411
412 char dt[100];
413
414 if (!drivetype(ff_pkt->fname, dt, sizeof(dt))) {
415 bstrncpy(dt, "unknown", sizeof(dt));
416 }
417
418 Jmsg(jcr, M_INFO, 0, _("Top level directory \"%s\" has an unlisted drive type \"%s\"\n"), fname, dt);
419 return 1; /* Just ignore this error - or the whole backup is cancelled */
420 }
421 ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
422 }
423
424 /*
425 * Ignore this entry if no_dump() returns true
426 */
427 if (no_dump(jcr, ff_pkt)) {
428 Dmsg1(100, "'%s' ignored (NODUMP flag set)\n",
429 ff_pkt->fname);
430 return 1;
431 }
432
433 /*
434 * If this is an Incremental backup, see if file was modified
435 * since our last "save_time", presumably the last Full save
436 * or Incremental.
437 */
438 if ( !S_ISDIR(ff_pkt->statp.st_mode)
439 && !check_changes(jcr, ff_pkt))
440 {
441 Dmsg1(500, "Non-directory incremental: %s\n", ff_pkt->fname);
442 ff_pkt->type = FT_NOCHG;
443 return handle_file(jcr, ff_pkt, top_level);
444 }
445
446 #ifdef HAVE_DARWIN_OS
447 if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->volhas_attrlist
448 && S_ISREG(ff_pkt->statp.st_mode)) {
449 /* TODO: initialise attrList once elsewhere? */
450 struct attrlist attrList;
451 memset(&attrList, 0, sizeof(attrList));
452 attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
453 attrList.commonattr = ATTR_CMN_FNDRINFO;
454 attrList.fileattr = ATTR_FILE_RSRCLENGTH;
455 if (getattrlist(fname, &attrList, &ff_pkt->hfsinfo,
456 sizeof(ff_pkt->hfsinfo), FSOPT_NOFOLLOW) != 0) {
457 ff_pkt->type = FT_NOSTAT;
458 ff_pkt->ff_errno = errno;
459 return handle_file(jcr, ff_pkt, top_level);
460 }
461 return -1; /* ignore */
462 }
463 #endif
464
465 ff_pkt->LinkFI = 0;
466 /*
467 * Handle hard linked files
468 *
469 * Maintain a list of hard linked files already backed up. This
470 * allows us to ensure that the data of each file gets backed
471 * up only once.
472 */
473 if (!(ff_pkt->flags & FO_NO_HARDLINK)
474 && ff_pkt->statp.st_nlink > 1
475 && (S_ISREG(ff_pkt->statp.st_mode)
476 || S_ISCHR(ff_pkt->statp.st_mode)
477 || S_ISBLK(ff_pkt->statp.st_mode)
478 || S_ISFIFO(ff_pkt->statp.st_mode)
479 || S_ISSOCK(ff_pkt->statp.st_mode))) {
480
481 struct f_link *lp;
482 if (ff_pkt->linkhash == NULL) {
483 ff_pkt->linkhash = (link_t **)bmalloc(LINK_HASHTABLE_SIZE * sizeof(link_t *));
484 memset(ff_pkt->linkhash, 0, LINK_HASHTABLE_SIZE * sizeof(link_t *));
485 }
486 const int linkhash = LINKHASH(ff_pkt->statp);
487
488 /* Search link list of hard linked files */
489 for (lp = ff_pkt->linkhash[linkhash]; lp; lp = lp->next)
490 if (lp->ino == (ino_t)ff_pkt->statp.st_ino &&
491 lp->dev == (dev_t)ff_pkt->statp.st_dev) {
492 /* If we have already backed up the hard linked file don't do it again */
493 if (strcmp(lp->name, fname) == 0) {
494 Dmsg2(400, "== Name identical skip FI=%d file=%s\n", lp->FileIndex, fname);
495 return 1; /* ignore */
496 }
497 ff_pkt->link = lp->name;
498 ff_pkt->type = FT_LNKSAVED; /* Handle link, file already saved */
499 ff_pkt->LinkFI = lp->FileIndex;
500 ff_pkt->linked = 0;
501 ff_pkt->digest = lp->digest;
502 ff_pkt->digest_stream = lp->digest_stream;
503 ff_pkt->digest_len = lp->digest_len;
504 rtn_stat = handle_file(jcr, ff_pkt, top_level);
505 Dmsg3(400, "FT_LNKSAVED FI=%d LinkFI=%d file=%s\n",
506 ff_pkt->FileIndex, lp->FileIndex, lp->name);
507 return rtn_stat;
508 }
509
510 /* File not previously dumped. Chain it into our list. */
511 len = strlen(fname) + 1;
512 lp = (struct f_link *)bmalloc(sizeof(struct f_link) + len);
513 lp->digest = NULL; /* set later */
514 lp->digest_stream = 0; /* set later */
515 lp->digest_len = 0; /* set later */
516 lp->ino = ff_pkt->statp.st_ino;
517 lp->dev = ff_pkt->statp.st_dev;
518 lp->FileIndex = 0; /* set later */
519 bstrncpy(lp->name, fname, len);
520 lp->next = ff_pkt->linkhash[linkhash];
521 ff_pkt->linkhash[linkhash] = lp;
522 ff_pkt->linked = lp; /* mark saved link */
523 Dmsg2(400, "added to hash FI=%d file=%s\n", ff_pkt->FileIndex, lp->name);
524 } else {
525 ff_pkt->linked = NULL;
526 }
527
528 /* This is not a link to a previously dumped file, so dump it. */
529 if (S_ISREG(ff_pkt->statp.st_mode)) {
530 boffset_t sizeleft;
531
532 sizeleft = ff_pkt->statp.st_size;
533
534 /* Don't bother opening empty, world readable files. Also do not open
535 files when archive is meant for /dev/null. */
536 if (ff_pkt->null_output_device || (sizeleft == 0
537 && MODE_RALL == (MODE_RALL & ff_pkt->statp.st_mode))) {
538 ff_pkt->type = FT_REGE;
539 } else {
540 ff_pkt->type = FT_REG;
541 }
542 rtn_stat = handle_file(jcr, ff_pkt, top_level);
543 if (ff_pkt->linked) {
544 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
545 }
546 Dmsg3(400, "FT_REG FI=%d linked=%d file=%s\n", ff_pkt->FileIndex,
547 ff_pkt->linked ? 1 : 0, fname);
548 if (ff_pkt->flags & FO_KEEPATIME) {
549 utime(fname, &restore_times);
550 }
551 return rtn_stat;
552
553
554 } else if (S_ISLNK(ff_pkt->statp.st_mode)) { /* soft link */
555 int size;
556 char *buffer = (char *)alloca(path_max + name_max + 102);
557
558 size = readlink(fname, buffer, path_max + name_max + 101);
559 if (size < 0) {
560 /* Could not follow link */
561 ff_pkt->type = FT_NOFOLLOW;
562 ff_pkt->ff_errno = errno;
563 rtn_stat = handle_file(jcr, ff_pkt, top_level);
564 if (ff_pkt->linked) {
565 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
566 }
567 return rtn_stat;
568 }
569 buffer[size] = 0;
570 ff_pkt->link = buffer; /* point to link */
571 ff_pkt->type = FT_LNK; /* got a real link */
572 rtn_stat = handle_file(jcr, ff_pkt, top_level);
573 if (ff_pkt->linked) {
574 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
575 }
576 return rtn_stat;
577
578 } else if (S_ISDIR(ff_pkt->statp.st_mode)) {
579 DIR *directory;
580 POOL_MEM dname(PM_FNAME);
581 char *link;
582 int link_len;
583 int len;
584 int status;
585 dev_t our_device = ff_pkt->statp.st_dev;
586 bool recurse = true;
587 bool volhas_attrlist = ff_pkt->volhas_attrlist; /* Remember this if we recurse */
588
589 /*
590 * Ignore this directory and everything below if the file .nobackup
591 * (or what is defined for IgnoreDir in this fileset) exists
592 */
593 if (have_ignoredir(ff_pkt)) {
594 return 1; /* Just ignore this directory */
595 }
596
597 /* Build a canonical directory name with a trailing slash in link var */
598 len = strlen(fname);
599 link_len = len + 200;
600 link = (char *)bmalloc(link_len + 2);
601 bstrncpy(link, fname, link_len);
602 /* Strip all trailing slashes */
603 while (len >= 1 && IsPathSeparator(link[len - 1]))
604 len--;
605 link[len++] = '/'; /* add back one */
606 link[len] = 0;
607
608 ff_pkt->link = link;
609 if (!check_changes(jcr, ff_pkt)) {
610 /* Incremental/Full+Base option, directory entry not changed */
611 ff_pkt->type = FT_DIRNOCHG;
612 } else {
613 ff_pkt->type = FT_DIRBEGIN;
614 }
615 /*
616 * We have set st_rdev to 1 if it is a reparse point, otherwise 0,
617 * if st_rdev is 2, it is a mount point
618 */
619 #if defined(HAVE_WIN32)
620 /*
621 * A reparse point (WIN32_REPARSE_POINT)
622 * is something special like one of the following:
623 * IO_REPARSE_TAG_DFS 0x8000000A
624 * IO_REPARSE_TAG_DFSR 0x80000012
625 * IO_REPARSE_TAG_HSM 0xC0000004
626 * IO_REPARSE_TAG_HSM2 0x80000006
627 * IO_REPARSE_TAG_SIS 0x80000007
628 * IO_REPARSE_TAG_SYMLINK 0xA000000C
629 *
630 * A junction point is a:
631 * IO_REPARSE_TAG_MOUNT_POINT 0xA0000003
632 * which can be either a link to a Volume (WIN32_MOUNT_POINT)
633 * or a link to a directory (WIN32_JUNCTION_POINT)
634 *
635 * Ignore WIN32_REPARSE_POINT and WIN32_JUNCTION_POINT
636 */
637 if (ff_pkt->statp.st_rdev == WIN32_REPARSE_POINT) {
638 ff_pkt->type = FT_REPARSE;
639 } else if (ff_pkt->statp.st_rdev == WIN32_JUNCTION_POINT) {
640 ff_pkt->type = FT_JUNCTION;
641 }
642 #endif
643 /*
644 * Note, we return the directory to the calling program (handle_file)
645 * when we first see the directory (FT_DIRBEGIN.
646 * This allows the program to apply matches and make a
647 * choice whether or not to accept it. If it is accepted, we
648 * do not immediately save it, but do so only after everything
649 * in the directory is seen (i.e. the FT_DIREND).
650 */
651 rtn_stat = handle_file(jcr, ff_pkt, top_level);
652 if (rtn_stat < 1 || ff_pkt->type == FT_REPARSE ||
653 ff_pkt->type == FT_JUNCTION) { /* ignore or error status */
654 free(link);
655 return rtn_stat;
656 }
657 /* Done with DIRBEGIN, next call will be DIREND */
658 if (ff_pkt->type == FT_DIRBEGIN) {
659 ff_pkt->type = FT_DIREND;
660 }
661
662 /*
663 * Create a temporary ff packet for this directory
664 * entry, and defer handling the directory until
665 * we have recursed into it. This saves the
666 * directory after all files have been processed, and
667 * during the restore, the directory permissions will
668 * be reset after all the files have been restored.
669 */
670 Dmsg1(300, "Create temp ff packet for dir: %s\n", ff_pkt->fname);
671 FF_PKT *dir_ff_pkt = new_dir_ff_pkt(ff_pkt);
672
673 /*
674 * Do not descend into subdirectories (recurse) if the
675 * user has turned it off for this directory.
676 *
677 * If we are crossing file systems, we are either not allowed
678 * to cross, or we may be restricted by a list of permitted
679 * file systems.
680 */
681 bool is_win32_mount_point = false;
682 #if defined(HAVE_WIN32)
683 is_win32_mount_point = ff_pkt->statp.st_rdev == WIN32_MOUNT_POINT;
684 #endif
685 if (!top_level && ff_pkt->flags & FO_NO_RECURSION) {
686 ff_pkt->type = FT_NORECURSE;
687 recurse = false;
688 } else if (!top_level && (parent_device != ff_pkt->statp.st_dev ||
689 is_win32_mount_point)) {
690 if(!(ff_pkt->flags & FO_MULTIFS)) {
691 ff_pkt->type = FT_NOFSCHG;
692 recurse = false;
693 } else if (!accept_fstype(ff_pkt, NULL)) {
694 ff_pkt->type = FT_INVALIDFS;
695 recurse = false;
696 } else {
697 ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
698 }
699 }
700 /* If not recursing, just backup dir and return */
701 if (!recurse) {
702 rtn_stat = handle_file(jcr, ff_pkt, top_level);
703 if (ff_pkt->linked) {
704 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
705 }
706 free(link);
707 free_dir_ff_pkt(dir_ff_pkt);
708 ff_pkt->link = ff_pkt->fname; /* reset "link" */
709 if (ff_pkt->flags & FO_KEEPATIME) {
710 utime(fname, &restore_times);
711 }
712 return rtn_stat;
713 }
714
715 ff_pkt->link = ff_pkt->fname; /* reset "link" */
716
717 /*
718 * Descend into or "recurse" into the directory to read
719 * all the files in it.
720 */
721 errno = 0;
722 if ((directory = opendir(fname)) == NULL) {
723 ff_pkt->type = FT_NOOPEN;
724 ff_pkt->ff_errno = errno;
725 rtn_stat = handle_file(jcr, ff_pkt, top_level);
726 if (ff_pkt->linked) {
727 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
728 }
729 free(link);
730 free_dir_ff_pkt(dir_ff_pkt);
731 return rtn_stat;
732 }
733
734 /*
735 * Process all files in this directory entry (recursing).
736 * This would possibly run faster if we chdir to the directory
737 * before traversing it.
738 */
739 rtn_stat = 1;
740 while (!job_canceled(jcr)) {
741 char *p, *q;
742 int l;
743 int i;
744
745 status = breaddir(directory, dname.addr());
746 if (status != 0) {
747 /* error or end of directory */
748 // Dmsg1(99, "breaddir returned stat=%d\n", status);
749 break;
750 }
751 p = dname.c_str();
752 /* Skip `.', `..', and excluded file names. */
753 if (p[0] == '\0' || (p[0] == '.' && (p[1] == '\0' ||
754 (p[1] == '.' && p[2] == '\0')))) {
755 continue;
756 }
757 l = strlen(dname.c_str());
758 if (l + len >= link_len) {
759 link_len = len + l + 1;
760 link = (char *)brealloc(link, link_len + 1);
761 }
762 q = link + len;
763 for (i=0; i < l; i++) {
764 *q++ = *p++;
765 }
766 *q = 0;
767 if (!file_is_excluded(ff_pkt, link)) {
768 rtn_stat = find_one_file(jcr, ff_pkt, handle_file, link, our_device, false);
769 if (ff_pkt->linked) {
770 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
771 }
772 }
773 }
774 closedir(directory);
775 free(link);
776
777 /*
778 * Now that we have recursed through all the files in the
779 * directory, we "save" the directory so that after all
780 * the files are restored, this entry will serve to reset
781 * the directory modes and dates. Temp directory values
782 * were used without this record.
783 */
784 handle_file(jcr, dir_ff_pkt, top_level); /* handle directory entry */
785 if (ff_pkt->linked) {
786 ff_pkt->linked->FileIndex = dir_ff_pkt->FileIndex;
787 }
788 free_dir_ff_pkt(dir_ff_pkt);
789
790 if (ff_pkt->flags & FO_KEEPATIME) {
791 utime(fname, &restore_times);
792 }
793 ff_pkt->volhas_attrlist = volhas_attrlist; /* Restore value in case it changed. */
794 return rtn_stat;
795 } /* end check for directory */
796
797 /*
798 * If it is explicitly mentioned (i.e. top_level) and is
799 * a block device, we do a raw backup of it or if it is
800 * a fifo, we simply read it.
801 */
802 #ifdef HAVE_FREEBSD_OS
803 /*
804 * On FreeBSD, all block devices are character devices, so
805 * to be able to read a raw disk, we need the check for
806 * a character device.
807 * crw-r----- 1 root operator - 116, 0x00040002 Jun 9 19:32 /dev/ad0s3
808 * crw-r----- 1 root operator - 116, 0x00040002 Jun 9 19:32 /dev/rad0s3
809 */
810 if (top_level && (S_ISBLK(ff_pkt->statp.st_mode) || S_ISCHR(ff_pkt->statp.st_mode))) {
811 #else
812 if (top_level && S_ISBLK(ff_pkt->statp.st_mode)) {
813 #endif
814 ff_pkt->type = FT_RAW; /* raw partition */
815 } else if (top_level && S_ISFIFO(ff_pkt->statp.st_mode) &&
816 ff_pkt->flags & FO_READFIFO) {
817 ff_pkt->type = FT_FIFO;
818 } else {
819 /* The only remaining types are special (character, ...) files */
820 ff_pkt->type = FT_SPEC;
821 }
822 rtn_stat = handle_file(jcr, ff_pkt, top_level);
823 if (ff_pkt->linked) {
824 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
825 }
826 return rtn_stat;
827 }
828
829 int term_find_one(FF_PKT *ff)
830 {
831 struct f_link *lp, *lc;
832 int count = 0;
833 int i;
834
835
836 if (ff->linkhash == NULL) return 0;
837
838 for (i =0 ; i < LINK_HASHTABLE_SIZE; i ++) {
839 /* Free up list of hard linked files */
840 lp = ff->linkhash[i];
841 while (lp) {
842 lc = lp;
843 lp = lp->next;
844 if (lc) {
845 if (lc->digest) {
846 free(lc->digest);
847 }
848 free(lc);
849 count++;
850 }
851 }
852 ff->linkhash[i] = NULL;
853 }
854 free(ff->linkhash);
855 ff->linkhash = NULL;
856 return count;
857 }
858