2 * Bacula File Daemon restore.c Restorefiles.
4 * Kern Sibbald, November MM
10 Copyright (C) 2000-2005 Kern Sibbald
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License
14 version 2 as amended with additional clauses defined in the
15 file LICENSE in the main source directory.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 the file LICENSE for additional details.
31 /* Data received from Storage Daemon */
32 static char rec_header[] = "rechdr %ld %ld %ld %ld %ld";
34 /* Forward referenced functions */
36 static const char *zlib_strerror(int stat);
38 int32_t extract_data(JCR *jcr, BFILE *bfd, POOLMEM *buf, int32_t buflen,
39 uint64_t *addr, int flags);
41 #define RETRY 10 /* retry wait time */
44 * Close a bfd check that we are at the expected file offset.
45 * Makes some code in set_attributes().
47 int bclose_chksize(JCR *jcr, BFILE *bfd, off_t osize)
49 char ec1[50], ec2[50];
52 fsize = blseek(bfd, 0, SEEK_CUR);
53 bclose(bfd); /* first close file */
54 if (fsize > 0 && fsize != osize) {
55 Jmsg3(jcr, M_ERROR, 0, _("Size of data or stream of %s not correct. Original %s, restored %s.\n"),
56 jcr->last_fname, edit_uint64(osize, ec1),
57 edit_uint64(fsize, ec2));
64 * Restore the requested files.
67 void do_restore(JCR *jcr)
72 uint32_t VolSessionId, VolSessionTime;
75 char ec1[50]; /* Buffer printing huge values */
77 BFILE bfd; /* File content */
78 uint64_t fileAddr = 0; /* file write address */
79 uint32_t size; /* Size of file */
80 BFILE altbfd; /* Alternative data stream */
81 uint64_t alt_addr = 0; /* Write address for alternative stream */
82 intmax_t alt_size = 0; /* Size of alternate stream */
83 int flags; /* Options for extract_data() */
87 /* The following variables keep track of "known unknowns" */
88 int non_support_data = 0;
89 int non_support_attr = 0;
90 int non_support_rsrc = 0;
91 int non_support_finfo = 0;
92 int non_support_acl = 0;
93 int non_support_progname = 0;
95 /* Finally, set up for special configurations */
97 intmax_t rsrc_len = 0; /* Original length of resource fork */
98 struct attrlist attrList;
100 memset(&attrList, 0, sizeof(attrList));
101 attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
102 attrList.commonattr = ATTR_CMN_FNDRINFO;
105 sd = jcr->store_bsock;
106 set_jcr_job_status(jcr, JS_Running);
109 CLIENT *client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
113 buf_size = client->max_network_buffer_size;
115 buf_size = 0; /* use default */
117 if (!bnet_set_buffer_size(sd, buf_size, BNET_SETBUF_WRITE)) {
118 set_jcr_job_status(jcr, JS_ErrorTerminated);
121 jcr->buf_size = sd->msglen;
124 uint32_t compress_buf_size = jcr->buf_size + 12 + ((jcr->buf_size+999) / 1000) + 100;
125 jcr->compress_buf = (char *)bmalloc(compress_buf_size);
126 jcr->compress_buf_size = compress_buf_size;
130 * Get a record from the Storage daemon. We are guaranteed to
131 * receive records in the following order:
132 * 1. Stream record header
134 * a. Attributes (Unix or Win32)
135 * or b. File data for the file
136 * or c. Alternate data stream (e.g. Resource Fork)
139 * or f. Possibly MD5 or SHA1 record
142 * NOTE: We keep track of two bacula file descriptors:
143 * 1. bfd for file data.
144 * This fd is opened for non empty files when an attribute stream is
145 * encountered and closed when we find the next attribute stream.
146 * 2. alt_bfd for alternate data streams
147 * This fd is opened every time we encounter a new alternate data
148 * stream for the current file. When we find any other stream, we
150 * The expected size of the stream, alt_len, should be set when
156 jcr->acl_text = get_pool_memory(PM_MESSAGE);
158 while (bget_msg(sd) >= 0 && !job_canceled(jcr)) {
159 /* Remember previous stream type */
160 prev_stream = stream;
162 /* First we expect a Stream Record Header */
163 if (sscanf(sd->msg, rec_header, &VolSessionId, &VolSessionTime, &file_index,
164 &stream, &size) != 5) {
165 Jmsg1(jcr, M_FATAL, 0, _("Record header scan error: %s\n"), sd->msg);
168 Dmsg2(30, "Got hdr: FilInx=%d Stream=%d.\n", file_index, stream);
170 /* * Now we expect the Stream Data */
171 if (bget_msg(sd) < 0) {
172 Jmsg1(jcr, M_FATAL, 0, _("Data record error. ERR=%s\n"), bnet_strerror(sd));
175 if (size != (uint32_t)sd->msglen) {
176 Jmsg2(jcr, M_FATAL, 0, _("Actual data size %d not same as header %d\n"), sd->msglen, size);
179 Dmsg1(30, "Got stream data, len=%d\n", sd->msglen);
181 /* If we change streams, close and reset alternate data streams */
182 if (prev_stream != stream) {
183 if (is_bopen(&altbfd)) {
184 bclose_chksize(jcr, &altbfd, alt_size);
186 alt_size = -1; /* Use an impossible value and set a proper one below */
190 /* File Attributes stream */
192 case STREAM_UNIX_ATTRIBUTES:
193 case STREAM_UNIX_ATTRIBUTES_EX:
194 Dmsg1(30, "Stream=Unix Attributes. extract=%d\n", extract);
196 * If extracting, it was from previous stream, so
197 * close the output file.
200 if (size > 0 && !is_bopen(&bfd)) {
201 Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should be open\n"));
203 set_attributes(jcr, attr, &bfd);
205 Dmsg0(30, "Stop extracting.\n");
206 } else if (is_bopen(&bfd)) {
207 Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should not be open\n"));
212 * Unpack and do sanity check fo attributes.
214 if (!unpack_attributes_record(jcr, stream, sd->msg, attr)) {
217 if (file_index != attr->file_index) {
218 Jmsg(jcr, M_FATAL, 0, _("Record header file index %ld not equal record index %ld\n"),
219 file_index, attr->file_index);
220 Dmsg0(100, "File index error\n");
224 Dmsg3(200, "File %s\nattrib=%s\nattribsEx=%s\n", attr->fname,
225 attr->attr, attr->attrEx);
227 attr->data_stream = decode_stat(attr->attr, &attr->statp, &attr->LinkFI);
229 if (!is_stream_supported(attr->data_stream)) {
230 if (!non_support_data++) {
231 Jmsg(jcr, M_ERROR, 0, _("%s stream not supported on this Client.\n"),
232 stream_to_ascii(attr->data_stream));
237 build_attr_output_fnames(jcr, attr);
240 * Now determine if we are extracting or not.
242 jcr->num_files_examined++;
243 Dmsg1(30, "Outfile=%s\n", attr->ofname);
245 stat = create_file(jcr, attr, &bfd, jcr->replace);
250 case CF_EXTRACT: /* File created and we expect file data */
253 case CF_CREATED: /* File created, but there is no content */
255 pm_strcpy(jcr->last_fname, attr->ofname);
259 print_ls_output(jcr, attr);
260 #ifdef HAVE_DARWIN_OS
261 /* Only restore the resource fork for regular files */
262 from_base64(&rsrc_len, attr->attrEx);
263 if (attr->type == FT_REG && rsrc_len > 0) {
268 /* set attributes now because file will not be extracted */
269 set_attributes(jcr, attr, &bfd);
276 case STREAM_FILE_DATA:
277 case STREAM_SPARSE_DATA:
278 case STREAM_WIN32_DATA:
279 case STREAM_GZIP_DATA:
280 case STREAM_SPARSE_GZIP_DATA:
281 case STREAM_WIN32_GZIP_DATA:
282 /* Force an expected, consistent stream type here */
283 if (extract && (prev_stream == stream || prev_stream == STREAM_UNIX_ATTRIBUTES
284 || prev_stream == STREAM_UNIX_ATTRIBUTES_EX)) {
286 if (stream == STREAM_SPARSE_DATA || stream == STREAM_SPARSE_GZIP_DATA) {
289 if (stream == STREAM_GZIP_DATA || stream == STREAM_SPARSE_GZIP_DATA
290 || stream == STREAM_WIN32_GZIP_DATA) {
293 if (extract_data(jcr, &bfd, sd->msg, sd->msglen, &fileAddr, flags) < 0) {
301 /* Resource fork stream - only recorded after a file to be restored */
302 /* Silently ignore if we cannot write - we already reported that */
303 case STREAM_MACOS_FORK_DATA:
304 #ifdef HAVE_DARWIN_OS
306 if (prev_stream != stream) {
307 if (bopen_rsrc(&altbfd, jcr->last_fname, O_WRONLY | O_TRUNC | O_BINARY, 0) < 0) {
308 Jmsg(jcr, M_ERROR, 0, _(" Cannot open resource fork for %s\n"), jcr->last_fname);
313 Dmsg0(30, "Restoring resource fork\n");
316 if (extract_data(jcr, &altbfd, sd->msg, sd->msglen, &alt_addr, flags) < 0) {
327 case STREAM_HFSPLUS_ATTRIBUTES:
328 #ifdef HAVE_DARWIN_OS
329 Dmsg0(30, "Restoring Finder Info\n");
330 if (sd->msglen != 32) {
331 Jmsg(jcr, M_ERROR, 0, _(" Invalid length of Finder Info (got %d, not 32)\n"), sd->msglen);
334 if (setattrlist(jcr->last_fname, &attrList, sd->msg, sd->msglen, 0) != 0) {
335 Jmsg(jcr, M_ERROR, 0, _(" Could not set Finder Info on %s\n"), jcr->last_fname);
342 case STREAM_UNIX_ATTRIBUTES_ACCESS_ACL:
344 pm_strcpy(jcr->acl_text, sd->msg);
345 Dmsg2(400, "Restoring ACL type 0x%2x <%s>\n", BACL_TYPE_ACCESS, jcr->acl_text);
346 if (bacl_set(jcr, BACL_TYPE_ACCESS) != 0) {
347 Jmsg1(jcr, M_WARNING, 0, "Can't restore ACL of %s\n", jcr->last_fname);
354 case STREAM_UNIX_ATTRIBUTES_DEFAULT_ACL:
356 pm_strcpy(jcr->acl_text, sd->msg);
357 Dmsg2(400, "Restoring ACL type 0x%2x <%s>\n", BACL_TYPE_DEFAULT, jcr->acl_text);
358 if (bacl_set(jcr, BACL_TYPE_DEFAULT) != 0) {
359 Jmsg1(jcr, M_WARNING, 0, "Can't restore default ACL of %s\n", jcr->last_fname);
366 case STREAM_MD5_SIGNATURE:
367 case STREAM_SHA1_SIGNATURE:
370 case STREAM_PROGRAM_NAMES:
371 case STREAM_PROGRAM_DATA:
372 if (!non_support_progname) {
373 Pmsg0(000, "Got Program Name or Data Stream. Ignored.\n");
374 non_support_progname++;
379 /* If extracting, wierd stream (not 1 or 2), close output file anyway */
381 Dmsg1(30, "Found wierd stream %d\n", stream);
382 if (size > 0 && !is_bopen(&bfd)) {
383 Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should be open\n"));
385 set_attributes(jcr, attr, &bfd);
387 } else if (is_bopen(&bfd)) {
388 Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should not be open\n"));
391 Jmsg(jcr, M_ERROR, 0, _("Unknown stream=%d ignored. This shouldn't happen!\n"), stream);
392 Dmsg2(0, "None of above!!! stream=%d data=%s\n", stream,sd->msg);
394 } /* end switch(stream) */
396 } /* end while get_msg() */
398 /* If output file is still open, it was the last one in the
399 * archive since we just hit an end of file, so close the file.
401 if (is_bopen(&altbfd)) {
402 bclose_chksize(jcr, &altbfd, alt_size);
405 set_attributes(jcr, attr, &bfd);
407 if (is_bopen(&bfd)) {
410 set_jcr_job_status(jcr, JS_Terminated);
414 set_jcr_job_status(jcr, JS_ErrorTerminated);
416 if (jcr->compress_buf) {
417 free(jcr->compress_buf);
418 jcr->compress_buf = NULL;
419 jcr->compress_buf_size = 0;
424 free_pool_memory(jcr->acl_text);
425 Dmsg2(10, "End Do Restore. Files=%d Bytes=%s\n", jcr->JobFiles,
426 edit_uint64(jcr->JobBytes, ec1));
427 if (non_support_data > 1 || non_support_attr > 1) {
428 Jmsg(jcr, M_ERROR, 0, _("%d non-supported data streams and %d non-supported attrib streams ignored.\n"),
429 non_support_data, non_support_attr);
431 if (non_support_rsrc) {
432 Jmsg(jcr, M_INFO, 0, _("%d non-supported resource fork streams ignored.\n"), non_support_rsrc);
434 if (non_support_finfo) {
435 Jmsg(jcr, M_INFO, 0, _("%d non-supported Finder Info streams ignored.\n"), non_support_rsrc);
437 if (non_support_acl) {
438 Jmsg(jcr, M_INFO, 0, _("%d non-supported acl streams ignored.\n"), non_support_acl);
445 * Convert ZLIB error code into an ASCII message
447 static const char *zlib_strerror(int stat)
456 return "Zlib stream error";
458 return "Zlib data error";
460 return "Zlib memory error";
462 return "Zlib buffer error";
463 case Z_VERSION_ERROR:
464 return "Zlib version error";
472 * In the context of jcr, write data to bfd.
473 * We write buflen bytes in buf at addr. addr is updated in place.
474 * The flags specify whether to use sparse files or compression.
475 * Return value is the number of bytes written, or -1 on errors.
477 int32_t extract_data(JCR *jcr, BFILE *bfd, POOLMEM *buf, int32_t buflen,
478 uint64_t *addr, int flags)
481 char *wbuf; /* write buffer */
482 uint32_t wsize; /* write size */
483 uint32_t rsize; /* read size */
484 char ec1[50]; /* Buffer printing huge values */
486 if (flags & FO_SPARSE) {
490 wbuf = buf + SPARSE_FADDR_SIZE;
491 rsize = buflen - SPARSE_FADDR_SIZE;
492 ser_begin(buf, SPARSE_FADDR_SIZE);
494 if (*addr != faddr) {
496 if (blseek(bfd, (off_t)*addr, SEEK_SET) < 0) {
498 Jmsg3(jcr, M_ERROR, 0, _("Seek to %s error on %s: ERR=%s\n"),
499 edit_uint64(*addr, ec1), jcr->last_fname,
500 be.strerror(bfd->berrno));
510 if (flags & FO_GZIP) {
514 * NOTE! We only use uLong and Byte because they are
515 * needed by the zlib routines, they should not otherwise
518 compress_len = jcr->compress_buf_size;
519 Dmsg2(100, "Comp_len=%d msglen=%d\n", compress_len, wsize);
520 if ((stat=uncompress((Byte *)jcr->compress_buf, &compress_len,
521 (const Byte *)wbuf, (uLong)rsize)) != Z_OK) {
522 Jmsg(jcr, M_ERROR, 0, _("Uncompression error on file %s. ERR=%s\n"),
523 jcr->last_fname, zlib_strerror(stat));
526 wbuf = jcr->compress_buf;
527 wsize = compress_len;
528 Dmsg2(100, "Write uncompressed %d bytes, total before write=%s\n", compress_len, edit_uint64(jcr->JobBytes, ec1));
530 Jmsg(jcr, M_ERROR, 0, _("GZIP data stream found, but GZIP not configured!\n"));
534 Dmsg2(30, "Write %u bytes, total before write=%s\n", wsize, edit_uint64(jcr->JobBytes, ec1));
537 if (bwrite(bfd, wbuf, wsize) != (ssize_t)wsize) {
539 Jmsg2(jcr, M_ERROR, 0, _("Write error on %s: %s\n"),
540 jcr->last_fname, be.strerror(bfd->berrno));
544 jcr->JobBytes += wsize;
545 jcr->ReadBytes += rsize;