]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/match_bsr.c
kes Implement bsr block level checking for disk files. However,
[bacula/bacula] / bacula / src / stored / match_bsr.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2002-2008 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  *   Match Bootstrap Records (used for restores) against
30  *     Volume Records
31  *
32  *     Kern Sibbald, June MMII
33  *
34  *   Version $Id$
35  */
36
37 /*
38  * ***FIXME***
39  * find_smallest_volfile needs to be fixed to only look at items that
40  *   are not marked as done.  Otherwise, it can find a bsr
41  *   that has already been consumed, and this will cause the
42  *   bsr to be used, thus we may seek back and re-read the
43  *   same records, causing an error.  This deficiency must
44  *   be fixed.  For the moment, it has been kludged in 
45  *   read_record.c to avoid seeking back if find_next_bsr
46  *   returns a bsr pointing to a smaller address (file/block).
47  *
48  * Also for efficiency, once a bsr is done, it really should be
49  *   delinked from the bsr chain.  This will avoid the above 
50  *   problem and make traversal of the bsr chain more efficient.
51  *
52  *   To be done ...
53  */
54
55 #include "bacula.h"
56 #include "stored.h"
57 #ifdef HAVE_FNMATCH
58 #include <fnmatch.h>
59 #else
60 #include "lib/fnmatch.h"
61 #endif
62
63 const int dbglevel = 500;
64
65 /* Forward references */
66 static int match_volume(BSR *bsr, BSR_VOLUME *volume, VOLUME_LABEL *volrec, bool done);
67 static int match_sesstime(BSR *bsr, BSR_SESSTIME *sesstime, DEV_RECORD *rec, bool done);
68 static int match_sessid(BSR *bsr, BSR_SESSID *sessid, DEV_RECORD *rec);
69 static int match_client(BSR *bsr, BSR_CLIENT *client, SESSION_LABEL *sessrec, bool done);
70 static int match_job(BSR *bsr, BSR_JOB *job, SESSION_LABEL *sessrec, bool done);
71 static int match_job_type(BSR *bsr, BSR_JOBTYPE *job_type, SESSION_LABEL *sessrec, bool done);
72 static int match_job_level(BSR *bsr, BSR_JOBLEVEL *job_level, SESSION_LABEL *sessrec, bool done);
73 static int match_jobid(BSR *bsr, BSR_JOBID *jobid, SESSION_LABEL *sessrec, bool done);
74 static int match_findex(BSR *bsr, BSR_FINDEX *findex, DEV_RECORD *rec, bool done);
75 static int match_volfile(BSR *bsr, BSR_VOLFILE *volfile, DEV_RECORD *rec, bool done);
76 static int match_volblock(BSR *bsr, BSR_VOLBLOCK *volblock, DEV_RECORD *rec, bool done);
77 static int match_stream(BSR *bsr, BSR_STREAM *stream, DEV_RECORD *rec, bool done);
78 static int match_all(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec, SESSION_LABEL *sessrec, bool done, JCR *jcr);
79 static int match_block_sesstime(BSR *bsr, BSR_SESSTIME *sesstime, DEV_BLOCK *block);
80 static int match_block_sessid(BSR *bsr, BSR_SESSID *sessid, DEV_BLOCK *block);
81 static BSR *find_smallest_volfile(BSR *fbsr, BSR *bsr);
82
83
84 /*********************************************************************
85  *
86  *  If possible, position the archive device (tape) to read the
87  *  next block.
88  */
89 void position_bsr_block(BSR *bsr, DEV_BLOCK *block)
90 {
91    /* To be implemented */
92 }
93
94 /*********************************************************************
95  *
96  *  Do fast block rejection based on bootstrap records.
97  *    use_fast_rejection will be set if we have VolSessionId and VolSessTime
98  *    in each record. When BlockVer is >= 2, we have those in the block header
99  *    so can do fast rejection.
100  *
101  *   returns:  1 if block may contain valid records
102  *             0 if block may be skipped (i.e. it contains no records of
103  *                  that can match the bsr).
104  *
105  */
106 int match_bsr_block(BSR *bsr, DEV_BLOCK *block)
107 {
108    if (!bsr || !bsr->use_fast_rejection || (block->BlockVer < 2)) {
109       return 1;                       /* cannot fast reject */
110    }
111
112    for ( ; bsr; bsr=bsr->next) {
113       if (!match_block_sesstime(bsr, bsr->sesstime, block)) {
114          continue;
115       }
116       if (!match_block_sessid(bsr, bsr->sessid, block)) {
117          continue;
118       }
119       return 1;
120    }
121    return 0;
122 }
123
124 static int match_block_sesstime(BSR *bsr, BSR_SESSTIME *sesstime, DEV_BLOCK *block)
125 {
126    if (!sesstime) {
127       return 1;                       /* no specification matches all */
128    }
129    if (sesstime->sesstime == block->VolSessionTime) {
130       return 1;
131    }
132    if (sesstime->next) {
133       return match_block_sesstime(bsr, sesstime->next, block);
134    }
135    return 0;
136 }
137
138 static int match_block_sessid(BSR *bsr, BSR_SESSID *sessid, DEV_BLOCK *block)
139 {
140    if (!sessid) {
141       return 1;                       /* no specification matches all */
142    }
143    if (sessid->sessid <= block->VolSessionId && sessid->sessid2 >= block->VolSessionId) {
144       return 1;
145    }
146    if (sessid->next) {
147       return match_block_sessid(bsr, sessid->next, block);
148    }
149    return 0;
150 }
151
152 static int match_fileregex(BSR *bsr, DEV_RECORD *rec, JCR *jcr)
153 {
154    if (bsr->fileregex_re == NULL)
155       return 1;
156
157    if (bsr->attr == NULL)
158       bsr->attr = new_attr(jcr);
159
160    /* The code breaks if the first record associated with a file is
161     * not of this type
162     */
163    if (rec->Stream == STREAM_UNIX_ATTRIBUTES ||
164        rec->Stream == STREAM_UNIX_ATTRIBUTES_EX) {
165       bsr->skip_file = false;
166       if (unpack_attributes_record(jcr, rec->Stream, rec->data, bsr->attr)) {
167          if (regexec(bsr->fileregex_re, bsr->attr->fname, 0, NULL, 0) == 0) {
168             Dmsg2(dbglevel, "Matched pattern, fname=%s FI=%d\n",
169                   bsr->attr->fname, rec->FileIndex);
170          } else {
171             Dmsg2(dbglevel, "Didn't match, skipping fname=%s FI=%d\n",
172                   bsr->attr->fname, rec->FileIndex);
173             bsr->skip_file = true;
174          }
175       }
176    }
177    return 1;
178 }
179
180 /*********************************************************************
181  *
182  *      Match Bootstrap records
183  *        returns  1 on match
184  *        returns  0 no match and reposition is set if we should
185  *                      reposition the tape
186  *       returns -1 no additional matches possible
187  */
188 int match_bsr(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec, SESSION_LABEL *sessrec, JCR *jcr)
189 {
190    int stat;
191
192    /*
193     * The bsr->reposition flag is set any time a bsr is done.
194     *   In this case, we can probably reposition the
195     *   tape to the next available bsr position.
196     */
197    if (bsr) {
198       bsr->reposition = false;
199       stat = match_all(bsr, rec, volrec, sessrec, true, jcr);
200       /*
201        * Note, bsr->reposition is set by match_all when
202        *  a bsr is done. We turn it off if a match was
203        *  found or if we cannot use positioning
204        */
205       if (stat != 0 || !bsr->use_positioning) {
206          bsr->reposition = false;
207       }
208    } else {
209       stat = 1;                       /* no bsr => match all */
210    }
211    return stat;
212 }
213
214 /*
215  * Find the next bsr that applies to the current tape.
216  *   It is the one with the smallest VolFile position.
217  */
218 BSR *find_next_bsr(BSR *root_bsr, DEVICE *dev)
219 {
220    BSR *bsr;
221    BSR *found_bsr = NULL;
222
223    /* Do tape/disk seeking only if CAP_POSITIONBLOCKS is on */
224    if (!root_bsr) {
225       Dmsg0(dbglevel, "NULL root bsr pointer passed to find_next_bsr.\n");
226       return NULL;
227    }
228    if (!root_bsr->use_positioning ||
229        !root_bsr->reposition || !dev->has_cap(CAP_POSITIONBLOCKS)) {
230       Dmsg2(dbglevel, "No nxt_bsr use_pos=%d repos=%d\n", root_bsr->use_positioning, root_bsr->reposition);
231       return NULL;
232    }
233    Dmsg2(dbglevel, "use_pos=%d repos=%d\n", root_bsr->use_positioning, root_bsr->reposition);
234    root_bsr->mount_next_volume = false;
235    /* Walk through all bsrs to find the next one to use => smallest file,block */
236    for (bsr=root_bsr; bsr; bsr=bsr->next) {
237       if (bsr->done || !match_volume(bsr, bsr->volume, &dev->VolHdr, 1)) {
238          continue;
239       }
240       if (found_bsr == NULL) {
241          found_bsr = bsr;
242       } else {
243          found_bsr = find_smallest_volfile(found_bsr, bsr);
244       }
245    }
246    /*
247     * If we get to this point and found no bsr, it means
248     *  that any additional bsr's must apply to the next
249     *  tape, so set a flag.
250     */
251    if (found_bsr == NULL) {
252       root_bsr->mount_next_volume = true;
253    }
254    return found_bsr;
255 }
256
257 /*
258  * ***FIXME***
259  * This routine needs to be fixed to only look at items that
260  *   are not marked as done.  Otherwise, it can find a bsr
261  *   that has already been consumed, and this will cause the
262  *   bsr to be used, thus we may seek back and re-read the
263  *   same records, causing an error.  This deficiency must
264  *   be fixed.  For the moment, it has been kludged in 
265  *   read_record.c to avoid seeking back if find_next_bsr
266  *   returns a bsr pointing to a smaller address (file/block).
267  */
268 static BSR *find_smallest_volfile(BSR *found_bsr, BSR *bsr)
269 {
270    BSR *return_bsr = found_bsr;
271    BSR_VOLFILE *vf;
272    BSR_VOLBLOCK *vb;
273    uint32_t found_bsr_sfile, bsr_sfile;
274    uint32_t found_bsr_sblock, bsr_sblock;
275
276    /* Find the smallest file in the found_bsr */
277    vf = found_bsr->volfile;
278    found_bsr_sfile = vf->sfile;
279    while ( (vf=vf->next) ) {
280       if (vf->sfile < found_bsr_sfile) {
281          found_bsr_sfile = vf->sfile;
282       }
283    }
284
285    /* Find the smallest file in the bsr */
286    vf = bsr->volfile;
287    bsr_sfile = vf->sfile;
288    while ( (vf=vf->next) ) {
289       if (vf->sfile < bsr_sfile) {
290          bsr_sfile = vf->sfile;
291       }
292    }
293     
294    /* if the bsr file is less than the found_bsr file, return bsr */
295    if (found_bsr_sfile > bsr_sfile) {
296       return_bsr = bsr;
297    } else if (found_bsr_sfile == bsr_sfile) {
298       /* Files are equal */
299       /* find smallest block in found_bsr */
300       vb = found_bsr->volblock;
301       found_bsr_sblock = vb->sblock;
302       while ( (vb=vb->next) ) {
303          if (vb->sblock < found_bsr_sblock) {
304             found_bsr_sblock = vb->sblock;
305          }
306       }
307       /* Find smallest block in bsr */
308       vb = bsr->volblock;
309       bsr_sblock = vb->sblock;
310       while ( (vb=vb->next) ) {
311          if (vb->sblock < bsr_sblock) {
312             bsr_sblock = vb->sblock;
313          }
314       }
315       /* Compare and return the smallest */
316       if (found_bsr_sblock > bsr_sblock) {
317          return_bsr = bsr;
318       }
319    }
320    return return_bsr;
321 }
322
323 /*
324  * Called after the signature record so that
325  *   we can see if the current bsr has been
326  *   fully processed (i.e. is done).
327  *  The bsr argument is not used, but is included
328  *    for consistency with the other match calls.
329  *
330  * Returns: true if we should reposition
331  *        : false otherwise.
332  */
333 bool is_this_bsr_done(BSR *bsr, DEV_RECORD *rec)
334 {
335    BSR *rbsr = rec->bsr;
336    Dmsg1(dbglevel, "match_set %d\n", rbsr != NULL);
337    if (!rbsr) {
338       return false;
339    }
340    rec->bsr = NULL;
341    rbsr->found++;
342    if (rbsr->count && rbsr->found >= rbsr->count) {
343       rbsr->done = true;
344       rbsr->root->reposition = true;
345       Dmsg2(dbglevel, "is_end_this_bsr set reposition=1 count=%d found=%d\n",
346          rbsr->count, rbsr->found);
347       return true;
348    }
349    return false;
350 }
351
352 /*
353  * Match all the components of current record
354  *   returns  1 on match
355  *   returns  0 no match
356  *   returns -1 no additional matches possible
357  */
358 static int match_all(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec,
359                      SESSION_LABEL *sessrec, bool done, JCR *jcr)
360 {
361    Dmsg0(050, "Enter match_all\n");
362    if (bsr->done) {
363 //    Dmsg0(dbglevel, "bsr->done set\n");
364       goto no_match;
365    }
366    if (!match_volume(bsr, bsr->volume, volrec, 1)) {
367       Dmsg2(dbglevel, "bsr fail bsr_vol=%s != rec read_vol=%s\n", bsr->volume->VolumeName,
368             volrec->VolumeName);
369       goto no_match;
370    }
371    Dmsg2(dbglevel, "OK bsr match bsr_vol=%s read_vol=%s\n", bsr->volume->VolumeName,
372             volrec->VolumeName);
373
374    if (!match_volfile(bsr, bsr->volfile, rec, 1)) {
375       Dmsg3(dbglevel, "Fail on file=%d. bsr=%d,%d\n", 
376          rec->File, bsr->volfile->sfile, bsr->volfile->efile);
377       goto no_match;
378    }
379    Dmsg3(dbglevel, "OK bsr file=%d. bsr=%d,%d\n", 
380          rec->File, bsr->volfile->sfile, bsr->volfile->efile);
381
382    if (!match_volblock(bsr, bsr->volblock, rec, 1)) {
383       Dmsg3(dbglevel, "Fail on Block=%d. bsr=%d,%d\n", 
384          rec->Block, bsr->volblock->sblock, bsr->volblock->eblock);
385       goto no_match;
386    }
387    Dmsg3(dbglevel, "OK bsr Block=%d. bsr=%d,%d\n", 
388       rec->Block, bsr->volblock->sblock, bsr->volblock->eblock);
389
390    if (!match_sesstime(bsr, bsr->sesstime, rec, 1)) {
391       Dmsg2(dbglevel, "Fail on sesstime. bsr=%d rec=%d\n",
392          bsr->sesstime->sesstime, rec->VolSessionTime);
393       goto no_match;
394    }
395
396    /* NOTE!! This test MUST come after the sesstime test */
397    if (!match_sessid(bsr, bsr->sessid, rec)) {
398       Dmsg2(dbglevel, "Fail on sessid. bsr=%d rec=%d\n",
399          bsr->sessid->sessid, rec->VolSessionId);
400       goto no_match;
401    }
402
403    /* NOTE!! This test MUST come after sesstime and sessid tests */
404    if (!match_findex(bsr, bsr->FileIndex, rec, 1)) {
405       Dmsg3(dbglevel, "Fail on findex=%d. bsr=%d,%d\n",
406          rec->FileIndex, bsr->FileIndex->findex, bsr->FileIndex->findex2);
407       goto no_match;
408    }
409    Dmsg3(dbglevel, "match on findex=%d. bsr=%d,%d\n",
410          rec->FileIndex, bsr->FileIndex->findex, bsr->FileIndex->findex2);
411
412    if (!match_fileregex(bsr, rec, jcr)) {
413      Dmsg1(dbglevel, "Fail on fileregex='%s'\n", bsr->fileregex);
414      goto no_match;
415    }
416
417    /* This flag is set by match_fileregex (and perhaps other tests) */
418    if (bsr->skip_file) {
419       Dmsg1(dbglevel, "Skipping findex=%d\n", rec->FileIndex);
420       goto no_match;
421    }
422
423    /*
424     * If a count was specified and we have a FileIndex, assume
425     *   it is a Bacula created bsr (or the equivalent). We
426     *   then save the bsr where the match occurred so that
427     *   after processing the record or records, we can update
428     *   the found count. I.e. rec->bsr points to the bsr that
429     *   satisfied the match.
430     */
431    if (bsr->count && bsr->FileIndex) {
432       rec->bsr = bsr;
433       Dmsg0(050, "Leave match_all 1\n");
434       return 1;                       /* this is a complete match */
435    }
436
437    /*
438     * The selections below are not used by Bacula's
439     *   restore command, and don't work because of
440     *   the rec->bsr = bsr optimization above.
441     */
442    if (!match_jobid(bsr, bsr->JobId, sessrec, 1)) {
443       Dmsg0(dbglevel, "fail on JobId\n");
444       goto no_match;
445
446    }
447    if (!match_job(bsr, bsr->job, sessrec, 1)) {
448       Dmsg0(dbglevel, "fail on Job\n");
449       goto no_match;
450    }
451    if (!match_client(bsr, bsr->client, sessrec, 1)) {
452       Dmsg0(dbglevel, "fail on Client\n");
453       goto no_match;
454    }
455    if (!match_job_type(bsr, bsr->JobType, sessrec, 1)) {
456       Dmsg0(dbglevel, "fail on Job type\n");
457       goto no_match;
458    }
459    if (!match_job_level(bsr, bsr->JobLevel, sessrec, 1)) {
460       Dmsg0(dbglevel, "fail on Job level\n");
461       goto no_match;
462    }
463    if (!match_stream(bsr, bsr->stream, rec, 1)) {
464       Dmsg0(dbglevel, "fail on stream\n");
465       goto no_match;
466    }
467    Dmsg0(050, "Leave match_all 1\n");
468    return 1;
469
470 no_match:
471    if (bsr->next) {
472       return match_all(bsr->next, rec, volrec, sessrec, bsr->done && done, jcr);
473    }
474    if (bsr->done && done) {
475       Dmsg0(050, "Leave match all -1\n");
476       return -1;
477    }
478    Dmsg0(050, "Leave match all 0\n");
479    return 0;
480 }
481
482 static int match_volume(BSR *bsr, BSR_VOLUME *volume, VOLUME_LABEL *volrec, bool done)
483 {
484    if (!volume) {
485       return 0;                       /* Volume must match */
486    }
487    if (strcmp(volume->VolumeName, volrec->VolumeName) == 0) {
488       Dmsg1(050, "match_volume=%s\n", volrec->VolumeName);
489       return 1;
490    }
491    if (volume->next) {
492       return match_volume(bsr, volume->next, volrec, 1);
493    }
494    return 0;
495 }
496
497 static int match_client(BSR *bsr, BSR_CLIENT *client, SESSION_LABEL *sessrec, bool done)
498 {
499    if (!client) {
500       return 1;                       /* no specification matches all */
501    }
502    if (strcmp(client->ClientName, sessrec->ClientName) == 0) {
503       return 1;
504    }
505    if (client->next) {
506       return match_client(bsr, client->next, sessrec, 1);
507    }
508    return 0;
509 }
510
511 static int match_job(BSR *bsr, BSR_JOB *job, SESSION_LABEL *sessrec, bool done)
512 {
513    if (!job) {
514       return 1;                       /* no specification matches all */
515    }
516    if (strcmp(job->Job, sessrec->Job) == 0) {
517       return 1;
518    }
519    if (job->next) {
520       return match_job(bsr, job->next, sessrec, 1);
521    }
522    return 0;
523 }
524
525 static int match_job_type(BSR *bsr, BSR_JOBTYPE *job_type, SESSION_LABEL *sessrec, bool done)
526 {
527    if (!job_type) {
528       return 1;                       /* no specification matches all */
529    }
530    if (job_type->JobType == sessrec->JobType) {
531       return 1;
532    }
533    if (job_type->next) {
534       return match_job_type(bsr, job_type->next, sessrec, 1);
535    }
536    return 0;
537 }
538
539 static int match_job_level(BSR *bsr, BSR_JOBLEVEL *job_level, SESSION_LABEL *sessrec, bool done)
540 {
541    if (!job_level) {
542       return 1;                       /* no specification matches all */
543    }
544    if (job_level->JobLevel == sessrec->JobLevel) {
545       return 1;
546    }
547    if (job_level->next) {
548       return match_job_level(bsr, job_level->next, sessrec, 1);
549    }
550    return 0;
551 }
552
553 static int match_jobid(BSR *bsr, BSR_JOBID *jobid, SESSION_LABEL *sessrec, bool done)
554 {
555    if (!jobid) {
556       return 1;                       /* no specification matches all */
557    }
558    if (jobid->JobId <= sessrec->JobId && jobid->JobId2 >= sessrec->JobId) {
559       return 1;
560    }
561    if (jobid->next) {
562       return match_jobid(bsr, jobid->next, sessrec, 1);
563    }
564    return 0;
565 }
566
567 static int match_volfile(BSR *bsr, BSR_VOLFILE *volfile, DEV_RECORD *rec, bool done)
568 {
569    if (!volfile) {
570       return 1;                       /* no specification matches all */
571    }
572 /*
573  * The following code is turned off because this should now work
574  *   with disk files too, though since a "volfile" is 4GB, it does
575  *   not improve performance much.
576  */
577 #ifdef xxx
578    /* For the moment, these tests work only with tapes. */
579    if (!(rec->state & REC_ISTAPE)) {
580       return 1;                       /* All File records OK for this match */
581    }
582    Dmsg3(dbglevel, "match_volfile: sfile=%d efile=%d recfile=%d\n",
583              volfile->sfile, volfile->efile, rec->File);
584 #endif
585    if (volfile->sfile <= rec->File && volfile->efile >= rec->File) {
586       return 1;
587    }
588    /* Once we get past last efile, we are done */
589    if (rec->File > volfile->efile) {
590       volfile->done = true;              /* set local done */
591    }
592    if (volfile->next) {
593       return match_volfile(bsr, volfile->next, rec, volfile->done && done);
594    }
595
596    /* If we are done and all prior matches are done, this bsr is finished */
597    if (volfile->done && done) {
598       bsr->done = true;
599       bsr->root->reposition = true;
600       Dmsg2(dbglevel, "bsr done from volfile rec=%d volefile=%d\n",
601          rec->File, volfile->efile);
602    }
603    return 0;
604 }
605
606 static int match_volblock(BSR *bsr, BSR_VOLBLOCK *volblock, DEV_RECORD *rec, bool done)
607 {
608    /*
609     * Currently block matching does not work correctly for disk
610     * files in all cases, so it is "turned off" by the following 
611     * return statement.
612     */
613    return 1;
614
615
616    if (!volblock) {
617       return 1;                       /* no specification matches all */
618    }
619    /* For the moment, these tests work only with disk. */
620    if (rec->state & REC_ISTAPE) {
621       return 1;                       /* All File records OK for this match */
622    }
623 //  Dmsg3(dbglevel, "match_volblock: sblock=%d eblock=%d recblock=%d\n",
624 //             volblock->sblock, volblock->eblock, rec->Block);
625    if (volblock->sblock <= rec->Block && volblock->eblock >= rec->Block) {
626       return 1;
627    }
628    /* Once we get past last eblock, we are done */
629    if (rec->Block > volblock->eblock) {
630       volblock->done = true;              /* set local done */
631    }
632    if (volblock->next) {
633       return match_volblock(bsr, volblock->next, rec, volblock->done && done);
634    }
635
636 /*
637  * This is turned off because I do not believe that we can mark
638  *   the bsr as done at this level.
639  */
640 #ifdef xxx
641    /* If we are done and all prior matches are done, this bsr is finished */
642    if (volblock->done && done) {
643       bsr->done = true;
644       bsr->root->reposition = true;
645       Dmsg2(dbglevel, "bsr done from volblock rec=%d voleblock=%d\n",
646          rec->Block, volblock->eblock);
647    }
648 #endif
649    return 0;
650 }
651
652
653 static int match_stream(BSR *bsr, BSR_STREAM *stream, DEV_RECORD *rec, bool done)
654 {
655    if (!stream) {
656       return 1;                       /* no specification matches all */
657    }
658    if (stream->stream == rec->Stream) {
659       return 1;
660    }
661    if (stream->next) {
662       return match_stream(bsr, stream->next, rec, 1);
663    }
664    return 0;
665 }
666
667 static int match_sesstime(BSR *bsr, BSR_SESSTIME *sesstime, DEV_RECORD *rec, bool done)
668 {
669    if (!sesstime) {
670       return 1;                       /* no specification matches all */
671    }
672    if (sesstime->sesstime == rec->VolSessionTime) {
673       return 1;
674    }
675    if (rec->VolSessionTime > sesstime->sesstime) {
676       sesstime->done = true;
677    }
678    if (sesstime->next) {
679       return match_sesstime(bsr, sesstime->next, rec, sesstime->done && done);
680    }
681    if (sesstime->done && done) {
682       bsr->done = true;
683       bsr->root->reposition = true;
684       Dmsg0(dbglevel, "bsr done from sesstime\n");
685    }
686    return 0;
687 }
688
689 static int match_sessid(BSR *bsr, BSR_SESSID *sessid, DEV_RECORD *rec)
690 {
691    if (!sessid) {
692       return 1;                       /* no specification matches all */
693    }
694    if (sessid->sessid <= rec->VolSessionId && sessid->sessid2 >= rec->VolSessionId) {
695       return 1;
696    }
697    if (sessid->next) {
698       return match_sessid(bsr, sessid->next, rec);
699    }
700    return 0;
701 }
702
703 /*
704  * When reading the Volume, the Volume Findex (rec->FileIndex) always
705  *   are found in sequential order. Thus we can make optimizations.
706  *
707  *  ***FIXME*** optimizations
708  * We could optimize by removing the recursion.
709  */
710 static int match_findex(BSR *bsr, BSR_FINDEX *findex, DEV_RECORD *rec, bool done)
711 {
712    if (!findex) {
713       return 1;                       /* no specification matches all */
714    }
715    if (!findex->done) {
716       if (findex->findex <= rec->FileIndex && findex->findex2 >= rec->FileIndex) {
717          Dmsg3(dbglevel, "Match on findex=%d. bsrFIs=%d,%d\n",
718                rec->FileIndex, findex->findex, findex->findex2);
719          return 1;
720       }
721       if (rec->FileIndex > findex->findex2) {
722          findex->done = true;
723       }
724    }
725    if (findex->next) {
726       return match_findex(bsr, findex->next, rec, findex->done && done);
727    }
728    if (findex->done && done) {
729       bsr->done = true;
730       bsr->root->reposition = true;
731       Dmsg1(dbglevel, "bsr done from findex %d\n", rec->FileIndex);
732    }
733    return 0;
734 }