]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/bsr.c
Apply Nicolas' bsr single block patch
[bacula/bacula] / bacula / src / dird / bsr.c
1 /*
2  *
3  *   Bacula Director -- Bootstrap Record routines.
4  *
5  *      BSR (bootstrap record) handling routines split from
6  *        ua_restore.c July MMIII
7  *
8  *     Kern Sibbald, July MMII
9  *
10  *   Version $Id$
11  */
12
13 /*
14    Copyright (C) 2002-2005 Kern Sibbald
15
16    This program is free software; you can redistribute it and/or
17    modify it under the terms of the GNU General Public License
18    version 2 as amended with additional clauses defined in the
19    file LICENSE in the main source directory.
20
21    This program is distributed in the hope that it will be useful,
22    but WITHOUT ANY WARRANTY; without even the implied warranty of
23    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
24    the file LICENSE for additional details.
25
26  */
27
28 #include "bacula.h"
29 #include "dird.h"
30
31 /* Forward referenced functions */
32 static uint32_t write_bsr(UAContext *ua, RBSR *bsr, FILE *fd);
33 void print_bsr(UAContext *ua, RBSR *bsr);
34
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 /* Free all BSR FileIndex entries */
47 static void free_findex(RBSR_FINDEX *fi)
48 {
49    RBSR_FINDEX *next;
50    for ( ; fi; fi=next) {
51       next = fi->next;
52       free(fi);
53    }
54 }
55
56 /*
57  * Our data structures were not designed completely
58  *  correctly, so the file indexes cover the full
59  *  range regardless of volume. The FirstIndex and LastIndex
60  *  passed in here are for the current volume, so when
61  *  writing out the fi, constrain them to those values.
62  *
63  * We are called here once for each JobMedia record
64  *  for each Volume.
65  */
66 static uint32_t write_findex(UAContext *ua, RBSR_FINDEX *fi,
67               int32_t FirstIndex, int32_t LastIndex, FILE *fd)
68 {
69    uint32_t count = 0;
70    for ( ; fi; fi=fi->next) {
71       int32_t findex, findex2;
72       if ((fi->findex >= FirstIndex && fi->findex <= LastIndex) ||
73           (fi->findex2 >= FirstIndex && fi->findex2 <= LastIndex) ||
74           (fi->findex < FirstIndex && fi->findex2 > LastIndex)) {
75          findex = fi->findex < FirstIndex ? FirstIndex : fi->findex;
76          findex2 = fi->findex2 > LastIndex ? LastIndex : fi->findex2;
77          if (findex == findex2) {
78             fprintf(fd, "FileIndex=%d\n", findex);
79             count++;
80          } else {
81             fprintf(fd, "FileIndex=%d-%d\n", findex, findex2);
82             count += findex2 - findex + 1;
83          }
84       }
85    }
86    return count;
87 }
88
89 /*
90  * Find out if Volume defined with FirstIndex and LastIndex
91  *   falls within the range of selected files in the bsr.
92  */
93 static bool is_volume_selected(RBSR_FINDEX *fi,
94               int32_t FirstIndex, int32_t LastIndex)
95 {
96    for ( ; fi; fi=fi->next) {
97       if ((fi->findex >= FirstIndex && fi->findex <= LastIndex) ||
98           (fi->findex2 >= FirstIndex && fi->findex2 <= LastIndex) ||
99           (fi->findex < FirstIndex && fi->findex2 > LastIndex)) {
100          return true;
101       }
102    }
103    return false;
104 }
105
106
107
108 static void print_findex(UAContext *ua, RBSR_FINDEX *fi)
109 {
110    bsendmsg(ua, "fi=0x%lx\n", fi);
111    for ( ; fi; fi=fi->next) {
112       if (fi->findex == fi->findex2) {
113          bsendmsg(ua, "FileIndex=%d\n", fi->findex);
114 //       Dmsg1(100, "FileIndex=%d\n", fi->findex);
115       } else {
116          bsendmsg(ua, "FileIndex=%d-%d\n", fi->findex, fi->findex2);
117 //       Dmsg2(100, "FileIndex=%d-%d\n", fi->findex, fi->findex2);
118       }
119    }
120 }
121
122 /* Create a new bootstrap record */
123 RBSR *new_bsr()
124 {
125    RBSR *bsr = (RBSR *)bmalloc(sizeof(RBSR));
126    memset(bsr, 0, sizeof(RBSR));
127    return bsr;
128 }
129
130 /* Free the entire BSR */
131 void free_bsr(RBSR *bsr)
132 {
133    RBSR *next;
134    for ( ; bsr; bsr=next) {
135       free_findex(bsr->fi);
136       if (bsr->VolParams) {
137          free(bsr->VolParams);
138       }
139       next = bsr->next;
140       free(bsr);
141    }
142 }
143
144 /*
145  * Complete the BSR by filling in the VolumeName and
146  *  VolSessionId and VolSessionTime using the JobId
147  */
148 bool complete_bsr(UAContext *ua, RBSR *bsr)
149 {
150    for ( ; bsr; bsr=bsr->next) {
151       JOB_DBR jr;
152       memset(&jr, 0, sizeof(jr));
153       jr.JobId = bsr->JobId;
154       if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
155          bsendmsg(ua, _("Unable to get Job record. ERR=%s\n"), db_strerror(ua->db));
156          return false;
157       }
158       bsr->VolSessionId = jr.VolSessionId;
159       bsr->VolSessionTime = jr.VolSessionTime;
160       if ((bsr->VolCount=db_get_job_volume_parameters(ua->jcr, ua->db, bsr->JobId,
161            &(bsr->VolParams))) == 0) {
162          bsendmsg(ua, _("Unable to get Job Volume Parameters. ERR=%s\n"), db_strerror(ua->db));
163          if (bsr->VolParams) {
164             free(bsr->VolParams);
165             bsr->VolParams = NULL;
166          }
167          return false;
168       }
169    }
170    return true;
171 }
172
173 void make_unique_restore_filename(UAContext *ua, POOLMEM **fname)
174 {
175    JCR *jcr = ua->jcr;
176    int i = find_arg_with_value(ua, "bootstrap");
177    if (i >= 0) {
178       Mmsg(fname, "%s", ua->argv[i]);              
179       jcr->unlink_bsr = false;
180    } else {
181       Mmsg(fname, "%s/%s.restore.%s.bsr", working_directory, my_name, 
182          jcr->Job);
183       jcr->unlink_bsr = true;
184    }
185 }
186
187 /*
188  * Write the bootstrap records to file
189  */
190 uint32_t write_bsr_file(UAContext *ua, RBSR *bsr)
191 {
192    FILE *fd;
193    POOLMEM *fname = get_pool_memory(PM_MESSAGE);
194    uint32_t count = 0;;
195    bool err;
196
197    make_unique_restore_filename(ua, &fname);
198    fd = fopen(fname, "w+");
199    if (!fd) {
200       berrno be;
201       bsendmsg(ua, _("Unable to create bootstrap file %s. ERR=%s\n"),
202          fname, be.strerror());
203       goto bail_out;
204    }
205    /* Write them to file */
206    count = write_bsr(ua, bsr, fd);
207    err = ferror(fd);
208    fclose(fd);
209    if (err) {
210       bsendmsg(ua, _("Error writing bsr file.\n"));
211       count = 0;
212       goto bail_out;
213    }
214
215
216    bsendmsg(ua, _("Bootstrap records written to %s\n"), fname);
217
218    /* Tell the user what he will need to mount */
219    bsendmsg(ua, "\n");
220    bsendmsg(ua, _("The job will require the following Volumes:\n"));
221    /* Create Unique list of Volumes using prompt list */
222    start_prompt(ua, "");
223    for (RBSR *nbsr=bsr; nbsr; nbsr=nbsr->next) {
224       for (int i=0; i < nbsr->VolCount; i++) {
225          if (nbsr->VolParams[i].VolumeName[0]) {
226             add_prompt(ua, nbsr->VolParams[i].VolumeName);
227          }
228       }
229    }
230    for (int i=0; i < ua->num_prompts; i++) {
231       bsendmsg(ua, "   %s\n", ua->prompt[i]);
232       free(ua->prompt[i]);
233    }
234    if (ua->num_prompts == 0) {
235       bsendmsg(ua, _("No Volumes found to restore.\n"));
236       count = 0;
237    }
238    ua->num_prompts = 0;
239    bsendmsg(ua, "\n");
240
241 bail_out:
242    free_pool_memory(fname);
243    return count;
244 }
245
246 static uint32_t write_bsr(UAContext *ua, RBSR *bsr, FILE *fd)
247 {
248    uint32_t count = 0;
249    uint32_t total_count = 0;
250    uint32_t LastIndex = 0;
251    bool first = true;
252    for ( ; bsr; bsr=bsr->next) {
253       /*
254        * For a given volume, loop over all the JobMedia records.
255        *   VolCount is the number of JobMedia records.
256        */
257       for (int i=0; i < bsr->VolCount; i++) {
258          if (!is_volume_selected(bsr->fi, bsr->VolParams[i].FirstIndex,
259               bsr->VolParams[i].LastIndex)) {
260             bsr->VolParams[i].VolumeName[0] = 0;  /* zap VolumeName */
261             continue;
262          }
263          fprintf(fd, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
264          fprintf(fd, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType);
265          fprintf(fd, "VolSessionId=%u\n", bsr->VolSessionId);
266          fprintf(fd, "VolSessionTime=%u\n", bsr->VolSessionTime);
267          if (bsr->VolParams[i].StartFile == bsr->VolParams[i].EndFile) {
268             fprintf(fd, "VolFile=%u\n", bsr->VolParams[i].StartFile);
269          } else {
270             fprintf(fd, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile,
271                     bsr->VolParams[i].EndFile);
272          }
273          if (bsr->VolParams[i].StartBlock == bsr->VolParams[i].EndBlock) {
274             fprintf(fd, "VolBlock=%u\n", bsr->VolParams[i].StartBlock);
275          } else {
276             fprintf(fd, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
277                     bsr->VolParams[i].EndBlock);
278          }
279 //       Dmsg2(100, "bsr VolParam FI=%u LI=%u\n",
280 //          bsr->VolParams[i].FirstIndex, bsr->VolParams[i].LastIndex);
281
282          count = write_findex(ua, bsr->fi, bsr->VolParams[i].FirstIndex,
283                               bsr->VolParams[i].LastIndex, fd);
284          if (count) {
285             fprintf(fd, "Count=%u\n", count);
286          }
287          total_count += count;
288          /* If the same file is present on two tapes or in two files
289           *   on a tape, it is a continuation, and should not be treated
290           *   twice in the totals.
291           */
292          if (!first && LastIndex == bsr->VolParams[i].FirstIndex) {
293             total_count--;
294          }
295          first = false;
296          LastIndex = bsr->VolParams[i].LastIndex;
297       }
298    }
299    return total_count;
300 }
301
302 void print_bsr(UAContext *ua, RBSR *bsr)
303 {
304    for ( ; bsr; bsr=bsr->next) {
305       for (int i=0; i < bsr->VolCount; i++) {
306          bsendmsg(ua, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
307          bsendmsg(ua, "MediaType\"%s\"\n", bsr->VolParams[i].MediaType);
308          bsendmsg(ua, "VolSessionId=%u\n", bsr->VolSessionId);
309          bsendmsg(ua, "VolSessionTime=%u\n", bsr->VolSessionTime);
310          bsendmsg(ua, "VolFile=%u-%u\n", bsr->VolParams[i].StartFile,
311                   bsr->VolParams[i].EndFile);
312          bsendmsg(ua, "VolBlock=%u-%u\n", bsr->VolParams[i].StartBlock,
313                   bsr->VolParams[i].EndBlock);
314          print_findex(ua, bsr->fi);
315       }
316       print_bsr(ua, bsr->next);
317    }
318 }
319
320
321
322
323 /*
324  * Add a FileIndex to the list of BootStrap records.
325  *  Here we are only dealing with JobId's and the FileIndexes
326  *  associated with those JobIds.
327  */
328 void add_findex(RBSR *bsr, uint32_t JobId, int32_t findex)
329 {
330    RBSR *nbsr;
331    RBSR_FINDEX *fi, *lfi;
332
333    if (findex == 0) {
334       return;                         /* probably a dummy directory */
335    }
336
337    if (bsr->fi == NULL) {             /* if no FI add one */
338       /* This is the first FileIndex item in the chain */
339       bsr->fi = new_findex();
340       bsr->JobId = JobId;
341       bsr->fi->findex = findex;
342       bsr->fi->findex2 = findex;
343       return;
344    }
345    /* Walk down list of bsrs until we find the JobId */
346    if (bsr->JobId != JobId) {
347       for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
348          if (nbsr->JobId == JobId) {
349             bsr = nbsr;
350             break;
351          }
352       }
353
354       if (!nbsr) {                    /* Must add new JobId */
355          /* Add new JobId at end of chain */
356          for (nbsr=bsr; nbsr->next; nbsr=nbsr->next)
357             {  }
358          nbsr->next = new_bsr();
359          nbsr->next->JobId = JobId;
360          nbsr->next->fi = new_findex();
361          nbsr->next->fi->findex = findex;
362          nbsr->next->fi->findex2 = findex;
363          return;
364       }
365    }
366
367    /*
368     * At this point, bsr points to bsr containing this JobId,
369     *  and we are sure that there is at least one fi record.
370     */
371    lfi = fi = bsr->fi;
372    /* Check if this findex is smaller than first item */
373    if (findex < fi->findex) {
374       if ((findex+1) == fi->findex) {
375          fi->findex = findex;         /* extend down */
376          return;
377       }
378       fi = new_findex();              /* yes, insert before first item */
379       fi->findex = findex;
380       fi->findex2 = findex;
381       fi->next = lfi;
382       bsr->fi = fi;
383       return;
384    }
385    /* Walk down fi chain and find where to insert insert new FileIndex */
386    for ( ; fi; fi=fi->next) {
387       if (findex == (fi->findex2 + 1)) {  /* extend up */
388          RBSR_FINDEX *nfi;
389          fi->findex2 = findex;
390          /*
391           * If the following record contains one higher, merge its
392           *   file index by extending it up.
393           */
394          if (fi->next && ((findex+1) == fi->next->findex)) {
395             nfi = fi->next;
396             fi->findex2 = nfi->findex2;
397             fi->next = nfi->next;
398             free(nfi);
399          }
400          return;
401       }
402       if (findex < fi->findex) {      /* add before */
403          if ((findex+1) == fi->findex) {
404             fi->findex = findex;
405             return;
406          }
407          break;
408       }
409       lfi = fi;
410    }
411    /* Add to last place found */
412    fi = new_findex();
413    fi->findex = findex;
414    fi->findex2 = findex;
415    fi->next = lfi->next;
416    lfi->next = fi;
417    return;
418 }
419
420 /*
421  * Add all possible  FileIndexes to the list of BootStrap records.
422  *  Here we are only dealing with JobId's and the FileIndexes
423  *  associated with those JobIds.
424  */
425 void add_findex_all(RBSR *bsr, uint32_t JobId)
426 {
427    RBSR *nbsr;
428    RBSR_FINDEX *fi;
429
430    if (bsr->fi == NULL) {             /* if no FI add one */
431       /* This is the first FileIndex item in the chain */
432       bsr->fi = new_findex();
433       bsr->JobId = JobId;
434       bsr->fi->findex = 1;
435       bsr->fi->findex2 = INT32_MAX;
436       return;
437    }
438    /* Walk down list of bsrs until we find the JobId */
439    if (bsr->JobId != JobId) {
440       for (nbsr=bsr->next; nbsr; nbsr=nbsr->next) {
441          if (nbsr->JobId == JobId) {
442             bsr = nbsr;
443             break;
444          }
445       }
446
447       if (!nbsr) {                    /* Must add new JobId */
448          /* Add new JobId at end of chain */
449          for (nbsr=bsr; nbsr->next; nbsr=nbsr->next)
450             {  }
451          nbsr->next = new_bsr();
452          nbsr->next->JobId = JobId;
453          nbsr->next->fi = new_findex();
454          nbsr->next->fi->findex = 1;
455          nbsr->next->fi->findex2 = INT32_MAX;
456          return;
457       }
458    }
459
460    /*
461     * At this point, bsr points to bsr containing this JobId,
462     *  and we are sure that there is at least one fi record.
463     */
464    fi = bsr->fi;
465    fi->findex = 1;
466    fi->findex2 = INT32_MAX;
467    return;
468 }