2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
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.
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.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
21 This file was derived from GNU TAR source code. Except for a few key
22 ideas, it has been entirely rewritten for Bacula.
26 Thanks to the TAR programmers.
33 #include <sys/param.h>
34 #include <sys/mount.h>
38 extern int32_t name_max; /* filename max length */
39 extern int32_t path_max; /* path name max length */
42 * Structure for keeping track of hard linked files, we
43 * keep an entry for each hardlinked file that we save,
44 * which is the first one found. For all the other files that
45 * are linked to this one, we save only the directory
46 * entry so we can link it.
50 dev_t dev; /* device */
51 ino_t ino; /* inode with device is unique */
52 uint32_t FileIndex; /* Bacula FileIndex of this file */
53 int32_t digest_stream; /* Digest type if needed */
54 uint32_t digest_len; /* Digest len if needed */
55 char *digest; /* Checksum of the file if needed */
56 char name[1]; /* The name */
59 typedef struct f_link link_t;
60 #define LINK_HASHTABLE_BITS 16
61 #define LINK_HASHTABLE_SIZE (1<<LINK_HASHTABLE_BITS)
62 #define LINK_HASHTABLE_MASK (LINK_HASHTABLE_SIZE-1)
64 static inline int LINKHASH(const struct stat &info)
66 int hash = info.st_dev;
67 unsigned long long i = info.st_ino;
75 return hash & LINK_HASHTABLE_MASK;
79 * Create a new directory Find File packet, but copy
80 * some of the essential info from the current packet.
81 * However, be careful to zero out the rest of the
84 static FF_PKT *new_dir_ff_pkt(FF_PKT *ff_pkt)
86 FF_PKT *dir_ff_pkt = (FF_PKT *)bmalloc(sizeof(FF_PKT));
87 memcpy(dir_ff_pkt, ff_pkt, sizeof(FF_PKT));
88 dir_ff_pkt->fname = bstrdup(ff_pkt->fname);
89 dir_ff_pkt->link = bstrdup(ff_pkt->link);
90 dir_ff_pkt->sys_fname = get_pool_memory(PM_FNAME);
92 if (ff_pkt->strip_snap_path) {
93 dir_ff_pkt->fname_save = get_pool_memory(PM_FNAME);
94 dir_ff_pkt->link_save = get_pool_memory(PM_FNAME);
95 pm_strcpy(dir_ff_pkt->fname_save, ff_pkt->fname_save);
96 pm_strcpy(dir_ff_pkt->link_save, ff_pkt->link_save);
99 dir_ff_pkt->fname_save = NULL;
100 dir_ff_pkt->link_save = NULL;
103 dir_ff_pkt->included_files_list = NULL;
104 dir_ff_pkt->excluded_files_list = NULL;
105 dir_ff_pkt->excluded_paths_list = NULL;
106 dir_ff_pkt->linkhash = NULL;
107 dir_ff_pkt->ignoredir_fname = NULL;
112 * Free the temp directory ff_pkt
114 static void free_dir_ff_pkt(FF_PKT *dir_ff_pkt)
116 free(dir_ff_pkt->fname);
117 free(dir_ff_pkt->link);
118 free_pool_memory(dir_ff_pkt->sys_fname);
119 if (dir_ff_pkt->fname_save) {
120 free_pool_memory(dir_ff_pkt->fname_save);
122 if (dir_ff_pkt->link_save) {
123 free_pool_memory(dir_ff_pkt->link_save);
129 * Check to see if we allow the file system type of a file or directory.
130 * If we do not have a list of file system types, we accept anything.
132 static int accept_fstype(FF_PKT *ff, void *dummy) {
137 if (ff->fstypes.size()) {
139 if (!fstype(ff, fs, sizeof(fs))) {
140 Dmsg1(50, "Cannot determine file system type for \"%s\"\n", ff->fname);
142 for (i = 0; i < ff->fstypes.size(); ++i) {
143 if (strcmp(fs, (char *)ff->fstypes.get(i)) == 0) {
144 Dmsg2(100, "Accepting fstype %s for \"%s\"\n", fs, ff->fname);
148 Dmsg3(200, "fstype %s for \"%s\" does not match %s\n", fs,
149 ff->fname, ff->fstypes.get(i));
157 * Check to see if we allow the drive type of a file or directory.
158 * If we do not have a list of drive types, we accept anything.
160 static int accept_drivetype(FF_PKT *ff, void *dummy) {
165 if (ff->drivetypes.size()) {
167 if (!drivetype(ff->fname, dt, sizeof(dt))) {
168 Dmsg1(50, "Cannot determine drive type for \"%s\"\n", ff->fname);
170 for (i = 0; i < ff->drivetypes.size(); ++i) {
171 if (strcmp(dt, (char *)ff->drivetypes.get(i)) == 0) {
172 Dmsg2(100, "Accepting drive type %s for \"%s\"\n", dt, ff->fname);
176 Dmsg3(200, "drive type %s for \"%s\" does not match %s\n", dt,
177 ff->fname, ff->drivetypes.get(i));
185 * This function determines whether we can use getattrlist()
186 * It's odd, but we have to use the function to determine that...
187 * Also, the man pages talk about things as if they were implemented.
189 * On Mac OS X, this succesfully differentiates between HFS+ and UFS
190 * volumes, which makes me trust it is OK for others, too.
192 static bool volume_has_attrlist(const char *fname)
194 #ifdef HAVE_DARWIN_OS
196 struct volinfo_struct {
197 unsigned long length; /* Mandatory field */
198 vol_capabilities_attr_t info; /* Volume capabilities */
200 struct attrlist attrList;
202 memset(&attrList, 0, sizeof(attrList));
203 attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
204 attrList.volattr = ATTR_VOL_INFO | ATTR_VOL_CAPABILITIES;
205 if (statfs(fname, &st) == 0) {
206 /* We need to check on the mount point */
207 if (getattrlist(st.f_mntonname, &attrList, &vol, sizeof(vol), FSOPT_NOFOLLOW) == 0
208 && (vol.info.capabilities[VOL_CAPABILITIES_INTERFACES] & VOL_CAP_INT_ATTRLIST)
209 && (vol.info.valid[VOL_CAPABILITIES_INTERFACES] & VOL_CAP_INT_ATTRLIST)) {
218 * check for BSD nodump flag
220 static bool no_dump(JCR *jcr, FF_PKT *ff_pkt)
222 #if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
223 if ( (ff_pkt->flags & FO_HONOR_NODUMP) &&
224 (ff_pkt->statp.st_flags & UF_NODUMP) ) {
225 Jmsg(jcr, M_INFO, 1, _(" NODUMP flag set - will not process %s\n"),
227 return true; /* do not backup this file */
230 return false; /* do backup */
233 /* check if a file have changed during backup and display an error */
234 bool has_file_changed(JCR *jcr, FF_PKT *ff_pkt)
237 Dmsg1(500, "has_file_changed fname=%s\n",ff_pkt->fname);
239 if (ff_pkt->type != FT_REG) { /* not a regular file */
243 if (lstat(ff_pkt->fname, &statp) != 0) {
245 Jmsg(jcr, M_WARNING, 0,
246 _("Cannot stat file %s: ERR=%s\n"),ff_pkt->fname,be.bstrerror());
250 if (statp.st_mtime != ff_pkt->statp.st_mtime) {
251 Jmsg(jcr, M_ERROR, 0, _("%s mtime changed during backup.\n"), ff_pkt->fname);
252 Dmsg3(50, "%s mtime (%lld) changed during backup (%lld).\n", ff_pkt->fname,
253 (int64_t)ff_pkt->statp.st_mtime, (int64_t)statp.st_mtime);
257 if (statp.st_ctime != ff_pkt->statp.st_ctime) {
258 Jmsg(jcr, M_ERROR, 0, _("%s ctime changed during backup.\n"), ff_pkt->fname);
259 Dmsg3(50, "%s ctime (%lld) changed during backup (%lld).\n", ff_pkt->fname,
260 (int64_t)ff_pkt->statp.st_ctime, (int64_t)statp.st_ctime);
264 if ((int64_t)statp.st_size != (int64_t)ff_pkt->statp.st_size) {
265 Jmsg(jcr, M_ERROR, 0, _("%s size of %lld changed during backup to %lld.n"),ff_pkt->fname,
266 (int64_t)ff_pkt->statp.st_size, (int64_t)statp.st_size);
267 Dmsg3(50, "%s size (%lld) changed during backup (%lld).\n", ff_pkt->fname,
268 (int64_t)ff_pkt->statp.st_size, (int64_t)statp.st_size);
276 * For incremental/diffential or accurate backups, we
277 * determine if the current file has changed.
279 bool check_changes(JCR *jcr, FF_PKT *ff_pkt)
281 /* in special mode (like accurate backup), the programmer can
282 * choose his comparison function.
284 if (ff_pkt->check_fct) {
285 return ff_pkt->check_fct(jcr, ff_pkt);
288 /* For normal backups (incr/diff), we use this default
291 if (ff_pkt->incremental &&
292 (ff_pkt->statp.st_mtime < ff_pkt->save_time &&
293 ((ff_pkt->flags & FO_MTIMEONLY) ||
294 ff_pkt->statp.st_ctime < ff_pkt->save_time)))
302 static bool have_ignoredir(FF_PKT *ff_pkt)
307 /* Ensure that pointers are defined */
308 if (!ff_pkt->fileset || !ff_pkt->fileset->incexe) {
311 ignoredir = ff_pkt->fileset->incexe->ignoredir;
314 if (!ff_pkt->ignoredir_fname) {
315 ff_pkt->ignoredir_fname = get_pool_memory(PM_FNAME);
317 Mmsg(ff_pkt->ignoredir_fname, "%s/%s", ff_pkt->fname, ignoredir);
318 if (stat(ff_pkt->ignoredir_fname, &sb) == 0) {
319 Dmsg2(100, "Directory '%s' ignored (found %s)\n",
320 ff_pkt->fname, ignoredir);
321 return true; /* Just ignore this directory */
328 * When the current file is a hardlink, the backup code can compute
329 * the checksum and store it into the link_t structure.
332 ff_pkt_set_link_digest(FF_PKT *ff_pkt,
333 int32_t digest_stream, const char *digest, uint32_t len)
335 if (ff_pkt->linked && !ff_pkt->linked->digest) { /* is a hardlink */
336 ff_pkt->linked->digest = (char *) bmalloc(len);
337 memcpy(ff_pkt->linked->digest, digest, len);
338 ff_pkt->linked->digest_len = len;
339 ff_pkt->linked->digest_stream = digest_stream;
344 * Find a single file.
345 * handle_file is the callback for handling the file.
347 * parent_device is the device we are currently on
348 * top_level is 1 when not recursing or 0 when
349 * descending into a directory.
352 find_one_file(JCR *jcr, FF_PKT *ff_pkt,
353 int handle_file(JCR *jcr, FF_PKT *ff, bool top_level),
354 char *fname, dev_t parent_device, bool top_level)
356 struct utimbuf restore_times;
360 ff_pkt->fname = ff_pkt->link = fname;
362 if (lstat(fname, &ff_pkt->statp) != 0) {
363 /* Cannot stat file */
364 ff_pkt->type = FT_NOSTAT;
365 ff_pkt->ff_errno = errno;
366 return handle_file(jcr, ff_pkt, top_level);
369 Dmsg1(300, "File ----: %s\n", fname);
371 /* Save current times of this directory in case we need to
372 * reset them because the user doesn't want them changed.
374 restore_times.actime = ff_pkt->statp.st_atime;
375 restore_times.modtime = ff_pkt->statp.st_mtime;
378 * We check for allowed fstypes and drivetypes at top_level and fstype change (below).
381 if (!accept_fstype(ff_pkt, NULL)) {
382 ff_pkt->type = FT_INVALIDFS;
383 if (ff_pkt->flags & FO_KEEPATIME) {
384 utime(fname, &restore_times);
389 if (!fstype(ff_pkt, fs, sizeof(fs))) {
390 bstrncpy(fs, "unknown", sizeof(fs));
393 Jmsg(jcr, M_INFO, 0, _("Top level directory \"%s\" has unlisted fstype \"%s\"\n"), fname, fs);
394 return 1; /* Just ignore this error - or the whole backup is cancelled */
396 if (!accept_drivetype(ff_pkt, NULL)) {
397 ff_pkt->type = FT_INVALIDDT;
398 if (ff_pkt->flags & FO_KEEPATIME) {
399 utime(fname, &restore_times);
404 if (!drivetype(ff_pkt->fname, dt, sizeof(dt))) {
405 bstrncpy(dt, "unknown", sizeof(dt));
408 Jmsg(jcr, M_INFO, 0, _("Top level directory \"%s\" has an unlisted drive type \"%s\"\n"), fname, dt);
409 return 1; /* Just ignore this error - or the whole backup is cancelled */
411 ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
415 * Ignore this entry if no_dump() returns true
417 if (no_dump(jcr, ff_pkt)) {
418 Dmsg1(100, "'%s' ignored (NODUMP flag set)\n",
424 * If this is an Incremental backup, see if file was modified
425 * since our last "save_time", presumably the last Full save
428 if ( !S_ISDIR(ff_pkt->statp.st_mode)
429 && !check_changes(jcr, ff_pkt))
431 Dmsg1(500, "Non-directory incremental: %s\n", ff_pkt->fname);
432 ff_pkt->type = FT_NOCHG;
433 return handle_file(jcr, ff_pkt, top_level);
436 #ifdef HAVE_DARWIN_OS
437 if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->volhas_attrlist
438 && S_ISREG(ff_pkt->statp.st_mode)) {
439 /* TODO: initialise attrList once elsewhere? */
440 struct attrlist attrList;
441 memset(&attrList, 0, sizeof(attrList));
442 attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
443 attrList.commonattr = ATTR_CMN_FNDRINFO;
444 attrList.fileattr = ATTR_FILE_RSRCLENGTH;
445 if (getattrlist(fname, &attrList, &ff_pkt->hfsinfo,
446 sizeof(ff_pkt->hfsinfo), FSOPT_NOFOLLOW) != 0) {
447 ff_pkt->type = FT_NOSTAT;
448 ff_pkt->ff_errno = errno;
449 return handle_file(jcr, ff_pkt, top_level);
451 return -1; /* ignore */
457 * Handle hard linked files
459 * Maintain a list of hard linked files already backed up. This
460 * allows us to ensure that the data of each file gets backed
463 if (!(ff_pkt->flags & FO_NO_HARDLINK)
464 && ff_pkt->statp.st_nlink > 1
465 && (S_ISREG(ff_pkt->statp.st_mode)
466 || S_ISCHR(ff_pkt->statp.st_mode)
467 || S_ISBLK(ff_pkt->statp.st_mode)
468 || S_ISFIFO(ff_pkt->statp.st_mode)
469 || S_ISSOCK(ff_pkt->statp.st_mode))) {
472 if (ff_pkt->linkhash == NULL) {
473 ff_pkt->linkhash = (link_t **)bmalloc(LINK_HASHTABLE_SIZE * sizeof(link_t *));
474 memset(ff_pkt->linkhash, 0, LINK_HASHTABLE_SIZE * sizeof(link_t *));
476 const int linkhash = LINKHASH(ff_pkt->statp);
478 /* Search link list of hard linked files */
479 for (lp = ff_pkt->linkhash[linkhash]; lp; lp = lp->next)
480 if (lp->ino == (ino_t)ff_pkt->statp.st_ino &&
481 lp->dev == (dev_t)ff_pkt->statp.st_dev) {
482 /* If we have already backed up the hard linked file don't do it again */
483 if (strcmp(lp->name, fname) == 0) {
484 Dmsg2(400, "== Name identical skip FI=%d file=%s\n", lp->FileIndex, fname);
485 return 1; /* ignore */
487 ff_pkt->link = lp->name;
488 ff_pkt->type = FT_LNKSAVED; /* Handle link, file already saved */
489 ff_pkt->LinkFI = lp->FileIndex;
491 ff_pkt->digest = lp->digest;
492 ff_pkt->digest_stream = lp->digest_stream;
493 ff_pkt->digest_len = lp->digest_len;
494 rtn_stat = handle_file(jcr, ff_pkt, top_level);
495 Dmsg3(400, "FT_LNKSAVED FI=%d LinkFI=%d file=%s\n",
496 ff_pkt->FileIndex, lp->FileIndex, lp->name);
500 /* File not previously dumped. Chain it into our list. */
501 len = strlen(fname) + 1;
502 lp = (struct f_link *)bmalloc(sizeof(struct f_link) + len);
503 lp->digest = NULL; /* set later */
504 lp->digest_stream = 0; /* set later */
505 lp->digest_len = 0; /* set later */
506 lp->ino = ff_pkt->statp.st_ino;
507 lp->dev = ff_pkt->statp.st_dev;
508 lp->FileIndex = 0; /* set later */
509 bstrncpy(lp->name, fname, len);
510 lp->next = ff_pkt->linkhash[linkhash];
511 ff_pkt->linkhash[linkhash] = lp;
512 ff_pkt->linked = lp; /* mark saved link */
513 Dmsg2(400, "added to hash FI=%d file=%s\n", ff_pkt->FileIndex, lp->name);
515 ff_pkt->linked = NULL;
518 /* This is not a link to a previously dumped file, so dump it. */
519 if (S_ISREG(ff_pkt->statp.st_mode)) {
522 sizeleft = ff_pkt->statp.st_size;
524 /* Don't bother opening empty, world readable files. Also do not open
525 files when archive is meant for /dev/null. */
526 if (ff_pkt->null_output_device || (sizeleft == 0
527 && MODE_RALL == (MODE_RALL & ff_pkt->statp.st_mode))) {
528 ff_pkt->type = FT_REGE;
530 ff_pkt->type = FT_REG;
532 rtn_stat = handle_file(jcr, ff_pkt, top_level);
533 if (ff_pkt->linked) {
534 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
536 Dmsg3(400, "FT_REG FI=%d linked=%d file=%s\n", ff_pkt->FileIndex,
537 ff_pkt->linked ? 1 : 0, fname);
538 if (ff_pkt->flags & FO_KEEPATIME) {
539 utime(fname, &restore_times);
544 } else if (S_ISLNK(ff_pkt->statp.st_mode)) { /* soft link */
546 char *buffer = (char *)alloca(path_max + name_max + 102);
548 size = readlink(fname, buffer, path_max + name_max + 101);
550 /* Could not follow link */
551 ff_pkt->type = FT_NOFOLLOW;
552 ff_pkt->ff_errno = errno;
553 rtn_stat = handle_file(jcr, ff_pkt, top_level);
554 if (ff_pkt->linked) {
555 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
560 ff_pkt->link = buffer; /* point to link */
561 ff_pkt->type = FT_LNK; /* got a real link */
562 rtn_stat = handle_file(jcr, ff_pkt, top_level);
563 if (ff_pkt->linked) {
564 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
568 } else if (S_ISDIR(ff_pkt->statp.st_mode)) {
570 struct dirent *entry, *result;
575 dev_t our_device = ff_pkt->statp.st_dev;
577 bool volhas_attrlist = ff_pkt->volhas_attrlist; /* Remember this if we recurse */
580 * Ignore this directory and everything below if the file .nobackup
581 * (or what is defined for IgnoreDir in this fileset) exists
583 if (have_ignoredir(ff_pkt)) {
584 return 1; /* Just ignore this directory */
587 /* Build a canonical directory name with a trailing slash in link var */
589 link_len = len + 200;
590 link = (char *)bmalloc(link_len + 2);
591 bstrncpy(link, fname, link_len);
592 /* Strip all trailing slashes */
593 while (len >= 1 && IsPathSeparator(link[len - 1]))
595 link[len++] = '/'; /* add back one */
599 if (!check_changes(jcr, ff_pkt)) {
600 /* Incremental/Full+Base option, directory entry not changed */
601 ff_pkt->type = FT_DIRNOCHG;
603 ff_pkt->type = FT_DIRBEGIN;
606 * We have set st_rdev to 1 if it is a reparse point, otherwise 0,
607 * if st_rdev is 2, it is a mount point
610 * Note, we return the directory to the calling program (handle_file)
611 * when we first see the directory (FT_DIRBEGIN.
612 * This allows the program to apply matches and make a
613 * choice whether or not to accept it. If it is accepted, we
614 * do not immediately save it, but do so only after everything
615 * in the directory is seen (i.e. the FT_DIREND).
617 rtn_stat = handle_file(jcr, ff_pkt, top_level);
618 if (rtn_stat < 1 || ff_pkt->type == FT_REPARSE ||
619 ff_pkt->type == FT_JUNCTION) { /* ignore or error status */
623 /* Done with DIRBEGIN, next call will be DIREND */
624 if (ff_pkt->type == FT_DIRBEGIN) {
625 ff_pkt->type = FT_DIREND;
629 * Create a temporary ff packet for this directory
630 * entry, and defer handling the directory until
631 * we have recursed into it. This saves the
632 * directory after all files have been processed, and
633 * during the restore, the directory permissions will
634 * be reset after all the files have been restored.
636 Dmsg1(300, "Create temp ff packet for dir: %s\n", ff_pkt->fname);
637 FF_PKT *dir_ff_pkt = new_dir_ff_pkt(ff_pkt);
640 * Do not descend into subdirectories (recurse) if the
641 * user has turned it off for this directory.
643 * If we are crossing file systems, we are either not allowed
644 * to cross, or we may be restricted by a list of permitted
647 bool is_win32_mount_point = false;
648 if (!top_level && ff_pkt->flags & FO_NO_RECURSION) {
649 ff_pkt->type = FT_NORECURSE;
651 } else if (!top_level && (parent_device != ff_pkt->statp.st_dev ||
652 is_win32_mount_point)) {
653 if(!(ff_pkt->flags & FO_MULTIFS)) {
654 ff_pkt->type = FT_NOFSCHG;
656 } else if (!accept_fstype(ff_pkt, NULL)) {
657 ff_pkt->type = FT_INVALIDFS;
660 ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
663 /* If not recursing, just backup dir and return */
665 rtn_stat = handle_file(jcr, ff_pkt, top_level);
666 if (ff_pkt->linked) {
667 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
670 free_dir_ff_pkt(dir_ff_pkt);
671 ff_pkt->link = ff_pkt->fname; /* reset "link" */
672 if (ff_pkt->flags & FO_KEEPATIME) {
673 utime(fname, &restore_times);
678 ff_pkt->link = ff_pkt->fname; /* reset "link" */
681 * Descend into or "recurse" into the directory to read
682 * all the files in it.
685 if ((directory = opendir(fname)) == NULL) {
686 ff_pkt->type = FT_NOOPEN;
687 ff_pkt->ff_errno = errno;
688 rtn_stat = handle_file(jcr, ff_pkt, top_level);
689 if (ff_pkt->linked) {
690 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
693 free_dir_ff_pkt(dir_ff_pkt);
698 * Process all files in this directory entry (recursing).
699 * This would possibly run faster if we chdir to the directory
700 * before traversing it.
703 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 100);
704 for ( ; !job_canceled(jcr); ) {
708 status = readdir_r(directory, entry, &result);
709 if (status != 0 || result == NULL) {
710 // Dmsg2(99, "readdir returned stat=%d result=0x%x\n",
711 // status, (long)result);
714 ASSERT(name_max+1 > (int)sizeof(struct dirent) + (int)NAMELEN(entry));
716 /* Skip `.', `..', and excluded file names. */
717 if (p[0] == '\0' || (p[0] == '.' && (p[1] == '\0' ||
718 (p[1] == '.' && p[2] == '\0')))) {
722 if ((int)NAMELEN(entry) + len >= link_len) {
723 link_len = len + NAMELEN(entry) + 1;
724 link = (char *)brealloc(link, link_len + 1);
727 for (i=0; i < (int)NAMELEN(entry); i++) {
731 if (!file_is_excluded(ff_pkt, link)) {
732 rtn_stat = find_one_file(jcr, ff_pkt, handle_file, link, our_device, false);
733 if (ff_pkt->linked) {
734 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
743 * Now that we have recursed through all the files in the
744 * directory, we "save" the directory so that after all
745 * the files are restored, this entry will serve to reset
746 * the directory modes and dates. Temp directory values
747 * were used without this record.
749 handle_file(jcr, dir_ff_pkt, top_level); /* handle directory entry */
750 if (ff_pkt->linked) {
751 ff_pkt->linked->FileIndex = dir_ff_pkt->FileIndex;
753 free_dir_ff_pkt(dir_ff_pkt);
755 if (ff_pkt->flags & FO_KEEPATIME) {
756 utime(fname, &restore_times);
758 ff_pkt->volhas_attrlist = volhas_attrlist; /* Restore value in case it changed. */
760 } /* end check for directory */
763 * If it is explicitly mentioned (i.e. top_level) and is
764 * a block device, we do a raw backup of it or if it is
765 * a fifo, we simply read it.
767 #if defined(HAVE_FREEBSD_OS) || defined(__FreeBSD_kernel__)
769 * On FreeBSD, all block devices are character devices, so
770 * to be able to read a raw disk, we need the check for
771 * a character device.
772 * crw-r----- 1 root operator - 116, 0x00040002 Jun 9 19:32 /dev/ad0s3
773 * crw-r----- 1 root operator - 116, 0x00040002 Jun 9 19:32 /dev/rad0s3
775 if (top_level && (S_ISBLK(ff_pkt->statp.st_mode) || S_ISCHR(ff_pkt->statp.st_mode))) {
777 if (top_level && S_ISBLK(ff_pkt->statp.st_mode)) {
779 ff_pkt->type = FT_RAW; /* raw partition */
780 } else if (top_level && S_ISFIFO(ff_pkt->statp.st_mode) &&
781 ff_pkt->flags & FO_READFIFO) {
782 ff_pkt->type = FT_FIFO;
784 /* The only remaining types are special (character, ...) files */
785 ff_pkt->type = FT_SPEC;
787 rtn_stat = handle_file(jcr, ff_pkt, top_level);
788 if (ff_pkt->linked) {
789 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
794 int term_find_one(FF_PKT *ff)
796 struct f_link *lp, *lc;
801 if (ff->linkhash == NULL) return 0;
803 for (i =0 ; i < LINK_HASHTABLE_SIZE; i ++) {
804 /* Free up list of hard linked files */
805 lp = ff->linkhash[i];
817 ff->linkhash[i] = NULL;