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;
534 /* We have set st_rdev to 1 if it is a reparse point, otherwise 0 */
535 if (have_win32_api() && ff_pkt->statp.st_rdev) {
536 ff_pkt->type = FT_REPARSE;
539 * Note, we return the directory to the calling program (handle_file)
540 * when we first see the directory (FT_DIRBEGIN.
541 * This allows the program to apply matches and make a
542 * choice whether or not to accept it. If it is accepted, we
543 * do not immediately save it, but do so only after everything
544 * in the directory is seen (i.e. the FT_DIREND).
546 rtn_stat = handle_file(jcr, ff_pkt, top_level);
547 if (rtn_stat < 1 || ff_pkt->type == FT_REPARSE) { /* ignore or error status */
551 /* Done with DIRBEGIN, next call will be DIREND */
552 if (ff_pkt->type == FT_DIRBEGIN) {
553 ff_pkt->type = FT_DIREND;
557 * Create a temporary ff packet for this directory
558 * entry, and defer handling the directory until
559 * we have recursed into it. This saves the
560 * directory after all files have been processed, and
561 * during the restore, the directory permissions will
562 * be reset after all the files have been restored.
564 Dmsg1(300, "Create temp ff packet for dir: %s\n", ff_pkt->fname);
565 FF_PKT *dir_ff_pkt = new_dir_ff_pkt(ff_pkt);
568 * Do not descend into subdirectories (recurse) if the
569 * user has turned it off for this directory.
571 * If we are crossing file systems, we are either not allowed
572 * to cross, or we may be restricted by a list of permitted
575 if (!top_level && ff_pkt->flags & FO_NO_RECURSION) {
576 ff_pkt->type = FT_NORECURSE;
578 } else if (!top_level && parent_device != ff_pkt->statp.st_dev) {
579 if(!(ff_pkt->flags & FO_MULTIFS)) {
580 ff_pkt->type = FT_NOFSCHG;
582 } else if (!accept_fstype(ff_pkt, NULL)) {
583 ff_pkt->type = FT_INVALIDFS;
586 ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
589 /* If not recursing, just backup dir and return */
591 rtn_stat = handle_file(jcr, ff_pkt, top_level);
592 if (ff_pkt->linked) {
593 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
596 free_dir_ff_pkt(dir_ff_pkt);
597 ff_pkt->link = ff_pkt->fname; /* reset "link" */
598 if (ff_pkt->flags & FO_KEEPATIME) {
599 utime(fname, &restore_times);
604 ff_pkt->link = ff_pkt->fname; /* reset "link" */
607 * Descend into or "recurse" into the directory to read
608 * all the files in it.
611 if ((directory = opendir(fname)) == NULL) {
612 ff_pkt->type = FT_NOOPEN;
613 ff_pkt->ff_errno = errno;
614 rtn_stat = handle_file(jcr, ff_pkt, top_level);
615 if (ff_pkt->linked) {
616 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
619 free_dir_ff_pkt(dir_ff_pkt);
624 * Process all files in this directory entry (recursing).
625 * This would possibly run faster if we chdir to the directory
626 * before traversing it.
629 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 100);
630 for ( ; !job_canceled(jcr); ) {
634 status = readdir_r(directory, entry, &result);
635 if (status != 0 || result == NULL) {
636 // Dmsg2(99, "readdir returned stat=%d result=0x%x\n",
637 // status, (long)result);
640 ASSERT(name_max+1 > (int)sizeof(struct dirent) + (int)NAMELEN(entry));
642 /* Skip `.', `..', and excluded file names. */
643 if (p[0] == '\0' || (p[0] == '.' && (p[1] == '\0' ||
644 (p[1] == '.' && p[2] == '\0')))) {
648 if ((int)NAMELEN(entry) + len >= link_len) {
649 link_len = len + NAMELEN(entry) + 1;
650 link = (char *)brealloc(link, link_len + 1);
653 for (i=0; i < (int)NAMELEN(entry); i++) {
657 if (!file_is_excluded(ff_pkt, link)) {
658 rtn_stat = find_one_file(jcr, ff_pkt, handle_file, link, our_device, false);
659 if (ff_pkt->linked) {
660 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
669 * Now that we have recursed through all the files in the
670 * directory, we "save" the directory so that after all
671 * the files are restored, this entry will serve to reset
672 * the directory modes and dates. Temp directory values
673 * were used without this record.
675 handle_file(jcr, dir_ff_pkt, top_level); /* handle directory entry */
676 if (ff_pkt->linked) {
677 ff_pkt->linked->FileIndex = dir_ff_pkt->FileIndex;
679 free_dir_ff_pkt(dir_ff_pkt);
681 if (ff_pkt->flags & FO_KEEPATIME) {
682 utime(fname, &restore_times);
684 ff_pkt->volhas_attrlist = volhas_attrlist; /* Restore value in case it changed. */
686 } /* end check for directory */
689 * If it is explicitly mentioned (i.e. top_level) and is
690 * a block device, we do a raw backup of it or if it is
691 * a fifo, we simply read it.
693 #ifdef HAVE_FREEBSD_OS
695 * On FreeBSD, all block devices are character devices, so
696 * to be able to read a raw disk, we need the check for
697 * a character device.
698 * crw-r----- 1 root operator - 116, 0x00040002 Jun 9 19:32 /dev/ad0s3
699 * crw-r----- 1 root operator - 116, 0x00040002 Jun 9 19:32 /dev/rad0s3
701 if (top_level && (S_ISBLK(ff_pkt->statp.st_mode) || S_ISCHR(ff_pkt->statp.st_mode))) {
703 if (top_level && S_ISBLK(ff_pkt->statp.st_mode)) {
705 ff_pkt->type = FT_RAW; /* raw partition */
706 } else if (top_level && S_ISFIFO(ff_pkt->statp.st_mode) &&
707 ff_pkt->flags & FO_READFIFO) {
708 ff_pkt->type = FT_FIFO;
710 /* The only remaining types are special (character, ...) files */
711 ff_pkt->type = FT_SPEC;
713 rtn_stat = handle_file(jcr, ff_pkt, top_level);
714 if (ff_pkt->linked) {
715 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
720 int term_find_one(FF_PKT *ff)
722 struct f_link *lp, *lc;
727 if (ff->linkhash == NULL) return 0;
729 for (i =0 ; i < LINK_HASHTABLE_SIZE; i ++) {
730 /* Free up list of hard linked files */
731 lp = ff->linkhash[i];
740 ff->linkhash[i] = NULL;