2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2009 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 three of the GNU Affero 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 Affero 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.
30 This file was derived from GNU TAR source code. Except for a few key
31 ideas, it has been entirely rewritten for Bacula.
35 Thanks to the TAR programmers.
44 #include <sys/param.h>
45 #include <sys/mount.h>
49 extern int32_t name_max; /* filename max length */
50 extern int32_t path_max; /* path name max length */
53 * Structure for keeping track of hard linked files, we
54 * keep an entry for each hardlinked file that we save,
55 * which is the first one found. For all the other files that
56 * are linked to this one, we save only the directory
57 * entry so we can link it.
61 dev_t dev; /* device */
62 ino_t ino; /* inode with device is unique */
63 uint32_t FileIndex; /* Bacula FileIndex of this file */
64 int32_t digest_stream; /* Digest type if needed */
65 uint32_t digest_len; /* Digest len if needed */
66 char *digest; /* Checksum of the file if needed */
67 char name[1]; /* The name */
70 typedef struct f_link link_t;
71 #define LINK_HASHTABLE_BITS 16
72 #define LINK_HASHTABLE_SIZE (1<<LINK_HASHTABLE_BITS)
73 #define LINK_HASHTABLE_MASK (LINK_HASHTABLE_SIZE-1)
75 static inline int LINKHASH(const struct stat &info)
77 int hash = info.st_dev;
78 unsigned long long i = info.st_ino;
86 return hash & LINK_HASHTABLE_MASK;
90 * Create a new directory Find File packet, but copy
91 * some of the essential info from the current packet.
92 * However, be careful to zero out the rest of the
95 static FF_PKT *new_dir_ff_pkt(FF_PKT *ff_pkt)
97 FF_PKT *dir_ff_pkt = (FF_PKT *)bmalloc(sizeof(FF_PKT));
98 memcpy(dir_ff_pkt, ff_pkt, sizeof(FF_PKT));
99 dir_ff_pkt->fname = bstrdup(ff_pkt->fname);
100 dir_ff_pkt->link = bstrdup(ff_pkt->link);
101 dir_ff_pkt->sys_fname = get_pool_memory(PM_FNAME);
102 dir_ff_pkt->included_files_list = NULL;
103 dir_ff_pkt->excluded_files_list = NULL;
104 dir_ff_pkt->excluded_paths_list = NULL;
105 dir_ff_pkt->linkhash = NULL;
106 dir_ff_pkt->fname_save = NULL;
107 dir_ff_pkt->link_save = 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->fname, 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 /* TODO: add time of changes */
252 Jmsg(jcr, M_ERROR, 0, _("%s mtime changed during backup.\n"), ff_pkt->fname);
256 if (statp.st_ctime != ff_pkt->statp.st_ctime) {
257 /* TODO: add time of changes */
258 Jmsg(jcr, M_ERROR, 0, _("%s ctime changed during backup.\n"), ff_pkt->fname);
262 if (statp.st_size != ff_pkt->statp.st_size) {
263 /* TODO: add size change */
264 Jmsg(jcr, M_ERROR, 0, _("%s size changed during backup.\n"),ff_pkt->fname);
268 if ((statp.st_blksize != ff_pkt->statp.st_blksize) ||
269 (statp.st_blocks != ff_pkt->statp.st_blocks)) {
270 /* TODO: add size change */
271 Jmsg(jcr, M_ERROR, 0, _("%s size changed during backup.\n"),ff_pkt->fname);
279 * For incremental/diffential or accurate backups, we
280 * determine if the current file has changed.
282 bool check_changes(JCR *jcr, FF_PKT *ff_pkt)
284 /* in special mode (like accurate backup), the programmer can
285 * choose his comparison function.
287 if (ff_pkt->check_fct) {
288 return ff_pkt->check_fct(jcr, ff_pkt);
291 /* For normal backups (incr/diff), we use this default
294 if (ff_pkt->incremental &&
295 (ff_pkt->statp.st_mtime < ff_pkt->save_time &&
296 ((ff_pkt->flags & FO_MTIMEONLY) ||
297 ff_pkt->statp.st_ctime < ff_pkt->save_time)))
305 static bool have_ignoredir(FF_PKT *ff_pkt)
308 char tmp_name[MAXPATHLEN];
311 /* Ensure that pointers are defined */
312 if (!ff_pkt->fileset || !ff_pkt->fileset->incexe) {
315 ignoredir = ff_pkt->fileset->incexe->ignoredir;
318 if (strlen(ff_pkt->fname) + strlen(ignoredir) + 2 > MAXPATHLEN) {
322 strcpy(tmp_name, ff_pkt->fname);
323 strcat(tmp_name, "/");
324 strcat(tmp_name, ignoredir);
325 if (stat(tmp_name, &sb) == 0) {
326 Dmsg2(100, "Directory '%s' ignored (found %s)\n",
327 ff_pkt->fname, ignoredir);
328 return true; /* Just ignore this directory */
335 * When the current file is a hardlink, the backup code can compute
336 * the checksum and store it into the link_t structure.
339 ff_pkt_set_link_digest(FF_PKT *ff_pkt,
340 int32_t digest_stream, const char *digest, uint32_t len)
342 if (ff_pkt->linked && !ff_pkt->linked->digest) { /* is a hardlink */
343 ff_pkt->linked->digest = (char *) bmalloc(len);
344 memcpy(ff_pkt->linked->digest, digest, len);
345 ff_pkt->linked->digest_len = len;
346 ff_pkt->linked->digest_stream = digest_stream;
351 * Find a single file.
352 * handle_file is the callback for handling the file.
354 * parent_device is the device we are currently on
355 * top_level is 1 when not recursing or 0 when
356 * descending into a directory.
359 find_one_file(JCR *jcr, FF_PKT *ff_pkt,
360 int handle_file(JCR *jcr, FF_PKT *ff, bool top_level),
361 char *fname, dev_t parent_device, bool top_level)
363 struct utimbuf restore_times;
367 ff_pkt->fname = ff_pkt->link = fname;
369 if (lstat(fname, &ff_pkt->statp) != 0) {
370 /* Cannot stat file */
371 ff_pkt->type = FT_NOSTAT;
372 ff_pkt->ff_errno = errno;
373 return handle_file(jcr, ff_pkt, top_level);
376 Dmsg1(300, "File ----: %s\n", fname);
378 /* Save current times of this directory in case we need to
379 * reset them because the user doesn't want them changed.
381 restore_times.actime = ff_pkt->statp.st_atime;
382 restore_times.modtime = ff_pkt->statp.st_mtime;
385 * We check for allowed fstypes and drivetypes at top_level and fstype change (below).
388 if (!accept_fstype(ff_pkt, NULL)) {
389 ff_pkt->type = FT_INVALIDFS;
390 if (ff_pkt->flags & FO_KEEPATIME) {
391 utime(fname, &restore_times);
396 if (!fstype(ff_pkt->fname, fs, sizeof(fs))) {
397 bstrncpy(fs, "unknown", sizeof(fs));
400 Jmsg(jcr, M_INFO, 0, _("Top level directory \"%s\" has unlisted fstype \"%s\"\n"), fname, fs);
401 return 1; /* Just ignore this error - or the whole backup is cancelled */
403 if (!accept_drivetype(ff_pkt, NULL)) {
404 ff_pkt->type = FT_INVALIDDT;
405 if (ff_pkt->flags & FO_KEEPATIME) {
406 utime(fname, &restore_times);
411 if (!drivetype(ff_pkt->fname, dt, sizeof(dt))) {
412 bstrncpy(dt, "unknown", sizeof(dt));
415 Jmsg(jcr, M_INFO, 0, _("Top level directory \"%s\" has an unlisted drive type \"%s\"\n"), fname, dt);
416 return 1; /* Just ignore this error - or the whole backup is cancelled */
418 ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
422 * Ignore this entry if no_dump() returns true
424 if (no_dump(jcr, ff_pkt)) {
425 Dmsg1(100, "'%s' ignored (NODUMP flag set)\n",
431 * If this is an Incremental backup, see if file was modified
432 * since our last "save_time", presumably the last Full save
435 if ( !S_ISDIR(ff_pkt->statp.st_mode)
436 && !check_changes(jcr, ff_pkt))
438 Dmsg1(500, "Non-directory incremental: %s\n", ff_pkt->fname);
439 ff_pkt->type = FT_NOCHG;
440 return handle_file(jcr, ff_pkt, top_level);
443 #ifdef HAVE_DARWIN_OS
444 if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->volhas_attrlist
445 && S_ISREG(ff_pkt->statp.st_mode)) {
446 /* TODO: initialise attrList once elsewhere? */
447 struct attrlist attrList;
448 memset(&attrList, 0, sizeof(attrList));
449 attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
450 attrList.commonattr = ATTR_CMN_FNDRINFO;
451 attrList.fileattr = ATTR_FILE_RSRCLENGTH;
452 if (getattrlist(fname, &attrList, &ff_pkt->hfsinfo,
453 sizeof(ff_pkt->hfsinfo), FSOPT_NOFOLLOW) != 0) {
454 ff_pkt->type = FT_NOSTAT;
455 ff_pkt->ff_errno = errno;
456 return handle_file(jcr, ff_pkt, top_level);
463 * Handle hard linked files
465 * Maintain a list of hard linked files already backed up. This
466 * allows us to ensure that the data of each file gets backed
469 if (!(ff_pkt->flags & FO_NO_HARDLINK)
470 && ff_pkt->statp.st_nlink > 1
471 && (S_ISREG(ff_pkt->statp.st_mode)
472 || S_ISCHR(ff_pkt->statp.st_mode)
473 || S_ISBLK(ff_pkt->statp.st_mode)
474 || S_ISFIFO(ff_pkt->statp.st_mode)
475 || S_ISSOCK(ff_pkt->statp.st_mode))) {
478 if (ff_pkt->linkhash == NULL) {
479 ff_pkt->linkhash = (link_t **)bmalloc(LINK_HASHTABLE_SIZE * sizeof(link_t *));
480 memset(ff_pkt->linkhash, 0, LINK_HASHTABLE_SIZE * sizeof(link_t *));
482 const int linkhash = LINKHASH(ff_pkt->statp);
484 /* Search link list of hard linked files */
485 for (lp = ff_pkt->linkhash[linkhash]; lp; lp = lp->next)
486 if (lp->ino == (ino_t)ff_pkt->statp.st_ino &&
487 lp->dev == (dev_t)ff_pkt->statp.st_dev) {
488 /* If we have already backed up the hard linked file don't do it again */
489 if (strcmp(lp->name, fname) == 0) {
490 Dmsg2(400, "== Name identical skip FI=%d file=%s\n", lp->FileIndex, fname);
491 return 1; /* ignore */
493 ff_pkt->link = lp->name;
494 ff_pkt->type = FT_LNKSAVED; /* Handle link, file already saved */
495 ff_pkt->LinkFI = lp->FileIndex;
497 ff_pkt->digest = lp->digest;
498 ff_pkt->digest_stream = lp->digest_stream;
499 ff_pkt->digest_len = lp->digest_len;
500 rtn_stat = handle_file(jcr, ff_pkt, top_level);
501 Dmsg3(400, "FT_LNKSAVED FI=%d LinkFI=%d file=%s\n",
502 ff_pkt->FileIndex, lp->FileIndex, lp->name);
506 /* File not previously dumped. Chain it into our list. */
507 len = strlen(fname) + 1;
508 lp = (struct f_link *)bmalloc(sizeof(struct f_link) + len);
509 lp->digest = NULL; /* set later */
510 lp->digest_stream = 0; /* set later */
511 lp->digest_len = 0; /* set later */
512 lp->ino = ff_pkt->statp.st_ino;
513 lp->dev = ff_pkt->statp.st_dev;
514 lp->FileIndex = 0; /* set later */
515 bstrncpy(lp->name, fname, len);
516 lp->next = ff_pkt->linkhash[linkhash];
517 ff_pkt->linkhash[linkhash] = lp;
518 ff_pkt->linked = lp; /* mark saved link */
519 Dmsg2(400, "added to hash FI=%d file=%s\n", ff_pkt->FileIndex, lp->name);
521 ff_pkt->linked = NULL;
524 /* This is not a link to a previously dumped file, so dump it. */
525 if (S_ISREG(ff_pkt->statp.st_mode)) {
528 sizeleft = ff_pkt->statp.st_size;
530 /* Don't bother opening empty, world readable files. Also do not open
531 files when archive is meant for /dev/null. */
532 if (ff_pkt->null_output_device || (sizeleft == 0
533 && MODE_RALL == (MODE_RALL & ff_pkt->statp.st_mode))) {
534 ff_pkt->type = FT_REGE;
536 ff_pkt->type = FT_REG;
538 rtn_stat = handle_file(jcr, ff_pkt, top_level);
539 if (ff_pkt->linked) {
540 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
542 Dmsg3(400, "FT_REG FI=%d linked=%d file=%s\n", ff_pkt->FileIndex,
543 ff_pkt->linked ? 1 : 0, fname);
544 if (ff_pkt->flags & FO_KEEPATIME) {
545 utime(fname, &restore_times);
550 } else if (S_ISLNK(ff_pkt->statp.st_mode)) { /* soft link */
552 char *buffer = (char *)alloca(path_max + name_max + 102);
554 size = readlink(fname, buffer, path_max + name_max + 101);
556 /* Could not follow link */
557 ff_pkt->type = FT_NOFOLLOW;
558 ff_pkt->ff_errno = errno;
559 rtn_stat = handle_file(jcr, ff_pkt, top_level);
560 if (ff_pkt->linked) {
561 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
566 ff_pkt->link = buffer; /* point to link */
567 ff_pkt->type = FT_LNK; /* got a real link */
568 rtn_stat = handle_file(jcr, ff_pkt, top_level);
569 if (ff_pkt->linked) {
570 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
574 } else if (S_ISDIR(ff_pkt->statp.st_mode)) {
576 struct dirent *entry, *result;
581 dev_t our_device = ff_pkt->statp.st_dev;
583 bool volhas_attrlist = ff_pkt->volhas_attrlist; /* Remember this if we recurse */
586 * Ignore this directory and everything below if the file .nobackup
587 * (or what is defined for IgnoreDir in this fileset) exists
589 if (have_ignoredir(ff_pkt)) {
590 return 1; /* Just ignore this directory */
593 /* Build a canonical directory name with a trailing slash in link var */
595 link_len = len + 200;
596 link = (char *)bmalloc(link_len + 2);
597 bstrncpy(link, fname, link_len);
598 /* Strip all trailing slashes */
599 while (len >= 1 && IsPathSeparator(link[len - 1]))
601 link[len++] = '/'; /* add back one */
605 if (!check_changes(jcr, ff_pkt)) {
606 /* Incremental/Full+Base option, directory entry not changed */
607 ff_pkt->type = FT_DIRNOCHG;
609 ff_pkt->type = FT_DIRBEGIN;
612 * We have set st_rdev to 1 if it is a reparse point, otherwise 0,
613 * if st_rdev is 2, it is a mount point
615 #if defined(HAVE_WIN32)
617 * A reparse point (WIN32_REPARSE_POINT)
618 * is something special like one of the following:
619 * IO_REPARSE_TAG_DFS 0x8000000A
620 * IO_REPARSE_TAG_DFSR 0x80000012
621 * IO_REPARSE_TAG_HSM 0xC0000004
622 * IO_REPARSE_TAG_HSM2 0x80000006
623 * IO_REPARSE_TAG_SIS 0x80000007
624 * IO_REPARSE_TAG_SYMLINK 0xA000000C
626 * A junction point is a:
627 * IO_REPARSE_TAG_MOUNT_POINT 0xA0000003
628 * which can be either a link to a Volume (WIN32_MOUNT_POINT)
629 * or a link to a directory (WIN32_JUNCTION_POINT)
631 * Ignore WIN32_REPARSE_POINT and WIN32_JUNCTION_POINT
633 if (ff_pkt->statp.st_rdev == WIN32_REPARSE_POINT) {
634 ff_pkt->type = FT_REPARSE;
635 } else if (ff_pkt->statp.st_rdev == WIN32_JUNCTION_POINT) {
636 ff_pkt->type = FT_JUNCTION;
640 * Note, we return the directory to the calling program (handle_file)
641 * when we first see the directory (FT_DIRBEGIN.
642 * This allows the program to apply matches and make a
643 * choice whether or not to accept it. If it is accepted, we
644 * do not immediately save it, but do so only after everything
645 * in the directory is seen (i.e. the FT_DIREND).
647 rtn_stat = handle_file(jcr, ff_pkt, top_level);
648 if (rtn_stat < 1 || ff_pkt->type == FT_REPARSE ||
649 ff_pkt->type == FT_JUNCTION) { /* ignore or error status */
653 /* Done with DIRBEGIN, next call will be DIREND */
654 if (ff_pkt->type == FT_DIRBEGIN) {
655 ff_pkt->type = FT_DIREND;
659 * Create a temporary ff packet for this directory
660 * entry, and defer handling the directory until
661 * we have recursed into it. This saves the
662 * directory after all files have been processed, and
663 * during the restore, the directory permissions will
664 * be reset after all the files have been restored.
666 Dmsg1(300, "Create temp ff packet for dir: %s\n", ff_pkt->fname);
667 FF_PKT *dir_ff_pkt = new_dir_ff_pkt(ff_pkt);
670 * Do not descend into subdirectories (recurse) if the
671 * user has turned it off for this directory.
673 * If we are crossing file systems, we are either not allowed
674 * to cross, or we may be restricted by a list of permitted
677 bool is_win32_mount_point = false;
678 #if defined(HAVE_WIN32)
679 is_win32_mount_point = ff_pkt->statp.st_rdev == WIN32_MOUNT_POINT;
681 if (!top_level && ff_pkt->flags & FO_NO_RECURSION) {
682 ff_pkt->type = FT_NORECURSE;
684 } else if (!top_level && (parent_device != ff_pkt->statp.st_dev ||
685 is_win32_mount_point)) {
686 if(!(ff_pkt->flags & FO_MULTIFS)) {
687 ff_pkt->type = FT_NOFSCHG;
689 } else if (!accept_fstype(ff_pkt, NULL)) {
690 ff_pkt->type = FT_INVALIDFS;
693 ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
696 /* If not recursing, just backup dir and return */
698 rtn_stat = handle_file(jcr, ff_pkt, top_level);
699 if (ff_pkt->linked) {
700 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
703 free_dir_ff_pkt(dir_ff_pkt);
704 ff_pkt->link = ff_pkt->fname; /* reset "link" */
705 if (ff_pkt->flags & FO_KEEPATIME) {
706 utime(fname, &restore_times);
711 ff_pkt->link = ff_pkt->fname; /* reset "link" */
714 * Descend into or "recurse" into the directory to read
715 * all the files in it.
718 if ((directory = opendir(fname)) == NULL) {
719 ff_pkt->type = FT_NOOPEN;
720 ff_pkt->ff_errno = errno;
721 rtn_stat = handle_file(jcr, ff_pkt, top_level);
722 if (ff_pkt->linked) {
723 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
726 free_dir_ff_pkt(dir_ff_pkt);
731 * Process all files in this directory entry (recursing).
732 * This would possibly run faster if we chdir to the directory
733 * before traversing it.
736 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 100);
737 for ( ; !job_canceled(jcr); ) {
741 status = readdir_r(directory, entry, &result);
742 if (status != 0 || result == NULL) {
743 // Dmsg2(99, "readdir returned stat=%d result=0x%x\n",
744 // status, (long)result);
747 ASSERT(name_max+1 > (int)sizeof(struct dirent) + (int)NAMELEN(entry));
749 /* Skip `.', `..', and excluded file names. */
750 if (p[0] == '\0' || (p[0] == '.' && (p[1] == '\0' ||
751 (p[1] == '.' && p[2] == '\0')))) {
755 if ((int)NAMELEN(entry) + len >= link_len) {
756 link_len = len + NAMELEN(entry) + 1;
757 link = (char *)brealloc(link, link_len + 1);
760 for (i=0; i < (int)NAMELEN(entry); i++) {
764 if (!file_is_excluded(ff_pkt, link)) {
765 rtn_stat = find_one_file(jcr, ff_pkt, handle_file, link, our_device, false);
766 if (ff_pkt->linked) {
767 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
776 * Now that we have recursed through all the files in the
777 * directory, we "save" the directory so that after all
778 * the files are restored, this entry will serve to reset
779 * the directory modes and dates. Temp directory values
780 * were used without this record.
782 handle_file(jcr, dir_ff_pkt, top_level); /* handle directory entry */
783 if (ff_pkt->linked) {
784 ff_pkt->linked->FileIndex = dir_ff_pkt->FileIndex;
786 free_dir_ff_pkt(dir_ff_pkt);
788 if (ff_pkt->flags & FO_KEEPATIME) {
789 utime(fname, &restore_times);
791 ff_pkt->volhas_attrlist = volhas_attrlist; /* Restore value in case it changed. */
793 } /* end check for directory */
796 * If it is explicitly mentioned (i.e. top_level) and is
797 * a block device, we do a raw backup of it or if it is
798 * a fifo, we simply read it.
800 #ifdef HAVE_FREEBSD_OS
802 * On FreeBSD, all block devices are character devices, so
803 * to be able to read a raw disk, we need the check for
804 * a character device.
805 * crw-r----- 1 root operator - 116, 0x00040002 Jun 9 19:32 /dev/ad0s3
806 * crw-r----- 1 root operator - 116, 0x00040002 Jun 9 19:32 /dev/rad0s3
808 if (top_level && (S_ISBLK(ff_pkt->statp.st_mode) || S_ISCHR(ff_pkt->statp.st_mode))) {
810 if (top_level && S_ISBLK(ff_pkt->statp.st_mode)) {
812 ff_pkt->type = FT_RAW; /* raw partition */
813 } else if (top_level && S_ISFIFO(ff_pkt->statp.st_mode) &&
814 ff_pkt->flags & FO_READFIFO) {
815 ff_pkt->type = FT_FIFO;
817 /* The only remaining types are special (character, ...) files */
818 ff_pkt->type = FT_SPEC;
820 rtn_stat = handle_file(jcr, ff_pkt, top_level);
821 if (ff_pkt->linked) {
822 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
827 int term_find_one(FF_PKT *ff)
829 struct f_link *lp, *lc;
834 if (ff->linkhash == NULL) return 0;
836 for (i =0 ; i < LINK_HASHTABLE_SIZE; i ++) {
837 /* Free up list of hard linked files */
838 lp = ff->linkhash[i];
850 ff->linkhash[i] = NULL;