]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/find_one.c
5619ea43a876caea2a71a642dc514f2761fcf14a
[bacula/bacula] / bacula / src / findlib / find_one.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
5
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
11    in the file LICENSE.
12
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.
17
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
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
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.
27 */
28 /*
29
30    This file was derived from GNU TAR source code. Except for a few key
31    ideas, it has been entirely rewritten for Bacula.
32
33       Kern Sibbald, MM
34
35    Thanks to the TAR programmers.
36
37      Version $Id$
38
39  */
40
41 #include "bacula.h"
42 #include "find.h"
43 #ifdef HAVE_DARWIN_OS
44 #include <sys/param.h>
45 #include <sys/mount.h>
46 #include <sys/attr.h>
47 #endif
48
49 extern int32_t name_max;              /* filename max length */
50 extern int32_t path_max;              /* path name max length */
51
52 /*
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.
58  */
59 struct f_link {
60     struct f_link *next;
61     dev_t dev;                        /* device */
62     ino_t ino;                        /* inode with device is unique */
63     uint32_t FileIndex;               /* Bacula FileIndex of this file */
64     char name[1];                     /* The name */
65 };
66
67 typedef struct f_link link_t;
68 #define LINK_HASHTABLE_BITS 16
69 #define LINK_HASHTABLE_SIZE (1<<LINK_HASHTABLE_BITS)
70 #define LINK_HASHTABLE_MASK (LINK_HASHTABLE_SIZE-1)
71
72 static inline int LINKHASH(const struct stat &info)
73 {
74     int hash = info.st_dev;
75     unsigned long long i = info.st_ino;
76     hash ^= i;
77     i >>= 16;
78     hash ^= i;
79     i >>= 16;
80     hash ^= i;
81     i >>= 16;
82     hash ^= i;
83     return hash & LINK_HASHTABLE_MASK;
84 }
85
86 /*
87  * Create a new directory Find File packet, but copy
88  *   some of the essential info from the current packet.
89  *   However, be careful to zero out the rest of the 
90  *   packet.
91  */
92 static FF_PKT *new_dir_ff_pkt(FF_PKT *ff_pkt)
93 {
94    FF_PKT *dir_ff_pkt = (FF_PKT *)bmalloc(sizeof(FF_PKT));
95    memcpy(dir_ff_pkt, ff_pkt, sizeof(FF_PKT));
96    dir_ff_pkt->fname = bstrdup(ff_pkt->fname);
97    dir_ff_pkt->link = bstrdup(ff_pkt->link);
98    dir_ff_pkt->sys_fname = get_pool_memory(PM_FNAME);
99    dir_ff_pkt->included_files_list = NULL;
100    dir_ff_pkt->excluded_files_list = NULL;
101    dir_ff_pkt->excluded_paths_list = NULL;
102    dir_ff_pkt->linkhash = NULL;
103    dir_ff_pkt->fname_save = NULL;
104    dir_ff_pkt->link_save = NULL;
105    return dir_ff_pkt;
106 }
107
108 /*
109  * Free the temp directory ff_pkt
110  */
111 static void free_dir_ff_pkt(FF_PKT *dir_ff_pkt)
112 {
113    free(dir_ff_pkt->fname);
114    free(dir_ff_pkt->link);
115    free_pool_memory(dir_ff_pkt->sys_fname);
116    if (dir_ff_pkt->fname_save) {
117       free_pool_memory(dir_ff_pkt->fname_save);
118    }
119    if (dir_ff_pkt->link_save) {
120       free_pool_memory(dir_ff_pkt->link_save);
121    }
122    free(dir_ff_pkt);
123 }
124
125 /*
126  * Check to see if we allow the file system type of a file or directory.
127  * If we do not have a list of file system types, we accept anything.
128  */
129 static int accept_fstype(FF_PKT *ff, void *dummy) {
130    int i;
131    char fs[1000];
132    bool accept = true;
133
134    if (ff->fstypes.size()) {
135       accept = false;
136       if (!fstype(ff->fname, fs, sizeof(fs))) {
137          Dmsg1(50, "Cannot determine file system type for \"%s\"\n", ff->fname);
138       } else {
139          for (i = 0; i < ff->fstypes.size(); ++i) {
140             if (strcmp(fs, (char *)ff->fstypes.get(i)) == 0) {
141                Dmsg2(100, "Accepting fstype %s for \"%s\"\n", fs, ff->fname);
142                accept = true;
143                break;
144             }
145             Dmsg3(200, "fstype %s for \"%s\" does not match %s\n", fs,
146                   ff->fname, ff->fstypes.get(i));
147          }
148       }
149    }
150    return accept;
151 }
152
153 /*
154  * Check to see if we allow the drive type of a file or directory.
155  * If we do not have a list of drive types, we accept anything.
156  */
157 static int accept_drivetype(FF_PKT *ff, void *dummy) {
158    int i;
159    char dt[100];
160    bool accept = true;
161
162    if (ff->drivetypes.size()) {
163       accept = false;
164       if (!drivetype(ff->fname, dt, sizeof(dt))) {
165          Dmsg1(50, "Cannot determine drive type for \"%s\"\n", ff->fname);
166       } else {
167          for (i = 0; i < ff->drivetypes.size(); ++i) {
168             if (strcmp(dt, (char *)ff->drivetypes.get(i)) == 0) {
169                Dmsg2(100, "Accepting drive type %s for \"%s\"\n", dt, ff->fname);
170                accept = true;
171                break;
172             }
173             Dmsg3(200, "drive type %s for \"%s\" does not match %s\n", dt,
174                   ff->fname, ff->drivetypes.get(i));
175          }
176       }
177    }
178    return accept;
179 }
180
181 /*
182  * This function determines whether we can use getattrlist()
183  * It's odd, but we have to use the function to determine that...
184  * Also, the man pages talk about things as if they were implemented.
185  *
186  * On Mac OS X, this succesfully differentiates between HFS+ and UFS
187  * volumes, which makes me trust it is OK for others, too.
188  */
189 static bool volume_has_attrlist(const char *fname)
190 {
191 #ifdef HAVE_DARWIN_OS
192    struct statfs st;
193    struct volinfo_struct {
194       unsigned long length;               /* Mandatory field */
195       vol_capabilities_attr_t info;       /* Volume capabilities */
196    } vol;
197    struct attrlist attrList;
198
199    memset(&attrList, 0, sizeof(attrList));
200    attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
201    attrList.volattr = ATTR_VOL_INFO | ATTR_VOL_CAPABILITIES;
202    if (statfs(fname, &st) == 0) {
203       /* We need to check on the mount point */
204       if (getattrlist(st.f_mntonname, &attrList, &vol, sizeof(vol), FSOPT_NOFOLLOW) == 0
205             && (vol.info.capabilities[VOL_CAPABILITIES_INTERFACES] & VOL_CAP_INT_ATTRLIST)
206             && (vol.info.valid[VOL_CAPABILITIES_INTERFACES] & VOL_CAP_INT_ATTRLIST)) {
207          return true;
208       }
209    }
210 #endif
211    return false;
212 }
213
214 /*
215  * check for BSD nodump flag
216  */
217 static bool no_dump(JCR *jcr, FF_PKT *ff_pkt)
218 {
219 #if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
220    if ( (ff_pkt->flags & FO_HONOR_NODUMP) &&
221         (ff_pkt->statp.st_flags & UF_NODUMP) ) {
222       Jmsg(jcr, M_INFO, 1, _("     NODUMP flag set - will not process %s\n"),
223            ff_pkt->fname);
224       return true;                    /* do not backup this file */
225    }
226 #endif
227    return false;                      /* do backup */
228 }
229
230 /* check if a file have changed during backup and display an error */
231 bool has_file_changed(JCR *jcr, FF_PKT *ff_pkt)
232 {
233    struct stat statp;
234    Dmsg1(500, "has_file_changed fname=%s\n",ff_pkt->fname);
235
236    if (ff_pkt->type != FT_REG) { /* not a regular file */
237       return false;
238    }
239
240    if (lstat(ff_pkt->fname, &statp) != 0) {
241       berrno be;
242       Jmsg(jcr, M_WARNING, 0, 
243            _("Cannot stat file %s: ERR=%s\n"),ff_pkt->fname,be.bstrerror());
244       return true;
245    }
246
247    if (statp.st_mtime != ff_pkt->statp.st_mtime) {
248       /* TODO: add time of changes */
249       Jmsg(jcr, M_ERROR, 0, _("%s mtime changed during backup.\n"), ff_pkt->fname);
250       return true;
251    }
252
253    if (statp.st_ctime != ff_pkt->statp.st_ctime) {
254       /* TODO: add time of changes */
255       Jmsg(jcr, M_ERROR, 0, _("%s ctime changed during backup.\n"), ff_pkt->fname);
256       return true;
257    }
258   
259    if (statp.st_size != ff_pkt->statp.st_size) {
260       /* TODO: add size change */
261       Jmsg(jcr, M_ERROR, 0, _("%s size changed during backup.\n"),ff_pkt->fname);
262       return true;
263    }
264
265    if ((statp.st_blksize != ff_pkt->statp.st_blksize) ||
266        (statp.st_blocks  != ff_pkt->statp.st_blocks)) {
267       /* TODO: add size change */
268       Jmsg(jcr, M_ERROR, 0, _("%s size changed during backup.\n"),ff_pkt->fname);
269       return true;
270    }
271
272    return false;
273 }
274
275 /*
276  * For incremental/diffential or accurate backups, we
277  *   determine if the current file has changed.
278  */
279 static bool check_changes(JCR *jcr, FF_PKT *ff_pkt)
280 {
281    /* in special mode (like accurate backup), the programmer can 
282     * choose his comparison function.
283     */
284    if (ff_pkt->check_fct) {
285       return ff_pkt->check_fct(jcr, ff_pkt);
286    }
287
288    /* For normal backups (incr/diff), we use this default
289     * behaviour
290     */
291    if (ff_pkt->incremental &&
292        (ff_pkt->statp.st_mtime < ff_pkt->save_time &&
293         ((ff_pkt->flags & FO_MTIMEONLY) ||
294          ff_pkt->statp.st_ctime < ff_pkt->save_time))) 
295    {
296       return false;
297    } 
298
299    return true;
300 }
301
302 /*
303  * Find a single file.
304  * handle_file is the callback for handling the file.
305  * p is the filename
306  * parent_device is the device we are currently on
307  * top_level is 1 when not recursing or 0 when
308  *  descending into a directory.
309  */
310 int
311 find_one_file(JCR *jcr, FF_PKT *ff_pkt, 
312                int handle_file(JCR *jcr, FF_PKT *ff, bool top_level),
313                char *fname, dev_t parent_device, bool top_level)
314 {
315    struct utimbuf restore_times;
316    int rtn_stat;
317    int len;
318
319    ff_pkt->fname = ff_pkt->link = fname;
320
321    if (lstat(fname, &ff_pkt->statp) != 0) {
322        /* Cannot stat file */
323        ff_pkt->type = FT_NOSTAT;
324        ff_pkt->ff_errno = errno;
325        return handle_file(jcr, ff_pkt, top_level);
326    }
327
328    Dmsg1(300, "File ----: %s\n", fname);
329
330    /* Save current times of this directory in case we need to
331     * reset them because the user doesn't want them changed.
332     */
333    restore_times.actime = ff_pkt->statp.st_atime;
334    restore_times.modtime = ff_pkt->statp.st_mtime;
335
336    /*
337     * We check for allowed fstypes and drivetypes at top_level and fstype change (below).
338     */
339    if (top_level) {
340       if (!accept_fstype(ff_pkt, NULL)) {
341          ff_pkt->type = FT_INVALIDFS;
342          if (ff_pkt->flags & FO_KEEPATIME) {
343             utime(fname, &restore_times);
344          }
345
346          char fs[100];
347
348          if (!fstype(ff_pkt->fname, fs, sizeof(fs))) {
349              bstrncpy(fs, "unknown", sizeof(fs));
350          }
351
352          Jmsg(jcr, M_INFO, 0, _("Top level directory \"%s\" has unlisted fstype \"%s\"\n"), fname, fs);
353          return 1;      /* Just ignore this error - or the whole backup is cancelled */
354       }
355       if (!accept_drivetype(ff_pkt, NULL)) {
356          ff_pkt->type = FT_INVALIDDT;
357          if (ff_pkt->flags & FO_KEEPATIME) {
358             utime(fname, &restore_times);
359          }
360
361          char dt[100];
362
363          if (!drivetype(ff_pkt->fname, dt, sizeof(dt))) {
364              bstrncpy(dt, "unknown", sizeof(dt));
365          }
366
367          Jmsg(jcr, M_INFO, 0, _("Top level directory \"%s\" has an unlisted drive type \"%s\"\n"), fname, dt);
368          return 1;      /* Just ignore this error - or the whole backup is cancelled */
369       }
370       ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
371    }
372
373    /*
374     * Ignore this entry if no_dump() returns true
375     */
376    if (no_dump(jcr, ff_pkt)) {
377            Dmsg1(100, "'%s' ignored (NODUMP flag set)\n",
378                  ff_pkt->fname);
379            return 1;
380    }
381
382    /*
383     * If this is an Incremental backup, see if file was modified
384     * since our last "save_time", presumably the last Full save
385     * or Incremental.
386     */
387    if (   ff_pkt->incremental 
388        && !S_ISDIR(ff_pkt->statp.st_mode) 
389        && !check_changes(jcr, ff_pkt)) 
390    {
391       Dmsg1(500, "Non-directory incremental: %s\n", ff_pkt->fname);
392       ff_pkt->type = FT_NOCHG;
393       return handle_file(jcr, ff_pkt, top_level);
394    }
395
396 #ifdef HAVE_DARWIN_OS
397    if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->volhas_attrlist
398          && S_ISREG(ff_pkt->statp.st_mode)) {
399        /* TODO: initialise attrList once elsewhere? */
400        struct attrlist attrList;
401        memset(&attrList, 0, sizeof(attrList));
402        attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
403        attrList.commonattr = ATTR_CMN_FNDRINFO;
404        attrList.fileattr = ATTR_FILE_RSRCLENGTH;
405        if (getattrlist(fname, &attrList, &ff_pkt->hfsinfo,
406                 sizeof(ff_pkt->hfsinfo), FSOPT_NOFOLLOW) != 0) {
407           ff_pkt->type = FT_NOSTAT;
408           ff_pkt->ff_errno = errno;
409           return handle_file(jcr, ff_pkt, top_level);
410        }
411    }
412 #endif
413
414    ff_pkt->LinkFI = 0;
415    /*
416     * Handle hard linked files
417     *
418     * Maintain a list of hard linked files already backed up. This
419     *  allows us to ensure that the data of each file gets backed
420     *  up only once.
421     */
422    if (!(ff_pkt->flags & FO_NO_HARDLINK)
423        && ff_pkt->statp.st_nlink > 1
424        && (S_ISREG(ff_pkt->statp.st_mode)
425            || S_ISCHR(ff_pkt->statp.st_mode)
426            || S_ISBLK(ff_pkt->statp.st_mode)
427            || S_ISFIFO(ff_pkt->statp.st_mode)
428            || S_ISSOCK(ff_pkt->statp.st_mode))) {
429
430        struct f_link *lp;
431        if (ff_pkt->linkhash == NULL) {
432            ff_pkt->linkhash = (link_t **)bmalloc(LINK_HASHTABLE_SIZE * sizeof(link_t *));
433            memset(ff_pkt->linkhash, 0, LINK_HASHTABLE_SIZE * sizeof(link_t *));
434        }
435        const int linkhash = LINKHASH(ff_pkt->statp);
436
437       /* Search link list of hard linked files */
438        for (lp = ff_pkt->linkhash[linkhash]; lp; lp = lp->next)
439          if (lp->ino == (ino_t)ff_pkt->statp.st_ino &&
440              lp->dev == (dev_t)ff_pkt->statp.st_dev) {
441              /* If we have already backed up the hard linked file don't do it again */
442              if (strcmp(lp->name, fname) == 0) {
443                 Dmsg2(400, "== Name identical skip FI=%d file=%s\n", lp->FileIndex, fname);
444                 return 1;             /* ignore */
445              }
446              ff_pkt->link = lp->name;
447              ff_pkt->type = FT_LNKSAVED;       /* Handle link, file already saved */
448              ff_pkt->LinkFI = lp->FileIndex;
449              ff_pkt->linked = 0;
450              rtn_stat = handle_file(jcr, ff_pkt, top_level);
451              Dmsg3(400, "FT_LNKSAVED FI=%d LinkFI=%d file=%s\n", 
452                 ff_pkt->FileIndex, lp->FileIndex, lp->name);
453              return rtn_stat;
454          }
455
456       /* File not previously dumped. Chain it into our list. */
457       len = strlen(fname) + 1;
458       lp = (struct f_link *)bmalloc(sizeof(struct f_link) + len);
459       lp->ino = ff_pkt->statp.st_ino;
460       lp->dev = ff_pkt->statp.st_dev;
461       lp->FileIndex = 0;                  /* set later */
462       bstrncpy(lp->name, fname, len);
463       lp->next = ff_pkt->linkhash[linkhash];
464       ff_pkt->linkhash[linkhash] = lp;
465       ff_pkt->linked = lp;            /* mark saved link */
466       Dmsg2(400, "added to hash FI=%d file=%s\n", ff_pkt->FileIndex, lp->name);
467    } else {
468       ff_pkt->linked = NULL;
469    }
470
471    /* This is not a link to a previously dumped file, so dump it.  */
472    if (S_ISREG(ff_pkt->statp.st_mode)) {
473       boffset_t sizeleft;
474
475       sizeleft = ff_pkt->statp.st_size;
476
477       /* Don't bother opening empty, world readable files.  Also do not open
478          files when archive is meant for /dev/null.  */
479       if (ff_pkt->null_output_device || (sizeleft == 0
480               && MODE_RALL == (MODE_RALL & ff_pkt->statp.st_mode))) {
481          ff_pkt->type = FT_REGE;
482       } else {
483          ff_pkt->type = FT_REG;
484       }
485       rtn_stat = handle_file(jcr, ff_pkt, top_level);
486       if (ff_pkt->linked) {
487          ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
488       }
489       Dmsg3(400, "FT_REG FI=%d linked=%d file=%s\n", ff_pkt->FileIndex, 
490          ff_pkt->linked ? 1 : 0, fname);
491       if (ff_pkt->flags & FO_KEEPATIME) {
492          utime(fname, &restore_times);
493       }       
494       return rtn_stat;
495
496
497    } else if (S_ISLNK(ff_pkt->statp.st_mode)) {  /* soft link */
498       int size;
499       char *buffer = (char *)alloca(path_max + name_max + 102);
500
501       size = readlink(fname, buffer, path_max + name_max + 101);
502       if (size < 0) {
503          /* Could not follow link */
504          ff_pkt->type = FT_NOFOLLOW;
505          ff_pkt->ff_errno = errno;
506          rtn_stat = handle_file(jcr, ff_pkt, top_level);
507          if (ff_pkt->linked) {
508             ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
509          }
510          return rtn_stat;
511       }
512       buffer[size] = 0;
513       ff_pkt->link = buffer;          /* point to link */
514       ff_pkt->type = FT_LNK;          /* got a real link */
515       rtn_stat = handle_file(jcr, ff_pkt, top_level);
516       if (ff_pkt->linked) {
517          ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
518       }
519       return rtn_stat;
520
521    } else if (S_ISDIR(ff_pkt->statp.st_mode)) {
522       DIR *directory;
523       struct dirent *entry, *result;
524       char *link;
525       int link_len;
526       int len;
527       int status;
528       dev_t our_device = ff_pkt->statp.st_dev;
529       bool recurse = true;
530       bool volhas_attrlist = ff_pkt->volhas_attrlist;    /* Remember this if we recurse */
531
532       /*
533        * If we are using Win32 (non-portable) backup API, don't check
534        *  access as everything is more complicated, and
535        *  in principle, we should be able to access everything.
536        */
537       if (!have_win32_api() || (ff_pkt->flags & FO_PORTABLE)) {
538          if (access(fname, R_OK) == -1 && geteuid() != 0) {
539             /* Could not access() directory */
540             ff_pkt->type = FT_NOACCESS;
541             ff_pkt->ff_errno = errno;
542             rtn_stat = handle_file(jcr, ff_pkt, top_level);
543             if (ff_pkt->linked) {
544                ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
545             }
546             return rtn_stat;
547          }
548       }
549
550       /*
551        * Ignore this directory and everything below if the file .nobackup
552        * (or what is defined for IgnoreDir in this fileset) exists
553        */
554       if (ff_pkt->ignoredir != NULL) {
555          struct stat sb;
556          char fname[MAXPATHLEN];
557
558          if (strlen(ff_pkt->fname) + strlen("/") +
559             strlen(ff_pkt->ignoredir) + 1 > MAXPATHLEN)
560             return 1;   /* Is this wisdom? */
561
562          strcpy(fname, ff_pkt->fname);
563          strcat(fname, "/");
564          strcat(fname, ff_pkt->ignoredir);
565          if (stat(fname, &sb) == 0) {
566             Dmsg2(100, "Directory '%s' ignored (found %s)\n",
567                ff_pkt->fname, ff_pkt->ignoredir);
568             return 1;      /* Just ignore this directory */
569          }
570       }
571
572       /* Build a canonical directory name with a trailing slash in link var */
573       len = strlen(fname);
574       link_len = len + 200;
575       link = (char *)bmalloc(link_len + 2);
576       bstrncpy(link, fname, link_len);
577       /* Strip all trailing slashes */
578       while (len >= 1 && IsPathSeparator(link[len - 1]))
579         len--;
580       link[len++] = '/';             /* add back one */
581       link[len] = 0;
582
583       ff_pkt->link = link;
584       if (ff_pkt->incremental && !check_changes(jcr, ff_pkt)) {
585          /* Incremental option, directory entry not changed */
586          ff_pkt->type = FT_DIRNOCHG;
587       } else {
588          ff_pkt->type = FT_DIRBEGIN;
589       }
590       /*
591        * We have set st_rdev to 1 if it is a reparse point, otherwise 0,
592        *  if st_rdev is 2, it is a mount point 
593        */
594 #if defined(HAVE_WIN32)
595       if (ff_pkt->statp.st_rdev == WIN32_REPARSE_POINT) {
596          ff_pkt->type = FT_REPARSE;
597       }
598 #endif 
599       /*
600        * Note, we return the directory to the calling program (handle_file)
601        * when we first see the directory (FT_DIRBEGIN.
602        * This allows the program to apply matches and make a
603        * choice whether or not to accept it.  If it is accepted, we
604        * do not immediately save it, but do so only after everything
605        * in the directory is seen (i.e. the FT_DIREND).
606        */
607       rtn_stat = handle_file(jcr, ff_pkt, top_level);
608       if (rtn_stat < 1 || ff_pkt->type == FT_REPARSE) {   /* ignore or error status */
609          free(link);
610          return rtn_stat;
611       }
612       /* Done with DIRBEGIN, next call will be DIREND */
613       if (ff_pkt->type == FT_DIRBEGIN) {
614          ff_pkt->type = FT_DIREND;
615       }
616
617       /*
618        * Create a temporary ff packet for this directory
619        *   entry, and defer handling the directory until
620        *   we have recursed into it.  This saves the
621        *   directory after all files have been processed, and
622        *   during the restore, the directory permissions will
623        *   be reset after all the files have been restored.
624        */
625       Dmsg1(300, "Create temp ff packet for dir: %s\n", ff_pkt->fname);
626       FF_PKT *dir_ff_pkt = new_dir_ff_pkt(ff_pkt);
627
628       /*
629        * Do not descend into subdirectories (recurse) if the
630        * user has turned it off for this directory.
631        *
632        * If we are crossing file systems, we are either not allowed
633        * to cross, or we may be restricted by a list of permitted
634        * file systems.
635        */
636       bool is_win32_mount_point = false;
637 #if defined(HAVE_WIN32)
638       is_win32_mount_point = ff_pkt->statp.st_rdev == WIN32_MOUNT_POINT;
639 #endif
640       if (!top_level && ff_pkt->flags & FO_NO_RECURSION) {
641          ff_pkt->type = FT_NORECURSE;
642          recurse = false;
643       } else if (!top_level && (parent_device != ff_pkt->statp.st_dev ||
644                  is_win32_mount_point)) {
645          if(!(ff_pkt->flags & FO_MULTIFS)) {
646             ff_pkt->type = FT_NOFSCHG;
647             recurse = false;
648          } else if (!accept_fstype(ff_pkt, NULL)) {
649             ff_pkt->type = FT_INVALIDFS;
650             recurse = false;
651          } else {
652             ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
653          }
654       }
655       /* If not recursing, just backup dir and return */
656       if (!recurse) {
657          rtn_stat = handle_file(jcr, ff_pkt, top_level);
658          if (ff_pkt->linked) {
659             ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
660          }
661          free(link);
662          free_dir_ff_pkt(dir_ff_pkt);
663          ff_pkt->link = ff_pkt->fname;     /* reset "link" */
664          if (ff_pkt->flags & FO_KEEPATIME) {
665             utime(fname, &restore_times);
666          }
667          return rtn_stat;
668       }
669
670       ff_pkt->link = ff_pkt->fname;     /* reset "link" */
671
672       /*
673        * Descend into or "recurse" into the directory to read
674        *   all the files in it.
675        */
676       errno = 0;
677       if ((directory = opendir(fname)) == NULL) {
678          ff_pkt->type = FT_NOOPEN;
679          ff_pkt->ff_errno = errno;
680          rtn_stat = handle_file(jcr, ff_pkt, top_level);
681          if (ff_pkt->linked) {
682             ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
683          }
684          free(link);
685          free_dir_ff_pkt(dir_ff_pkt);
686          return rtn_stat;
687       }
688
689       /*
690        * Process all files in this directory entry (recursing).
691        *    This would possibly run faster if we chdir to the directory
692        *    before traversing it.
693        */
694       rtn_stat = 1;
695       entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 100);
696       for ( ; !job_canceled(jcr); ) {
697          char *p, *q;
698          int i;
699
700          status  = readdir_r(directory, entry, &result);
701          if (status != 0 || result == NULL) {
702 //          Dmsg2(99, "readdir returned stat=%d result=0x%x\n",
703 //             status, (long)result);
704             break;
705          }
706          ASSERT(name_max+1 > (int)sizeof(struct dirent) + (int)NAMELEN(entry));
707          p = entry->d_name;
708          /* Skip `.', `..', and excluded file names.  */
709          if (p[0] == '\0' || (p[0] == '.' && (p[1] == '\0' ||
710              (p[1] == '.' && p[2] == '\0')))) {
711             continue;
712          }
713
714          if ((int)NAMELEN(entry) + len >= link_len) {
715              link_len = len + NAMELEN(entry) + 1;
716              link = (char *)brealloc(link, link_len + 1);
717          }
718          q = link + len;
719          for (i=0; i < (int)NAMELEN(entry); i++) {
720             *q++ = *p++;
721          }
722          *q = 0;
723          if (!file_is_excluded(ff_pkt, link)) {
724             rtn_stat = find_one_file(jcr, ff_pkt, handle_file, link, our_device, false);
725             if (ff_pkt->linked) {
726                ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
727             }
728          }
729       }
730       closedir(directory);
731       free(link);
732       free(entry);
733
734       /*
735        * Now that we have recursed through all the files in the
736        *  directory, we "save" the directory so that after all
737        *  the files are restored, this entry will serve to reset
738        *  the directory modes and dates.  Temp directory values
739        *  were used without this record.
740        */
741       handle_file(jcr, dir_ff_pkt, top_level);       /* handle directory entry */
742       if (ff_pkt->linked) {
743          ff_pkt->linked->FileIndex = dir_ff_pkt->FileIndex;
744       }
745       free_dir_ff_pkt(dir_ff_pkt);
746
747       if (ff_pkt->flags & FO_KEEPATIME) {
748          utime(fname, &restore_times);
749       }
750       ff_pkt->volhas_attrlist = volhas_attrlist;      /* Restore value in case it changed. */
751       return rtn_stat;
752    } /* end check for directory */
753
754    /*
755     * If it is explicitly mentioned (i.e. top_level) and is
756     *  a block device, we do a raw backup of it or if it is
757     *  a fifo, we simply read it.
758     */
759 #ifdef HAVE_FREEBSD_OS
760    /*
761     * On FreeBSD, all block devices are character devices, so
762     *   to be able to read a raw disk, we need the check for
763     *   a character device.
764     * crw-r----- 1 root  operator - 116, 0x00040002 Jun 9 19:32 /dev/ad0s3
765     * crw-r----- 1 root  operator - 116, 0x00040002 Jun 9 19:32 /dev/rad0s3
766     */
767    if (top_level && (S_ISBLK(ff_pkt->statp.st_mode) || S_ISCHR(ff_pkt->statp.st_mode))) {
768 #else
769    if (top_level && S_ISBLK(ff_pkt->statp.st_mode)) {
770 #endif
771       ff_pkt->type = FT_RAW;          /* raw partition */
772    } else if (top_level && S_ISFIFO(ff_pkt->statp.st_mode) &&
773               ff_pkt->flags & FO_READFIFO) {
774       ff_pkt->type = FT_FIFO;
775    } else {
776       /* The only remaining types are special (character, ...) files */
777       ff_pkt->type = FT_SPEC;
778    }
779    rtn_stat = handle_file(jcr, ff_pkt, top_level);
780    if (ff_pkt->linked) {
781       ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
782    }
783    return rtn_stat;
784 }
785
786 int term_find_one(FF_PKT *ff)
787 {
788    struct f_link *lp, *lc;
789    int count = 0;
790    int i;
791
792    
793    if (ff->linkhash == NULL) return 0;
794
795    for (i =0 ; i < LINK_HASHTABLE_SIZE; i ++) {
796    /* Free up list of hard linked files */
797        lp = ff->linkhash[i];
798        while (lp) {
799       lc = lp;
800       lp = lp->next;
801       if (lc) {
802          free(lc);
803          count++;
804       }
805    }
806        ff->linkhash[i] = NULL;
807    }
808    free(ff->linkhash);
809    ff->linkhash = NULL;
810    return count;
811 }