2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2007 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 two of the GNU 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 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 John Walker.
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 */
64 uint32_t FileIndex; /* Bacula FileIndex of this file */
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)) {
215 /* check if a file have changed during backup and display an error */
216 bool has_file_changed(JCR *jcr, FF_PKT *ff_pkt)
219 Dmsg1(500, "has_file_changed fname=%s\n",ff_pkt->fname);
221 if (ff_pkt->type != FT_REG) { /* not a regular file */
225 if (lstat(ff_pkt->fname, &statp) != 0) {
227 Jmsg(jcr, M_WARNING, 0,
228 _("Cannot stat file %s: ERR=%s\n"),ff_pkt->fname,be.bstrerror());
232 if (statp.st_mtime != ff_pkt->statp.st_mtime) {
233 /* TODO: add time of changes */
234 Jmsg(jcr, M_ERROR, 0, _("%s mtime changed during backup.\n"), ff_pkt->fname);
238 if (statp.st_ctime != ff_pkt->statp.st_ctime) {
239 /* TODO: add time of changes */
240 Jmsg(jcr, M_ERROR, 0, _("%s ctime changed during backup.\n"), ff_pkt->fname);
244 if (statp.st_size != ff_pkt->statp.st_size) {
245 /* TODO: add size change */
246 Jmsg(jcr, M_ERROR, 0, _("%s size changed during backup.\n"),ff_pkt->fname);
250 if ((statp.st_blksize != ff_pkt->statp.st_blksize) ||
251 (statp.st_blocks != ff_pkt->statp.st_blocks)) {
252 /* TODO: add size change */
253 Jmsg(jcr, M_ERROR, 0, _("%s size changed during backup.\n"),ff_pkt->fname);
261 * In incremental/diffential or accurate backup, we
262 * say if the current file has changed.
264 static bool check_changes(JCR *jcr, FF_PKT *ff_pkt)
266 /* in special mode (like accurate backup), user can
267 * choose his comparison function.
269 if (ff_pkt->check_fct) {
270 return ff_pkt->check_fct(jcr, ff_pkt);
273 /* in normal modes (incr/diff), we use this default
276 if (ff_pkt->incremental &&
277 (ff_pkt->statp.st_mtime < ff_pkt->save_time &&
278 ((ff_pkt->flags & FO_MTIMEONLY) ||
279 ff_pkt->statp.st_ctime < ff_pkt->save_time)))
288 * Find a single file.
289 * handle_file is the callback for handling the file.
291 * parent_device is the device we are currently on
292 * top_level is 1 when not recursing or 0 when
293 * descending into a directory.
296 find_one_file(JCR *jcr, FF_PKT *ff_pkt,
297 int handle_file(JCR *jcr, FF_PKT *ff, bool top_level),
298 char *fname, dev_t parent_device, bool top_level)
300 struct utimbuf restore_times;
304 ff_pkt->fname = ff_pkt->link = fname;
306 if (lstat(fname, &ff_pkt->statp) != 0) {
307 /* Cannot stat file */
308 ff_pkt->type = FT_NOSTAT;
309 ff_pkt->ff_errno = errno;
310 return handle_file(jcr, ff_pkt, top_level);
313 Dmsg1(300, "File ----: %s\n", fname);
315 /* Save current times of this directory in case we need to
316 * reset them because the user doesn't want them changed.
318 restore_times.actime = ff_pkt->statp.st_atime;
319 restore_times.modtime = ff_pkt->statp.st_mtime;
322 * We check for allowed fstypes and drivetypes at top_level and fstype change (below).
325 if (!accept_fstype(ff_pkt, NULL)) {
326 ff_pkt->type = FT_INVALIDFS;
327 if (ff_pkt->flags & FO_KEEPATIME) {
328 utime(fname, &restore_times);
333 if (!fstype(ff_pkt->fname, fs, sizeof(fs))) {
334 bstrncpy(fs, "unknown", sizeof(fs));
337 Jmsg(jcr, M_INFO, 0, _("Top level directory \"%s\" has unlisted fstype \"%s\"\n"), fname, fs);
338 return 1; /* Just ignore this error - or the whole backup is cancelled */
340 if (!accept_drivetype(ff_pkt, NULL)) {
341 ff_pkt->type = FT_INVALIDDT;
342 if (ff_pkt->flags & FO_KEEPATIME) {
343 utime(fname, &restore_times);
348 if (!drivetype(ff_pkt->fname, dt, sizeof(dt))) {
349 bstrncpy(dt, "unknown", sizeof(dt));
352 Jmsg(jcr, M_INFO, 0, _("Top level directory \"%s\" has an unlisted drive type \"%s\"\n"), fname, dt);
353 return 1; /* Just ignore this error - or the whole backup is cancelled */
355 ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
358 * If this is an Incremental backup, see if file was modified
359 * since our last "save_time", presumably the last Full save
362 if ( ff_pkt->incremental
363 && !S_ISDIR(ff_pkt->statp.st_mode)
364 && !check_changes(jcr, ff_pkt))
366 Dmsg1(500, "Non-directory incremental: %s\n", ff_pkt->fname);
367 ff_pkt->type = FT_NOCHG;
368 return handle_file(jcr, ff_pkt, top_level);
371 #ifdef HAVE_DARWIN_OS
372 if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->volhas_attrlist
373 && S_ISREG(ff_pkt->statp.st_mode)) {
374 /* TODO: initialise attrList once elsewhere? */
375 struct attrlist attrList;
376 memset(&attrList, 0, sizeof(attrList));
377 attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
378 attrList.commonattr = ATTR_CMN_FNDRINFO;
379 attrList.fileattr = ATTR_FILE_RSRCLENGTH;
380 if (getattrlist(fname, &attrList, &ff_pkt->hfsinfo,
381 sizeof(ff_pkt->hfsinfo), FSOPT_NOFOLLOW) != 0) {
382 ff_pkt->type = FT_NOSTAT;
383 ff_pkt->ff_errno = errno;
384 return handle_file(jcr, ff_pkt, top_level);
391 * Handle hard linked files
393 * Maintain a list of hard linked files already backed up. This
394 * allows us to ensure that the data of each file gets backed
397 if (!(ff_pkt->flags & FO_NO_HARDLINK)
398 && ff_pkt->statp.st_nlink > 1
399 && (S_ISREG(ff_pkt->statp.st_mode)
400 || S_ISCHR(ff_pkt->statp.st_mode)
401 || S_ISBLK(ff_pkt->statp.st_mode)
402 || S_ISFIFO(ff_pkt->statp.st_mode)
403 || S_ISSOCK(ff_pkt->statp.st_mode))) {
406 if (ff_pkt->linkhash == NULL) {
407 ff_pkt->linkhash = (link_t **)bmalloc(LINK_HASHTABLE_SIZE * sizeof(link_t *));
408 memset(ff_pkt->linkhash, 0, LINK_HASHTABLE_SIZE * sizeof(link_t *));
410 const int linkhash = LINKHASH(ff_pkt->statp);
412 /* Search link list of hard linked files */
413 for (lp = ff_pkt->linkhash[linkhash]; lp; lp = lp->next)
414 if (lp->ino == (ino_t)ff_pkt->statp.st_ino &&
415 lp->dev == (dev_t)ff_pkt->statp.st_dev) {
416 /* If we have already backed up the hard linked file don't do it again */
417 if (strcmp(lp->name, fname) == 0) {
418 return 1; /* ignore */
420 ff_pkt->link = lp->name;
421 ff_pkt->type = FT_LNKSAVED; /* Handle link, file already saved */
422 ff_pkt->LinkFI = lp->FileIndex;
423 return handle_file(jcr, ff_pkt, top_level);
426 /* File not previously dumped. Chain it into our list. */
427 len = strlen(fname) + 1;
428 lp = (struct f_link *)bmalloc(sizeof(struct f_link) + len);
429 lp->ino = ff_pkt->statp.st_ino;
430 lp->dev = ff_pkt->statp.st_dev;
431 bstrncpy(lp->name, fname, len);
432 lp->next = ff_pkt->linkhash[linkhash];
433 ff_pkt->linkhash[linkhash] = lp;
434 ff_pkt->linked = lp; /* mark saved link */
436 ff_pkt->linked = NULL;
439 /* This is not a link to a previously dumped file, so dump it. */
440 if (S_ISREG(ff_pkt->statp.st_mode)) {
443 sizeleft = ff_pkt->statp.st_size;
445 /* Don't bother opening empty, world readable files. Also do not open
446 files when archive is meant for /dev/null. */
447 if (ff_pkt->null_output_device || (sizeleft == 0
448 && MODE_RALL == (MODE_RALL & ff_pkt->statp.st_mode))) {
449 ff_pkt->type = FT_REGE;
451 ff_pkt->type = FT_REG;
453 rtn_stat = handle_file(jcr, ff_pkt, top_level);
454 if (ff_pkt->linked) {
455 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
457 if (ff_pkt->flags & FO_KEEPATIME) {
458 utime(fname, &restore_times);
463 } else if (S_ISLNK(ff_pkt->statp.st_mode)) { /* soft link */
465 char *buffer = (char *)alloca(path_max + name_max + 102);
467 size = readlink(fname, buffer, path_max + name_max + 101);
469 /* Could not follow link */
470 ff_pkt->type = FT_NOFOLLOW;
471 ff_pkt->ff_errno = errno;
472 rtn_stat = handle_file(jcr, ff_pkt, top_level);
473 if (ff_pkt->linked) {
474 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
479 ff_pkt->link = buffer; /* point to link */
480 ff_pkt->type = FT_LNK; /* got a real link */
481 rtn_stat = handle_file(jcr, ff_pkt, top_level);
482 if (ff_pkt->linked) {
483 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
487 } else if (S_ISDIR(ff_pkt->statp.st_mode)) {
489 struct dirent *entry, *result;
494 dev_t our_device = ff_pkt->statp.st_dev;
496 bool volhas_attrlist = ff_pkt->volhas_attrlist; /* Remember this if we recurse */
499 * If we are using Win32 (non-portable) backup API, don't check
500 * access as everything is more complicated, and
501 * in principle, we should be able to access everything.
503 if (!have_win32_api() || (ff_pkt->flags & FO_PORTABLE)) {
504 if (access(fname, R_OK) == -1 && geteuid() != 0) {
505 /* Could not access() directory */
506 ff_pkt->type = FT_NOACCESS;
507 ff_pkt->ff_errno = errno;
508 rtn_stat = handle_file(jcr, ff_pkt, top_level);
509 if (ff_pkt->linked) {
510 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
516 /* Build a canonical directory name with a trailing slash in link var */
518 link_len = len + 200;
519 link = (char *)bmalloc(link_len + 2);
520 bstrncpy(link, fname, link_len);
521 /* Strip all trailing slashes */
522 while (len >= 1 && IsPathSeparator(link[len - 1]))
524 link[len++] = '/'; /* add back one */
528 if (ff_pkt->incremental && !check_changes(jcr, ff_pkt)) {
529 /* Incremental option, directory entry not changed */
530 ff_pkt->type = FT_DIRNOCHG;
532 ff_pkt->type = FT_DIRBEGIN;
535 * We have set st_rdev to 1 if it is a reparse point, otherwise 0,
536 * if st_rdev is 2, it is a mount point
538 if (have_win32_api() && ff_pkt->statp.st_rdev == 1) {
539 ff_pkt->type = FT_REPARSE;
542 * Note, we return the directory to the calling program (handle_file)
543 * when we first see the directory (FT_DIRBEGIN.
544 * This allows the program to apply matches and make a
545 * choice whether or not to accept it. If it is accepted, we
546 * do not immediately save it, but do so only after everything
547 * in the directory is seen (i.e. the FT_DIREND).
549 rtn_stat = handle_file(jcr, ff_pkt, top_level);
550 if (rtn_stat < 1 || ff_pkt->type == FT_REPARSE) { /* ignore or error status */
554 /* Done with DIRBEGIN, next call will be DIREND */
555 if (ff_pkt->type == FT_DIRBEGIN) {
556 ff_pkt->type = FT_DIREND;
560 * Create a temporary ff packet for this directory
561 * entry, and defer handling the directory until
562 * we have recursed into it. This saves the
563 * directory after all files have been processed, and
564 * during the restore, the directory permissions will
565 * be reset after all the files have been restored.
567 Dmsg1(300, "Create temp ff packet for dir: %s\n", ff_pkt->fname);
568 FF_PKT *dir_ff_pkt = new_dir_ff_pkt(ff_pkt);
571 * Do not descend into subdirectories (recurse) if the
572 * user has turned it off for this directory.
574 * If we are crossing file systems, we are either not allowed
575 * to cross, or we may be restricted by a list of permitted
578 if (!top_level && ff_pkt->flags & FO_NO_RECURSION) {
579 ff_pkt->type = FT_NORECURSE;
581 } else if (!top_level && parent_device != ff_pkt->statp.st_dev) {
582 if(!(ff_pkt->flags & FO_MULTIFS)) {
583 ff_pkt->type = FT_NOFSCHG;
585 } else if (!accept_fstype(ff_pkt, NULL)) {
586 ff_pkt->type = FT_INVALIDFS;
589 ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
592 /* If not recursing, just backup dir and return */
594 rtn_stat = handle_file(jcr, ff_pkt, top_level);
595 if (ff_pkt->linked) {
596 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
599 free_dir_ff_pkt(dir_ff_pkt);
600 ff_pkt->link = ff_pkt->fname; /* reset "link" */
601 if (ff_pkt->flags & FO_KEEPATIME) {
602 utime(fname, &restore_times);
607 ff_pkt->link = ff_pkt->fname; /* reset "link" */
610 * Descend into or "recurse" into the directory to read
611 * all the files in it.
614 if ((directory = opendir(fname)) == NULL) {
615 ff_pkt->type = FT_NOOPEN;
616 ff_pkt->ff_errno = errno;
617 rtn_stat = handle_file(jcr, ff_pkt, top_level);
618 if (ff_pkt->linked) {
619 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
622 free_dir_ff_pkt(dir_ff_pkt);
627 * Process all files in this directory entry (recursing).
628 * This would possibly run faster if we chdir to the directory
629 * before traversing it.
632 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 100);
633 for ( ; !job_canceled(jcr); ) {
637 status = readdir_r(directory, entry, &result);
638 if (status != 0 || result == NULL) {
639 // Dmsg2(99, "readdir returned stat=%d result=0x%x\n",
640 // status, (long)result);
643 ASSERT(name_max+1 > (int)sizeof(struct dirent) + (int)NAMELEN(entry));
645 /* Skip `.', `..', and excluded file names. */
646 if (p[0] == '\0' || (p[0] == '.' && (p[1] == '\0' ||
647 (p[1] == '.' && p[2] == '\0')))) {
651 if ((int)NAMELEN(entry) + len >= link_len) {
652 link_len = len + NAMELEN(entry) + 1;
653 link = (char *)brealloc(link, link_len + 1);
656 for (i=0; i < (int)NAMELEN(entry); i++) {
660 if (!file_is_excluded(ff_pkt, link)) {
661 rtn_stat = find_one_file(jcr, ff_pkt, handle_file, link, our_device, false);
662 if (ff_pkt->linked) {
663 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
672 * Now that we have recursed through all the files in the
673 * directory, we "save" the directory so that after all
674 * the files are restored, this entry will serve to reset
675 * the directory modes and dates. Temp directory values
676 * were used without this record.
678 handle_file(jcr, dir_ff_pkt, top_level); /* handle directory entry */
679 if (ff_pkt->linked) {
680 ff_pkt->linked->FileIndex = dir_ff_pkt->FileIndex;
682 free_dir_ff_pkt(dir_ff_pkt);
684 if (ff_pkt->flags & FO_KEEPATIME) {
685 utime(fname, &restore_times);
687 ff_pkt->volhas_attrlist = volhas_attrlist; /* Restore value in case it changed. */
689 } /* end check for directory */
692 * If it is explicitly mentioned (i.e. top_level) and is
693 * a block device, we do a raw backup of it or if it is
694 * a fifo, we simply read it.
696 #ifdef HAVE_FREEBSD_OS
698 * On FreeBSD, all block devices are character devices, so
699 * to be able to read a raw disk, we need the check for
700 * a character device.
701 * crw-r----- 1 root operator - 116, 0x00040002 Jun 9 19:32 /dev/ad0s3
702 * crw-r----- 1 root operator - 116, 0x00040002 Jun 9 19:32 /dev/rad0s3
704 if (top_level && (S_ISBLK(ff_pkt->statp.st_mode) || S_ISCHR(ff_pkt->statp.st_mode))) {
706 if (top_level && S_ISBLK(ff_pkt->statp.st_mode)) {
708 ff_pkt->type = FT_RAW; /* raw partition */
709 } else if (top_level && S_ISFIFO(ff_pkt->statp.st_mode) &&
710 ff_pkt->flags & FO_READFIFO) {
711 ff_pkt->type = FT_FIFO;
713 /* The only remaining types are special (character, ...) files */
714 ff_pkt->type = FT_SPEC;
716 rtn_stat = handle_file(jcr, ff_pkt, top_level);
717 if (ff_pkt->linked) {
718 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
723 int term_find_one(FF_PKT *ff)
725 struct f_link *lp, *lc;
730 if (ff->linkhash == NULL) return 0;
732 for (i =0 ; i < LINK_HASHTABLE_SIZE; i ++) {
733 /* Free up list of hard linked files */
734 lp = ff->linkhash[i];
743 ff->linkhash[i] = NULL;