]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/find_one.c
kes This patch fixes the infinite loop when trying to increase the
[bacula/bacula] / bacula / src / findlib / find_one.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2007 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 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.
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     short linkcount;
64     uint32_t FileIndex;               /* Bacula FileIndex of this file */
65     char name[1];                     /* The name */
66 };
67
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)
72
73 static inline int LINKHASH(const struct stat &info)
74 {
75     int hash = info.st_dev;
76     unsigned long long i = info.st_ino;
77     hash ^= i;
78     i >>= 16;
79     hash ^= i;
80     i >>= 16;
81     hash ^= i;
82     i >>= 16;
83     hash ^= i;
84     return hash & LINK_HASHTABLE_MASK;
85 }
86
87 /*
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 
91  *   packet.
92  */
93 static FF_PKT *new_dir_ff_pkt(FF_PKT *ff_pkt)
94 {
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;
106    return dir_ff_pkt;
107 }
108
109 /*
110  * Free the temp directory ff_pkt
111  */
112 static void free_dir_ff_pkt(FF_PKT *dir_ff_pkt)
113 {
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);
119    }
120    if (dir_ff_pkt->link_save) {
121       free_pool_memory(dir_ff_pkt->link_save);
122    }
123    free(dir_ff_pkt);
124 }
125
126 /*
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.
129  */
130 static int accept_fstype(FF_PKT *ff, void *dummy) {
131    int i;
132    char fs[1000];
133    bool accept = true;
134
135    if (ff->fstypes.size()) {
136       accept = false;
137       if (!fstype(ff->fname, fs, sizeof(fs))) {
138          Dmsg1(50, "Cannot determine file system type for \"%s\"\n", ff->fname);
139       } else {
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);
143                accept = true;
144                break;
145             }
146             Dmsg3(200, "fstype %s for \"%s\" does not match %s\n", fs,
147                   ff->fname, ff->fstypes.get(i));
148          }
149       }
150    }
151    return accept;
152 }
153
154 /*
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.
157  */
158 static int accept_drivetype(FF_PKT *ff, void *dummy) {
159    int i;
160    char dt[100];
161    bool accept = true;
162
163    if (ff->drivetypes.size()) {
164       accept = false;
165       if (!drivetype(ff->fname, dt, sizeof(dt))) {
166          Dmsg1(50, "Cannot determine drive type for \"%s\"\n", ff->fname);
167       } else {
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);
171                accept = true;
172                break;
173             }
174             Dmsg3(200, "drive type %s for \"%s\" does not match %s\n", dt,
175                   ff->fname, ff->drivetypes.get(i));
176          }
177       }
178    }
179    return accept;
180 }
181
182 /*
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.
186  *
187  * On Mac OS X, this succesfully differentiates between HFS+ and UFS
188  * volumes, which makes me trust it is OK for others, too.
189  */
190 static bool volume_has_attrlist(const char *fname)
191 {
192 #ifdef HAVE_DARWIN_OS
193    struct statfs st;
194    struct volinfo_struct {
195       unsigned long length;               /* Mandatory field */
196       vol_capabilities_attr_t info;       /* Volume capabilities */
197    } vol;
198    struct attrlist attrList;
199
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)) {
208          return true;
209       }
210    }
211 #endif
212    return false;
213 }
214
215 /* check if a file have changed during backup and display an error */
216 bool has_file_changed(JCR *jcr, FF_PKT *ff_pkt)
217 {
218    struct stat statp;
219    Dmsg1(500, "has_file_changed fname=%s\n",ff_pkt->fname);
220
221    if (ff_pkt->type != FT_REG) { /* not a regular file */
222       return false;
223    }
224
225    if (lstat(ff_pkt->fname, &statp) != 0) {
226       berrno be;
227       Jmsg(jcr, M_WARNING, 0, 
228            _("Cannot stat file %s: ERR=%s\n"),ff_pkt->fname,be.bstrerror());
229       return true;
230    }
231
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);
235       return true;
236    }
237
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);
241       return true;
242    }
243   
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);
247       return true;
248    }
249
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);
254       return true;
255    }
256
257    return false;
258 }
259
260 /*
261  * Find a single file.
262  * handle_file is the callback for handling the file.
263  * p is the filename
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.
267  */
268 int
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)
272 {
273    struct utimbuf restore_times;
274    int rtn_stat;
275    int len;
276
277    ff_pkt->fname = ff_pkt->link = fname;
278
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);
284    }
285
286    Dmsg1(300, "File ----: %s\n", fname);
287
288    /* Save current times of this directory in case we need to
289     * reset them because the user doesn't want them changed.
290     */
291    restore_times.actime = ff_pkt->statp.st_atime;
292    restore_times.modtime = ff_pkt->statp.st_mtime;
293
294    /*
295     * We check for allowed fstypes and drivetypes at top_level and fstype change (below).
296     */
297    if (top_level) {
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);
302          }
303
304          char fs[100];
305
306          if (!fstype(ff_pkt->fname, fs, sizeof(fs))) {
307              bstrncpy(fs, "unknown", sizeof(fs));
308          }
309
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 */
312       }
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);
317          }
318
319          char dt[100];
320
321          if (!drivetype(ff_pkt->fname, dt, sizeof(dt))) {
322              bstrncpy(dt, "unknown", sizeof(dt));
323          }
324
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 */
327       }
328       ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
329    }
330
331    /*
332     * If this is an Incremental backup, see if file was modified
333     * since our last "save_time", presumably the last Full save
334     * or Incremental.
335     */
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);
345       }
346    }
347
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);
362        }
363    }
364 #endif
365
366    ff_pkt->LinkFI = 0;
367    /*
368     * Handle hard linked files
369     *
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
372     *  up only once.
373     */
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))) {
381
382        struct f_link *lp;
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 *));
386        }
387        const int linkhash = LINKHASH(ff_pkt->statp);
388
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 */
396              }
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);
401          }
402
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 */
412    } else {
413       ff_pkt->linked = NULL;
414    }
415
416    /* This is not a link to a previously dumped file, so dump it.  */
417    if (S_ISREG(ff_pkt->statp.st_mode)) {
418       boffset_t sizeleft;
419
420       sizeleft = ff_pkt->statp.st_size;
421
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;
427       } else {
428          ff_pkt->type = FT_REG;
429       }
430       rtn_stat = handle_file(ff_pkt, pkt, top_level);
431       if (ff_pkt->linked) {
432          ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
433       }
434       if (ff_pkt->flags & FO_KEEPATIME) {
435          utime(fname, &restore_times);
436       }       
437       return rtn_stat;
438
439
440    } else if (S_ISLNK(ff_pkt->statp.st_mode)) {  /* soft link */
441       int size;
442       char *buffer = (char *)alloca(path_max + name_max + 102);
443
444       size = readlink(fname, buffer, path_max + name_max + 101);
445       if (size < 0) {
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;
452          }
453          return rtn_stat;
454       }
455       buffer[size] = 0;
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;
461       }
462       return rtn_stat;
463
464    } else if (S_ISDIR(ff_pkt->statp.st_mode)) {
465       DIR *directory;
466       struct dirent *entry, *result;
467       char *link;
468       int link_len;
469       int len;
470       int status;
471       dev_t our_device = ff_pkt->statp.st_dev;
472       bool recurse = true;
473       bool volhas_attrlist = ff_pkt->volhas_attrlist;    /* Remember this if we recurse */
474
475       /*
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.
479        */
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;
488             }
489             return rtn_stat;
490          }
491       }
492
493       /* Build a canonical directory name with a trailing slash in link var */
494       len = strlen(fname);
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]))
500         len--;
501       link[len++] = '/';             /* add back one */
502       link[len] = 0;
503
504       ff_pkt->link = link;
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;
511       } else {
512          ff_pkt->type = FT_DIRBEGIN;
513       }
514       /* We have set st_rdev to 1 if it is a reparse point, otherwise 0 */
515       if (have_win32_api() && ff_pkt->statp.st_rdev) {
516          ff_pkt->type = FT_REPARSE;
517       }
518       /*
519        * Note, we return the directory to the calling program (handle_file)
520        * when we first see the directory (FT_DIRBEGIN.
521        * This allows the program to apply matches and make a
522        * choice whether or not to accept it.  If it is accepted, we
523        * do not immediately save it, but do so only after everything
524        * in the directory is seen (i.e. the FT_DIREND).
525        */
526       rtn_stat = handle_file(ff_pkt, pkt, top_level);
527       if (rtn_stat < 1 || ff_pkt->type == FT_REPARSE) {   /* ignore or error status */
528          free(link);
529          return rtn_stat;
530       }
531       /* Done with DIRBEGIN, next call will be DIREND */
532       if (ff_pkt->type == FT_DIRBEGIN) {
533          ff_pkt->type = FT_DIREND;
534       }
535
536       /*
537        * Create a temporary ff packet for this directory
538        *   entry, and defer handling the directory until
539        *   we have recursed into it.  This saves the
540        *   directory after all files have been processed, and
541        *   during the restore, the directory permissions will
542        *   be reset after all the files have been restored.
543        */
544       Dmsg1(300, "Create temp ff packet for dir: %s\n", ff_pkt->fname);
545       FF_PKT *dir_ff_pkt = new_dir_ff_pkt(ff_pkt);
546
547       /*
548        * Do not descend into subdirectories (recurse) if the
549        * user has turned it off for this directory.
550        *
551        * If we are crossing file systems, we are either not allowed
552        * to cross, or we may be restricted by a list of permitted
553        * file systems.
554        */
555       if (!top_level && ff_pkt->flags & FO_NO_RECURSION) {
556          ff_pkt->type = FT_NORECURSE;
557          recurse = false;
558       } else if (!top_level && parent_device != ff_pkt->statp.st_dev) {
559          if(!(ff_pkt->flags & FO_MULTIFS)) {
560             ff_pkt->type = FT_NOFSCHG;
561             recurse = false;
562          } else if (!accept_fstype(ff_pkt, NULL)) {
563             ff_pkt->type = FT_INVALIDFS;
564             recurse = false;
565          } else {
566             ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
567          }
568       }
569       /* If not recursing, just backup dir and return */
570       if (!recurse) {
571          rtn_stat = handle_file(ff_pkt, pkt, top_level);
572          if (ff_pkt->linked) {
573             ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
574          }
575          free(link);
576          free_dir_ff_pkt(dir_ff_pkt);
577          ff_pkt->link = ff_pkt->fname;     /* reset "link" */
578          if (ff_pkt->flags & FO_KEEPATIME) {
579             utime(fname, &restore_times);
580          }
581          return rtn_stat;
582       }
583
584       ff_pkt->link = ff_pkt->fname;     /* reset "link" */
585
586       /*
587        * Descend into or "recurse" into the directory to read
588        *   all the files in it.
589        */
590       errno = 0;
591       if ((directory = opendir(fname)) == NULL) {
592          ff_pkt->type = FT_NOOPEN;
593          ff_pkt->ff_errno = errno;
594          rtn_stat = handle_file(ff_pkt, pkt, top_level);
595          if (ff_pkt->linked) {
596             ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
597          }
598          free(link);
599          free_dir_ff_pkt(dir_ff_pkt);
600          return rtn_stat;
601       }
602
603       /*
604        * Process all files in this directory entry (recursing).
605        *    This would possibly run faster if we chdir to the directory
606        *    before traversing it.
607        */
608       rtn_stat = 1;
609       entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 100);
610       for ( ; !job_canceled(jcr); ) {
611          char *p, *q;
612          int i;
613
614          status  = readdir_r(directory, entry, &result);
615          if (status != 0 || result == NULL) {
616 //          Dmsg2(99, "readdir returned stat=%d result=0x%x\n",
617 //             status, (long)result);
618             break;
619          }
620          ASSERT(name_max+1 > (int)sizeof(struct dirent) + (int)NAMELEN(entry));
621          p = entry->d_name;
622          /* Skip `.', `..', and excluded file names.  */
623          if (p[0] == '\0' || (p[0] == '.' && (p[1] == '\0' ||
624              (p[1] == '.' && p[2] == '\0')))) {
625             continue;
626          }
627
628          if ((int)NAMELEN(entry) + len >= link_len) {
629              link_len = len + NAMELEN(entry) + 1;
630              link = (char *)brealloc(link, link_len + 1);
631          }
632          q = link + len;
633          for (i=0; i < (int)NAMELEN(entry); i++) {
634             *q++ = *p++;
635          }
636          *q = 0;
637          if (!file_is_excluded(ff_pkt, link)) {
638             rtn_stat = find_one_file(jcr, ff_pkt, handle_file, pkt, link, our_device, false);
639             if (ff_pkt->linked) {
640                ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
641             }
642          }
643       }
644       closedir(directory);
645       free(link);
646       free(entry);
647
648       /*
649        * Now that we have recursed through all the files in the
650        *  directory, we "save" the directory so that after all
651        *  the files are restored, this entry will serve to reset
652        *  the directory modes and dates.  Temp directory values
653        *  were used without this record.
654        */
655       handle_file(dir_ff_pkt, pkt, top_level);       /* handle directory entry */
656       if (ff_pkt->linked) {
657          ff_pkt->linked->FileIndex = dir_ff_pkt->FileIndex;
658       }
659       free_dir_ff_pkt(dir_ff_pkt);
660
661       if (ff_pkt->flags & FO_KEEPATIME) {
662          utime(fname, &restore_times);
663       }
664       ff_pkt->volhas_attrlist = volhas_attrlist;      /* Restore value in case it changed. */
665       return rtn_stat;
666    } /* end check for directory */
667
668    /*
669     * If it is explicitly mentioned (i.e. top_level) and is
670     *  a block device, we do a raw backup of it or if it is
671     *  a fifo, we simply read it.
672     */
673 #ifdef HAVE_FREEBSD_OS
674    /*
675     * On FreeBSD, all block devices are character devices, so
676     *   to be able to read a raw disk, we need the check for
677     *   a character device.
678     * crw-r----- 1 root  operator - 116, 0x00040002 Jun 9 19:32 /dev/ad0s3
679     * crw-r----- 1 root  operator - 116, 0x00040002 Jun 9 19:32 /dev/rad0s3
680     */
681    if (top_level && (S_ISBLK(ff_pkt->statp.st_mode) || S_ISCHR(ff_pkt->statp.st_mode))) {
682 #else
683    if (top_level && S_ISBLK(ff_pkt->statp.st_mode)) {
684 #endif
685       ff_pkt->type = FT_RAW;          /* raw partition */
686    } else if (top_level && S_ISFIFO(ff_pkt->statp.st_mode) &&
687               ff_pkt->flags & FO_READFIFO) {
688       ff_pkt->type = FT_FIFO;
689    } else {
690       /* The only remaining types are special (character, ...) files */
691       ff_pkt->type = FT_SPEC;
692    }
693    rtn_stat = handle_file(ff_pkt, pkt, top_level);
694    if (ff_pkt->linked) {
695       ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
696    }
697    return rtn_stat;
698 }
699
700 int term_find_one(FF_PKT *ff)
701 {
702    struct f_link *lp, *lc;
703    int count = 0;
704    int i;
705
706    
707    if (ff->linkhash == NULL) return 0;
708
709    for (i =0 ; i < LINK_HASHTABLE_SIZE; i ++) {
710    /* Free up list of hard linked files */
711        lp = ff->linkhash[i];
712        while (lp) {
713       lc = lp;
714       lp = lp->next;
715       if (lc) {
716          free(lc);
717          count++;
718       }
719    }
720        ff->linkhash[i] = NULL;
721    }
722    free(ff->linkhash);
723    ff->linkhash = NULL;
724    return count;
725 }