2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2010 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.
42 #include <sys/param.h>
43 #include <sys/mount.h>
47 extern int32_t name_max; /* filename max length */
48 extern int32_t path_max; /* path name max length */
51 * Structure for keeping track of hard linked files, we
52 * keep an entry for each hardlinked file that we save,
53 * which is the first one found. For all the other files that
54 * are linked to this one, we save only the directory
55 * entry so we can link it.
59 dev_t dev; /* device */
60 ino_t ino; /* inode with device is unique */
61 uint32_t FileIndex; /* Bacula FileIndex of this file */
62 int32_t digest_stream; /* Digest type if needed */
63 uint32_t digest_len; /* Digest len if needed */
64 char *digest; /* Checksum of the file if needed */
65 char name[1]; /* The name */
68 typedef struct f_link link_t;
69 #define LINK_HASHTABLE_BITS 16
70 #define LINK_HASHTABLE_SIZE (1<<LINK_HASHTABLE_BITS)
71 #define LINK_HASHTABLE_MASK (LINK_HASHTABLE_SIZE-1)
73 static inline int LINKHASH(const struct stat &info)
75 int hash = info.st_dev;
76 unsigned long long i = info.st_ino;
84 return hash & LINK_HASHTABLE_MASK;
88 * Create a new directory Find File packet, but copy
89 * some of the essential info from the current packet.
90 * However, be careful to zero out the rest of the
93 static FF_PKT *new_dir_ff_pkt(FF_PKT *ff_pkt)
95 FF_PKT *dir_ff_pkt = (FF_PKT *)bmalloc(sizeof(FF_PKT));
96 memcpy(dir_ff_pkt, ff_pkt, sizeof(FF_PKT));
97 dir_ff_pkt->fname = bstrdup(ff_pkt->fname);
98 dir_ff_pkt->link = bstrdup(ff_pkt->link);
99 dir_ff_pkt->sys_fname = get_pool_memory(PM_FNAME);
100 dir_ff_pkt->included_files_list = NULL;
101 dir_ff_pkt->excluded_files_list = NULL;
102 dir_ff_pkt->excluded_paths_list = NULL;
103 dir_ff_pkt->linkhash = NULL;
104 dir_ff_pkt->fname_save = NULL;
105 dir_ff_pkt->link_save = NULL;
110 * Free the temp directory ff_pkt
112 static void free_dir_ff_pkt(FF_PKT *dir_ff_pkt)
114 free(dir_ff_pkt->fname);
115 free(dir_ff_pkt->link);
116 free_pool_memory(dir_ff_pkt->sys_fname);
117 if (dir_ff_pkt->fname_save) {
118 free_pool_memory(dir_ff_pkt->fname_save);
120 if (dir_ff_pkt->link_save) {
121 free_pool_memory(dir_ff_pkt->link_save);
127 * Check to see if we allow the file system type of a file or directory.
128 * If we do not have a list of file system types, we accept anything.
130 static int accept_fstype(FF_PKT *ff, void *dummy) {
135 if (ff->fstypes.size()) {
137 if (!fstype(ff->fname, fs, sizeof(fs))) {
138 Dmsg1(50, "Cannot determine file system type for \"%s\"\n", ff->fname);
140 for (i = 0; i < ff->fstypes.size(); ++i) {
141 if (strcmp(fs, (char *)ff->fstypes.get(i)) == 0) {
142 Dmsg2(100, "Accepting fstype %s for \"%s\"\n", fs, ff->fname);
146 Dmsg3(200, "fstype %s for \"%s\" does not match %s\n", fs,
147 ff->fname, ff->fstypes.get(i));
155 * Check to see if we allow the drive type of a file or directory.
156 * If we do not have a list of drive types, we accept anything.
158 static int accept_drivetype(FF_PKT *ff, void *dummy) {
163 if (ff->drivetypes.size()) {
165 if (!drivetype(ff->fname, dt, sizeof(dt))) {
166 Dmsg1(50, "Cannot determine drive type for \"%s\"\n", ff->fname);
168 for (i = 0; i < ff->drivetypes.size(); ++i) {
169 if (strcmp(dt, (char *)ff->drivetypes.get(i)) == 0) {
170 Dmsg2(100, "Accepting drive type %s for \"%s\"\n", dt, ff->fname);
174 Dmsg3(200, "drive type %s for \"%s\" does not match %s\n", dt,
175 ff->fname, ff->drivetypes.get(i));
183 * This function determines whether we can use getattrlist()
184 * It's odd, but we have to use the function to determine that...
185 * Also, the man pages talk about things as if they were implemented.
187 * On Mac OS X, this succesfully differentiates between HFS+ and UFS
188 * volumes, which makes me trust it is OK for others, too.
190 static bool volume_has_attrlist(const char *fname)
192 #ifdef HAVE_DARWIN_OS
194 struct volinfo_struct {
195 unsigned long length; /* Mandatory field */
196 vol_capabilities_attr_t info; /* Volume capabilities */
198 struct attrlist attrList;
200 memset(&attrList, 0, sizeof(attrList));
201 attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
202 attrList.volattr = ATTR_VOL_INFO | ATTR_VOL_CAPABILITIES;
203 if (statfs(fname, &st) == 0) {
204 /* We need to check on the mount point */
205 if (getattrlist(st.f_mntonname, &attrList, &vol, sizeof(vol), FSOPT_NOFOLLOW) == 0
206 && (vol.info.capabilities[VOL_CAPABILITIES_INTERFACES] & VOL_CAP_INT_ATTRLIST)
207 && (vol.info.valid[VOL_CAPABILITIES_INTERFACES] & VOL_CAP_INT_ATTRLIST)) {
216 * check for BSD nodump flag
218 static bool no_dump(JCR *jcr, FF_PKT *ff_pkt)
220 #if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
221 if ( (ff_pkt->flags & FO_HONOR_NODUMP) &&
222 (ff_pkt->statp.st_flags & UF_NODUMP) ) {
223 Jmsg(jcr, M_INFO, 1, _(" NODUMP flag set - will not process %s\n"),
225 return true; /* do not backup this file */
228 return false; /* do backup */
231 /* check if a file have changed during backup and display an error */
232 bool has_file_changed(JCR *jcr, FF_PKT *ff_pkt)
235 Dmsg1(500, "has_file_changed fname=%s\n",ff_pkt->fname);
237 if (ff_pkt->type != FT_REG) { /* not a regular file */
241 if (lstat(ff_pkt->fname, &statp) != 0) {
243 Jmsg(jcr, M_WARNING, 0,
244 _("Cannot stat file %s: ERR=%s\n"),ff_pkt->fname,be.bstrerror());
248 if (statp.st_mtime != ff_pkt->statp.st_mtime) {
249 /* TODO: add time of changes */
250 Jmsg(jcr, M_ERROR, 0, _("%s mtime changed during backup.\n"), ff_pkt->fname);
254 if (statp.st_ctime != ff_pkt->statp.st_ctime) {
255 /* TODO: add time of changes */
256 Jmsg(jcr, M_ERROR, 0, _("%s ctime changed during backup.\n"), ff_pkt->fname);
260 if (statp.st_size != ff_pkt->statp.st_size) {
261 /* TODO: add size change */
262 Jmsg(jcr, M_ERROR, 0, _("%s size changed during backup.\n"),ff_pkt->fname);
266 if ((statp.st_blksize != ff_pkt->statp.st_blksize) ||
267 (statp.st_blocks != ff_pkt->statp.st_blocks)) {
268 /* TODO: add size change */
269 Jmsg(jcr, M_ERROR, 0, _("%s size changed during backup.\n"),ff_pkt->fname);
277 * For incremental/diffential or accurate backups, we
278 * determine if the current file has changed.
280 bool check_changes(JCR *jcr, FF_PKT *ff_pkt)
282 /* in special mode (like accurate backup), the programmer can
283 * choose his comparison function.
285 if (ff_pkt->check_fct) {
286 return ff_pkt->check_fct(jcr, ff_pkt);
289 /* For normal backups (incr/diff), we use this default
292 if (ff_pkt->incremental &&
293 (ff_pkt->statp.st_mtime < ff_pkt->save_time &&
294 ((ff_pkt->flags & FO_MTIMEONLY) ||
295 ff_pkt->statp.st_ctime < ff_pkt->save_time)))
303 static bool have_ignoredir(FF_PKT *ff_pkt)
306 char tmp_name[MAXPATHLEN];
309 /* Ensure that pointers are defined */
310 if (!ff_pkt->fileset || !ff_pkt->fileset->incexe) {
313 ignoredir = ff_pkt->fileset->incexe->ignoredir;
316 if (strlen(ff_pkt->fname) + strlen(ignoredir) + 2 > MAXPATHLEN) {
320 strcpy(tmp_name, ff_pkt->fname);
321 strcat(tmp_name, "/");
322 strcat(tmp_name, ignoredir);
323 if (stat(tmp_name, &sb) == 0) {
324 Dmsg2(100, "Directory '%s' ignored (found %s)\n",
325 ff_pkt->fname, ignoredir);
326 return true; /* Just ignore this directory */
333 * When the current file is a hardlink, the backup code can compute
334 * the checksum and store it into the link_t structure.
337 ff_pkt_set_link_digest(FF_PKT *ff_pkt,
338 int32_t digest_stream, const char *digest, uint32_t len)
340 if (ff_pkt->linked && !ff_pkt->linked->digest) { /* is a hardlink */
341 ff_pkt->linked->digest = (char *) bmalloc(len);
342 memcpy(ff_pkt->linked->digest, digest, len);
343 ff_pkt->linked->digest_len = len;
344 ff_pkt->linked->digest_stream = digest_stream;
349 * Find a single file.
350 * handle_file is the callback for handling the file.
352 * parent_device is the device we are currently on
353 * top_level is 1 when not recursing or 0 when
354 * descending into a directory.
357 find_one_file(JCR *jcr, FF_PKT *ff_pkt,
358 int handle_file(JCR *jcr, FF_PKT *ff, bool top_level),
359 char *fname, dev_t parent_device, bool top_level)
361 struct utimbuf restore_times;
365 ff_pkt->fname = ff_pkt->link = fname;
367 if (lstat(fname, &ff_pkt->statp) != 0) {
368 /* Cannot stat file */
369 ff_pkt->type = FT_NOSTAT;
370 ff_pkt->ff_errno = errno;
371 return handle_file(jcr, ff_pkt, top_level);
374 Dmsg1(300, "File ----: %s\n", fname);
376 /* Save current times of this directory in case we need to
377 * reset them because the user doesn't want them changed.
379 restore_times.actime = ff_pkt->statp.st_atime;
380 restore_times.modtime = ff_pkt->statp.st_mtime;
383 * We check for allowed fstypes and drivetypes at top_level and fstype change (below).
386 if (!accept_fstype(ff_pkt, NULL)) {
387 ff_pkt->type = FT_INVALIDFS;
388 if (ff_pkt->flags & FO_KEEPATIME) {
389 utime(fname, &restore_times);
394 if (!fstype(ff_pkt->fname, fs, sizeof(fs))) {
395 bstrncpy(fs, "unknown", sizeof(fs));
398 Jmsg(jcr, M_INFO, 0, _("Top level directory \"%s\" has unlisted fstype \"%s\"\n"), fname, fs);
399 return 1; /* Just ignore this error - or the whole backup is cancelled */
401 if (!accept_drivetype(ff_pkt, NULL)) {
402 ff_pkt->type = FT_INVALIDDT;
403 if (ff_pkt->flags & FO_KEEPATIME) {
404 utime(fname, &restore_times);
409 if (!drivetype(ff_pkt->fname, dt, sizeof(dt))) {
410 bstrncpy(dt, "unknown", sizeof(dt));
413 Jmsg(jcr, M_INFO, 0, _("Top level directory \"%s\" has an unlisted drive type \"%s\"\n"), fname, dt);
414 return 1; /* Just ignore this error - or the whole backup is cancelled */
416 ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
420 * Ignore this entry if no_dump() returns true
422 if (no_dump(jcr, ff_pkt)) {
423 Dmsg1(100, "'%s' ignored (NODUMP flag set)\n",
429 * If this is an Incremental backup, see if file was modified
430 * since our last "save_time", presumably the last Full save
433 if ( !S_ISDIR(ff_pkt->statp.st_mode)
434 && !check_changes(jcr, ff_pkt))
436 Dmsg1(500, "Non-directory incremental: %s\n", ff_pkt->fname);
437 ff_pkt->type = FT_NOCHG;
438 return handle_file(jcr, ff_pkt, top_level);
441 #ifdef HAVE_DARWIN_OS
442 if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->volhas_attrlist
443 && S_ISREG(ff_pkt->statp.st_mode)) {
444 /* TODO: initialise attrList once elsewhere? */
445 struct attrlist attrList;
446 memset(&attrList, 0, sizeof(attrList));
447 attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
448 attrList.commonattr = ATTR_CMN_FNDRINFO;
449 attrList.fileattr = ATTR_FILE_RSRCLENGTH;
450 if (getattrlist(fname, &attrList, &ff_pkt->hfsinfo,
451 sizeof(ff_pkt->hfsinfo), FSOPT_NOFOLLOW) != 0) {
452 ff_pkt->type = FT_NOSTAT;
453 ff_pkt->ff_errno = errno;
454 return handle_file(jcr, ff_pkt, top_level);
461 * Handle hard linked files
463 * Maintain a list of hard linked files already backed up. This
464 * allows us to ensure that the data of each file gets backed
467 if (!(ff_pkt->flags & FO_NO_HARDLINK)
468 && ff_pkt->statp.st_nlink > 1
469 && (S_ISREG(ff_pkt->statp.st_mode)
470 || S_ISCHR(ff_pkt->statp.st_mode)
471 || S_ISBLK(ff_pkt->statp.st_mode)
472 || S_ISFIFO(ff_pkt->statp.st_mode)
473 || S_ISSOCK(ff_pkt->statp.st_mode))) {
476 if (ff_pkt->linkhash == NULL) {
477 ff_pkt->linkhash = (link_t **)bmalloc(LINK_HASHTABLE_SIZE * sizeof(link_t *));
478 memset(ff_pkt->linkhash, 0, LINK_HASHTABLE_SIZE * sizeof(link_t *));
480 const int linkhash = LINKHASH(ff_pkt->statp);
482 /* Search link list of hard linked files */
483 for (lp = ff_pkt->linkhash[linkhash]; lp; lp = lp->next)
484 if (lp->ino == (ino_t)ff_pkt->statp.st_ino &&
485 lp->dev == (dev_t)ff_pkt->statp.st_dev) {
486 /* If we have already backed up the hard linked file don't do it again */
487 if (strcmp(lp->name, fname) == 0) {
488 Dmsg2(400, "== Name identical skip FI=%d file=%s\n", lp->FileIndex, fname);
489 return 1; /* ignore */
491 ff_pkt->link = lp->name;
492 ff_pkt->type = FT_LNKSAVED; /* Handle link, file already saved */
493 ff_pkt->LinkFI = lp->FileIndex;
495 ff_pkt->digest = lp->digest;
496 ff_pkt->digest_stream = lp->digest_stream;
497 ff_pkt->digest_len = lp->digest_len;
498 rtn_stat = handle_file(jcr, ff_pkt, top_level);
499 Dmsg3(400, "FT_LNKSAVED FI=%d LinkFI=%d file=%s\n",
500 ff_pkt->FileIndex, lp->FileIndex, lp->name);
504 /* File not previously dumped. Chain it into our list. */
505 len = strlen(fname) + 1;
506 lp = (struct f_link *)bmalloc(sizeof(struct f_link) + len);
507 lp->digest = NULL; /* set later */
508 lp->digest_stream = 0; /* set later */
509 lp->digest_len = 0; /* set later */
510 lp->ino = ff_pkt->statp.st_ino;
511 lp->dev = ff_pkt->statp.st_dev;
512 lp->FileIndex = 0; /* set later */
513 bstrncpy(lp->name, fname, len);
514 lp->next = ff_pkt->linkhash[linkhash];
515 ff_pkt->linkhash[linkhash] = lp;
516 ff_pkt->linked = lp; /* mark saved link */
517 Dmsg2(400, "added to hash FI=%d file=%s\n", ff_pkt->FileIndex, lp->name);
519 ff_pkt->linked = NULL;
522 /* This is not a link to a previously dumped file, so dump it. */
523 if (S_ISREG(ff_pkt->statp.st_mode)) {
526 sizeleft = ff_pkt->statp.st_size;
528 /* Don't bother opening empty, world readable files. Also do not open
529 files when archive is meant for /dev/null. */
530 if (ff_pkt->null_output_device || (sizeleft == 0
531 && MODE_RALL == (MODE_RALL & ff_pkt->statp.st_mode))) {
532 ff_pkt->type = FT_REGE;
534 ff_pkt->type = FT_REG;
536 rtn_stat = handle_file(jcr, ff_pkt, top_level);
537 if (ff_pkt->linked) {
538 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
540 Dmsg3(400, "FT_REG FI=%d linked=%d file=%s\n", ff_pkt->FileIndex,
541 ff_pkt->linked ? 1 : 0, fname);
542 if (ff_pkt->flags & FO_KEEPATIME) {
543 utime(fname, &restore_times);
548 } else if (S_ISLNK(ff_pkt->statp.st_mode)) { /* soft link */
550 char *buffer = (char *)alloca(path_max + name_max + 102);
552 size = readlink(fname, buffer, path_max + name_max + 101);
554 /* Could not follow link */
555 ff_pkt->type = FT_NOFOLLOW;
556 ff_pkt->ff_errno = errno;
557 rtn_stat = handle_file(jcr, ff_pkt, top_level);
558 if (ff_pkt->linked) {
559 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
564 ff_pkt->link = buffer; /* point to link */
565 ff_pkt->type = FT_LNK; /* got a real link */
566 rtn_stat = handle_file(jcr, ff_pkt, top_level);
567 if (ff_pkt->linked) {
568 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
572 } else if (S_ISDIR(ff_pkt->statp.st_mode)) {
574 struct dirent *entry, *result;
579 dev_t our_device = ff_pkt->statp.st_dev;
581 bool volhas_attrlist = ff_pkt->volhas_attrlist; /* Remember this if we recurse */
584 * Ignore this directory and everything below if the file .nobackup
585 * (or what is defined for IgnoreDir in this fileset) exists
587 if (have_ignoredir(ff_pkt)) {
588 return 1; /* Just ignore this directory */
591 /* Build a canonical directory name with a trailing slash in link var */
593 link_len = len + 200;
594 link = (char *)bmalloc(link_len + 2);
595 bstrncpy(link, fname, link_len);
596 /* Strip all trailing slashes */
597 while (len >= 1 && IsPathSeparator(link[len - 1]))
599 link[len++] = '/'; /* add back one */
603 if (!check_changes(jcr, ff_pkt)) {
604 /* Incremental/Full+Base option, directory entry not changed */
605 ff_pkt->type = FT_DIRNOCHG;
607 ff_pkt->type = FT_DIRBEGIN;
610 * We have set st_rdev to 1 if it is a reparse point, otherwise 0,
611 * if st_rdev is 2, it is a mount point
613 #if defined(HAVE_WIN32)
615 * A reparse point (WIN32_REPARSE_POINT)
616 * is something special like one of the following:
617 * IO_REPARSE_TAG_DFS 0x8000000A
618 * IO_REPARSE_TAG_DFSR 0x80000012
619 * IO_REPARSE_TAG_HSM 0xC0000004
620 * IO_REPARSE_TAG_HSM2 0x80000006
621 * IO_REPARSE_TAG_SIS 0x80000007
622 * IO_REPARSE_TAG_SYMLINK 0xA000000C
624 * A junction point is a:
625 * IO_REPARSE_TAG_MOUNT_POINT 0xA0000003
626 * which can be either a link to a Volume (WIN32_MOUNT_POINT)
627 * or a link to a directory (WIN32_JUNCTION_POINT)
629 * Ignore WIN32_REPARSE_POINT and WIN32_JUNCTION_POINT
631 if (ff_pkt->statp.st_rdev == WIN32_REPARSE_POINT) {
632 ff_pkt->type = FT_REPARSE;
633 } else if (ff_pkt->statp.st_rdev == WIN32_JUNCTION_POINT) {
634 ff_pkt->type = FT_JUNCTION;
638 * Note, we return the directory to the calling program (handle_file)
639 * when we first see the directory (FT_DIRBEGIN.
640 * This allows the program to apply matches and make a
641 * choice whether or not to accept it. If it is accepted, we
642 * do not immediately save it, but do so only after everything
643 * in the directory is seen (i.e. the FT_DIREND).
645 rtn_stat = handle_file(jcr, ff_pkt, top_level);
646 if (rtn_stat < 1 || ff_pkt->type == FT_REPARSE ||
647 ff_pkt->type == FT_JUNCTION) { /* ignore or error status */
651 /* Done with DIRBEGIN, next call will be DIREND */
652 if (ff_pkt->type == FT_DIRBEGIN) {
653 ff_pkt->type = FT_DIREND;
657 * Create a temporary ff packet for this directory
658 * entry, and defer handling the directory until
659 * we have recursed into it. This saves the
660 * directory after all files have been processed, and
661 * during the restore, the directory permissions will
662 * be reset after all the files have been restored.
664 Dmsg1(300, "Create temp ff packet for dir: %s\n", ff_pkt->fname);
665 FF_PKT *dir_ff_pkt = new_dir_ff_pkt(ff_pkt);
668 * Do not descend into subdirectories (recurse) if the
669 * user has turned it off for this directory.
671 * If we are crossing file systems, we are either not allowed
672 * to cross, or we may be restricted by a list of permitted
675 bool is_win32_mount_point = false;
676 #if defined(HAVE_WIN32)
677 is_win32_mount_point = ff_pkt->statp.st_rdev == WIN32_MOUNT_POINT;
679 if (!top_level && ff_pkt->flags & FO_NO_RECURSION) {
680 ff_pkt->type = FT_NORECURSE;
682 } else if (!top_level && (parent_device != ff_pkt->statp.st_dev ||
683 is_win32_mount_point)) {
684 if(!(ff_pkt->flags & FO_MULTIFS)) {
685 ff_pkt->type = FT_NOFSCHG;
687 } else if (!accept_fstype(ff_pkt, NULL)) {
688 ff_pkt->type = FT_INVALIDFS;
691 ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
694 /* If not recursing, just backup dir and return */
696 rtn_stat = handle_file(jcr, ff_pkt, top_level);
697 if (ff_pkt->linked) {
698 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
701 free_dir_ff_pkt(dir_ff_pkt);
702 ff_pkt->link = ff_pkt->fname; /* reset "link" */
703 if (ff_pkt->flags & FO_KEEPATIME) {
704 utime(fname, &restore_times);
709 ff_pkt->link = ff_pkt->fname; /* reset "link" */
712 * Descend into or "recurse" into the directory to read
713 * all the files in it.
716 if ((directory = opendir(fname)) == NULL) {
717 ff_pkt->type = FT_NOOPEN;
718 ff_pkt->ff_errno = errno;
719 rtn_stat = handle_file(jcr, ff_pkt, top_level);
720 if (ff_pkt->linked) {
721 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
724 free_dir_ff_pkt(dir_ff_pkt);
729 * Process all files in this directory entry (recursing).
730 * This would possibly run faster if we chdir to the directory
731 * before traversing it.
734 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 100);
735 for ( ; !job_canceled(jcr); ) {
739 status = readdir_r(directory, entry, &result);
740 if (status != 0 || result == NULL) {
741 // Dmsg2(99, "readdir returned stat=%d result=0x%x\n",
742 // status, (long)result);
745 ASSERT(name_max+1 > (int)sizeof(struct dirent) + (int)NAMELEN(entry));
747 /* Skip `.', `..', and excluded file names. */
748 if (p[0] == '\0' || (p[0] == '.' && (p[1] == '\0' ||
749 (p[1] == '.' && p[2] == '\0')))) {
753 if ((int)NAMELEN(entry) + len >= link_len) {
754 link_len = len + NAMELEN(entry) + 1;
755 link = (char *)brealloc(link, link_len + 1);
758 for (i=0; i < (int)NAMELEN(entry); i++) {
762 if (!file_is_excluded(ff_pkt, link)) {
763 rtn_stat = find_one_file(jcr, ff_pkt, handle_file, link, our_device, false);
764 if (ff_pkt->linked) {
765 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
774 * Now that we have recursed through all the files in the
775 * directory, we "save" the directory so that after all
776 * the files are restored, this entry will serve to reset
777 * the directory modes and dates. Temp directory values
778 * were used without this record.
780 handle_file(jcr, dir_ff_pkt, top_level); /* handle directory entry */
781 if (ff_pkt->linked) {
782 ff_pkt->linked->FileIndex = dir_ff_pkt->FileIndex;
784 free_dir_ff_pkt(dir_ff_pkt);
786 if (ff_pkt->flags & FO_KEEPATIME) {
787 utime(fname, &restore_times);
789 ff_pkt->volhas_attrlist = volhas_attrlist; /* Restore value in case it changed. */
791 } /* end check for directory */
794 * If it is explicitly mentioned (i.e. top_level) and is
795 * a block device, we do a raw backup of it or if it is
796 * a fifo, we simply read it.
798 #ifdef HAVE_FREEBSD_OS
800 * On FreeBSD, all block devices are character devices, so
801 * to be able to read a raw disk, we need the check for
802 * a character device.
803 * crw-r----- 1 root operator - 116, 0x00040002 Jun 9 19:32 /dev/ad0s3
804 * crw-r----- 1 root operator - 116, 0x00040002 Jun 9 19:32 /dev/rad0s3
806 if (top_level && (S_ISBLK(ff_pkt->statp.st_mode) || S_ISCHR(ff_pkt->statp.st_mode))) {
808 if (top_level && S_ISBLK(ff_pkt->statp.st_mode)) {
810 ff_pkt->type = FT_RAW; /* raw partition */
811 } else if (top_level && S_ISFIFO(ff_pkt->statp.st_mode) &&
812 ff_pkt->flags & FO_READFIFO) {
813 ff_pkt->type = FT_FIFO;
815 /* The only remaining types are special (character, ...) files */
816 ff_pkt->type = FT_SPEC;
818 rtn_stat = handle_file(jcr, ff_pkt, top_level);
819 if (ff_pkt->linked) {
820 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
825 int term_find_one(FF_PKT *ff)
827 struct f_link *lp, *lc;
832 if (ff->linkhash == NULL) return 0;
834 for (i =0 ; i < LINK_HASHTABLE_SIZE; i ++) {
835 /* Free up list of hard linked files */
836 lp = ff->linkhash[i];
848 ff->linkhash[i] = NULL;