]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/find_one.c
d6c25fbdee2ad89290ce2a770c7798a8b794abbc
[bacula/bacula] / bacula / src / findlib / find_one.c
1 /*
2
3    This file is based on GNU TAR source code. Except for a few key
4    ideas, it has been entirely rewritten for Bacula.
5
6       Kern Sibbald, MM
7
8    Thanks to the TAR programmers.
9
10      Version $Id$
11
12  */
13 /*
14    Bacula® - The Network Backup Solution
15
16    Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
17
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.
24
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.
29
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
33    02110-1301, USA.
34
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.
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 static void free_dir_ff_pkt(FF_PKT *dir_ff_pkt)
88 {
89    free(dir_ff_pkt->fname);
90    free(dir_ff_pkt->link);
91    free_pool_memory(dir_ff_pkt->sys_fname);
92    free(dir_ff_pkt);
93 }
94
95 /*
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.
98  */
99 static int accept_fstype(FF_PKT *ff, void *dummy) {
100    int i;
101    char fs[1000];
102    bool accept = true;
103
104    if (ff->fstypes.size()) {
105       accept = false;
106       if (!fstype(ff->fname, fs, sizeof(fs))) {
107          Dmsg1(50, "Cannot determine file system type for \"%s\"\n", ff->fname);
108       } else {
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);
112                accept = true;
113                break;
114             }
115             Dmsg3(200, "fstype %s for \"%s\" does not match %s\n", fs,
116                   ff->fname, ff->fstypes.get(i));
117          }
118       }
119    }
120    return accept;
121 }
122
123 /*
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.
126  */
127 static int accept_drivetype(FF_PKT *ff, void *dummy) {
128    int i;
129    char dt[100];
130    bool accept = true;
131
132    if (ff->drivetypes.size()) {
133       accept = false;
134       if (!drivetype(ff->fname, dt, sizeof(dt))) {
135          Dmsg1(50, "Cannot determine drive type for \"%s\"\n", ff->fname);
136       } else {
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);
140                accept = true;
141                break;
142             }
143             Dmsg3(200, "drive type %s for \"%s\" does not match %s\n", dt,
144                   ff->fname, ff->drivetypes.get(i));
145          }
146       }
147    }
148    return accept;
149 }
150
151 /*
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.
155  *
156  * On Mac OS X, this succesfully differentiates between HFS+ and UFS
157  * volumes, which makes me trust it is OK for others, too.
158  */
159 static bool volume_has_attrlist(const char *fname)
160 {
161 #ifdef HAVE_DARWIN_OS
162    struct statfs st;
163    struct volinfo_struct {
164       unsigned long length;               /* Mandatory field */
165       vol_capabilities_attr_t info;       /* Volume capabilities */
166    } vol;
167    struct attrlist attrList;
168
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)) {
177          return true;
178       }
179    }
180 #endif
181    return false;
182 }
183
184 /* check if a file have changed during backup and display an error */
185 bool has_file_changed(JCR *jcr, FF_PKT *ff_pkt)
186 {
187    struct stat statp;
188    Dmsg1(500, "has_file_changed fname=%s\n",ff_pkt->fname);
189
190    if (ff_pkt->type != FT_REG) { /* not a regular file */
191       return false;
192    }
193
194    if (lstat(ff_pkt->fname, &statp) != 0) {
195       berrno be;
196       Jmsg(jcr, M_WARNING, 0, 
197            _("Cannot stat file %s: ERR=%s\n"),ff_pkt->fname,be.strerror());
198       return true;
199    }
200
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);
204       return true;
205    }
206
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);
210       return true;
211    }
212   
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);
216       return true;
217    }
218
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);
223       return true;
224    }
225
226    return false;
227 }
228
229 /*
230  * Find a single file.
231  * handle_file is the callback for handling the file.
232  * p is the filename
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.
236  */
237 int
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)
241 {
242    struct utimbuf restore_times;
243    int rtn_stat;
244    int len;
245
246    ff_pkt->fname = ff_pkt->link = fname;
247
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);
253    }
254
255    Dmsg1(300, "File ----: %s\n", fname);
256
257    /* Save current times of this directory in case we need to
258     * reset them because the user doesn't want them changed.
259     */
260    restore_times.actime = ff_pkt->statp.st_atime;
261    restore_times.modtime = ff_pkt->statp.st_mtime;
262
263    /*
264     * We check for allowed fstypes and drivetypes at top_level and fstype change (below).
265     */
266    if (top_level) {
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);
271          }
272
273          char fs[100];
274
275          if (!fstype(ff_pkt->fname, fs, sizeof(fs))) {
276              bstrncpy(fs, "unknown", sizeof(fs));
277          }
278
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 */
281       }
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);
286          }
287
288          char dt[100];
289
290          if (!drivetype(ff_pkt->fname, dt, sizeof(dt))) {
291              bstrncpy(dt, "unknown", sizeof(dt));
292          }
293
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 */
296       }
297       ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
298    }
299
300    /*
301     * If this is an Incremental backup, see if file was modified
302     * since our last "save_time", presumably the last Full save
303     * or Incremental.
304     */
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);
314       }
315    }
316
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);
331        }
332    }
333 #endif
334
335 /* ***FIXME*** implement this */
336 #if xxxxxxx
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);
341    }
342 #endif
343    ff_pkt->LinkFI = 0;
344    /*
345     * Handle hard linked files
346     *
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
349     *  up only once.
350     */
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))) {
358
359        struct f_link *lp;
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 *));
363        }
364        const int linkhash = LINKHASH(ff_pkt->statp);
365
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 */
373              }
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);
378          }
379
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 */
389    } else {
390       ff_pkt->linked = NULL;
391    }
392
393    /* This is not a link to a previously dumped file, so dump it.  */
394    if (S_ISREG(ff_pkt->statp.st_mode)) {
395       boffset_t sizeleft;
396
397       sizeleft = ff_pkt->statp.st_size;
398
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;
404       } else {
405          ff_pkt->type = FT_REG;
406       }
407       rtn_stat = handle_file(ff_pkt, pkt, top_level);
408       if (ff_pkt->linked) {
409          ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
410       }
411       if (ff_pkt->flags & FO_KEEPATIME) {
412          utime(fname, &restore_times);
413       }       
414       return rtn_stat;
415
416
417    } else if (S_ISLNK(ff_pkt->statp.st_mode)) {  /* soft link */
418       int size;
419       char *buffer = (char *)alloca(path_max + name_max + 102);
420
421       size = readlink(fname, buffer, path_max + name_max + 101);
422       if (size < 0) {
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;
429          }
430          return rtn_stat;
431       }
432       buffer[size] = 0;
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;
438       }
439       return rtn_stat;
440
441    } else if (S_ISDIR(ff_pkt->statp.st_mode)) {
442       DIR *directory;
443       struct dirent *entry, *result;
444       char *link;
445       int link_len;
446       int len;
447       int status;
448       dev_t our_device = ff_pkt->statp.st_dev;
449       bool recurse = true;
450       bool volhas_attrlist = ff_pkt->volhas_attrlist;    /* Remember this if we recurse */
451
452       /*
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.
456        */
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;
465             }
466             return rtn_stat;
467          }
468       }
469
470       /* Build a canonical directory name with a trailing slash in link var */
471       len = strlen(fname);
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]))
477         len--;
478       link[len++] = '/';             /* add back one */
479       link[len] = 0;
480
481       ff_pkt->link = link;
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;
488       } else {
489          ff_pkt->type = FT_DIRBEGIN;
490       }
491       /*
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).
498        */
499       rtn_stat = handle_file(ff_pkt, pkt, top_level);
500       if (rtn_stat < 1) {             /* ignore or error status */
501          free(link);
502          return rtn_stat;
503       }
504       /* Done with DIRBEGIN, next call will be DIREND */
505       if (ff_pkt->type == FT_DIRBEGIN) {
506          ff_pkt->type = FT_DIREND;
507       }
508
509       /*
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.
516        */
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;
527
528       /*
529        * Do not descend into subdirectories (recurse) if the
530        * user has turned it off for this directory.
531        *
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
534        * file systems.
535        */
536       if (!top_level && ff_pkt->flags & FO_NO_RECURSION) {
537          ff_pkt->type = FT_NORECURSE;
538          recurse = false;
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;
542             recurse = false;
543          } else if (!accept_fstype(ff_pkt, NULL)) {
544             ff_pkt->type = FT_INVALIDFS;
545             recurse = false;
546          } else {
547             ff_pkt->volhas_attrlist = volume_has_attrlist(fname);
548          }
549       }
550       /* If not recursing, just backup dir and return */
551       if (!recurse) {
552          rtn_stat = handle_file(ff_pkt, pkt, top_level);
553          if (ff_pkt->linked) {
554             ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
555          }
556          free(link);
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);
561          }
562          return rtn_stat;
563       }
564
565       ff_pkt->link = ff_pkt->fname;     /* reset "link" */
566
567       /*
568        * Descend into or "recurse" into the directory to read
569        *   all the files in it.
570        */
571       errno = 0;
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;
578          }
579          free(link);
580          free_dir_ff_pkt(dir_ff_pkt);
581          return rtn_stat;
582       }
583
584       /*
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.
588        */
589       rtn_stat = 1;
590       entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 100);
591       for ( ; !job_canceled(jcr); ) {
592          char *p, *q;
593          int i;
594
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);
599             break;
600          }
601          ASSERT(name_max+1 > (int)sizeof(struct dirent) + (int)NAMELEN(entry));
602          p = entry->d_name;
603          /* Skip `.', `..', and excluded file names.  */
604          if (p[0] == '\0' || (p[0] == '.' && (p[1] == '\0' ||
605              (p[1] == '.' && p[2] == '\0')))) {
606             continue;
607          }
608
609          if ((int)NAMELEN(entry) + len >= link_len) {
610              link_len = len + NAMELEN(entry) + 1;
611              link = (char *)brealloc(link, link_len + 1);
612          }
613          q = link + len;
614          for (i=0; i < (int)NAMELEN(entry); i++) {
615             *q++ = *p++;
616          }
617          *q = 0;
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;
622             }
623          }
624       }
625       closedir(directory);
626       free(link);
627       free(entry);
628
629       /*
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.
635        */
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;
639       }
640       free_dir_ff_pkt(dir_ff_pkt);
641
642       if (ff_pkt->flags & FO_KEEPATIME) {
643          utime(fname, &restore_times);
644       }
645       ff_pkt->volhas_attrlist = volhas_attrlist;      /* Restore value in case it changed. */
646       return rtn_stat;
647    } /* end check for directory */
648
649    /*
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.
653     */
654 #ifdef HAVE_FREEBSD_OS
655    /*
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
661     */
662    if (top_level && (S_ISBLK(ff_pkt->statp.st_mode) || S_ISCHR(ff_pkt->statp.st_mode))) {
663 #else
664    if (top_level && S_ISBLK(ff_pkt->statp.st_mode)) {
665 #endif
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;
670    } else {
671       /* The only remaining types are special (character, ...) files */
672       ff_pkt->type = FT_SPEC;
673    }
674    rtn_stat = handle_file(ff_pkt, pkt, top_level);
675    if (ff_pkt->linked) {
676       ff_pkt->linked->FileIndex = ff_pkt->FileIndex;
677    }
678    return rtn_stat;
679 }
680
681 int term_find_one(FF_PKT *ff)
682 {
683    struct f_link *lp, *lc;
684    int count = 0;
685    int i;
686
687    
688    if (ff->linkhash == NULL) return 0;
689
690    for (i =0 ; i < LINK_HASHTABLE_SIZE; i ++) {
691    /* Free up list of hard linked files */
692        lp = ff->linkhash[i];
693        while (lp) {
694       lc = lp;
695       lp = lp->next;
696       if (lc) {
697          free(lc);
698          count++;
699       }
700    }
701        ff->linkhash[i] = NULL;
702    }
703    free(ff->linkhash);
704    ff->linkhash = NULL;
705    return count;
706 }