2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 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 * Find a single file.
262 * handle_file is the callback for handling the file.
264 * parent_device is the device we are currently on
265 * top_level is 1 when not recursing or 0 when
266 * descending into a directory.
269 find_one_file(JCR *jcr, FF_PKT *ff_pkt,
270 int handle_file(FF_PKT *ff, void *hpkt, bool top_level),
271 void *pkt, char *fname, dev_t parent_device, bool top_level)
273 struct utimbuf restore_times;
277 ff_pkt->fname = ff_pkt->link = fname;
279 if (lstat(fname, &ff_pkt->statp) != 0) {
280 /* Cannot stat file */
281 ff_pkt->type = FT_NOSTAT;
282 ff_pkt->ff_errno = errno;
283 return handle_file(ff_pkt, pkt, top_level);
286 Dmsg1(300, "File ----: %s\n", fname);
288 /* Save current times of this directory in case we need to
289 * reset them because the user doesn't want them changed.
291 restore_times.actime = ff_pkt->statp.st_atime;
292 restore_times.modtime = ff_pkt->statp.st_mtime;
295 * We check for allowed fstypes and drivetypes at top_level and fstype change (below).
298 if (!accept_fstype(ff_pkt, NULL)) {
299 ff_pkt->type = FT_INVALIDFS;
300 if (ff_pkt->flags & FO_KEEPATIME) {
301 utime(fname, &restore_times);
306 if (!fstype(ff_pkt->fname, fs, sizeof(fs))) {
307 bstrncpy(fs, "unknown", sizeof(fs));
310 Jmsg(jcr, M_INFO, 0, _("Top level directory \"%s\" has unlisted fstype \"%s\"\n"), fname, fs);
311 return 1; /* Just ignore this error - or the whole backup is cancelled */
313 if (!accept_drivetype(ff_pkt, NULL)) {
314 ff_pkt->type = FT_INVALIDDT;
315 if (ff_pkt->flags & FO_KEEPATIME) {
316 utime(fname, &restore_times);
321 if (!drivetype(ff_pkt->fname, dt, sizeof(dt))) {
322 bstrncpy(dt, "unknown", sizeof(dt));
325 Jmsg(jcr, M_INFO, 0, _("Top level directory \"%s\" has an unlisted drive type \"%s\"\n"), fname, dt);
326 return 1; /* Just ignore this error - or the whole backup is cancelled */
328 ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
332 * If this is an Incremental backup, see if file was modified
333 * since our last "save_time", presumably the last Full save
336 if (ff_pkt->incremental && !S_ISDIR(ff_pkt->statp.st_mode)) {
337 Dmsg1(300, "Non-directory incremental: %s\n", ff_pkt->fname);
338 /* Not a directory */
339 if (ff_pkt->statp.st_mtime < ff_pkt->save_time
340 && ((ff_pkt->flags & FO_MTIMEONLY) ||
341 ff_pkt->statp.st_ctime < ff_pkt->save_time)) {
342 /* Incremental option, file not changed */
343 ff_pkt->type = FT_NOCHG;
344 return handle_file(ff_pkt, pkt, top_level);
348 #ifdef HAVE_DARWIN_OS
349 if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->volhas_attrlist
350 && S_ISREG(ff_pkt->statp.st_mode)) {
351 /* TODO: initialise attrList once elsewhere? */
352 struct attrlist attrList;
353 memset(&attrList, 0, sizeof(attrList));
354 attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
355 attrList.commonattr = ATTR_CMN_FNDRINFO;
356 attrList.fileattr = ATTR_FILE_RSRCLENGTH;
357 if (getattrlist(fname, &attrList, &ff_pkt->hfsinfo,
358 sizeof(ff_pkt->hfsinfo), FSOPT_NOFOLLOW) != 0) {
359 ff_pkt->type = FT_NOSTAT;
360 ff_pkt->ff_errno = errno;
361 return handle_file(ff_pkt, pkt, top_level);
368 * Handle hard linked files
370 * Maintain a list of hard linked files already backed up. This
371 * allows us to ensure that the data of each file gets backed
374 if (!(ff_pkt->flags & FO_NO_HARDLINK)
375 && ff_pkt->statp.st_nlink > 1
376 && (S_ISREG(ff_pkt->statp.st_mode)
377 || S_ISCHR(ff_pkt->statp.st_mode)
378 || S_ISBLK(ff_pkt->statp.st_mode)
379 || S_ISFIFO(ff_pkt->statp.st_mode)
380 || S_ISSOCK(ff_pkt->statp.st_mode))) {
383 if (ff_pkt->linkhash == NULL) {
384 ff_pkt->linkhash = (link_t **)bmalloc(LINK_HASHTABLE_SIZE * sizeof(link_t *));
385 memset(ff_pkt->linkhash, 0, LINK_HASHTABLE_SIZE * sizeof(link_t *));
387 const int linkhash = LINKHASH(ff_pkt->statp);
389 /* Search link list of hard linked files */
390 for (lp = ff_pkt->linkhash[linkhash]; lp; lp = lp->next)
391 if (lp->ino == (ino_t)ff_pkt->statp.st_ino &&
392 lp->dev == (dev_t)ff_pkt->statp.st_dev) {
393 /* If we have already backed up the hard linked file don't do it again */
394 if (strcmp(lp->name, fname) == 0) {
395 return 1; /* ignore */
397 ff_pkt->link = lp->name;
398 ff_pkt->type = FT_LNKSAVED; /* Handle link, file already saved */
399 ff_pkt->LinkFI = lp->FileIndex;
400 return handle_file(ff_pkt, pkt, top_level);
403 /* File not previously dumped. Chain it into our list. */
404 len = strlen(fname) + 1;
405 lp = (struct f_link *)bmalloc(sizeof(struct f_link) + len);
406 lp->ino = ff_pkt->statp.st_ino;
407 lp->dev = ff_pkt->statp.st_dev;
408 bstrncpy(lp->name, fname, len);
409 lp->next = ff_pkt->linkhash[linkhash];
410 ff_pkt->linkhash[linkhash] = lp;
411 ff_pkt->linked = lp; /* mark saved link */
413 ff_pkt->linked = NULL;
416 /* This is not a link to a previously dumped file, so dump it. */
417 if (S_ISREG(ff_pkt->statp.st_mode)) {
420 sizeleft = ff_pkt->statp.st_size;
422 /* Don't bother opening empty, world readable files. Also do not open
423 files when archive is meant for /dev/null. */
424 if (ff_pkt->null_output_device || (sizeleft == 0
425 && MODE_RALL == (MODE_RALL & ff_pkt->statp.st_mode))) {
426 ff_pkt->type = FT_REGE;
428 ff_pkt->type = FT_REG;
430 rtn_stat = handle_file(ff_pkt, pkt, top_level);
431 if (ff_pkt->linked) {
432 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
434 if (ff_pkt->flags & FO_KEEPATIME) {
435 utime(fname, &restore_times);
440 } else if (S_ISLNK(ff_pkt->statp.st_mode)) { /* soft link */
442 char *buffer = (char *)alloca(path_max + name_max + 102);
444 size = readlink(fname, buffer, path_max + name_max + 101);
446 /* Could not follow link */
447 ff_pkt->type = FT_NOFOLLOW;
448 ff_pkt->ff_errno = errno;
449 rtn_stat = handle_file(ff_pkt, pkt, top_level);
450 if (ff_pkt->linked) {
451 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
456 ff_pkt->link = buffer; /* point to link */
457 ff_pkt->type = FT_LNK; /* got a real link */
458 rtn_stat = handle_file(ff_pkt, pkt, top_level);
459 if (ff_pkt->linked) {
460 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
464 } else if (S_ISDIR(ff_pkt->statp.st_mode)) {
466 struct dirent *entry, *result;
471 dev_t our_device = ff_pkt->statp.st_dev;
473 bool volhas_attrlist = ff_pkt->volhas_attrlist; /* Remember this if we recurse */
476 * If we are using Win32 (non-portable) backup API, don't check
477 * access as everything is more complicated, and
478 * in principle, we should be able to access everything.
480 if (!have_win32_api() || (ff_pkt->flags & FO_PORTABLE)) {
481 if (access(fname, R_OK) == -1 && geteuid() != 0) {
482 /* Could not access() directory */
483 ff_pkt->type = FT_NOACCESS;
484 ff_pkt->ff_errno = errno;
485 rtn_stat = handle_file(ff_pkt, pkt, top_level);
486 if (ff_pkt->linked) {
487 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
493 /* Build a canonical directory name with a trailing slash in link var */
495 link_len = len + 200;
496 link = (char *)bmalloc(link_len + 2);
497 bstrncpy(link, fname, link_len);
498 /* Strip all trailing slashes */
499 while (len >= 1 && IsPathSeparator(link[len - 1]))
501 link[len++] = '/'; /* add back one */
505 if (ff_pkt->incremental &&
506 (ff_pkt->statp.st_mtime < ff_pkt->save_time &&
507 ((ff_pkt->flags & FO_MTIMEONLY) ||
508 ff_pkt->statp.st_ctime < ff_pkt->save_time))) {
509 /* Incremental option, directory entry not changed */
510 ff_pkt->type = FT_DIRNOCHG;
512 ff_pkt->type = FT_DIRBEGIN;
515 * We have set st_rdev to 1 if it is a reparse point, otherwise 0,
516 * if st_rdev is 2, it is a mount point
518 if (have_win32_api() && ff_pkt->statp.st_rdev == 1) {
519 ff_pkt->type = FT_REPARSE;
522 * Note, we return the directory to the calling program (handle_file)
523 * when we first see the directory (FT_DIRBEGIN.
524 * This allows the program to apply matches and make a
525 * choice whether or not to accept it. If it is accepted, we
526 * do not immediately save it, but do so only after everything
527 * in the directory is seen (i.e. the FT_DIREND).
529 rtn_stat = handle_file(ff_pkt, pkt, top_level);
530 if (rtn_stat < 1 || ff_pkt->type == FT_REPARSE) { /* ignore or error status */
534 /* Done with DIRBEGIN, next call will be DIREND */
535 if (ff_pkt->type == FT_DIRBEGIN) {
536 ff_pkt->type = FT_DIREND;
540 * Create a temporary ff packet for this directory
541 * entry, and defer handling the directory until
542 * we have recursed into it. This saves the
543 * directory after all files have been processed, and
544 * during the restore, the directory permissions will
545 * be reset after all the files have been restored.
547 Dmsg1(300, "Create temp ff packet for dir: %s\n", ff_pkt->fname);
548 FF_PKT *dir_ff_pkt = new_dir_ff_pkt(ff_pkt);
551 * Do not descend into subdirectories (recurse) if the
552 * user has turned it off for this directory.
554 * If we are crossing file systems, we are either not allowed
555 * to cross, or we may be restricted by a list of permitted
558 if (!top_level && ff_pkt->flags & FO_NO_RECURSION) {
559 ff_pkt->type = FT_NORECURSE;
561 } else if (!top_level && parent_device != ff_pkt->statp.st_dev) {
562 if(!(ff_pkt->flags & FO_MULTIFS)) {
563 ff_pkt->type = FT_NOFSCHG;
565 } else if (!accept_fstype(ff_pkt, NULL)) {
566 ff_pkt->type = FT_INVALIDFS;
569 ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
572 /* If not recursing, just backup dir and return */
574 rtn_stat = handle_file(ff_pkt, pkt, top_level);
575 if (ff_pkt->linked) {
576 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
579 free_dir_ff_pkt(dir_ff_pkt);
580 ff_pkt->link = ff_pkt->fname; /* reset "link" */
581 if (ff_pkt->flags & FO_KEEPATIME) {
582 utime(fname, &restore_times);
587 ff_pkt->link = ff_pkt->fname; /* reset "link" */
590 * Descend into or "recurse" into the directory to read
591 * all the files in it.
594 if ((directory = opendir(fname)) == NULL) {
595 ff_pkt->type = FT_NOOPEN;
596 ff_pkt->ff_errno = errno;
597 rtn_stat = handle_file(ff_pkt, pkt, top_level);
598 if (ff_pkt->linked) {
599 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
602 free_dir_ff_pkt(dir_ff_pkt);
607 * Process all files in this directory entry (recursing).
608 * This would possibly run faster if we chdir to the directory
609 * before traversing it.
612 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 100);
613 for ( ; !job_canceled(jcr); ) {
617 status = readdir_r(directory, entry, &result);
618 if (status != 0 || result == NULL) {
619 // Dmsg2(99, "readdir returned stat=%d result=0x%x\n",
620 // status, (long)result);
623 ASSERT(name_max+1 > (int)sizeof(struct dirent) + (int)NAMELEN(entry));
625 /* Skip `.', `..', and excluded file names. */
626 if (p[0] == '\0' || (p[0] == '.' && (p[1] == '\0' ||
627 (p[1] == '.' && p[2] == '\0')))) {
631 if ((int)NAMELEN(entry) + len >= link_len) {
632 link_len = len + NAMELEN(entry) + 1;
633 link = (char *)brealloc(link, link_len + 1);
636 for (i=0; i < (int)NAMELEN(entry); i++) {
640 if (!file_is_excluded(ff_pkt, link)) {
641 rtn_stat = find_one_file(jcr, ff_pkt, handle_file, pkt, link, our_device, false);
642 if (ff_pkt->linked) {
643 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
652 * Now that we have recursed through all the files in the
653 * directory, we "save" the directory so that after all
654 * the files are restored, this entry will serve to reset
655 * the directory modes and dates. Temp directory values
656 * were used without this record.
658 handle_file(dir_ff_pkt, pkt, top_level); /* handle directory entry */
659 if (ff_pkt->linked) {
660 ff_pkt->linked->FileIndex = dir_ff_pkt->FileIndex;
662 free_dir_ff_pkt(dir_ff_pkt);
664 if (ff_pkt->flags & FO_KEEPATIME) {
665 utime(fname, &restore_times);
667 ff_pkt->volhas_attrlist = volhas_attrlist; /* Restore value in case it changed. */
669 } /* end check for directory */
672 * If it is explicitly mentioned (i.e. top_level) and is
673 * a block device, we do a raw backup of it or if it is
674 * a fifo, we simply read it.
676 #ifdef HAVE_FREEBSD_OS
678 * On FreeBSD, all block devices are character devices, so
679 * to be able to read a raw disk, we need the check for
680 * a character device.
681 * crw-r----- 1 root operator - 116, 0x00040002 Jun 9 19:32 /dev/ad0s3
682 * crw-r----- 1 root operator - 116, 0x00040002 Jun 9 19:32 /dev/rad0s3
684 if (top_level && (S_ISBLK(ff_pkt->statp.st_mode) || S_ISCHR(ff_pkt->statp.st_mode))) {
686 if (top_level && S_ISBLK(ff_pkt->statp.st_mode)) {
688 ff_pkt->type = FT_RAW; /* raw partition */
689 } else if (top_level && S_ISFIFO(ff_pkt->statp.st_mode) &&
690 ff_pkt->flags & FO_READFIFO) {
691 ff_pkt->type = FT_FIFO;
693 /* The only remaining types are special (character, ...) files */
694 ff_pkt->type = FT_SPEC;
696 rtn_stat = handle_file(ff_pkt, pkt, top_level);
697 if (ff_pkt->linked) {
698 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
703 int term_find_one(FF_PKT *ff)
705 struct f_link *lp, *lc;
710 if (ff->linkhash == NULL) return 0;
712 for (i =0 ; i < LINK_HASHTABLE_SIZE; i ++) {
713 /* Free up list of hard linked files */
714 lp = ff->linkhash[i];
723 ff->linkhash[i] = NULL;