3 This file is based on GNU TAR source code. Except for a few key
4 ideas, it has been entirely rewritten for Bacula.
8 Thanks to the TAR programmers.
14 Bacula® - The Network Backup Solution
16 Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
18 The main author of Bacula is Kern Sibbald, with contributions from
19 many others, a complete list can be found in the file AUTHORS.
20 This program is Free Software; you can redistribute it and/or
21 modify it under the terms of version two of the GNU General Public
22 License as published by the Free Software Foundation plus additions
23 that are listed in the file LICENSE.
25 This program is distributed in the hope that it will be useful, but
26 WITHOUT ANY WARRANTY; without even the implied warranty of
27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 General Public License for more details.
30 You should have received a copy of the GNU General Public License
31 along with this program; if not, write to the Free Software
32 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
35 Bacula® is a registered trademark of John Walker.
36 The licensor of Bacula is the Free Software Foundation Europe
37 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
38 Switzerland, email:ftf@fsfeurope.org.
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;
87 static void free_dir_ff_pkt(FF_PKT *dir_ff_pkt)
89 free(dir_ff_pkt->fname);
90 free(dir_ff_pkt->link);
91 free_pool_memory(dir_ff_pkt->sys_fname);
96 * Check to see if we allow the file system type of a file or directory.
97 * If we do not have a list of file system types, we accept anything.
99 static int accept_fstype(FF_PKT *ff, void *dummy) {
104 if (ff->fstypes.size()) {
106 if (!fstype(ff->fname, fs, sizeof(fs))) {
107 Dmsg1(50, "Cannot determine file system type for \"%s\"\n", ff->fname);
109 for (i = 0; i < ff->fstypes.size(); ++i) {
110 if (strcmp(fs, (char *)ff->fstypes.get(i)) == 0) {
111 Dmsg2(100, "Accepting fstype %s for \"%s\"\n", fs, ff->fname);
115 Dmsg3(200, "fstype %s for \"%s\" does not match %s\n", fs,
116 ff->fname, ff->fstypes.get(i));
124 * Check to see if we allow the drive type of a file or directory.
125 * If we do not have a list of drive types, we accept anything.
127 static int accept_drivetype(FF_PKT *ff, void *dummy) {
132 if (ff->drivetypes.size()) {
134 if (!drivetype(ff->fname, dt, sizeof(dt))) {
135 Dmsg1(50, "Cannot determine drive type for \"%s\"\n", ff->fname);
137 for (i = 0; i < ff->drivetypes.size(); ++i) {
138 if (strcmp(dt, (char *)ff->drivetypes.get(i)) == 0) {
139 Dmsg2(100, "Accepting drive type %s for \"%s\"\n", dt, ff->fname);
143 Dmsg3(200, "drive type %s for \"%s\" does not match %s\n", dt,
144 ff->fname, ff->drivetypes.get(i));
152 * This function determines whether we can use getattrlist()
153 * It's odd, but we have to use the function to determine that...
154 * Also, the man pages talk about things as if they were implemented.
156 * On Mac OS X, this succesfully differentiates between HFS+ and UFS
157 * volumes, which makes me trust it is OK for others, too.
159 static bool volume_has_attrlist(const char *fname)
161 #ifdef HAVE_DARWIN_OS
163 struct volinfo_struct {
164 unsigned long length; /* Mandatory field */
165 vol_capabilities_attr_t info; /* Volume capabilities */
167 struct attrlist attrList;
169 memset(&attrList, 0, sizeof(attrList));
170 attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
171 attrList.volattr = ATTR_VOL_INFO | ATTR_VOL_CAPABILITIES;
172 if (statfs(fname, &st) == 0) {
173 /* We need to check on the mount point */
174 if (getattrlist(st.f_mntonname, &attrList, &vol, sizeof(vol), FSOPT_NOFOLLOW) == 0
175 && (vol.info.capabilities[VOL_CAPABILITIES_INTERFACES] & VOL_CAP_INT_ATTRLIST)
176 && (vol.info.valid[VOL_CAPABILITIES_INTERFACES] & VOL_CAP_INT_ATTRLIST)) {
184 /* check if a file have changed during backup and display an error */
185 bool has_file_changed(JCR *jcr, FF_PKT *ff_pkt)
188 Dmsg1(500, "has_file_changed fname=%s\n",ff_pkt->fname);
190 if (ff_pkt->type != FT_REG) { /* not a regular file */
194 if (lstat(ff_pkt->fname, &statp) != 0) {
196 Jmsg(jcr, M_WARNING, 0,
197 _("Cannot stat file %s: ERR=%s\n"),ff_pkt->fname,be.strerror());
201 if (statp.st_mtime != ff_pkt->statp.st_mtime) {
202 /* TODO: add time of changes */
203 Jmsg(jcr, M_ERROR, 0, _("%s mtime changed during backup.\n"), ff_pkt->fname);
207 if (statp.st_ctime != ff_pkt->statp.st_ctime) {
208 /* TODO: add time of changes */
209 Jmsg(jcr, M_ERROR, 0, _("%s ctime changed during backup.\n"), ff_pkt->fname);
213 if (statp.st_size != ff_pkt->statp.st_size) {
214 /* TODO: add size change */
215 Jmsg(jcr, M_ERROR, 0, _("%s size changed during backup.\n"),ff_pkt->fname);
219 if ((statp.st_blksize != ff_pkt->statp.st_blksize) ||
220 (statp.st_blocks != ff_pkt->statp.st_blocks)) {
221 /* TODO: add size change */
222 Jmsg(jcr, M_ERROR, 0, _("%s size changed during backup.\n"),ff_pkt->fname);
230 * Find a single file.
231 * handle_file is the callback for handling the file.
233 * parent_device is the device we are currently on
234 * top_level is 1 when not recursing or 0 when
235 * descending into a directory.
238 find_one_file(JCR *jcr, FF_PKT *ff_pkt,
239 int handle_file(FF_PKT *ff, void *hpkt, bool top_level),
240 void *pkt, char *fname, dev_t parent_device, bool top_level)
242 struct utimbuf restore_times;
246 ff_pkt->fname = ff_pkt->link = fname;
248 if (lstat(fname, &ff_pkt->statp) != 0) {
249 /* Cannot stat file */
250 ff_pkt->type = FT_NOSTAT;
251 ff_pkt->ff_errno = errno;
252 return handle_file(ff_pkt, pkt, top_level);
255 Dmsg1(300, "File ----: %s\n", fname);
257 /* Save current times of this directory in case we need to
258 * reset them because the user doesn't want them changed.
260 restore_times.actime = ff_pkt->statp.st_atime;
261 restore_times.modtime = ff_pkt->statp.st_mtime;
264 * We check for allowed fstypes and drivetypes at top_level and fstype change (below).
267 if (!accept_fstype(ff_pkt, NULL)) {
268 ff_pkt->type = FT_INVALIDFS;
269 if (ff_pkt->flags & FO_KEEPATIME) {
270 utime(fname, &restore_times);
275 if (!fstype(ff_pkt->fname, fs, sizeof(fs))) {
276 bstrncpy(fs, "unknown", sizeof(fs));
279 Jmsg(jcr, M_INFO, 0, _("Top level directory \"%s\" has unlisted fstype \"%s\"\n"), fname, fs);
280 return 1; /* Just ignore this error - or the whole backup is cancelled */
282 if (!accept_drivetype(ff_pkt, NULL)) {
283 ff_pkt->type = FT_INVALIDDT;
284 if (ff_pkt->flags & FO_KEEPATIME) {
285 utime(fname, &restore_times);
290 if (!drivetype(ff_pkt->fname, dt, sizeof(dt))) {
291 bstrncpy(dt, "unknown", sizeof(dt));
294 Jmsg(jcr, M_INFO, 0, _("Top level directory \"%s\" has an unlisted drive type \"%s\"\n"), fname, dt);
295 return 1; /* Just ignore this error - or the whole backup is cancelled */
297 ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
301 * If this is an Incremental backup, see if file was modified
302 * since our last "save_time", presumably the last Full save
305 if (ff_pkt->incremental && !S_ISDIR(ff_pkt->statp.st_mode)) {
306 Dmsg1(300, "Non-directory incremental: %s\n", ff_pkt->fname);
307 /* Not a directory */
308 if (ff_pkt->statp.st_mtime < ff_pkt->save_time
309 && ((ff_pkt->flags & FO_MTIMEONLY) ||
310 ff_pkt->statp.st_ctime < ff_pkt->save_time)) {
311 /* Incremental option, file not changed */
312 ff_pkt->type = FT_NOCHG;
313 return handle_file(ff_pkt, pkt, top_level);
317 #ifdef HAVE_DARWIN_OS
318 if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->volhas_attrlist
319 && S_ISREG(ff_pkt->statp.st_mode)) {
320 /* TODO: initialise attrList once elsewhere? */
321 struct attrlist attrList;
322 memset(&attrList, 0, sizeof(attrList));
323 attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
324 attrList.commonattr = ATTR_CMN_FNDRINFO;
325 attrList.fileattr = ATTR_FILE_RSRCLENGTH;
326 if (getattrlist(fname, &attrList, &ff_pkt->hfsinfo,
327 sizeof(ff_pkt->hfsinfo), FSOPT_NOFOLLOW) != 0) {
328 ff_pkt->type = FT_NOSTAT;
329 ff_pkt->ff_errno = errno;
330 return handle_file(ff_pkt, pkt, top_level);
335 /* ***FIXME*** implement this */
337 /* See if we are trying to dump the archive. */
338 if (ar_dev && ff_pkt->statp.st_dev == ar_dev && ff_pkt->statp.st_ino == ar_ino) {
339 ff_pkt->type = FT_ISARCH;
340 return handle_file(ff_pkt, pkt, top_level);
345 * Handle hard linked files
347 * Maintain a list of hard linked files already backed up. This
348 * allows us to ensure that the data of each file gets backed
351 if (!(ff_pkt->flags & FO_NO_HARDLINK)
352 && ff_pkt->statp.st_nlink > 1
353 && (S_ISREG(ff_pkt->statp.st_mode)
354 || S_ISCHR(ff_pkt->statp.st_mode)
355 || S_ISBLK(ff_pkt->statp.st_mode)
356 || S_ISFIFO(ff_pkt->statp.st_mode)
357 || S_ISSOCK(ff_pkt->statp.st_mode))) {
360 if (ff_pkt->linkhash == NULL) {
361 ff_pkt->linkhash = (link_t **)bmalloc(LINK_HASHTABLE_SIZE * sizeof(link_t *));
362 memset(ff_pkt->linkhash, 0, LINK_HASHTABLE_SIZE * sizeof(link_t *));
364 const int linkhash = LINKHASH(ff_pkt->statp);
366 /* Search link list of hard linked files */
367 for (lp = ff_pkt->linkhash[linkhash]; lp; lp = lp->next)
368 if (lp->ino == (ino_t)ff_pkt->statp.st_ino &&
369 lp->dev == (dev_t)ff_pkt->statp.st_dev) {
370 /* If we have already backed up the hard linked file don't do it again */
371 if (strcmp(lp->name, fname) == 0) {
372 return 1; /* ignore */
374 ff_pkt->link = lp->name;
375 ff_pkt->type = FT_LNKSAVED; /* Handle link, file already saved */
376 ff_pkt->LinkFI = lp->FileIndex;
377 return handle_file(ff_pkt, pkt, top_level);
380 /* File not previously dumped. Chain it into our list. */
381 len = strlen(fname) + 1;
382 lp = (struct f_link *)bmalloc(sizeof(struct f_link) + len);
383 lp->ino = ff_pkt->statp.st_ino;
384 lp->dev = ff_pkt->statp.st_dev;
385 bstrncpy(lp->name, fname, len);
386 lp->next = ff_pkt->linkhash[linkhash];
387 ff_pkt->linkhash[linkhash] = lp;
388 ff_pkt->linked = lp; /* mark saved link */
390 ff_pkt->linked = NULL;
393 /* This is not a link to a previously dumped file, so dump it. */
394 if (S_ISREG(ff_pkt->statp.st_mode)) {
397 sizeleft = ff_pkt->statp.st_size;
399 /* Don't bother opening empty, world readable files. Also do not open
400 files when archive is meant for /dev/null. */
401 if (ff_pkt->null_output_device || (sizeleft == 0
402 && MODE_RALL == (MODE_RALL & ff_pkt->statp.st_mode))) {
403 ff_pkt->type = FT_REGE;
405 ff_pkt->type = FT_REG;
407 rtn_stat = handle_file(ff_pkt, pkt, top_level);
408 if (ff_pkt->linked) {
409 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
411 if (ff_pkt->flags & FO_KEEPATIME) {
412 utime(fname, &restore_times);
417 } else if (S_ISLNK(ff_pkt->statp.st_mode)) { /* soft link */
419 char *buffer = (char *)alloca(path_max + name_max + 102);
421 size = readlink(fname, buffer, path_max + name_max + 101);
423 /* Could not follow link */
424 ff_pkt->type = FT_NOFOLLOW;
425 ff_pkt->ff_errno = errno;
426 rtn_stat = handle_file(ff_pkt, pkt, top_level);
427 if (ff_pkt->linked) {
428 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
433 ff_pkt->link = buffer; /* point to link */
434 ff_pkt->type = FT_LNK; /* got a real link */
435 rtn_stat = handle_file(ff_pkt, pkt, top_level);
436 if (ff_pkt->linked) {
437 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
441 } else if (S_ISDIR(ff_pkt->statp.st_mode)) {
443 struct dirent *entry, *result;
448 dev_t our_device = ff_pkt->statp.st_dev;
450 bool volhas_attrlist = ff_pkt->volhas_attrlist; /* Remember this if we recurse */
453 * If we are using Win32 (non-portable) backup API, don't check
454 * access as everything is more complicated, and
455 * in principle, we should be able to access everything.
457 if (!have_win32_api() || (ff_pkt->flags & FO_PORTABLE)) {
458 if (access(fname, R_OK) == -1 && geteuid() != 0) {
459 /* Could not access() directory */
460 ff_pkt->type = FT_NOACCESS;
461 ff_pkt->ff_errno = errno;
462 rtn_stat = handle_file(ff_pkt, pkt, top_level);
463 if (ff_pkt->linked) {
464 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
470 /* Build a canonical directory name with a trailing slash in link var */
472 link_len = len + 200;
473 link = (char *)bmalloc(link_len + 2);
474 bstrncpy(link, fname, link_len);
475 /* Strip all trailing slashes */
476 while (len >= 1 && IsPathSeparator(link[len - 1]))
478 link[len++] = '/'; /* add back one */
482 if (ff_pkt->incremental &&
483 (ff_pkt->statp.st_mtime < ff_pkt->save_time &&
484 ((ff_pkt->flags & FO_MTIMEONLY) ||
485 ff_pkt->statp.st_ctime < ff_pkt->save_time))) {
486 /* Incremental option, directory entry not changed */
487 ff_pkt->type = FT_DIRNOCHG;
489 ff_pkt->type = FT_DIRBEGIN;
492 * Note, we return the directory to the calling program (handle_file)
493 * when we first see the directory (FT_DIRBEGIN.
494 * This allows the program to apply matches and make a
495 * choice whether or not to accept it. If it is accepted, we
496 * do not immediately save it, but do so only after everything
497 * in the directory is seen (i.e. the FT_DIREND).
499 rtn_stat = handle_file(ff_pkt, pkt, top_level);
500 if (rtn_stat < 1) { /* ignore or error status */
504 /* Done with DIRBEGIN, next call will be DIREND */
505 if (ff_pkt->type == FT_DIRBEGIN) {
506 ff_pkt->type = FT_DIREND;
510 * Create a temporary ff packet for this directory
511 * entry, and defer handling the directory until
512 * we have recursed into it. This saves the
513 * directory after all files have been processed, and
514 * during the restore, the directory permissions will
515 * be reset after all the files have been restored.
517 Dmsg1(300, "Create temp ff packet for dir: %s\n", ff_pkt->fname);
518 FF_PKT *dir_ff_pkt = (FF_PKT *)bmalloc(sizeof(FF_PKT));
519 memcpy(dir_ff_pkt, ff_pkt, sizeof(FF_PKT));
520 dir_ff_pkt->fname = bstrdup(ff_pkt->fname);
521 dir_ff_pkt->link = bstrdup(ff_pkt->link);
522 dir_ff_pkt->sys_fname = get_pool_memory(PM_FNAME);
523 dir_ff_pkt->included_files_list = NULL;
524 dir_ff_pkt->excluded_files_list = NULL;
525 dir_ff_pkt->excluded_paths_list = NULL;
526 dir_ff_pkt->linkhash = NULL;
529 * Do not descend into subdirectories (recurse) if the
530 * user has turned it off for this directory.
532 * If we are crossing file systems, we are either not allowed
533 * to cross, or we may be restricted by a list of permitted
536 if (!top_level && ff_pkt->flags & FO_NO_RECURSION) {
537 ff_pkt->type = FT_NORECURSE;
539 } else if (!top_level && parent_device != ff_pkt->statp.st_dev) {
540 if(!(ff_pkt->flags & FO_MULTIFS)) {
541 ff_pkt->type = FT_NOFSCHG;
543 } else if (!accept_fstype(ff_pkt, NULL)) {
544 ff_pkt->type = FT_INVALIDFS;
547 ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
550 /* If not recursing, just backup dir and return */
552 rtn_stat = handle_file(ff_pkt, pkt, top_level);
553 if (ff_pkt->linked) {
554 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
557 free_dir_ff_pkt(dir_ff_pkt);
558 ff_pkt->link = ff_pkt->fname; /* reset "link" */
559 if (ff_pkt->flags & FO_KEEPATIME) {
560 utime(fname, &restore_times);
565 ff_pkt->link = ff_pkt->fname; /* reset "link" */
568 * Descend into or "recurse" into the directory to read
569 * all the files in it.
572 if ((directory = opendir(fname)) == NULL) {
573 ff_pkt->type = FT_NOOPEN;
574 ff_pkt->ff_errno = errno;
575 rtn_stat = handle_file(ff_pkt, pkt, top_level);
576 if (ff_pkt->linked) {
577 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
580 free_dir_ff_pkt(dir_ff_pkt);
585 * Process all files in this directory entry (recursing).
586 * This would possibly run faster if we chdir to the directory
587 * before traversing it.
590 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 100);
591 for ( ; !job_canceled(jcr); ) {
595 status = readdir_r(directory, entry, &result);
596 if (status != 0 || result == NULL) {
597 // Dmsg2(99, "readdir returned stat=%d result=0x%x\n",
598 // status, (long)result);
601 ASSERT(name_max+1 > (int)sizeof(struct dirent) + (int)NAMELEN(entry));
603 /* Skip `.', `..', and excluded file names. */
604 if (p[0] == '\0' || (p[0] == '.' && (p[1] == '\0' ||
605 (p[1] == '.' && p[2] == '\0')))) {
609 if ((int)NAMELEN(entry) + len >= link_len) {
610 link_len = len + NAMELEN(entry) + 1;
611 link = (char *)brealloc(link, link_len + 1);
614 for (i=0; i < (int)NAMELEN(entry); i++) {
618 if (!file_is_excluded(ff_pkt, link)) {
619 rtn_stat = find_one_file(jcr, ff_pkt, handle_file, pkt, link, our_device, false);
620 if (ff_pkt->linked) {
621 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
630 * Now that we have recursed through all the files in the
631 * directory, we "save" the directory so that after all
632 * the files are restored, this entry will serve to reset
633 * the directory modes and dates. Temp directory values
634 * were used without this record.
636 handle_file(dir_ff_pkt, pkt, top_level); /* handle directory entry */
637 if (ff_pkt->linked) {
638 ff_pkt->linked->FileIndex = dir_ff_pkt->FileIndex;
640 free_dir_ff_pkt(dir_ff_pkt);
642 if (ff_pkt->flags & FO_KEEPATIME) {
643 utime(fname, &restore_times);
645 ff_pkt->volhas_attrlist = volhas_attrlist; /* Restore value in case it changed. */
647 } /* end check for directory */
650 * If it is explicitly mentioned (i.e. top_level) and is
651 * a block device, we do a raw backup of it or if it is
652 * a fifo, we simply read it.
654 #ifdef HAVE_FREEBSD_OS
656 * On FreeBSD, all block devices are character devices, so
657 * to be able to read a raw disk, we need the check for
658 * a character device.
659 * crw-r----- 1 root operator - 116, 0x00040002 Jun 9 19:32 /dev/ad0s3
660 * crw-r----- 1 root operator - 116, 0x00040002 Jun 9 19:32 /dev/rad0s3
662 if (top_level && (S_ISBLK(ff_pkt->statp.st_mode) || S_ISCHR(ff_pkt->statp.st_mode))) {
664 if (top_level && S_ISBLK(ff_pkt->statp.st_mode)) {
666 ff_pkt->type = FT_RAW; /* raw partition */
667 } else if (top_level && S_ISFIFO(ff_pkt->statp.st_mode) &&
668 ff_pkt->flags & FO_READFIFO) {
669 ff_pkt->type = FT_FIFO;
671 /* The only remaining types are special (character, ...) files */
672 ff_pkt->type = FT_SPEC;
674 rtn_stat = handle_file(ff_pkt, pkt, top_level);
675 if (ff_pkt->linked) {
676 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
681 int term_find_one(FF_PKT *ff)
683 struct f_link *lp, *lc;
688 if (ff->linkhash == NULL) return 0;
690 for (i =0 ; i < LINK_HASHTABLE_SIZE; i ++) {
691 /* Free up list of hard linked files */
692 lp = ff->linkhash[i];
701 ff->linkhash[i] = NULL;