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;
106 dir_ff_pkt->ignoredir_fname = NULL;
111 * Free the temp directory ff_pkt
113 static void free_dir_ff_pkt(FF_PKT *dir_ff_pkt)
115 free(dir_ff_pkt->fname);
116 free(dir_ff_pkt->link);
117 free_pool_memory(dir_ff_pkt->sys_fname);
118 if (dir_ff_pkt->fname_save) {
119 free_pool_memory(dir_ff_pkt->fname_save);
121 if (dir_ff_pkt->link_save) {
122 free_pool_memory(dir_ff_pkt->link_save);
124 if (dir_ff_pkt->ignoredir_fname) {
125 free_pool_memory(dir_ff_pkt->ignoredir_fname);
131 * Check to see if we allow the file system type of a file or directory.
132 * If we do not have a list of file system types, we accept anything.
134 static int accept_fstype(FF_PKT *ff, void *dummy) {
139 if (ff->fstypes.size()) {
141 if (!fstype(ff->fname, fs, sizeof(fs))) {
142 Dmsg1(50, "Cannot determine file system type for \"%s\"\n", ff->fname);
144 for (i = 0; i < ff->fstypes.size(); ++i) {
145 if (strcmp(fs, (char *)ff->fstypes.get(i)) == 0) {
146 Dmsg2(100, "Accepting fstype %s for \"%s\"\n", fs, ff->fname);
150 Dmsg3(200, "fstype %s for \"%s\" does not match %s\n", fs,
151 ff->fname, ff->fstypes.get(i));
159 * Check to see if we allow the drive type of a file or directory.
160 * If we do not have a list of drive types, we accept anything.
162 static int accept_drivetype(FF_PKT *ff, void *dummy) {
167 if (ff->drivetypes.size()) {
169 if (!drivetype(ff->fname, dt, sizeof(dt))) {
170 Dmsg1(50, "Cannot determine drive type for \"%s\"\n", ff->fname);
172 for (i = 0; i < ff->drivetypes.size(); ++i) {
173 if (strcmp(dt, (char *)ff->drivetypes.get(i)) == 0) {
174 Dmsg2(100, "Accepting drive type %s for \"%s\"\n", dt, ff->fname);
178 Dmsg3(200, "drive type %s for \"%s\" does not match %s\n", dt,
179 ff->fname, ff->drivetypes.get(i));
187 * This function determines whether we can use getattrlist()
188 * It's odd, but we have to use the function to determine that...
189 * Also, the man pages talk about things as if they were implemented.
191 * On Mac OS X, this succesfully differentiates between HFS+ and UFS
192 * volumes, which makes me trust it is OK for others, too.
194 static bool volume_has_attrlist(const char *fname)
196 #ifdef HAVE_DARWIN_OS
198 struct volinfo_struct {
199 unsigned long length; /* Mandatory field */
200 vol_capabilities_attr_t info; /* Volume capabilities */
202 struct attrlist attrList;
204 memset(&attrList, 0, sizeof(attrList));
205 attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
206 attrList.volattr = ATTR_VOL_INFO | ATTR_VOL_CAPABILITIES;
207 if (statfs(fname, &st) == 0) {
208 /* We need to check on the mount point */
209 if (getattrlist(st.f_mntonname, &attrList, &vol, sizeof(vol), FSOPT_NOFOLLOW) == 0
210 && (vol.info.capabilities[VOL_CAPABILITIES_INTERFACES] & VOL_CAP_INT_ATTRLIST)
211 && (vol.info.valid[VOL_CAPABILITIES_INTERFACES] & VOL_CAP_INT_ATTRLIST)) {
220 * check for BSD nodump flag
222 static bool no_dump(JCR *jcr, FF_PKT *ff_pkt)
224 #if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
225 if ( (ff_pkt->flags & FO_HONOR_NODUMP) &&
226 (ff_pkt->statp.st_flags & UF_NODUMP) ) {
227 Jmsg(jcr, M_INFO, 1, _(" NODUMP flag set - will not process %s\n"),
229 return true; /* do not backup this file */
232 return false; /* do backup */
235 /* check if a file have changed during backup and display an error */
236 bool has_file_changed(JCR *jcr, FF_PKT *ff_pkt)
239 Dmsg1(500, "has_file_changed fname=%s\n",ff_pkt->fname);
241 if (ff_pkt->type != FT_REG) { /* not a regular file */
245 if (lstat(ff_pkt->fname, &statp) != 0) {
247 Jmsg(jcr, M_WARNING, 0,
248 _("Cannot stat file %s: ERR=%s\n"),ff_pkt->fname,be.bstrerror());
252 if (statp.st_mtime != ff_pkt->statp.st_mtime) {
253 Jmsg(jcr, M_ERROR, 0, _("%s mtime changed during backup.\n"), ff_pkt->fname);
254 Dmsg3(50, "%s mtime (%lld) changed during backup (%lld).\n", ff_pkt->fname,
255 (int64_t)ff_pkt->statp.st_mtime, (int64_t)statp.st_mtime);
259 if (statp.st_ctime != ff_pkt->statp.st_ctime) {
260 Jmsg(jcr, M_ERROR, 0, _("%s ctime changed during backup.\n"), ff_pkt->fname);
261 Dmsg3(50, "%s ctime (%lld) changed during backup (%lld).\n", ff_pkt->fname,
262 (int64_t)ff_pkt->statp.st_ctime, (int64_t)statp.st_ctime);
266 if (statp.st_size != ff_pkt->statp.st_size) {
267 /* TODO: add size change */
268 Jmsg(jcr, M_ERROR, 0, _("%s size changed during backup.\n"),ff_pkt->fname);
269 Dmsg3(50, "%s size (%lld) changed during backup (%lld).\n", ff_pkt->fname,
270 (int64_t)ff_pkt->statp.st_size, (int64_t)statp.st_size);
274 if ((statp.st_blksize != ff_pkt->statp.st_blksize) ||
275 (statp.st_blocks != ff_pkt->statp.st_blocks)) {
276 Jmsg(jcr, M_ERROR, 0, _("%s size changed during backup.\n"),ff_pkt->fname);
277 Dmsg3(50, "%s size (%lld) changed during backup (%lld).\n", ff_pkt->fname,
278 (int64_t)ff_pkt->statp.st_blocks, (int64_t)statp.st_blocks);
286 * For incremental/diffential or accurate backups, we
287 * determine if the current file has changed.
289 bool check_changes(JCR *jcr, FF_PKT *ff_pkt)
291 /* in special mode (like accurate backup), the programmer can
292 * choose his comparison function.
294 if (ff_pkt->check_fct) {
295 return ff_pkt->check_fct(jcr, ff_pkt);
298 /* For normal backups (incr/diff), we use this default
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)))
312 static bool have_ignoredir(FF_PKT *ff_pkt)
317 /* Ensure that pointers are defined */
318 if (!ff_pkt->fileset || !ff_pkt->fileset->incexe) {
321 ignoredir = ff_pkt->fileset->incexe->ignoredir;
324 if (!ff_pkt->ignoredir_fname) {
325 ff_pkt->ignoredir_fname = get_pool_memory(PM_FNAME);
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 */
338 * When the current file is a hardlink, the backup code can compute
339 * the checksum and store it into the link_t structure.
342 ff_pkt_set_link_digest(FF_PKT *ff_pkt,
343 int32_t digest_stream, const char *digest, uint32_t len)
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;
354 * Find a single file.
355 * handle_file is the callback for handling the file.
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.
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)
366 struct utimbuf restore_times;
370 ff_pkt->fname = ff_pkt->link = fname;
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);
379 Dmsg1(300, "File ----: %s\n", fname);
381 /* Save current times of this directory in case we need to
382 * reset them because the user doesn't want them changed.
384 restore_times.actime = ff_pkt->statp.st_atime;
385 restore_times.modtime = ff_pkt->statp.st_mtime;
388 * We check for allowed fstypes and drivetypes at top_level and fstype change (below).
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);
399 if (!fstype(ff_pkt->fname, fs, sizeof(fs))) {
400 bstrncpy(fs, "unknown", sizeof(fs));
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 */
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);
414 if (!drivetype(ff_pkt->fname, dt, sizeof(dt))) {
415 bstrncpy(dt, "unknown", sizeof(dt));
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 */
421 ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
425 * Ignore this entry if no_dump() returns true
427 if (no_dump(jcr, ff_pkt)) {
428 Dmsg1(100, "'%s' ignored (NODUMP flag set)\n",
434 * If this is an Incremental backup, see if file was modified
435 * since our last "save_time", presumably the last Full save
438 if ( !S_ISDIR(ff_pkt->statp.st_mode)
439 && !check_changes(jcr, ff_pkt))
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);
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);
466 * Handle hard linked files
468 * Maintain a list of hard linked files already backed up. This
469 * allows us to ensure that the data of each file gets backed
472 if (!(ff_pkt->flags & FO_NO_HARDLINK)
473 && ff_pkt->statp.st_nlink > 1
474 && (S_ISREG(ff_pkt->statp.st_mode)
475 || S_ISCHR(ff_pkt->statp.st_mode)
476 || S_ISBLK(ff_pkt->statp.st_mode)
477 || S_ISFIFO(ff_pkt->statp.st_mode)
478 || S_ISSOCK(ff_pkt->statp.st_mode))) {
481 if (ff_pkt->linkhash == NULL) {
482 ff_pkt->linkhash = (link_t **)bmalloc(LINK_HASHTABLE_SIZE * sizeof(link_t *));
483 memset(ff_pkt->linkhash, 0, LINK_HASHTABLE_SIZE * sizeof(link_t *));
485 const int linkhash = LINKHASH(ff_pkt->statp);
487 /* Search link list of hard linked files */
488 for (lp = ff_pkt->linkhash[linkhash]; lp; lp = lp->next)
489 if (lp->ino == (ino_t)ff_pkt->statp.st_ino &&
490 lp->dev == (dev_t)ff_pkt->statp.st_dev) {
491 /* If we have already backed up the hard linked file don't do it again */
492 if (strcmp(lp->name, fname) == 0) {
493 Dmsg2(400, "== Name identical skip FI=%d file=%s\n", lp->FileIndex, fname);
494 return 1; /* ignore */
496 ff_pkt->link = lp->name;
497 ff_pkt->type = FT_LNKSAVED; /* Handle link, file already saved */
498 ff_pkt->LinkFI = lp->FileIndex;
500 ff_pkt->digest = lp->digest;
501 ff_pkt->digest_stream = lp->digest_stream;
502 ff_pkt->digest_len = lp->digest_len;
503 rtn_stat = handle_file(jcr, ff_pkt, top_level);
504 Dmsg3(400, "FT_LNKSAVED FI=%d LinkFI=%d file=%s\n",
505 ff_pkt->FileIndex, lp->FileIndex, lp->name);
509 /* File not previously dumped. Chain it into our list. */
510 len = strlen(fname) + 1;
511 lp = (struct f_link *)bmalloc(sizeof(struct f_link) + len);
512 lp->digest = NULL; /* set later */
513 lp->digest_stream = 0; /* set later */
514 lp->digest_len = 0; /* set later */
515 lp->ino = ff_pkt->statp.st_ino;
516 lp->dev = ff_pkt->statp.st_dev;
517 lp->FileIndex = 0; /* set later */
518 bstrncpy(lp->name, fname, len);
519 lp->next = ff_pkt->linkhash[linkhash];
520 ff_pkt->linkhash[linkhash] = lp;
521 ff_pkt->linked = lp; /* mark saved link */
522 Dmsg2(400, "added to hash FI=%d file=%s\n", ff_pkt->FileIndex, lp->name);
524 ff_pkt->linked = NULL;
527 /* This is not a link to a previously dumped file, so dump it. */
528 if (S_ISREG(ff_pkt->statp.st_mode)) {
531 sizeleft = ff_pkt->statp.st_size;
533 /* Don't bother opening empty, world readable files. Also do not open
534 files when archive is meant for /dev/null. */
535 if (ff_pkt->null_output_device || (sizeleft == 0
536 && MODE_RALL == (MODE_RALL & ff_pkt->statp.st_mode))) {
537 ff_pkt->type = FT_REGE;
539 ff_pkt->type = FT_REG;
541 rtn_stat = handle_file(jcr, ff_pkt, top_level);
542 if (ff_pkt->linked) {
543 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
545 Dmsg3(400, "FT_REG FI=%d linked=%d file=%s\n", ff_pkt->FileIndex,
546 ff_pkt->linked ? 1 : 0, fname);
547 if (ff_pkt->flags & FO_KEEPATIME) {
548 utime(fname, &restore_times);
553 } else if (S_ISLNK(ff_pkt->statp.st_mode)) { /* soft link */
555 char *buffer = (char *)alloca(path_max + name_max + 102);
557 size = readlink(fname, buffer, path_max + name_max + 101);
559 /* Could not follow link */
560 ff_pkt->type = FT_NOFOLLOW;
561 ff_pkt->ff_errno = errno;
562 rtn_stat = handle_file(jcr, ff_pkt, top_level);
563 if (ff_pkt->linked) {
564 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
569 ff_pkt->link = buffer; /* point to link */
570 ff_pkt->type = FT_LNK; /* got a real link */
571 rtn_stat = handle_file(jcr, ff_pkt, top_level);
572 if (ff_pkt->linked) {
573 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
577 } else if (S_ISDIR(ff_pkt->statp.st_mode)) {
579 struct dirent *entry, *result;
584 dev_t our_device = ff_pkt->statp.st_dev;
586 bool volhas_attrlist = ff_pkt->volhas_attrlist; /* Remember this if we recurse */
589 * Ignore this directory and everything below if the file .nobackup
590 * (or what is defined for IgnoreDir in this fileset) exists
592 if (have_ignoredir(ff_pkt)) {
593 return 1; /* Just ignore this directory */
596 /* Build a canonical directory name with a trailing slash in link var */
598 link_len = len + 200;
599 link = (char *)bmalloc(link_len + 2);
600 bstrncpy(link, fname, link_len);
601 /* Strip all trailing slashes */
602 while (len >= 1 && IsPathSeparator(link[len - 1]))
604 link[len++] = '/'; /* add back one */
608 if (!check_changes(jcr, ff_pkt)) {
609 /* Incremental/Full+Base option, directory entry not changed */
610 ff_pkt->type = FT_DIRNOCHG;
612 ff_pkt->type = FT_DIRBEGIN;
615 * We have set st_rdev to 1 if it is a reparse point, otherwise 0,
616 * if st_rdev is 2, it is a mount point
618 #if defined(HAVE_WIN32)
620 * A reparse point (WIN32_REPARSE_POINT)
621 * is something special like one of the following:
622 * IO_REPARSE_TAG_DFS 0x8000000A
623 * IO_REPARSE_TAG_DFSR 0x80000012
624 * IO_REPARSE_TAG_HSM 0xC0000004
625 * IO_REPARSE_TAG_HSM2 0x80000006
626 * IO_REPARSE_TAG_SIS 0x80000007
627 * IO_REPARSE_TAG_SYMLINK 0xA000000C
629 * A junction point is a:
630 * IO_REPARSE_TAG_MOUNT_POINT 0xA0000003
631 * which can be either a link to a Volume (WIN32_MOUNT_POINT)
632 * or a link to a directory (WIN32_JUNCTION_POINT)
634 * Ignore WIN32_REPARSE_POINT and WIN32_JUNCTION_POINT
636 if (ff_pkt->statp.st_rdev == WIN32_REPARSE_POINT) {
637 ff_pkt->type = FT_REPARSE;
638 } else if (ff_pkt->statp.st_rdev == WIN32_JUNCTION_POINT) {
639 ff_pkt->type = FT_JUNCTION;
643 * Note, we return the directory to the calling program (handle_file)
644 * when we first see the directory (FT_DIRBEGIN.
645 * This allows the program to apply matches and make a
646 * choice whether or not to accept it. If it is accepted, we
647 * do not immediately save it, but do so only after everything
648 * in the directory is seen (i.e. the FT_DIREND).
650 rtn_stat = handle_file(jcr, ff_pkt, top_level);
651 if (rtn_stat < 1 || ff_pkt->type == FT_REPARSE ||
652 ff_pkt->type == FT_JUNCTION) { /* ignore or error status */
656 /* Done with DIRBEGIN, next call will be DIREND */
657 if (ff_pkt->type == FT_DIRBEGIN) {
658 ff_pkt->type = FT_DIREND;
662 * Create a temporary ff packet for this directory
663 * entry, and defer handling the directory until
664 * we have recursed into it. This saves the
665 * directory after all files have been processed, and
666 * during the restore, the directory permissions will
667 * be reset after all the files have been restored.
669 Dmsg1(300, "Create temp ff packet for dir: %s\n", ff_pkt->fname);
670 FF_PKT *dir_ff_pkt = new_dir_ff_pkt(ff_pkt);
673 * Do not descend into subdirectories (recurse) if the
674 * user has turned it off for this directory.
676 * If we are crossing file systems, we are either not allowed
677 * to cross, or we may be restricted by a list of permitted
680 bool is_win32_mount_point = false;
681 #if defined(HAVE_WIN32)
682 is_win32_mount_point = ff_pkt->statp.st_rdev == WIN32_MOUNT_POINT;
684 if (!top_level && ff_pkt->flags & FO_NO_RECURSION) {
685 ff_pkt->type = FT_NORECURSE;
687 } else if (!top_level && (parent_device != ff_pkt->statp.st_dev ||
688 is_win32_mount_point)) {
689 if(!(ff_pkt->flags & FO_MULTIFS)) {
690 ff_pkt->type = FT_NOFSCHG;
692 } else if (!accept_fstype(ff_pkt, NULL)) {
693 ff_pkt->type = FT_INVALIDFS;
696 ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
699 /* If not recursing, just backup dir and return */
701 rtn_stat = handle_file(jcr, ff_pkt, top_level);
702 if (ff_pkt->linked) {
703 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
706 free_dir_ff_pkt(dir_ff_pkt);
707 ff_pkt->link = ff_pkt->fname; /* reset "link" */
708 if (ff_pkt->flags & FO_KEEPATIME) {
709 utime(fname, &restore_times);
714 ff_pkt->link = ff_pkt->fname; /* reset "link" */
717 * Descend into or "recurse" into the directory to read
718 * all the files in it.
721 if ((directory = opendir(fname)) == NULL) {
722 ff_pkt->type = FT_NOOPEN;
723 ff_pkt->ff_errno = errno;
724 rtn_stat = handle_file(jcr, ff_pkt, top_level);
725 if (ff_pkt->linked) {
726 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
729 free_dir_ff_pkt(dir_ff_pkt);
734 * Process all files in this directory entry (recursing).
735 * This would possibly run faster if we chdir to the directory
736 * before traversing it.
739 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 100);
740 for ( ; !job_canceled(jcr); ) {
744 status = readdir_r(directory, entry, &result);
745 if (status != 0 || result == NULL) {
746 // Dmsg2(99, "readdir returned stat=%d result=0x%x\n",
747 // status, (long)result);
750 ASSERT(name_max+1 > (int)sizeof(struct dirent) + (int)NAMELEN(entry));
752 /* Skip `.', `..', and excluded file names. */
753 if (p[0] == '\0' || (p[0] == '.' && (p[1] == '\0' ||
754 (p[1] == '.' && p[2] == '\0')))) {
758 if ((int)NAMELEN(entry) + len >= link_len) {
759 link_len = len + NAMELEN(entry) + 1;
760 link = (char *)brealloc(link, link_len + 1);
763 for (i=0; i < (int)NAMELEN(entry); i++) {
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;
779 * Now that we have recursed through all the files in the
780 * directory, we "save" the directory so that after all
781 * the files are restored, this entry will serve to reset
782 * the directory modes and dates. Temp directory values
783 * were used without this record.
785 handle_file(jcr, dir_ff_pkt, top_level); /* handle directory entry */
786 if (ff_pkt->linked) {
787 ff_pkt->linked->FileIndex = dir_ff_pkt->FileIndex;
789 free_dir_ff_pkt(dir_ff_pkt);
791 if (ff_pkt->flags & FO_KEEPATIME) {
792 utime(fname, &restore_times);
794 ff_pkt->volhas_attrlist = volhas_attrlist; /* Restore value in case it changed. */
796 } /* end check for directory */
799 * If it is explicitly mentioned (i.e. top_level) and is
800 * a block device, we do a raw backup of it or if it is
801 * a fifo, we simply read it.
803 #ifdef HAVE_FREEBSD_OS
805 * On FreeBSD, all block devices are character devices, so
806 * to be able to read a raw disk, we need the check for
807 * a character device.
808 * crw-r----- 1 root operator - 116, 0x00040002 Jun 9 19:32 /dev/ad0s3
809 * crw-r----- 1 root operator - 116, 0x00040002 Jun 9 19:32 /dev/rad0s3
811 if (top_level && (S_ISBLK(ff_pkt->statp.st_mode) || S_ISCHR(ff_pkt->statp.st_mode))) {
813 if (top_level && S_ISBLK(ff_pkt->statp.st_mode)) {
815 ff_pkt->type = FT_RAW; /* raw partition */
816 } else if (top_level && S_ISFIFO(ff_pkt->statp.st_mode) &&
817 ff_pkt->flags & FO_READFIFO) {
818 ff_pkt->type = FT_FIFO;
820 /* The only remaining types are special (character, ...) files */
821 ff_pkt->type = FT_SPEC;
823 rtn_stat = handle_file(jcr, ff_pkt, top_level);
824 if (ff_pkt->linked) {
825 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
830 int term_find_one(FF_PKT *ff)
832 struct f_link *lp, *lc;
837 if (ff->linkhash == NULL) return 0;
839 for (i =0 ; i < LINK_HASHTABLE_SIZE; i ++) {
840 /* Free up list of hard linked files */
841 lp = ff->linkhash[i];
853 ff->linkhash[i] = NULL;