]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/record.c
Make cd accept wildcards
[bacula/bacula] / bacula / src / stored / record.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2001-2010 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 three of the GNU Affero 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 Affero 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  *
30  *   record.c -- tape record handling functions
31  *
32  *              Kern Sibbald, April MMI
33  *                added BB02 format October MMII
34  *
35  */
36
37
38 #include "bacula.h"
39 #include "stored.h"
40
41 /*
42  * Convert a FileIndex into a printable
43  *   ASCII string.  Not reentrant.
44  * If the FileIndex is negative, it flags the
45  *   record as a Label, otherwise it is simply
46  *   the FileIndex of the current file.
47  */
48 const char *FI_to_ascii(char *buf, int fi)
49 {
50    if (fi >= 0) {
51       sprintf(buf, "%d", fi);
52       return buf;
53    }
54    switch (fi) {
55    case PRE_LABEL:
56       return "PRE_LABEL";
57    case VOL_LABEL:
58       return "VOL_LABEL";
59    case EOM_LABEL:
60       return "EOM_LABEL";
61    case SOS_LABEL:
62       return "SOS_LABEL";
63    case EOS_LABEL:
64       return "EOS_LABEL";
65    case EOT_LABEL:
66       return "EOT_LABEL";
67       break;
68    case SOB_LABEL:
69       return "SOB_LABEL";
70       break;
71    case EOB_LABEL:
72       return "EOB_LABEL";
73       break;
74    default:
75      sprintf(buf, _("unknown: %d"), fi);
76      return buf;
77    }
78 }
79
80
81 /*
82  * Convert a Stream ID into a printable
83  * ASCII string.  Not reentrant.
84
85  * A negative stream number represents
86  *   stream data that is continued from a
87  *   record in the previous block.
88  * If the FileIndex is negative, we are
89  *   dealing with a Label, hence the
90  *   stream is the JobId.
91  */
92 const char *stream_to_ascii(char *buf, int stream, int fi)
93 {
94
95    if (fi < 0) {
96       sprintf(buf, "%d", stream);
97       return buf;
98    }
99    if (stream < 0) {
100       stream = -stream;
101       stream &= STREAMMASK_TYPE;
102       /* Stream was negative => all are continuation items */
103       switch (stream) {
104       case STREAM_UNIX_ATTRIBUTES:
105          return "contUATTR";
106       case STREAM_FILE_DATA:
107          return "contDATA";
108       case STREAM_WIN32_DATA:
109          return "contWIN32-DATA";
110       case STREAM_WIN32_GZIP_DATA:
111          return "contWIN32-GZIP";
112       case STREAM_WIN32_COMPRESSED_DATA:
113          return "contWIN32-COMPRESSED";
114       case STREAM_MD5_DIGEST:
115          return "contMD5";
116       case STREAM_SHA1_DIGEST:
117          return "contSHA1";
118       case STREAM_GZIP_DATA:
119          return "contGZIP";
120       case STREAM_COMPRESSED_DATA:
121          return "contCOMPRESSED";
122       case STREAM_UNIX_ATTRIBUTES_EX:
123          return "contUNIX-ATTR-EX";
124       case STREAM_RESTORE_OBJECT:
125          return "contRESTORE-OBJECT";
126       case STREAM_SPARSE_DATA:
127          return "contSPARSE-DATA";
128       case STREAM_SPARSE_GZIP_DATA:
129          return "contSPARSE-GZIP";
130       case STREAM_SPARSE_COMPRESSED_DATA:
131          return "contSPARSE-COMPRESSED";
132       case STREAM_PROGRAM_NAMES:
133          return "contPROG-NAMES";
134       case STREAM_PROGRAM_DATA:
135          return "contPROG-DATA";
136       case STREAM_MACOS_FORK_DATA:
137          return "contMACOS-RSRC";
138       case STREAM_HFSPLUS_ATTRIBUTES:
139          return "contHFSPLUS-ATTR";
140       case STREAM_SHA256_DIGEST:
141          return "contSHA256";
142       case STREAM_SHA512_DIGEST:
143          return "contSHA512";
144       case STREAM_SIGNED_DIGEST:
145          return "contSIGNED-DIGEST";
146       case STREAM_ENCRYPTED_SESSION_DATA:
147          return "contENCRYPTED-SESSION-DATA";
148       case STREAM_ENCRYPTED_FILE_DATA:
149          return "contENCRYPTED-FILE";
150       case STREAM_ENCRYPTED_FILE_GZIP_DATA:
151          return "contENCRYPTED-GZIP";
152       case STREAM_ENCRYPTED_FILE_COMPRESSED_DATA:
153          return "contENCRYPTED-COMPRESSED";
154       case STREAM_ENCRYPTED_WIN32_DATA:
155          return "contENCRYPTED-WIN32-DATA";
156       case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
157          return "contENCRYPTED-WIN32-GZIP";
158       case STREAM_ENCRYPTED_WIN32_COMPRESSED_DATA:
159          return "contENCRYPTED-WIN32-COMPRESSED";
160       case STREAM_ENCRYPTED_MACOS_FORK_DATA:
161          return "contENCRYPTED-MACOS-RSRC";
162       case STREAM_PLUGIN_NAME:
163          return "contPLUGIN-NAME";
164
165       default:
166          sprintf(buf, "%d", -stream);
167          return buf;
168       }
169    }
170
171    switch (stream & STREAMMASK_TYPE) {
172    case STREAM_UNIX_ATTRIBUTES:
173       return "UATTR";
174    case STREAM_FILE_DATA:
175       return "DATA";
176    case STREAM_WIN32_DATA:
177       return "WIN32-DATA";
178    case STREAM_WIN32_GZIP_DATA:
179       return "WIN32-GZIP";
180    case STREAM_WIN32_COMPRESSED_DATA:
181       return "WIN32-COMPRESSED";
182    case STREAM_MD5_DIGEST:
183       return "MD5";
184    case STREAM_SHA1_DIGEST:
185       return "SHA1";
186    case STREAM_GZIP_DATA:
187       return "GZIP";
188    case STREAM_COMPRESSED_DATA:
189       return "COMPRESSED";
190    case STREAM_UNIX_ATTRIBUTES_EX:
191       return "UNIX-ATTR-EX";
192    case STREAM_RESTORE_OBJECT:
193       return "RESTORE-OBJECT";
194    case STREAM_SPARSE_DATA:
195       return "SPARSE-DATA";
196    case STREAM_SPARSE_GZIP_DATA:
197       return "SPARSE-GZIP";
198    case STREAM_SPARSE_COMPRESSED_DATA:
199       return "SPARSE-COMPRESSED";
200    case STREAM_PROGRAM_NAMES:
201       return "PROG-NAMES";
202    case STREAM_PROGRAM_DATA:
203       return "PROG-DATA";
204    case STREAM_PLUGIN_NAME:
205       return "PLUGIN-NAME";
206    case STREAM_MACOS_FORK_DATA:
207       return "MACOS-RSRC";
208    case STREAM_HFSPLUS_ATTRIBUTES:
209       return "HFSPLUS-ATTR";
210    case STREAM_SHA256_DIGEST:
211       return "SHA256";
212    case STREAM_SHA512_DIGEST:
213       return "SHA512";
214    case STREAM_SIGNED_DIGEST:
215       return "SIGNED-DIGEST";
216    case STREAM_ENCRYPTED_SESSION_DATA:
217       return "ENCRYPTED-SESSION-DATA";
218    case STREAM_ENCRYPTED_FILE_DATA:
219       return "ENCRYPTED-FILE";
220    case STREAM_ENCRYPTED_FILE_GZIP_DATA:
221       return "ENCRYPTED-GZIP";
222    case STREAM_ENCRYPTED_FILE_COMPRESSED_DATA:
223       return "ENCRYPTED-COMPRESSED";
224    case STREAM_ENCRYPTED_WIN32_DATA:
225       return "ENCRYPTED-WIN32-DATA";
226    case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
227       return "ENCRYPTED-WIN32-GZIP";
228    case STREAM_ENCRYPTED_WIN32_COMPRESSED_DATA:
229       return "ENCRYPTED-WIN32-COMPRESSED";
230    case STREAM_ENCRYPTED_MACOS_FORK_DATA:
231       return "ENCRYPTED-MACOS-RSRC";
232
233       default:
234          sprintf(buf, "%d", stream);
235          return buf;
236       }
237 }
238
239 /*
240  * Return a new record entity
241  */
242 DEV_RECORD *new_record(void)
243 {
244    DEV_RECORD *rec;
245
246    rec = (DEV_RECORD *)get_memory(sizeof(DEV_RECORD));
247    memset(rec, 0, sizeof(DEV_RECORD));
248    rec->data = get_pool_memory(PM_MESSAGE);
249    return rec;
250 }
251
252 void empty_record(DEV_RECORD *rec)
253 {
254    rec->File = rec->Block = 0;
255    rec->VolSessionId = rec->VolSessionTime = 0;
256    rec->FileIndex = rec->Stream = 0;
257    rec->data_len = rec->remainder = 0;
258    rec->state &= ~(REC_PARTIAL_RECORD|REC_BLOCK_EMPTY|REC_NO_MATCH|REC_CONTINUATION);
259 }
260
261 /*
262  * Free the record entity
263  *
264  */
265 void free_record(DEV_RECORD *rec)
266 {
267    Dmsg0(950, "Enter free_record.\n");
268    if (rec->data) {
269       free_pool_memory(rec->data);
270    }
271    Dmsg0(950, "Data buf is freed.\n");
272    free_pool_memory((POOLMEM *)rec);
273    Dmsg0(950, "Leave free_record.\n");
274 }
275
276
277 /*
278  * Write a Record to the block
279  *
280  *  Returns: false on failure (none or partially written)
281  *           true  on success (all bytes written)
282  *
283  *  and remainder returned in packet.
284  *
285  *  We require enough room for the header, and we deal with
286  *  two special cases. 1. Only part of the record may have
287  *  been transferred the last time (when remainder is
288  *  non-zero), and 2. The remaining bytes to write may not
289  *  all fit into the block.
290  */
291 bool write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec)
292 {
293    ser_declare;
294    uint32_t remlen;
295    char buf1[100], buf2[100];
296
297    remlen = block->buf_len - block->binbuf;
298
299    ASSERT(block->binbuf == (uint32_t) (block->bufp - block->buf));
300    ASSERT(block->buf_len >= block->binbuf);
301
302    Dmsg6(890, "write_record_to_block() FI=%s SessId=%d Strm=%s len=%d\n"
303       "rem=%d remainder=%d\n",
304       FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
305       stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
306       remlen, rec->remainder);
307
308    /*
309     * If rec->remainder is non-zero, we have been called a
310     *  second (or subsequent) time to finish writing a record
311     *  that did not previously fit into the block.
312     */
313    if (rec->remainder == 0) {
314       /* Require enough room to write a full header */
315       if (remlen >= WRITE_RECHDR_LENGTH) {
316          ser_begin(block->bufp, WRITE_RECHDR_LENGTH);
317          if (BLOCK_VER == 1) {
318             ser_uint32(rec->VolSessionId);
319             ser_uint32(rec->VolSessionTime);
320          } else {
321             block->VolSessionId = rec->VolSessionId;
322             block->VolSessionTime = rec->VolSessionTime;
323          }
324          ser_int32(rec->FileIndex);
325          ser_int32(rec->Stream);
326          ser_uint32(rec->data_len);
327
328          block->bufp += WRITE_RECHDR_LENGTH;
329          block->binbuf += WRITE_RECHDR_LENGTH;
330          remlen -= WRITE_RECHDR_LENGTH;
331          rec->remainder = rec->data_len;
332          if (rec->FileIndex > 0) {
333             /* If data record, update what we have in this block */
334             if (block->FirstIndex == 0) {
335                block->FirstIndex = rec->FileIndex;
336             }
337             block->LastIndex = rec->FileIndex;
338          }
339       } else {
340          rec->remainder = rec->data_len + WRITE_RECHDR_LENGTH;
341          return false;
342       }
343    } else {
344       /*
345        * We are here to write unwritten bytes from a previous
346        * time. Presumably we have a new buffer (possibly
347        * containing a volume label), so the new header
348        * should be able to fit in the block -- otherwise we have
349        * an error.  Note, we have to continue splitting the
350        * data record if it is longer than the block.
351        *
352        * First, write the header, then write as much as
353        * possible of the data record.
354        *
355        * Every time we write a header and it is a continuation
356        * of a previous partially written record, we store the
357        * Stream as -Stream in the record header.
358        */
359       ser_begin(block->bufp, WRITE_RECHDR_LENGTH);
360       if (BLOCK_VER == 1) {
361          ser_uint32(rec->VolSessionId);
362          ser_uint32(rec->VolSessionTime);
363       } else {
364          block->VolSessionId = rec->VolSessionId;
365          block->VolSessionTime = rec->VolSessionTime;
366       }
367       ser_int32(rec->FileIndex);
368       if (rec->remainder > rec->data_len) {
369          ser_int32(rec->Stream);      /* normal full header */
370          ser_uint32(rec->data_len);
371          rec->remainder = rec->data_len; /* must still do data record */
372       } else {
373          ser_int32(-rec->Stream);     /* mark this as a continuation record */
374          ser_uint32(rec->remainder);  /* bytes to do */
375       }
376
377       /* Require enough room to write a full header */
378       ASSERT(remlen >= WRITE_RECHDR_LENGTH);
379
380       block->bufp += WRITE_RECHDR_LENGTH;
381       block->binbuf += WRITE_RECHDR_LENGTH;
382       remlen -= WRITE_RECHDR_LENGTH;
383       if (rec->FileIndex > 0) {
384          /* If data record, update what we have in this block */
385          if (block->FirstIndex == 0) {
386             block->FirstIndex = rec->FileIndex;
387          }
388          block->LastIndex = rec->FileIndex;
389       }
390    }
391    if (remlen == 0) {
392       return false;                   /* partial transfer */
393    }
394
395    /*
396     * Now deal with data record.
397     * Part of it may have already been transferred, and we
398     * may not have enough room to transfer the whole this time.
399     */
400    if (rec->remainder > 0) {
401       /* Write as much of data as possible */
402       if (remlen >= rec->remainder) {
403          memcpy(block->bufp, rec->data+rec->data_len-rec->remainder,
404                 rec->remainder);
405          block->bufp += rec->remainder;
406          block->binbuf += rec->remainder;
407       } else {
408          memcpy(block->bufp, rec->data+rec->data_len-rec->remainder,
409                 remlen);
410 #ifdef xxxxxSMCHECK
411          if (!sm_check_rtn(__FILE__, __LINE__, False)) {
412             /* We damaged a buffer */
413             Dmsg6(0, "Damaged block FI=%s SessId=%d Strm=%s len=%d\n"
414                "rem=%d remainder=%d\n",
415                FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
416                stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
417                remlen, rec->remainder);
418             Dmsg5(0, "Damaged block: bufp=%x binbuf=%d buf_len=%d rem=%d moved=%d\n",
419                block->bufp, block->binbuf, block->buf_len, block->buf_len-block->binbuf,
420                remlen);
421             Dmsg2(0, "Damaged block: buf=%x binbuffrombuf=%d \n",
422                block->buf, block->bufp-block->buf);
423
424                Emsg0(M_ABORT, 0, _("Damaged buffer\n"));
425          }
426 #endif
427
428          block->bufp += remlen;
429          block->binbuf += remlen;
430          rec->remainder -= remlen;
431          return false;                /* did partial transfer */
432       }
433    }
434    rec->remainder = 0;                /* did whole transfer */
435    return true;
436 }
437
438
439 /*
440  * Test if we can write whole record to the block
441  *
442  *  Returns: false on failure
443  *           true  on success (all bytes can be written)
444  */
445 bool can_write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec)
446 {
447    uint32_t remlen;
448
449    remlen = block->buf_len - block->binbuf;
450    if (rec->remainder == 0) {
451       if (remlen >= WRITE_RECHDR_LENGTH) {
452          remlen -= WRITE_RECHDR_LENGTH;
453          rec->remainder = rec->data_len;
454       } else {
455          return false;
456       }
457    } else {
458       return false;
459    }
460    if (rec->remainder > 0 && remlen < rec->remainder) {
461       return false;
462    }
463    return true;
464 }
465
466 uint64_t get_record_address(DEV_RECORD *rec)
467 {
468    return ((uint64_t)rec->File)<<32 | rec->Block;
469 }
470
471 /*
472  * Read a Record from the block
473  *  Returns: false if nothing read or if the continuation record does not match.
474  *                 In both of these cases, a block read must be done.
475  *           true  if at least the record header was read, this
476  *                 routine may have to be called again with a new
477  *                 block if the entire record was not read.
478  */
479 bool read_record_from_block(DCR *dcr, DEV_BLOCK *block, DEV_RECORD *rec)
480 {
481    ser_declare;
482    uint32_t remlen;
483    uint32_t VolSessionId;
484    uint32_t VolSessionTime;
485    int32_t  FileIndex;
486    int32_t  Stream;
487    uint32_t data_bytes;
488    uint32_t rhl;
489    char buf1[100], buf2[100];
490
491    remlen = block->binbuf;
492
493    /* Clear state flags */
494    rec->state = 0;
495    if (block->dev->is_tape()) {
496       rec->state |= REC_ISTAPE;
497    }
498    rec->Block = ((DEVICE *)block->dev)->EndBlock;
499    rec->File = ((DEVICE *)block->dev)->EndFile;
500
501    /*
502     * Get the header. There is always a full header,
503     * otherwise we find it in the next block.
504     */
505    Dmsg3(450, "Block=%d Ver=%d size=%u\n", block->BlockNumber, block->BlockVer,
506          block->block_len);
507    if (block->BlockVer == 1) {
508       rhl = RECHDR1_LENGTH;
509    } else {
510       rhl = RECHDR2_LENGTH;
511    }
512    if (remlen >= rhl) {
513       Dmsg4(450, "Enter read_record_block: remlen=%d data_len=%d rem=%d blkver=%d\n",
514             remlen, rec->data_len, rec->remainder, block->BlockVer);
515
516       unser_begin(block->bufp, WRITE_RECHDR_LENGTH);
517       if (block->BlockVer == 1) {
518          unser_uint32(VolSessionId);
519          unser_uint32(VolSessionTime);
520       } else {
521          VolSessionId = block->VolSessionId;
522          VolSessionTime = block->VolSessionTime;
523       }
524       unser_int32(FileIndex);
525       unser_int32(Stream);
526       unser_uint32(data_bytes);
527
528       block->bufp += rhl;
529       block->binbuf -= rhl;
530       remlen -= rhl;
531
532       /* If we are looking for more (remainder!=0), we reject anything
533        *  where the VolSessionId and VolSessionTime don't agree
534        */
535       if (rec->remainder && (rec->VolSessionId != VolSessionId ||
536                              rec->VolSessionTime != VolSessionTime)) {
537          rec->state |= REC_NO_MATCH;
538          Dmsg0(450, "remainder and VolSession doesn't match\n");
539          return false;             /* This is from some other Session */
540       }
541
542       /* if Stream is negative, it means that this is a continuation
543        * of a previous partially written record.
544        */
545       if (Stream < 0) {               /* continuation record? */
546          Dmsg1(500, "Got negative Stream => continuation. remainder=%d\n",
547             rec->remainder);
548          rec->state |= REC_CONTINUATION;
549          if (!rec->remainder) {       /* if we didn't read previously */
550             rec->data_len = 0;        /* return data as if no continuation */
551          } else if (rec->Stream != -Stream) {
552             rec->state |= REC_NO_MATCH;
553             return false;             /* This is from some other Session */
554          }
555          rec->Stream = -Stream;       /* set correct Stream */
556          rec->maskedStream = rec->Stream & STREAMMASK_TYPE;
557       } else {                        /* Regular record */
558          rec->Stream = Stream;
559          rec->maskedStream = rec->Stream & STREAMMASK_TYPE;
560          rec->data_len = 0;           /* transfer to beginning of data */
561       }
562       rec->VolSessionId = VolSessionId;
563       rec->VolSessionTime = VolSessionTime;
564       rec->FileIndex = FileIndex;
565       if (FileIndex > 0) {
566          if (block->FirstIndex == 0) {
567             block->FirstIndex = FileIndex;
568          }
569          block->LastIndex = FileIndex;
570       }
571
572       Dmsg6(450, "rd_rec_blk() got FI=%s SessId=%d Strm=%s len=%u\n"
573                  "remlen=%d data_len=%d\n",
574          FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
575          stream_to_ascii(buf2, rec->Stream, rec->FileIndex), data_bytes, remlen,
576          rec->data_len);
577    } else {
578       /*
579        * No more records in this block because the number
580        * of remaining bytes are less than a record header
581        * length, so return empty handed, but indicate that
582        * he must read again. By returning, we allow the
583        * higher level routine to fetch the next block and
584        * then reread.
585        */
586       Dmsg0(450, "read_record_block: nothing\n");
587       rec->state |= (REC_NO_HEADER | REC_BLOCK_EMPTY);
588       empty_block(block);                      /* mark block empty */
589       return false;
590    }
591
592    /* Sanity check */
593    if (data_bytes >= MAX_BLOCK_LENGTH) {
594       /*
595        * Something is wrong, force read of next block, abort 
596        *   continuing with this block.
597        */
598       rec->state |= (REC_NO_HEADER | REC_BLOCK_EMPTY);
599       empty_block(block);
600       Jmsg2(dcr->jcr, M_WARNING, 0, _("Sanity check failed. maxlen=%d datalen=%d. Block discarded.\n"),
601          MAX_BLOCK_LENGTH, data_bytes);
602       return false;
603    }
604
605    rec->data = check_pool_memory_size(rec->data, rec->data_len+data_bytes);
606
607    /*
608     * At this point, we have read the header, now we
609     * must transfer as much of the data record as
610     * possible taking into account: 1. A partial
611     * data record may have previously been transferred,
612     * 2. The current block may not contain the whole data
613     * record.
614     */
615    if (remlen >= data_bytes) {
616       /* Got whole record */
617       memcpy(rec->data+rec->data_len, block->bufp, data_bytes);
618       block->bufp += data_bytes;
619       block->binbuf -= data_bytes;
620       rec->data_len += data_bytes;
621    } else {
622       /* Partial record */
623       memcpy(rec->data+rec->data_len, block->bufp, remlen);
624       block->bufp += remlen;
625       block->binbuf -= remlen;
626       rec->data_len += remlen;
627       rec->remainder = 1;             /* partial record transferred */
628       Dmsg1(450, "read_record_block: partial xfered=%d\n", rec->data_len);
629       rec->state |= (REC_PARTIAL_RECORD | REC_BLOCK_EMPTY);
630       return true;
631    }
632    rec->remainder = 0;
633    Dmsg4(450, "Rtn full rd_rec_blk FI=%s SessId=%d Strm=%s len=%d\n",
634       FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
635       stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len);
636    return true;                       /* transferred full record */
637 }