1 /*
2    Bacula(R) - The Network Backup Solution
3 
4    Copyright (C) 2000-2020 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  *   record-util.c -- Utilities for record handling
22  *
23  *            Kern Sibbald, October MMXII
24  *
25  */
26 
27 #include "bacula.h"
28 #include "stored.h"
29 
30 /*
31  * Convert a FileIndex into a printable
32  *   ASCII string.  Not reentrant.
33  * If the FileIndex is negative, it flags the
34  *   record as a Label, otherwise it is simply
35  *   the FileIndex of the current file.
36  */
FI_to_ascii(char * buf,int fi)37 const char *FI_to_ascii(char *buf, int fi)
38 {
39    if (fi >= 0) {
40       sprintf(buf, "%d", fi);
41       return buf;
42    }
43    switch (fi) {
44    case PRE_LABEL:
45       return "PRE_LABEL";
46    case VOL_LABEL:
47       return "VOL_LABEL";
48    case EOM_LABEL:
49       return "EOM_LABEL";
50    case SOS_LABEL:
51       return "SOS_LABEL";
52    case EOS_LABEL:
53       return "EOS_LABEL";
54    case EOT_LABEL:
55       return "EOT_LABEL";
56       break;
57    case SOB_LABEL:
58       return "SOB_LABEL";
59       break;
60    case EOB_LABEL:
61       return "EOB_LABEL";
62       break;
63    default:
64      sprintf(buf, _("unknown: %d"), fi);
65      return buf;
66    }
67 }
68 
69 /*
70  * Convert a Stream ID into a printable
71  * ASCII string.  Not reentrant.
72 
73  * A negative stream number represents
74  *   stream data that is continued from a
75  *   record in the previous block.
76  * If the FileIndex is negative, we are
77  *   dealing with a Label, hence the
78  *   stream is the JobId.
79  */
stream_to_ascii(char * buf,int stream,int fi)80 const char *stream_to_ascii(char *buf, int stream, int fi)
81 {
82 
83    if (fi < 0) {
84       sprintf(buf, "%d", stream);
85       return buf;
86    }
87    if (stream < 0) {
88       stream = -stream;
89       stream &= STREAMMASK_TYPE;
90       /* Stream was negative => all are continuation items */
91       switch (stream) {
92       case STREAM_UNIX_ATTRIBUTES:
93          return "contUATTR";
94       case STREAM_FILE_DATA:
95          return "contDATA";
96       case STREAM_WIN32_DATA:
97          return "contWIN32-DATA";
98       case STREAM_WIN32_GZIP_DATA:
99          return "contWIN32-GZIP";
100       case STREAM_WIN32_COMPRESSED_DATA:
101          return "contWIN32-COMPRESSED";
102       case STREAM_MD5_DIGEST:
103          return "contMD5";
104       case STREAM_SHA1_DIGEST:
105          return "contSHA1";
106       case STREAM_GZIP_DATA:
107          return "contGZIP";
108       case STREAM_COMPRESSED_DATA:
109          return "contCOMPRESSED";
110       case STREAM_UNIX_ATTRIBUTES_EX:
111          return "contUNIX-ATTR-EX";
112       case STREAM_RESTORE_OBJECT:
113          return "contRESTORE-OBJECT";
114       case STREAM_SPARSE_DATA:
115          return "contSPARSE-DATA";
116       case STREAM_SPARSE_GZIP_DATA:
117          return "contSPARSE-GZIP";
118       case STREAM_SPARSE_COMPRESSED_DATA:
119          return "contSPARSE-COMPRESSED";
120       case STREAM_PROGRAM_NAMES:
121          return "contPROG-NAMES";
122       case STREAM_PROGRAM_DATA:
123          return "contPROG-DATA";
124       case STREAM_MACOS_FORK_DATA:
125          return "contMACOS-RSRC";
126       case STREAM_HFSPLUS_ATTRIBUTES:
127          return "contHFSPLUS-ATTR";
128       case STREAM_SHA256_DIGEST:
129          return "contSHA256";
130       case STREAM_SHA512_DIGEST:
131          return "contSHA512";
132       case STREAM_SIGNED_DIGEST:
133          return "contSIGNED-DIGEST";
134       case STREAM_ENCRYPTED_SESSION_DATA:
135          return "contENCRYPTED-SESSION-DATA";
136       case STREAM_ENCRYPTED_FILE_DATA:
137          return "contENCRYPTED-FILE";
138       case STREAM_ENCRYPTED_FILE_GZIP_DATA:
139          return "contENCRYPTED-GZIP";
140       case STREAM_ENCRYPTED_FILE_COMPRESSED_DATA:
141          return "contENCRYPTED-COMPRESSED";
142       case STREAM_ENCRYPTED_WIN32_DATA:
143          return "contENCRYPTED-WIN32-DATA";
144       case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
145          return "contENCRYPTED-WIN32-GZIP";
146       case STREAM_ENCRYPTED_WIN32_COMPRESSED_DATA:
147          return "contENCRYPTED-WIN32-COMPRESSED";
148       case STREAM_ENCRYPTED_MACOS_FORK_DATA:
149          return "contENCRYPTED-MACOS-RSRC";
150       case STREAM_PLUGIN_NAME:
151          return "contPLUGIN-NAME";
152       case STREAM_ADATA_BLOCK_HEADER:
153          return "contADATA-BLOCK-HEADER";
154       case STREAM_ADATA_RECORD_HEADER:
155          return "contADATA-RECORD-HEADER";
156 
157       default:
158          sprintf(buf, "%d", -stream);
159          return buf;
160       }
161    }
162 
163    switch (stream & STREAMMASK_TYPE) {
164    case STREAM_UNIX_ATTRIBUTES:
165       return "UATTR";
166    case STREAM_FILE_DATA:
167       return "DATA";
168    case STREAM_WIN32_DATA:
169       return "WIN32-DATA";
170    case STREAM_WIN32_GZIP_DATA:
171       return "WIN32-GZIP";
172    case STREAM_WIN32_COMPRESSED_DATA:
173       return "WIN32-COMPRESSED";
174    case STREAM_MD5_DIGEST:
175       return "MD5";
176    case STREAM_SHA1_DIGEST:
177       return "SHA1";
178    case STREAM_GZIP_DATA:
179       return "GZIP";
180    case STREAM_COMPRESSED_DATA:
181       return "COMPRESSED";
182    case STREAM_UNIX_ATTRIBUTES_EX:
183       return "UNIX-ATTR-EX";
184    case STREAM_RESTORE_OBJECT:
185       return "RESTORE-OBJECT";
186    case STREAM_SPARSE_DATA:
187       return "SPARSE-DATA";
188    case STREAM_SPARSE_GZIP_DATA:
189       return "SPARSE-GZIP";
190    case STREAM_SPARSE_COMPRESSED_DATA:
191       return "SPARSE-COMPRESSED";
192    case STREAM_PROGRAM_NAMES:
193       return "PROG-NAMES";
194    case STREAM_PROGRAM_DATA:
195       return "PROG-DATA";
196    case STREAM_PLUGIN_NAME:
197       return "PLUGIN-NAME";
198    case STREAM_MACOS_FORK_DATA:
199       return "MACOS-RSRC";
200    case STREAM_HFSPLUS_ATTRIBUTES:
201       return "HFSPLUS-ATTR";
202    case STREAM_SHA256_DIGEST:
203       return "SHA256";
204    case STREAM_SHA512_DIGEST:
205       return "SHA512";
206    case STREAM_SIGNED_DIGEST:
207       return "SIGNED-DIGEST";
208    case STREAM_ENCRYPTED_SESSION_DATA:
209       return "ENCRYPTED-SESSION-DATA";
210    case STREAM_ENCRYPTED_FILE_DATA:
211       return "ENCRYPTED-FILE";
212    case STREAM_ENCRYPTED_FILE_GZIP_DATA:
213       return "ENCRYPTED-GZIP";
214    case STREAM_ENCRYPTED_FILE_COMPRESSED_DATA:
215       return "ENCRYPTED-COMPRESSED";
216    case STREAM_ENCRYPTED_WIN32_DATA:
217       return "ENCRYPTED-WIN32-DATA";
218    case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
219       return "ENCRYPTED-WIN32-GZIP";
220    case STREAM_ENCRYPTED_WIN32_COMPRESSED_DATA:
221       return "ENCRYPTED-WIN32-COMPRESSED";
222    case STREAM_ENCRYPTED_MACOS_FORK_DATA:
223       return "ENCRYPTED-MACOS-RSRC";
224    case STREAM_ADATA_BLOCK_HEADER:
225       return "ADATA-BLOCK-HEADER";
226    case STREAM_ADATA_RECORD_HEADER:
227       return "ADATA-RECORD-HEADER";
228    default:
229       sprintf(buf, "%d", stream);
230       return buf;
231    }
232 }
233 
stream_to_ascii_ex(char * buf,int stream,int fi)234 const char *stream_to_ascii_ex(char *buf, int stream, int fi)
235 {
236    if (fi < 0) {
237       return stream_to_ascii(buf, stream, fi);
238    }
239    int ustream = (stream>=0)?stream:-stream;
240    const char *p = stream_to_ascii(buf, stream, fi);
241    if (ustream & (STREAM_BIT_DEDUPLICATION_DATA|STREAM_BIT_NO_DEDUPLICATION)) {
242       if (p!=buf) {
243          strcpy(buf, p);
244       }
245       strcat(buf, "-");
246       if (ustream & STREAM_BIT_DEDUPLICATION_DATA) {
247          strcat(buf, "D");
248       }
249       if (ustream & STREAM_BIT_NO_DEDUPLICATION) {
250          strcat(buf, "d");
251       }
252       return buf;
253    } else {
254       return p;
255    }
256 }
257 /*
258  * Return a new record entity
259  */
new_record(void)260 DEV_RECORD *new_record(void)
261 {
262    DEV_RECORD *rec;
263 
264    rec = (DEV_RECORD *)get_memory(sizeof(DEV_RECORD));
265    memset(rec, 0, sizeof(DEV_RECORD));
266    rec->data = get_pool_memory(PM_MESSAGE);
267    rec->wstate = st_none;
268    rec->rstate = st_none;
269    return rec;
270 }
271 
empty_record(DEV_RECORD * rec)272 void empty_record(DEV_RECORD *rec)
273 {
274    rec->RecNum = 0;
275    rec->StartAddr = rec->Addr = 0;
276    rec->VolSessionId = rec->VolSessionTime = 0;
277    rec->FileIndex = rec->Stream = 0;
278    rec->data_len = rec->remainder = 0;
279    rec->state_bits &= ~(REC_PARTIAL_RECORD|REC_ADATA_EMPTY|REC_BLOCK_EMPTY|REC_NO_MATCH|REC_CONTINUATION);
280    rec->FileOffset = 0;
281    rec->wstate = st_none;
282    rec->rstate = st_none;
283    rec->VolumeName = NULL;
284 }
285 
286 /*
287  * Free the record entity
288  *
289  */
free_record(DEV_RECORD * rec)290 void free_record(DEV_RECORD *rec)
291 {
292    Dmsg0(950, "Enter free_record.\n");
293    if (rec->data) {
294       free_pool_memory(rec->data);
295    }
296    Dmsg0(950, "Data buf is freed.\n");
297    free_pool_memory((POOLMEM *)rec);
298    Dmsg0(950, "Leave free_record.\n");
299 }
300 
dump_record(DEV_RECORD * rec)301 void dump_record(DEV_RECORD *rec)
302 {
303    char buf[32];
304    Dmsg11(100|DT_VOLUME, "Dump record %s 0x%p:\n\tStart=%lld addr=%lld #%d\n"
305          "\tVolSess: %ld:%ld\n"
306          "\tFileIndex: %ld\n"
307          "\tStream: 0x%lx\n\tLen: %ld\n\tData: %s\n",
308          rec, NPRT(rec->VolumeName),
309          rec->StartAddr, rec->Addr, rec->RecNum,
310          rec->VolSessionId, rec->VolSessionTime, rec->FileIndex,
311          rec->Stream, rec->data_len,
312          asciidump(rec->data, rec->data_len, buf, sizeof(buf)));
313 }
314 
315 /*
316  * Test if we can write whole record to the block
317  *
318  *  Returns: false on failure
319  *           true  on success (all bytes can be written)
320  */
can_write_record_to_block(DEV_BLOCK * block,DEV_RECORD * rec)321 bool can_write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec)
322 {
323    uint32_t remlen;
324 
325    remlen = block->buf_len - block->binbuf;
326    if (rec->remainder == 0) {
327       if (remlen >= WRITE_RECHDR_LENGTH) {
328          remlen -= WRITE_RECHDR_LENGTH;
329          rec->remainder = rec->data_len;
330       } else {
331          return false;
332       }
333    } else {
334       return false;
335    }
336    if (rec->remainder > 0 && remlen < rec->remainder) {
337       return false;
338    }
339    return true;
340 }
341 
get_record_address(DEV_RECORD * rec)342 uint64_t get_record_address(DEV_RECORD *rec)
343 {
344      return rec->Addr;
345 }
346 
get_record_start_address(DEV_RECORD * rec)347 uint64_t get_record_start_address(DEV_RECORD *rec)
348 {
349      return rec->StartAddr;
350 }
351