2 Copyright (C) 2000-2004 Kern Sibbald and John Walker
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License as
6 published by the Free Software Foundation; either version 2 of
7 the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
14 You should have received a copy of the GNU General Public
15 License along with this program; if not, write to the Free
16 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
19 This file is based on GNU TAR source code. Except for a few key
20 ideas, it has been rewritten for Bacula.
24 Thanks to the TAR programmers.
36 extern int32_t name_max; /* filename max length */
37 extern int32_t path_max; /* path name max length */
40 * Structure for keeping track of hard linked files, we
41 * keep an entry for each hardlinked file that we save,
42 * which is the first one found. For all the other files that
43 * are linked to this one, we save only the directory
44 * entry so we can link it.
48 dev_t dev; /* device */
49 ino_t ino; /* inode with device is unique */
51 uint32_t FileIndex; /* Bacula FileIndex of this file */
52 char name[1]; /* The name */
55 static void free_dir_ff_pkt(FF_PKT *dir_ff_pkt)
57 free(dir_ff_pkt->fname);
58 free(dir_ff_pkt->link);
59 free_pool_memory(dir_ff_pkt->sys_fname);
64 * Check to see if we allow the file system type of a file or directory.
65 * If we do not have a list of file system types, we accept anything.
67 static int accept_fstype(FF_PKT *ff, void *dummy) {
72 if (ff->fstypes->size()) {
74 fs = fstype(ff->fname);
76 Dmsg1(50, "Cannot determine file system type for \"%s\"\n", ff->fname);
78 for (i = 0; i <ff->fstypes->size(); ++i) {
79 if (strcmp(fs, (char *)ff->fstypes->get(i)) == 0) {
80 Dmsg2(100, "Accepting fstype %s for \"%s\"\n", fs, ff->fname);
84 Dmsg3(200, "fstype %s for \"%s\" does not match %s\n", fs,
85 ff->fname, ff->fstypes->get(i));
95 * handle_file is the callback for handling the file.
97 * parent_device is the device we are currently on
98 * top_level is 1 when not recursing or 0 when
99 * descending into a directory.
102 find_one_file(JCR *jcr, FF_PKT *ff_pkt, int handle_file(FF_PKT *ff, void *hpkt),
103 void *pkt, char *fname, dev_t parent_device, int top_level)
105 struct utimbuf restore_times;
108 ff_pkt->fname = ff_pkt->link = fname;
110 if (lstat(fname, &ff_pkt->statp) != 0) {
111 /* Cannot stat file */
112 ff_pkt->type = FT_NOSTAT;
113 ff_pkt->ff_errno = errno;
114 return handle_file(ff_pkt, pkt);
117 #ifdef HAVE_DARWIN_OS
118 if (S_ISREG(ff_pkt->statp.st_mode) && ff_pkt->flags & FO_HFSPLUS) {
119 /* TODO: initialise attrList once elsewhere? */
120 struct attrlist attrList;
121 memset(&attrList, 0, sizeof(attrList));
122 attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
123 attrList.commonattr = ATTR_CMN_FNDRINFO;
124 attrList.fileattr = ATTR_FILE_RSRCLENGTH;
125 if (getattrlist(fname, &attrList, &ff_pkt->hfsinfo,
126 sizeof(ff_pkt->hfsinfo), 0) != 0) {
127 ff_pkt->type = FT_NOSTAT;
128 ff_pkt->ff_errno = errno;
129 return handle_file(ff_pkt, pkt);
134 Dmsg1(300, "File ----: %s\n", fname);
136 /* Save current times of this directory in case we need to
137 * reset them because the user doesn't want them changed.
139 restore_times.actime = ff_pkt->statp.st_atime;
140 restore_times.modtime = ff_pkt->statp.st_mtime;
144 * Check if we start with an allowed file system.
146 * handle_file() calls accept_file() which fills in ff_pkt->fstypes
147 * Temporarily use our own handler with a fake, but probable, type.
149 int (*callback)(FF_PKT *, void *) = ff_pkt->callback;
150 ff_pkt->callback = accept_fstype;
151 ff_pkt->type = FT_DIRBEGIN;
152 rtn_stat = handle_file(ff_pkt, pkt);
153 ff_pkt->callback = callback;
155 ff_pkt->type = FT_INVALIDFS;
156 if (ff_pkt->flags & FO_KEEPATIME) {
157 utime(fname, &restore_times);
159 Jmsg1(jcr, M_ERROR, 0, _("Top level entry \"%s\" has an unlisted fstype\n"), fname);
165 * If this is an Incremental backup, see if file was modified
166 * since our last "save_time", presumably the last Full save
169 if (ff_pkt->incremental && !S_ISDIR(ff_pkt->statp.st_mode)) {
170 Dmsg1(300, "Non-directory incremental: %s\n", ff_pkt->fname);
171 /* Not a directory */
172 if (ff_pkt->statp.st_mtime < ff_pkt->save_time
173 && ((ff_pkt->flags & FO_MTIMEONLY) ||
174 ff_pkt->statp.st_ctime < ff_pkt->save_time)) {
175 /* Incremental option, file not changed */
176 ff_pkt->type = FT_NOCHG;
177 return handle_file(ff_pkt, pkt);
181 /* ***FIXME*** implement this */
183 /* See if we are trying to dump the archive. */
184 if (ar_dev && ff_pkt->statp.st_dev == ar_dev && ff_pkt->statp.st_ino == ar_ino) {
185 ff_pkt->type = FT_ISARCH;
186 return handle_file(ff_pkt, pkt);
191 * Handle hard linked files
193 * Maintain a list of hard linked files already backed up. This
194 * allows us to ensure that the data of each file gets backed
197 if (!(ff_pkt->flags & FO_NO_HARDLINK)
198 && ff_pkt->statp.st_nlink > 1
199 && (S_ISREG(ff_pkt->statp.st_mode)
200 || S_ISCHR(ff_pkt->statp.st_mode)
201 || S_ISBLK(ff_pkt->statp.st_mode)
202 || S_ISFIFO(ff_pkt->statp.st_mode)
203 || S_ISSOCK(ff_pkt->statp.st_mode))) {
207 /* Search link list of hard linked files */
208 for (lp = ff_pkt->linklist; lp; lp = lp->next)
209 if (lp->ino == (ino_t)ff_pkt->statp.st_ino &&
210 lp->dev == (dev_t)ff_pkt->statp.st_dev) {
211 /* If we have already backed up the hard linked file don't do it again */
212 if (strcmp(lp->name, fname) == 0) {
213 Jmsg1(jcr, M_WARNING, 0, _("Attempt to backup hard linked file %s twice ignored.\n"),
215 return 1; /* ignore */
217 ff_pkt->link = lp->name;
218 ff_pkt->type = FT_LNKSAVED; /* Handle link, file already saved */
219 ff_pkt->LinkFI = lp->FileIndex;
220 return handle_file(ff_pkt, pkt);
223 /* File not previously dumped. Chain it into our list. */
224 lp = (struct f_link *)bmalloc(sizeof(struct f_link) + strlen(fname) +1);
225 lp->ino = ff_pkt->statp.st_ino;
226 lp->dev = ff_pkt->statp.st_dev;
227 strcpy(lp->name, fname);
228 lp->next = ff_pkt->linklist;
229 ff_pkt->linklist = lp;
230 ff_pkt->linked = lp; /* mark saved link */
232 ff_pkt->linked = NULL;
235 /* This is not a link to a previously dumped file, so dump it. */
236 if (S_ISREG(ff_pkt->statp.st_mode)) {
239 sizeleft = ff_pkt->statp.st_size;
241 /* Don't bother opening empty, world readable files. Also do not open
242 files when archive is meant for /dev/null. */
243 if (ff_pkt->null_output_device || (sizeleft == 0
244 && MODE_RALL == (MODE_RALL & ff_pkt->statp.st_mode))) {
245 ff_pkt->type = FT_REGE;
247 ff_pkt->type = FT_REG;
249 rtn_stat = handle_file(ff_pkt, pkt);
250 if (ff_pkt->linked) {
251 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
256 } else if (S_ISLNK(ff_pkt->statp.st_mode)) { /* soft link */
258 char *buffer = (char *)alloca(path_max + name_max + 102);
260 size = readlink(fname, buffer, path_max + name_max + 101);
262 /* Could not follow link */
263 ff_pkt->type = FT_NOFOLLOW;
264 ff_pkt->ff_errno = errno;
265 rtn_stat = handle_file(ff_pkt, pkt);
266 if (ff_pkt->linked) {
267 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
272 ff_pkt->link = buffer; /* point to link */
273 ff_pkt->type = FT_LNK; /* got a real link */
274 rtn_stat = handle_file(ff_pkt, pkt);
275 if (ff_pkt->linked) {
276 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
280 } else if (S_ISDIR(ff_pkt->statp.st_mode)) {
282 struct dirent *entry, *result;
287 dev_t our_device = ff_pkt->statp.st_dev;
291 * If we are using Win32 (non-portable) backup API, don't check
292 * access as everything is more complicated, and
293 * in principle, we should be able to access everything.
295 if (!have_win32_api() || (ff_pkt->flags & FO_PORTABLE)) {
296 if (access(fname, R_OK) == -1 && geteuid() != 0) {
297 /* Could not access() directory */
298 ff_pkt->type = FT_NOACCESS;
299 ff_pkt->ff_errno = errno;
300 rtn_stat = handle_file(ff_pkt, pkt);
301 if (ff_pkt->linked) {
302 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
308 /* Build a canonical directory name with a trailing slash in link var */
310 link_len = len + 200;
311 link = (char *)bmalloc(link_len + 2);
312 bstrncpy(link, fname, link_len);
313 /* Strip all trailing slashes */
314 while (len >= 1 && link[len - 1] == '/')
316 link[len++] = '/'; /* add back one */
320 if (ff_pkt->incremental &&
321 (ff_pkt->statp.st_mtime < ff_pkt->save_time &&
322 ff_pkt->statp.st_ctime < ff_pkt->save_time)) {
323 /* Incremental option, directory entry not changed */
324 ff_pkt->type = FT_DIRNOCHG;
326 ff_pkt->type = FT_DIRBEGIN;
329 * Note, we return the directory to the calling program (handle_file)
330 * when we first see the directory (FT_DIRBEGIN.
331 * This allows the program to apply matches and make a
332 * choice whether or not to accept it. If it is accepted, we
333 * do not immediately save it, but do so only after everything
334 * in the directory is seen (i.e. the FT_DIREND).
336 rtn_stat = handle_file(ff_pkt, pkt);
337 if (rtn_stat < 1) { /* ignore or error status */
341 /* Done with DIRBEGIN, next call will be DIREND */
342 if (ff_pkt->type == FT_DIRBEGIN) {
343 ff_pkt->type = FT_DIREND;
347 * Create a temporary ff packet for this directory
348 * entry, and defer handling the directory until
349 * we have recursed into it. This saves the
350 * directory after all files have been processed, and
351 * during the restore, the directory permissions will
352 * be reset after all the files have been restored.
354 Dmsg1(300, "Create temp ff packet for dir: %s\n", ff_pkt->fname);
355 FF_PKT *dir_ff_pkt = (FF_PKT *)bmalloc(sizeof(FF_PKT));
356 memcpy(dir_ff_pkt, ff_pkt, sizeof(FF_PKT));
357 dir_ff_pkt->fname = bstrdup(ff_pkt->fname);
358 dir_ff_pkt->link = bstrdup(ff_pkt->link);
359 dir_ff_pkt->sys_fname = get_pool_memory(PM_FNAME);
360 dir_ff_pkt->included_files_list = NULL;
361 dir_ff_pkt->excluded_files_list = NULL;
362 dir_ff_pkt->excluded_paths_list = NULL;
363 dir_ff_pkt->linklist = NULL;
366 * Do not descend into subdirectories (recurse) if the
367 * user has turned it off for this directory.
369 * If we are crossing file systems, we are either not allowed
370 * to cross, or we may be restricted by a list of permitted
373 if (ff_pkt->flags & FO_NO_RECURSION) {
374 ff_pkt->type = FT_NORECURSE;
376 } else if (!top_level && parent_device != ff_pkt->statp.st_dev) {
377 if(!(ff_pkt->flags & FO_MULTIFS)) {
378 ff_pkt->type = FT_NOFSCHG;
380 } else if (!accept_fstype(ff_pkt, NULL)) {
381 ff_pkt->type = FT_INVALIDFS;
386 rtn_stat = handle_file(ff_pkt, pkt);
387 if (ff_pkt->linked) {
388 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
391 free_dir_ff_pkt(dir_ff_pkt);
392 ff_pkt->link = ff_pkt->fname; /* reset "link" */
393 if (ff_pkt->flags & FO_KEEPATIME) {
394 utime(fname, &restore_times);
399 ff_pkt->link = ff_pkt->fname; /* reset "link" */
402 * Descend into or "recurse" into the directory to read
403 * all the files in it.
406 if ((directory = opendir(fname)) == NULL) {
407 ff_pkt->type = FT_NOOPEN;
408 ff_pkt->ff_errno = errno;
409 rtn_stat = handle_file(ff_pkt, pkt);
410 if (ff_pkt->linked) {
411 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
414 free_dir_ff_pkt(dir_ff_pkt);
419 * Process all files in this directory entry (recursing).
420 * This would possibly run faster if we chdir to the directory
421 * before traversing it.
424 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 100);
425 for ( ; !job_canceled(jcr); ) {
429 status = readdir_r(directory, entry, &result);
430 if (status != 0 || result == NULL) {
431 // Dmsg2(99, "readdir returned stat=%d result=0x%x\n",
432 // status, (long)result);
435 ASSERT(name_max+1 > (int)sizeof(struct dirent) + (int)NAMELEN(entry));
437 /* Skip `.', `..', and excluded file names. */
438 if (p[0] == '\0' || (p[0] == '.' && (p[1] == '\0' ||
439 (p[1] == '.' && p[2] == '\0')))) {
443 if ((int)NAMELEN(entry) + len >= link_len) {
444 link_len = len + NAMELEN(entry) + 1;
445 link = (char *)brealloc(link, link_len + 1);
448 for (i=0; i < (int)NAMELEN(entry); i++) {
452 if (!file_is_excluded(ff_pkt, link)) {
453 rtn_stat = find_one_file(jcr, ff_pkt, handle_file, pkt, link, our_device, 0);
454 if (ff_pkt->linked) {
455 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
464 * Now that we have recursed through all the files in the
465 * directory, we "save" the directory so that after all
466 * the files are restored, this entry will serve to reset
467 * the directory modes and dates. Temp directory values
468 * were used without this record.
470 handle_file(dir_ff_pkt, pkt); /* handle directory entry */
471 if (ff_pkt->linked) {
472 ff_pkt->linked->FileIndex = dir_ff_pkt->FileIndex;
474 free_dir_ff_pkt(dir_ff_pkt);
476 if (ff_pkt->flags & FO_KEEPATIME) {
477 utime(fname, &restore_times);
480 } /* end check for directory */
483 * If it is explicitly mentioned (i.e. top_level) and is
484 * a block device, we do a raw backup of it or if it is
485 * a fifo, we simply read it.
487 #ifdef HAVE_FREEBSD_OS
489 * On FreeBSD, all block devices are character devices, so
490 * to be able to read a raw disk, we need the check for
491 * a character device.
492 * crw-r----- 1 root operator - 116, 0x00040002 Jun 9 19:32 /dev/ad0s3
493 * crw-r----- 1 root operator - 116, 0x00040002 Jun 9 19:32 /dev/rad0s3
495 if (top_level && (S_ISBLK(ff_pkt->statp.st_mode) || S_ISCHR(ff_pkt->statp.st_mode))) {
497 if (top_level && S_ISBLK(ff_pkt->statp.st_mode)) {
499 ff_pkt->type = FT_RAW; /* raw partition */
500 } else if (top_level && S_ISFIFO(ff_pkt->statp.st_mode) &&
501 ff_pkt->flags & FO_READFIFO) {
502 ff_pkt->type = FT_FIFO;
504 /* The only remaining types are special (character, ...) files */
505 ff_pkt->type = FT_SPEC;
507 rtn_stat = handle_file(ff_pkt, pkt);
508 if (ff_pkt->linked) {
509 ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
514 int term_find_one(FF_PKT *ff)
516 struct f_link *lp, *lc;
519 /* Free up list of hard linked files */
520 for (lp = ff->linklist; lp;) {