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