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)) {
185 * Find a single file.
186 * handle_file is the callback for handling the file.
188 * parent_device is the device we are currently on
189 * top_level is 1 when not recursing or 0 when
190 * descending into a directory.
193 find_one_file(JCR *jcr, FF_PKT *ff_pkt,
194 int handle_file(FF_PKT *ff, void *hpkt, bool top_level),
195 void *pkt, char *fname, dev_t parent_device, bool top_level)
197 struct utimbuf restore_times;
201 ff_pkt->fname = ff_pkt->link = fname;
203 if (lstat(fname, &ff_pkt->statp) != 0) {
204 /* Cannot stat file */
205 ff_pkt->type = FT_NOSTAT;
206 ff_pkt->ff_errno = errno;
207 return handle_file(ff_pkt, pkt, top_level);
210 Dmsg1(300, "File ----: %s\n", fname);
212 /* Save current times of this directory in case we need to
213 * reset them because the user doesn't want them changed.
215 restore_times.actime = ff_pkt->statp.st_atime;
216 restore_times.modtime = ff_pkt->statp.st_mtime;
219 * We check for allowed fstypes and drivetypes at top_level and fstype change (below).
222 if (!accept_fstype(ff_pkt, NULL)) {
223 ff_pkt->type = FT_INVALIDFS;
224 if (ff_pkt->flags & FO_KEEPATIME) {
225 utime(fname, &restore_times);
230 if (!fstype(ff_pkt->fname, fs, sizeof(fs))) {
231 bstrncpy(fs, "unknown", sizeof(fs));
234 Jmsg(jcr, M_INFO, 0, _("Top level directory \"%s\" has unlisted fstype \"%s\"\n"), fname, fs);
235 return 1; /* Just ignore this error - or the whole backup is cancelled */
237 if (!accept_drivetype(ff_pkt, NULL)) {
238 ff_pkt->type = FT_INVALIDDT;
239 if (ff_pkt->flags & FO_KEEPATIME) {
240 utime(fname, &restore_times);
245 if (!drivetype(ff_pkt->fname, dt, sizeof(dt))) {
246 bstrncpy(dt, "unknown", sizeof(dt));
249 Jmsg(jcr, M_INFO, 0, _("Top level directory \"%s\" has an unlisted drive type \"%s\"\n"), fname, dt);
250 return 1; /* Just ignore this error - or the whole backup is cancelled */
252 ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
256 * If this is an Incremental backup, see if file was modified
257 * since our last "save_time", presumably the last Full save
260 if (ff_pkt->incremental && !S_ISDIR(ff_pkt->statp.st_mode)) {
261 Dmsg1(300, "Non-directory incremental: %s\n", ff_pkt->fname);
262 /* Not a directory */
263 if (ff_pkt->statp.st_mtime < ff_pkt->save_time
264 && ((ff_pkt->flags & FO_MTIMEONLY) ||
265 ff_pkt->statp.st_ctime < ff_pkt->save_time)) {
266 /* Incremental option, file not changed */
267 ff_pkt->type = FT_NOCHG;
268 return handle_file(ff_pkt, pkt, top_level);
272 #ifdef HAVE_DARWIN_OS
273 if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->volhas_attrlist
274 && S_ISREG(ff_pkt->statp.st_mode)) {
275 /* TODO: initialise attrList once elsewhere? */
276 struct attrlist attrList;
277 memset(&attrList, 0, sizeof(attrList));
278 attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
279 attrList.commonattr = ATTR_CMN_FNDRINFO;
280 attrList.fileattr = ATTR_FILE_RSRCLENGTH;
281 if (getattrlist(fname, &attrList, &ff_pkt->hfsinfo,
282 sizeof(ff_pkt->hfsinfo), FSOPT_NOFOLLOW) != 0) {
283 ff_pkt->type = FT_NOSTAT;
284 ff_pkt->ff_errno = errno;
285 return handle_file(ff_pkt, pkt, top_level);
290 /* ***FIXME*** implement this */
292 /* See if we are trying to dump the archive. */
293 if (ar_dev && ff_pkt->statp.st_dev == ar_dev && ff_pkt->statp.st_ino == ar_ino) {
294 ff_pkt->type = FT_ISARCH;
295 return handle_file(ff_pkt, pkt, top_level);
300 * Handle hard linked files
302 * Maintain a list of hard linked files already backed up. This
303 * allows us to ensure that the data of each file gets backed
306 if (!(ff_pkt->flags & FO_NO_HARDLINK)
307 && ff_pkt->statp.st_nlink > 1
308 && (S_ISREG(ff_pkt->statp.st_mode)
309 || S_ISCHR(ff_pkt->statp.st_mode)
310 || S_ISBLK(ff_pkt->statp.st_mode)
311 || S_ISFIFO(ff_pkt->statp.st_mode)
312 || S_ISSOCK(ff_pkt->statp.st_mode))) {
315 if (ff_pkt->linkhash == NULL) {
316 ff_pkt->linkhash = (link_t **)bmalloc(LINK_HASHTABLE_SIZE * sizeof(link_t *));
317 memset(ff_pkt->linkhash, 0, LINK_HASHTABLE_SIZE * sizeof(link_t *));
319 const int linkhash = LINKHASH(ff_pkt->statp);
321 /* Search link list of hard linked files */
322 for (lp = ff_pkt->linkhash[linkhash]; lp; lp = lp->next)
323 if (lp->ino == (ino_t)ff_pkt->statp.st_ino &&
324 lp->dev == (dev_t)ff_pkt->statp.st_dev) {
325 /* If we have already backed up the hard linked file don't do it again */
326 if (strcmp(lp->name, fname) == 0) {
327 return 1; /* ignore */
329 ff_pkt->link = lp->name;
330 ff_pkt->type = FT_LNKSAVED; /* Handle link, file already saved */
331 ff_pkt->LinkFI = lp->FileIndex;
332 return handle_file(ff_pkt, pkt, top_level);
335 /* File not previously dumped. Chain it into our list. */
336 len = strlen(fname) + 1;
337 lp = (struct f_link *)bmalloc(sizeof(struct f_link) + len);
338 lp->ino = ff_pkt->statp.st_ino;
339 lp->dev = ff_pkt->statp.st_dev;
340 bstrncpy(lp->name, fname, len);
341 lp->next = ff_pkt->linkhash[linkhash];
342 ff_pkt->linkhash[linkhash] = lp;
343 ff_pkt->linked = lp; /* mark saved link */
345 ff_pkt->linked = NULL;
348 /* This is not a link to a previously dumped file, so dump it. */
349 if (S_ISREG(ff_pkt->statp.st_mode)) {
352 sizeleft = ff_pkt->statp.st_size;
354 /* Don't bother opening empty, world readable files. Also do not open
355 files when archive is meant for /dev/null. */
356 if (ff_pkt->null_output_device || (sizeleft == 0
357 && MODE_RALL == (MODE_RALL & ff_pkt->statp.st_mode))) {
358 ff_pkt->type = FT_REGE;
360 ff_pkt->type = FT_REG;
362 rtn_stat = handle_file(ff_pkt, pkt, top_level);
363 if (ff_pkt->linked) {
364 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
366 if (ff_pkt->flags & FO_KEEPATIME) {
367 utime(fname, &restore_times);
372 } else if (S_ISLNK(ff_pkt->statp.st_mode)) { /* soft link */
374 char *buffer = (char *)alloca(path_max + name_max + 102);
376 size = readlink(fname, buffer, path_max + name_max + 101);
378 /* Could not follow link */
379 ff_pkt->type = FT_NOFOLLOW;
380 ff_pkt->ff_errno = errno;
381 rtn_stat = handle_file(ff_pkt, pkt, top_level);
382 if (ff_pkt->linked) {
383 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
388 ff_pkt->link = buffer; /* point to link */
389 ff_pkt->type = FT_LNK; /* got a real link */
390 rtn_stat = handle_file(ff_pkt, pkt, top_level);
391 if (ff_pkt->linked) {
392 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
396 } else if (S_ISDIR(ff_pkt->statp.st_mode)) {
398 struct dirent *entry, *result;
403 dev_t our_device = ff_pkt->statp.st_dev;
405 bool volhas_attrlist = ff_pkt->volhas_attrlist; /* Remember this if we recurse */
408 * If we are using Win32 (non-portable) backup API, don't check
409 * access as everything is more complicated, and
410 * in principle, we should be able to access everything.
412 if (!have_win32_api() || (ff_pkt->flags & FO_PORTABLE)) {
413 if (access(fname, R_OK) == -1 && geteuid() != 0) {
414 /* Could not access() directory */
415 ff_pkt->type = FT_NOACCESS;
416 ff_pkt->ff_errno = errno;
417 rtn_stat = handle_file(ff_pkt, pkt, top_level);
418 if (ff_pkt->linked) {
419 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
425 /* Build a canonical directory name with a trailing slash in link var */
427 link_len = len + 200;
428 link = (char *)bmalloc(link_len + 2);
429 bstrncpy(link, fname, link_len);
430 /* Strip all trailing slashes */
431 while (len >= 1 && IsPathSeparator(link[len - 1]))
433 link[len++] = '/'; /* add back one */
437 if (ff_pkt->incremental &&
438 (ff_pkt->statp.st_mtime < ff_pkt->save_time &&
439 ((ff_pkt->flags & FO_MTIMEONLY) ||
440 ff_pkt->statp.st_ctime < ff_pkt->save_time))) {
441 /* Incremental option, directory entry not changed */
442 ff_pkt->type = FT_DIRNOCHG;
444 ff_pkt->type = FT_DIRBEGIN;
447 * Note, we return the directory to the calling program (handle_file)
448 * when we first see the directory (FT_DIRBEGIN.
449 * This allows the program to apply matches and make a
450 * choice whether or not to accept it. If it is accepted, we
451 * do not immediately save it, but do so only after everything
452 * in the directory is seen (i.e. the FT_DIREND).
454 rtn_stat = handle_file(ff_pkt, pkt, top_level);
455 if (rtn_stat < 1) { /* ignore or error status */
459 /* Done with DIRBEGIN, next call will be DIREND */
460 if (ff_pkt->type == FT_DIRBEGIN) {
461 ff_pkt->type = FT_DIREND;
465 * Create a temporary ff packet for this directory
466 * entry, and defer handling the directory until
467 * we have recursed into it. This saves the
468 * directory after all files have been processed, and
469 * during the restore, the directory permissions will
470 * be reset after all the files have been restored.
472 Dmsg1(300, "Create temp ff packet for dir: %s\n", ff_pkt->fname);
473 FF_PKT *dir_ff_pkt = (FF_PKT *)bmalloc(sizeof(FF_PKT));
474 memcpy(dir_ff_pkt, ff_pkt, sizeof(FF_PKT));
475 dir_ff_pkt->fname = bstrdup(ff_pkt->fname);
476 dir_ff_pkt->link = bstrdup(ff_pkt->link);
477 dir_ff_pkt->sys_fname = get_pool_memory(PM_FNAME);
478 dir_ff_pkt->included_files_list = NULL;
479 dir_ff_pkt->excluded_files_list = NULL;
480 dir_ff_pkt->excluded_paths_list = NULL;
481 dir_ff_pkt->linkhash = NULL;
484 * Do not descend into subdirectories (recurse) if the
485 * user has turned it off for this directory.
487 * If we are crossing file systems, we are either not allowed
488 * to cross, or we may be restricted by a list of permitted
491 if (!top_level && ff_pkt->flags & FO_NO_RECURSION) {
492 ff_pkt->type = FT_NORECURSE;
494 } else if (!top_level && parent_device != ff_pkt->statp.st_dev) {
495 if(!(ff_pkt->flags & FO_MULTIFS)) {
496 ff_pkt->type = FT_NOFSCHG;
498 } else if (!accept_fstype(ff_pkt, NULL)) {
499 ff_pkt->type = FT_INVALIDFS;
502 ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
505 /* If not recursing, just backup dir and return */
507 rtn_stat = handle_file(ff_pkt, pkt, top_level);
508 if (ff_pkt->linked) {
509 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
512 free_dir_ff_pkt(dir_ff_pkt);
513 ff_pkt->link = ff_pkt->fname; /* reset "link" */
514 if (ff_pkt->flags & FO_KEEPATIME) {
515 utime(fname, &restore_times);
520 ff_pkt->link = ff_pkt->fname; /* reset "link" */
523 * Descend into or "recurse" into the directory to read
524 * all the files in it.
527 if ((directory = opendir(fname)) == NULL) {
528 ff_pkt->type = FT_NOOPEN;
529 ff_pkt->ff_errno = errno;
530 rtn_stat = handle_file(ff_pkt, pkt, top_level);
531 if (ff_pkt->linked) {
532 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
535 free_dir_ff_pkt(dir_ff_pkt);
540 * Process all files in this directory entry (recursing).
541 * This would possibly run faster if we chdir to the directory
542 * before traversing it.
545 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 100);
546 for ( ; !job_canceled(jcr); ) {
550 status = readdir_r(directory, entry, &result);
551 if (status != 0 || result == NULL) {
552 // Dmsg2(99, "readdir returned stat=%d result=0x%x\n",
553 // status, (long)result);
556 ASSERT(name_max+1 > (int)sizeof(struct dirent) + (int)NAMELEN(entry));
558 /* Skip `.', `..', and excluded file names. */
559 if (p[0] == '\0' || (p[0] == '.' && (p[1] == '\0' ||
560 (p[1] == '.' && p[2] == '\0')))) {
564 if ((int)NAMELEN(entry) + len >= link_len) {
565 link_len = len + NAMELEN(entry) + 1;
566 link = (char *)brealloc(link, link_len + 1);
569 for (i=0; i < (int)NAMELEN(entry); i++) {
573 if (!file_is_excluded(ff_pkt, link)) {
574 rtn_stat = find_one_file(jcr, ff_pkt, handle_file, pkt, link, our_device, false);
575 if (ff_pkt->linked) {
576 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
585 * Now that we have recursed through all the files in the
586 * directory, we "save" the directory so that after all
587 * the files are restored, this entry will serve to reset
588 * the directory modes and dates. Temp directory values
589 * were used without this record.
591 handle_file(dir_ff_pkt, pkt, top_level); /* handle directory entry */
592 if (ff_pkt->linked) {
593 ff_pkt->linked->FileIndex = dir_ff_pkt->FileIndex;
595 free_dir_ff_pkt(dir_ff_pkt);
597 if (ff_pkt->flags & FO_KEEPATIME) {
598 utime(fname, &restore_times);
600 ff_pkt->volhas_attrlist = volhas_attrlist; /* Restore value in case it changed. */
602 } /* end check for directory */
605 * If it is explicitly mentioned (i.e. top_level) and is
606 * a block device, we do a raw backup of it or if it is
607 * a fifo, we simply read it.
609 #ifdef HAVE_FREEBSD_OS
611 * On FreeBSD, all block devices are character devices, so
612 * to be able to read a raw disk, we need the check for
613 * a character device.
614 * crw-r----- 1 root operator - 116, 0x00040002 Jun 9 19:32 /dev/ad0s3
615 * crw-r----- 1 root operator - 116, 0x00040002 Jun 9 19:32 /dev/rad0s3
617 if (top_level && (S_ISBLK(ff_pkt->statp.st_mode) || S_ISCHR(ff_pkt->statp.st_mode))) {
619 if (top_level && S_ISBLK(ff_pkt->statp.st_mode)) {
621 ff_pkt->type = FT_RAW; /* raw partition */
622 } else if (top_level && S_ISFIFO(ff_pkt->statp.st_mode) &&
623 ff_pkt->flags & FO_READFIFO) {
624 ff_pkt->type = FT_FIFO;
626 /* The only remaining types are special (character, ...) files */
627 ff_pkt->type = FT_SPEC;
629 rtn_stat = handle_file(ff_pkt, pkt, top_level);
630 if (ff_pkt->linked) {
631 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
636 int term_find_one(FF_PKT *ff)
638 struct f_link *lp, *lc;
643 if (ff->linkhash == NULL) return 0;
645 for (i =0 ; i < LINK_HASHTABLE_SIZE; i ++) {
646 /* Free up list of hard linked files */
647 lp = ff->linkhash[i];
656 ff->linkhash[i] = NULL;