]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/bsr.c
Restore win32 dir from Branch-5.2 and update it
[bacula/bacula] / bacula / src / dird / bsr.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2018 Kern Sibbald
5
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *
21  *   Bacula Director -- Bootstrap Record routines.
22  *
23  *      BSR (bootstrap record) handling routines split from
24  *        ua_restore.c July MMIII
25  *
26  *     Kern Sibbald, July MMII
27  *
28  */
29
30 #include "bacula.h"
31 #include "dird.h"
32
33 /* Forward referenced functions */
34 static uint32_t write_bsr(UAContext *ua, RESTORE_CTX &rx, FILE *fd);
35
36 /*
37  * Create new FileIndex entry for BSR
38  */
39 RBSR_FINDEX *new_findex()
40 {
41    RBSR_FINDEX *fi = (RBSR_FINDEX *)bmalloc(sizeof(RBSR_FINDEX));
42    memset(fi, 0, sizeof(RBSR_FINDEX));
43    return fi;
44 }
45
46 /*
47  * Get storage device name from Storage resource
48  */
49 static bool get_storage_device(char *device, char *storage)
50 {
51    STORE *store;
52    if (storage[0] == 0) {
53       return false;
54    }
55    store = (STORE *)GetResWithName(R_STORAGE, storage);
56    if (!store) {
57       return false;
58    }
59    DEVICE *dev = (DEVICE *)(store->device->first());
60    if (!dev) {
61       return false;
62    }
63    bstrncpy(device, dev->hdr.name, MAX_NAME_LENGTH);
64    return true;
65 }
66
67 /*
68  * Our data structures were not designed completely
69  *  correctly, so the file indexes cover the full
70  *  range regardless of volume. The FirstIndex and LastIndex
71  *  passed in here are for the current volume, so when
72  *  writing out the fi, constrain them to those values.
73  *
74  * We are called here once for each JobMedia record
75  *  for each Volume.
76  */
77 static uint32_t write_findex(rblist *fi_list,
78               int32_t FirstIndex, int32_t LastIndex, FILE *fd)
79 {
80    RBSR_FINDEX *fi;
81    uint32_t count = 0;
82
83    fi = (RBSR_FINDEX *) fi_list->first();
84    while (fi) {
85       int32_t findex, findex2;
86
87       /* fi points to the first item of the list, or the next item that is not
88        * contigous to the previous group
89        */
90       findex = fi->findex;
91       findex2 = fi->findex2;
92
93       /* Sometime (with the restore command for example), the fi_list can
94        * contain false gaps (1-10, 11-11, 12-20 instead of 1-20). The for loop
95        * is here to merge blocks and reduce the bsr output. The next while(fi)
96        * iteration will use the next_fi that points to the last merged element.
97        */
98       RBSR_FINDEX *next_fi;
99       for (next_fi = (RBSR_FINDEX*) fi_list->next(fi);
100            next_fi && next_fi->findex == (findex2+1);
101            next_fi = (RBSR_FINDEX *) fi_list->next(next_fi))
102       {
103          findex2 = next_fi->findex2;
104       }
105
106       /* next_fi points after the current block (or to the end of the list), so
107        * the next while() iteration will use the next value
108        */
109       fi = next_fi;
110
111       /* We look if the current FI block match the volume information */
112       if ((findex >= FirstIndex && findex <= LastIndex) ||
113           (findex2 >= FirstIndex && findex2 <= LastIndex) ||
114           (findex < FirstIndex && findex2 > LastIndex)) {
115
116          findex = findex < FirstIndex ? FirstIndex : findex;
117          findex2 = findex2 > LastIndex ? LastIndex : findex2;
118
119          if (findex == findex2) {
120             fprintf(fd, "FileIndex=%d\n", findex);
121             count++;
122          } else {
123             fprintf(fd, "FileIndex=%d-%d\n", findex, findex2);
124             count += findex2 - findex + 1;
125          }
126       }
127    }
128
129    return count;
130 }
131
132 /*
133  * Find out if Volume defined with FirstIndex and LastIndex
134  *   falls within the range of selected files in the bsr.
135  */
136 static bool is_volume_selected(rblist *fi_list,
137               int32_t FirstIndex, int32_t LastIndex)
138 {
139    RBSR_FINDEX *fi;
140    foreach_rblist(fi, fi_list) {
141       if ((fi->findex >= FirstIndex && fi->findex <= LastIndex) ||
142           (fi->findex2 >= FirstIndex && fi->findex2 <= LastIndex) ||
143           (fi->findex < FirstIndex && fi->findex2 > LastIndex)) {
144          return true;
145       }
146    }
147    return false;
148 }
149
150
151 /* Create a new bootstrap record */
152 RBSR *new_bsr()
153 {
154    RBSR_FINDEX *fi=NULL;
155    RBSR *bsr = (RBSR *)bmalloc(sizeof(RBSR));
156    memset(bsr, 0, sizeof(RBSR));
157    bsr->fi_list = New(rblist(fi, &fi->link));
158    return bsr;
159 }
160
161 /* Free the entire BSR */
162 void free_bsr(rblist *bsr_list)
163 {
164    RBSR *bsr;
165    foreach_rblist(bsr, bsr_list) {
166       delete bsr->fi_list;
167       if (bsr->VolParams) {
168          free(bsr->VolParams);
169       }
170       if (bsr->fileregex) {
171          free(bsr->fileregex);
172       }
173       if (bsr->m_fi) {
174          free(bsr->m_fi);
175       }
176    }
177    delete bsr_list;
178 }
179
180 /*
181  * Complete the BSR by filling in the VolumeName and
182  *  VolSessionId and VolSessionTime using the JobId
183  */
184 bool complete_bsr(UAContext *ua, rblist *bsr_list)
185 {
186    RBSR *bsr;
187    foreach_rblist(bsr, bsr_list) {
188       JOB_DBR jr;
189       memset(&jr, 0, sizeof(jr));
190       jr.JobId = bsr->JobId;
191       if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
192          ua->error_msg(_("Unable to get Job record. ERR=%s\n"), db_strerror(ua->db));
193          return false;
194       }
195       bsr->VolSessionId = jr.VolSessionId;
196       bsr->VolSessionTime = jr.VolSessionTime;
197       if (jr.JobFiles == 0) {      /* zero files is OK, not an error, but */
198          bsr->VolCount = 0;        /*   there are no volumes */
199          continue;
200       }
201       if ((bsr->VolCount=db_get_job_volume_parameters(ua->jcr, ua->db, bsr->JobId,
202            &(bsr->VolParams))) == 0) {
203          ua->error_msg(_("Unable to get Job Volume Parameters. ERR=%s\n"), db_strerror(ua->db));
204          if (bsr->VolParams) {
205             free(bsr->VolParams);
206             bsr->VolParams = NULL;
207          }
208          return false;
209       }
210    }
211    return true;
212 }
213
214 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
215 static uint32_t uniq = 0;
216
217 static void make_unique_restore_filename(UAContext *ua, POOL_MEM &fname)
218 {
219    JCR *jcr = ua->jcr;
220    int i = find_arg_with_value(ua, "bootstrap");
221    if (i >= 0) {
222       Mmsg(fname, "%s", ua->argv[i]);
223       jcr->unlink_bsr = false;
224    } else {
225       P(mutex);
226       uniq++;
227       V(mutex);
228       Mmsg(fname, "%s/%s.restore.%u.bsr", working_directory, my_name, uniq);
229       jcr->unlink_bsr = true;
230    }
231    if (jcr->RestoreBootstrap) {
232       free(jcr->RestoreBootstrap);
233    }
234    jcr->RestoreBootstrap = bstrdup(fname.c_str());
235 }
236
237 /*
238  * Write the bootstrap records to file
239  */
240 uint32_t write_bsr_file(UAContext *ua, RESTORE_CTX &rx)
241 {
242    FILE *fd;
243    POOL_MEM fname(PM_MESSAGE);
244    uint32_t count = 0;;
245    bool err;
246
247    make_unique_restore_filename(ua, fname);
248    fd = bfopen(fname.c_str(), "w+b");
249    if (!fd) {
250       berrno be;
251       ua->error_msg(_("Unable to create bootstrap file %s. ERR=%s\n"),
252          fname.c_str(), be.bstrerror());
253       goto bail_out;
254    }
255    /* Write them to file */
256    count = write_bsr(ua, rx, fd);
257    err = ferror(fd);
258    fclose(fd);
259    if (count == 0) {
260       ua->info_msg(_("No files found to read. No bootstrap file written.\n"));
261       goto bail_out;
262    }
263    if (err) {
264       ua->error_msg(_("Error writing bsr file.\n"));
265       count = 0;
266       goto bail_out;
267    }
268
269    if (chk_dbglvl(10)) {
270       print_bsr(ua, rx);
271    }
272
273 bail_out:
274    return count;
275 }
276
277 static void display_vol_info(UAContext *ua, RESTORE_CTX &rx, JobId_t JobId)
278 {
279    POOL_MEM volmsg(PM_MESSAGE);
280    char Device[MAX_NAME_LENGTH];
281    char online;
282    RBSR *bsr;
283
284    foreach_rblist(bsr, rx.bsr_list) {
285       if (JobId && JobId != bsr->JobId) {
286          continue;
287       }
288
289       for (int i=0; i < bsr->VolCount; i++) {
290          if (bsr->VolParams[i].VolumeName[0]) {
291             if (!get_storage_device(Device, bsr->VolParams[i].Storage)) {
292                Device[0] = 0;
293             }
294             if (bsr->VolParams[i].InChanger && bsr->VolParams[i].Slot) {
295                online = '*';
296             } else {
297                online = ' ';
298             }
299             Mmsg(volmsg, "%c%-25s %-25s %-25s",
300                  online, bsr->VolParams[i].VolumeName,
301                  bsr->VolParams[i].Storage, Device);
302             add_prompt(ua, volmsg.c_str());
303          }
304       }
305    }
306 }
307
308 void display_bsr_info(UAContext *ua, RESTORE_CTX &rx)
309 {
310    char *p;
311    JobId_t JobId;
312
313    /* Tell the user what he will need to mount */
314    ua->send_msg("\n");
315    ua->send_msg(_("The Job will require the following (*=>InChanger):\n"
316                   "   Volume(s)                 Storage(s)                SD Device(s)\n"
317                   "===========================================================================\n"));
318    /* Create Unique list of Volumes using prompt list */
319    start_prompt(ua, "");
320    if (*rx.JobIds == 0) {
321       /* Print Volumes in any order */
322       display_vol_info(ua, rx, 0);
323    } else {
324       /* Ensure that the volumes are printed in JobId order */
325       for (p=rx.JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
326          display_vol_info(ua, rx, JobId);
327       }
328    }
329    for (int i=0; i < ua->num_prompts; i++) {
330       ua->send_msg("   %s\n", ua->prompt[i]);
331       free(ua->prompt[i]);
332       if (ua->unique[i]) free(ua->unique[i]);
333    }
334    if (ua->num_prompts == 0) {
335       ua->send_msg(_("No Volumes found to restore.\n"));
336    } else {
337       ua->send_msg(_("\nVolumes marked with \"*\" are in the Autochanger.\n"));
338    }
339    ua->num_prompts = 0;
340    ua->send_msg("\n");
341
342    return;
343 }
344
345 /*
346  * Write bsr data for a single bsr record
347  */
348 static uint32_t write_bsr_item(RBSR *bsr, UAContext *ua,
349                    RESTORE_CTX &rx, FILE *fd, bool &first, uint32_t &LastIndex)
350 {
351    char ed1[50], ed2[50];
352    uint32_t count = 0;
353    uint32_t total_count = 0;
354    char device[MAX_NAME_LENGTH];
355
356    /*
357     * For a given volume, loop over all the JobMedia records.
358     *   VolCount is the number of JobMedia records.
359     */
360    for (int i=0; i < bsr->VolCount; i++) {
361       if (!is_volume_selected(bsr->fi_list, bsr->VolParams[i].FirstIndex,
362            bsr->VolParams[i].LastIndex)) {
363          bsr->VolParams[i].VolumeName[0] = 0;  /* zap VolumeName */
364          continue;
365       }
366       if (!rx.store) {
367          find_storage_resource(ua, rx, bsr->VolParams[i].Storage,
368                                        bsr->VolParams[i].MediaType);
369       }
370       fprintf(fd, "Storage=\"%s\"\n", bsr->VolParams[i].Storage);
371       fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
372       fprintf(fd, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType);
373       if (bsr->fileregex) {
374          fprintf(fd, "FileRegex=%s\n", bsr->fileregex);
375       }
376       if (get_storage_device(device, bsr->VolParams[i].Storage)) {
377          fprintf(fd, "Device=\"%s\"\n", device);
378       }
379       if (bsr->VolParams[i].Slot > 0) {
380          fprintf(fd, "Slot=%d\n", bsr->VolParams[i].Slot);
381       }
382       fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId);
383       fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime);
384       fprintf(fd, "VolAddr=%s-%s\n", edit_uint64(bsr->VolParams[i].StartAddr, ed1),
385               edit_uint64(bsr->VolParams[i].EndAddr, ed2));
386       Dmsg2(100, "bsr VolParam FI=%u LI=%u\n",
387             bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex);
388
389       count = write_findex(bsr->fi_list, bsr->VolParams[i].FirstIndex,
390                            bsr->VolParams[i].LastIndex, fd);
391       if (count) {
392          fprintf(fd, "Count=%u\n", count);
393       }
394       total_count += count;
395       /* If the same file is present on two tapes or in two files
396        *   on a tape, it is a continuation, and should not be treated
397        *   twice in the totals.
398        */
399       if (!first && LastIndex == bsr->VolParams[i].FirstIndex) {
400          total_count--;
401       }
402       first = false;
403       LastIndex = bsr->VolParams[i].LastIndex;
404    }
405    return total_count;
406 }
407
408
409 /*
410  * Here we actually write out the details of the bsr file.
411  *  Note, there is one bsr for each JobId, but the bsr may
412  *  have multiple volumes, which have been entered in the
413  *  order they were written.
414  * The bsrs must be written out in the order the JobIds
415  *  are found in the jobid list.
416  */
417 static uint32_t write_bsr(UAContext *ua, RESTORE_CTX &rx, FILE *fd)
418 {
419    bool first = true;
420    uint32_t LastIndex = 0;
421    uint32_t total_count = 0;
422    char *p;
423    JobId_t JobId;
424    RBSR *bsr;
425    if (*rx.JobIds == 0) {
426       foreach_rblist(bsr, rx.bsr_list) {
427          total_count += write_bsr_item(bsr, ua, rx, fd, first, LastIndex);
428       }
429       return total_count;
430    }
431    for (p=rx.JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
432       foreach_rblist(bsr, rx.bsr_list) {
433          if (JobId == bsr->JobId) {
434             total_count += write_bsr_item(bsr, ua, rx, fd, first, LastIndex);
435          }
436       }
437    }
438    return total_count;
439 }
440
441 void print_bsr(UAContext *ua, RESTORE_CTX &rx)
442 {
443    write_bsr(ua, rx, stdout);
444 }
445
446 static int search_rbsr(void *elt1, void *elt2)
447 {
448    RBSR *bsr1 = (RBSR *)elt1;
449    RBSR *bsr = (RBSR *)elt2;
450
451    /* We might replace by a simple JobId - JobId */
452    if (bsr->JobId == bsr1->JobId) {
453       return 0;
454
455    } else if (bsr->JobId < bsr1->JobId) {
456       return 1;
457    }
458
459    return -1;
460 }
461
462 static int search_fi(void *elt1, void *elt2)
463 {
464    RBSR_FINDEX *f1 = (RBSR_FINDEX *) elt1;
465    RBSR_FINDEX *f2 = (RBSR_FINDEX *) elt2;
466
467    if (f1->findex == (f2->findex - 1)) {
468       return 0;
469
470    } else if (f1->findex2 == (f2->findex2 + 1)) {
471       return 0;
472
473    } else if (f1->findex >= f2->findex && f1->findex2 <= f2->findex2) {
474       return 0;
475    }
476
477    return (f1->findex > f2->findex) ? 1 : -1;
478 }
479
480 rblist *create_bsr_list(uint32_t JobId, int findex, int findex2)
481 {
482    RBSR *bsr = NULL;
483    RBSR_FINDEX *fi = NULL;
484    rblist *bsr_list = New(rblist(bsr, &bsr->link));
485
486    bsr = new_bsr();
487    bsr->JobId = JobId;
488
489    bsr_list->insert(bsr, search_rbsr);
490
491    fi = new_findex();
492    fi->findex = findex;
493    fi->findex2 = findex2;
494
495    bsr->fi_list->insert(fi, search_fi);
496
497    return bsr_list;
498 }
499
500 /*
501  * Add a FileIndex to the list of BootStrap records.
502  *  Here we are only dealing with JobId's and the FileIndexes
503  *  associated with those JobIds.
504  * We expect that JobId, FileIndex are sorted ascending.
505  *
506  * When doing restore from tree, FileIndex are not sorted, so it can
507  * create gaps.
508  */
509 void add_findex(rblist *bsr_list, uint32_t JobId, int32_t findex)
510 {
511    RBSR *bsr, bsr2;
512    RBSR_FINDEX *fi, *nfi;
513
514    if (findex == 0) {
515       return;                         /* probably a dummy directory */
516    }
517
518    bsr2.JobId = JobId;
519    /* Walk down list of bsrs until we find the JobId */
520    bsr = (RBSR *)bsr_list->search(&bsr2, search_rbsr);
521
522    /* The list is empty, or the JobId is not already in,
523     * Must add new JobId
524     */
525    if (!bsr) {
526       bsr = new_bsr();
527       bsr->JobId = JobId;
528       bsr_list->insert(bsr, search_rbsr);
529    }
530
531    if (bsr->m_fi) {
532       fi = bsr->m_fi;
533
534    } else {
535       fi = bsr->m_fi = new_findex();
536    }
537
538    fi->findex  = findex;
539    fi->findex2 = findex;
540
541    Dmsg1(1000, "Trying to insert %ld\n", findex);
542    /* try to insert our fi */
543    nfi = (RBSR_FINDEX*) bsr->fi_list->insert((void *)fi, search_fi);
544
545    /* We found an existing one, extend it */
546    if (nfi != fi) {
547       if (findex == (nfi->findex2 + 1)) {
548          Dmsg2(1000, "Extend %ld-%ld\n", nfi->findex, findex);
549          nfi->findex2 = findex;
550
551       } else if (findex == (nfi->findex - 1)) {
552          Dmsg2(1000, "Extend %ld-%ld\n", findex, nfi->findex2);
553          nfi->findex = findex;
554
555       } else {
556          Dmsg2(1000, "Found the same values? %ld-%ld\n", nfi->findex, nfi->findex2);
557       }
558
559    } else {
560       Dmsg2(1000, "Inserted %ld-%ld\n", fi->findex, fi->findex2);
561       bsr->m_fi = NULL;         /* comsumed */
562    }
563 }
564
565 /*
566  * Add all possible  FileIndexes to the list of BootStrap records.
567  *  Here we are only dealing with JobId's and the FileIndexes
568  *  associated with those JobIds.
569  */
570 void add_findex_all(rblist *bsr_list, uint32_t JobId, const char *fileregex)
571 {
572    RBSR *bsr, bsr2;
573    RBSR_FINDEX *fi;
574
575    bsr2.JobId = JobId;
576    /* Walk down list of bsrs until we find the JobId */
577    bsr = (RBSR *)bsr_list->search(&bsr2, search_rbsr);
578
579    if (!bsr) {                    /* Must add new JobId */
580       fi = new_findex();
581       fi->findex = 1;
582       fi->findex2 = INT32_MAX;
583
584       bsr = new_bsr();
585       bsr->JobId = JobId;
586       bsr->fi_list->insert(fi, search_fi);
587       bsr_list->insert(bsr, search_rbsr);
588
589       if (fileregex) {
590          /* If we use regexp to restore, set it for each jobid */
591          bsr->fileregex = bstrdup(fileregex);
592       }
593       return;
594    }
595
596    /*
597     * At this point, bsr points to bsr containing this JobId,
598     */
599    fi = new_findex();
600    fi->findex = 1;
601    fi->findex2 = INT32_MAX;
602    bsr->fi_list->insert(fi, search_fi);
603    return;
604 }
605
606 #ifdef needed
607 /* Foreach files in currrent list, send "/path/fname\0LStat\0MD5\0Delta" to FD
608  *      row[0]=Path, row[1]=Filename, row[2]=FileIndex
609  *      row[3]=JobId row[4]=LStat row[5]=DeltaSeq row[6]=MD5
610  */
611 static int sendit(void *arg, int num_fields, char **row)
612 {
613    JCR *jcr = (JCR *)arg;
614
615    if (job_canceled(jcr)) {
616       return 1;
617    }
618
619    if (row[2][0] == '0') {           /* discard when file_index == 0 */
620       return 0;
621    }
622
623    /* sending with checksum */
624    if (num_fields == 7
625        && row[6][0] /* skip checksum = '0' */
626        && row[6][1])
627    {
628       jcr->file_bsock->fsend("%s%s%c%s%c%s%c%s",
629                              row[0], row[1], 0, row[4], 0, row[6], 0, row[5]);
630    } else {
631       jcr->file_bsock->fsend("%s%s%c%s%c%c%s",
632                              row[0], row[1], 0, row[4], 0, 0, row[5]);
633    }
634    return 0;
635 }
636 #endif
637
638 /* We list all files for a given FI structure */
639 static void scan_findex(JCR *jcr, RBSR *bsr,
640                         int32_t FirstIndex, int32_t LastIndex,
641                         int32_t &lastFileIndex, uint32_t &lastJobId)
642 {
643    RBSR_FINDEX *fi;
644    FILE_DBR fdbr;
645    memset(&fdbr, 0, sizeof(fdbr));
646
647    fi = (RBSR_FINDEX *) bsr->fi_list->first();
648    while (fi) {
649       int32_t findex, findex2;
650
651       /* fi points to the first item of the list, or the next item that is not
652        * contigous to the previous group
653        */
654       findex = fi->findex;
655       findex2 = fi->findex2;
656
657       /* Sometime (with the restore command for example), the fi_list can
658        * contain false gaps (1-10, 11-11, 12-20 instead of 1-20). The for loop
659        * is here to merge blocks and reduce the bsr output. The next while(fi)
660        * iteration will use the next_fi that points to the last merged element.
661        */
662       RBSR_FINDEX *next_fi;
663       for (next_fi = (RBSR_FINDEX*) bsr->fi_list->next(fi);
664            next_fi && next_fi->findex == (findex2+1);
665            next_fi = (RBSR_FINDEX *) bsr->fi_list->next(next_fi))
666       {
667          findex2 = next_fi->findex2;
668       }
669
670       /* next_fi points after the current block (or to the end of the list), so
671        * the next while() iteration will use the next value
672        */
673       fi = next_fi;
674
675       /* We look if the current FI block match the volume information */
676       if ((findex >= FirstIndex && findex <= LastIndex) ||
677           (findex2 >= FirstIndex && findex2 <= LastIndex) ||
678           (findex < FirstIndex && findex2 > LastIndex)) {
679
680          findex = findex < FirstIndex ? FirstIndex : findex;
681          findex2 = findex2 > LastIndex ? LastIndex : findex2;
682
683          bool dolist=false;
684          /* Display only new files */
685          if (findex != lastFileIndex || bsr->JobId != lastJobId) {
686             /* Not the same file, or not the same job */
687             fdbr.FileIndex = findex;
688             //dolist = true;
689
690          } else if (findex2 != lastFileIndex) {
691             /* We are in the same job, and the first index was already generated */
692             fdbr.FileIndex = findex + 1;
693             //dolist = true;
694          }
695
696          /* Keep the current values for the next loop */
697          lastJobId = bsr->JobId;
698          lastFileIndex = findex2;
699
700          /* Generate if needed the list of files */
701          if (dolist) {
702             fdbr.FileIndex2 = findex2;
703             fdbr.JobId = bsr->JobId;
704             /* New code not working */
705             //db_list_files(jcr, jcr->db, &fdbr, sendit, jcr);
706          }
707       }
708    }
709 }
710
711 /*
712  * Scan bsr data for a single bsr record
713  */
714 static void scan_bsr_item(JCR *jcr, RBSR *bsr)
715 {
716    int32_t lastFileIndex=0;
717    uint32_t lastJobId=0;
718    /*
719     * For a given volume, loop over all the JobMedia records.
720     *   VolCount is the number of JobMedia records.
721     */
722    for (int i=0; i < bsr->VolCount; i++) {
723       if (!is_volume_selected(bsr->fi_list,
724                               bsr->VolParams[i].FirstIndex,
725                               bsr->VolParams[i].LastIndex))
726       {
727          continue;
728       }
729
730       scan_findex(jcr, bsr,
731                   bsr->VolParams[i].FirstIndex,
732                   bsr->VolParams[i].LastIndex,
733                   lastFileIndex, lastJobId);
734    }
735 }
736
737 /*
738  * We need to find all files from the BSR. All files are listed, this is used
739  * to send the list of the files to be restored to a plugin for example.
740  */
741 void scan_bsr(JCR *jcr)
742 {
743    char *p;
744    JobId_t JobId;
745    RBSR *bsr;
746    if (!jcr->JobIds || *jcr->JobIds == 0) {
747       foreach_rblist(bsr, jcr->bsr_list) {
748          scan_bsr_item(jcr, bsr);
749       }
750       return;
751    }
752    for (p=jcr->JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) {
753       foreach_rblist(bsr, jcr->bsr_list) {
754          if (JobId == bsr->JobId) {
755             scan_bsr_item(jcr, bsr);
756          }
757       }
758    }
759    return;
760 }