]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/restore.c
ae1ff8e00e02ee0a40dea98866aee6dca1174216
[bacula/bacula] / bacula / src / filed / restore.c
1 /*
2  *  Bacula File Daemon  restore.c Restorefiles.
3  *
4  *    Kern Sibbald, November MM
5  *
6  *   Version $Id$
7  *
8  */
9 /*
10    Copyright (C) 2000-2005 Kern Sibbald
11
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.
16
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.
21
22  */
23
24 #include "bacula.h"
25 #include "filed.h"
26
27 #ifdef HAVE_DARWIN_OS
28 #include <sys/attr.h>
29 #endif
30
31 /* Data received from Storage Daemon */
32 static char rec_header[] = "rechdr %ld %ld %ld %ld %ld";
33
34 /* Forward referenced functions */
35 #ifdef HAVE_LIBZ
36 static const char *zlib_strerror(int stat);
37 #endif
38
39 int32_t extract_data(JCR *jcr, BFILE *bfd, POOLMEM *buf, int32_t buflen,
40       uint64_t *addr, int flags);
41
42 #define RETRY 10                      /* retry wait time */
43
44 /*
45  * Close a bfd check that we are at the expected file offset.
46  * Makes some code in set_attributes().
47  */
48 int bclose_chksize(JCR *jcr, BFILE *bfd, off_t osize)
49 {
50    char ec1[50], ec2[50];
51    off_t fsize;
52
53    fsize = blseek(bfd, 0, SEEK_CUR);
54    bclose(bfd);                              /* first close file */
55    if (fsize > 0 && fsize != osize) {
56       Jmsg3(jcr, M_ERROR, 0, _("Size of data or stream of %s not correct. Original %s, restored %s.\n"),
57             jcr->last_fname, edit_uint64(osize, ec1),
58             edit_uint64(fsize, ec2));
59       return -1;
60    }
61    return 0;
62 }
63
64 /*
65  * Restore the requested files.
66  *
67  */
68 void do_restore(JCR *jcr)
69 {
70    BSOCK *sd;
71    int32_t stream = 0;
72    int32_t prev_stream;
73    uint32_t VolSessionId, VolSessionTime;
74    bool extract = false;
75    int32_t file_index;
76    char ec1[50];                      /* Buffer printing huge values */
77
78    BFILE bfd;                         /* File content */
79    uint64_t fileAddr = 0;             /* file write address */
80    uint32_t size;                     /* Size of file */
81    BFILE altbfd;                      /* Alternative data stream */
82    uint64_t alt_addr = 0;             /* Write address for alternative stream */
83    intmax_t alt_size = 0;             /* Size of alternate stream */
84    int flags;                         /* Options for extract_data() */
85    int stat;
86    ATTR *attr;
87
88    /* The following variables keep track of "known unknowns" */
89    int non_support_data = 0;
90    int non_support_attr = 0;
91    int non_support_rsrc = 0;
92    int non_support_finfo = 0;
93    int non_support_acl = 0;
94    int non_support_progname = 0;
95
96    /* Finally, set up for special configurations */
97 #ifdef HAVE_DARWIN_OS
98    intmax_t rsrc_len = 0;             /* Original length of resource fork */
99    struct attrlist attrList;
100
101    memset(&attrList, 0, sizeof(attrList));
102    attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
103    attrList.commonattr = ATTR_CMN_FNDRINFO;
104 #endif
105
106    sd = jcr->store_bsock;
107    set_jcr_job_status(jcr, JS_Running);
108
109    LockRes();
110    CLIENT *client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
111    UnlockRes();
112    uint32_t buf_size;
113    if (client) {
114       buf_size = client->max_network_buffer_size;
115    } else {
116       buf_size = 0;                   /* use default */
117    }
118    if (!bnet_set_buffer_size(sd, buf_size, BNET_SETBUF_WRITE)) {
119       set_jcr_job_status(jcr, JS_ErrorTerminated);
120       return;
121    }
122    jcr->buf_size = sd->msglen;
123
124 #ifdef HAVE_LIBZ
125    uint32_t compress_buf_size = jcr->buf_size + 12 + ((jcr->buf_size+999) / 1000) + 100;
126    jcr->compress_buf = (char *)bmalloc(compress_buf_size);
127    jcr->compress_buf_size = compress_buf_size;
128 #endif
129
130    /*
131     * Get a record from the Storage daemon. We are guaranteed to
132     *   receive records in the following order:
133     *   1. Stream record header
134     *   2. Stream data
135     *        a. Attributes (Unix or Win32)
136     *    or  b. File data for the file
137     *    or  c. Alternate data stream (e.g. Resource Fork)
138     *    or  d. Finder info
139     *    or  e. ACLs
140     *    or  f. Possibly MD5 or SHA1 record
141     *   3. Repeat step 1
142     *
143     * NOTE: We keep track of two bacula file descriptors:
144     *   1. bfd for file data.
145     *      This fd is opened for non empty files when an attribute stream is
146     *      encountered and closed when we find the next attribute stream.
147     *   2. alt_bfd for alternate data streams
148     *      This fd is opened every time we encounter a new alternate data
149     *      stream for the current file. When we find any other stream, we
150     *      close it again.
151     *      The expected size of the stream, alt_len, should be set when
152     *      opening the fd.
153     */
154    binit(&bfd);
155    binit(&altbfd);
156    attr = new_attr();
157    jcr->acl_text = get_pool_memory(PM_MESSAGE);
158
159    while (bget_msg(sd) >= 0 && !job_canceled(jcr)) {
160       /* Remember previous stream type */
161       prev_stream = stream;
162
163       /* First we expect a Stream Record Header */
164       if (sscanf(sd->msg, rec_header, &VolSessionId, &VolSessionTime, &file_index,
165           &stream, &size) != 5) {
166          Jmsg1(jcr, M_FATAL, 0, _("Record header scan error: %s\n"), sd->msg);
167          goto bail_out;
168       }
169       Dmsg2(30, "Got hdr: FilInx=%d Stream=%d.\n", file_index, stream);
170
171       /* * Now we expect the Stream Data */
172       if (bget_msg(sd) < 0) {
173          Jmsg1(jcr, M_FATAL, 0, _("Data record error. ERR=%s\n"), bnet_strerror(sd));
174          goto bail_out;
175       }
176       if (size != (uint32_t)sd->msglen) {
177          Jmsg2(jcr, M_FATAL, 0, _("Actual data size %d not same as header %d\n"), sd->msglen, size);
178          goto bail_out;
179       }
180       Dmsg1(30, "Got stream data, len=%d\n", sd->msglen);
181
182       /* If we change streams, close and reset alternate data streams */
183       if (prev_stream != stream) {
184          if (is_bopen(&altbfd)) {
185             bclose_chksize(jcr, &altbfd, alt_size);
186          }
187          alt_size = -1; /* Use an impossible value and set a proper one below */
188          alt_addr = 0;
189       }
190
191       /* File Attributes stream */
192       switch (stream) {
193       case STREAM_UNIX_ATTRIBUTES:
194       case STREAM_UNIX_ATTRIBUTES_EX:
195          Dmsg1(30, "Stream=Unix Attributes. extract=%d\n", extract);
196          /*
197           * If extracting, it was from previous stream, so
198           * close the output file.
199           */
200          if (extract) {
201             if (size > 0 && !is_bopen(&bfd)) {
202                Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should be open\n"));
203             }
204             set_attributes(jcr, attr, &bfd);
205             extract = false;
206             Dmsg0(30, "Stop extracting.\n");
207          } else if (is_bopen(&bfd)) {
208             Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should not be open\n"));
209             bclose(&bfd);
210          }
211
212          /*
213           * Unpack and do sanity check fo attributes.
214           */
215          if (!unpack_attributes_record(jcr, stream, sd->msg, attr)) {
216             goto bail_out;
217          }
218          if (file_index != attr->file_index) {
219             Jmsg(jcr, M_FATAL, 0, _("Record header file index %ld not equal record index %ld\n"),
220                  file_index, attr->file_index);
221             Dmsg0(100, "File index error\n");
222             goto bail_out;
223          }
224
225          Dmsg3(200, "File %s\nattrib=%s\nattribsEx=%s\n", attr->fname,
226                attr->attr, attr->attrEx);
227
228          attr->data_stream = decode_stat(attr->attr, &attr->statp, &attr->LinkFI);
229
230          if (!is_stream_supported(attr->data_stream)) {
231             if (!non_support_data++) {
232                Jmsg(jcr, M_ERROR, 0, _("%s stream not supported on this Client.\n"),
233                   stream_to_ascii(attr->data_stream));
234             }
235             continue;
236          }
237
238          build_attr_output_fnames(jcr, attr);
239
240          /*
241           * Now determine if we are extracting or not.
242           */
243          jcr->num_files_examined++;
244          Dmsg1(30, "Outfile=%s\n", attr->ofname);
245          extract = false;
246          stat = create_file(jcr, attr, &bfd, jcr->replace);
247          switch (stat) {
248          case CF_ERROR:
249          case CF_SKIP:
250             break;
251          case CF_EXTRACT:        /* File created and we expect file data */
252             extract = true;
253             /* FALLTHROUGH */
254          case CF_CREATED:        /* File created, but there is no content */
255             P(jcr->mutex);
256             pm_strcpy(jcr->last_fname, attr->ofname);
257             V(jcr->mutex);
258             jcr->JobFiles++;
259             fileAddr = 0;
260             print_ls_output(jcr, attr);
261 #ifdef HAVE_DARWIN_OS
262             /* Only restore the resource fork for regular files */
263             from_base64(&rsrc_len, attr->attrEx);
264             if (attr->type == FT_REG && rsrc_len > 0) {
265                extract = true;
266             }
267 #endif
268             if (!extract) {
269                /* set attributes now because file will not be extracted */
270                set_attributes(jcr, attr, &bfd);
271             }
272             break;
273          }
274          break;
275
276       /* Data stream */
277       case STREAM_FILE_DATA:
278       case STREAM_SPARSE_DATA:
279       case STREAM_WIN32_DATA:
280       case STREAM_GZIP_DATA:
281       case STREAM_SPARSE_GZIP_DATA:
282       case STREAM_WIN32_GZIP_DATA:
283          /* Force an expected, consistent stream type here */
284          if (extract && (prev_stream == stream || prev_stream == STREAM_UNIX_ATTRIBUTES
285                   || prev_stream == STREAM_UNIX_ATTRIBUTES_EX)) {
286             flags = 0;
287             if (stream == STREAM_SPARSE_DATA || stream == STREAM_SPARSE_GZIP_DATA) {
288                flags |= FO_SPARSE;
289             }
290             if (stream == STREAM_GZIP_DATA || stream == STREAM_SPARSE_GZIP_DATA
291                   || stream == STREAM_WIN32_GZIP_DATA) {
292                flags |= FO_GZIP;
293             }
294
295             if (is_win32_stream(stream) && !have_win32_api()) {
296                set_portable_backup(&bfd);
297                flags |= FO_WIN32DECOMP;    /* "decompose BackupWrite data */
298             }
299
300             if (extract_data(jcr, &bfd, sd->msg, sd->msglen, &fileAddr, flags) < 0) {
301                extract = false;
302                bclose(&bfd);
303                continue;
304             }
305          }
306          break;
307
308       /* Resource fork stream - only recorded after a file to be restored */
309       /* Silently ignore if we cannot write - we already reported that */
310       case STREAM_MACOS_FORK_DATA:
311 #ifdef HAVE_DARWIN_OS
312          if (extract) {
313             if (prev_stream != stream) {
314                if (bopen_rsrc(&altbfd, jcr->last_fname, O_WRONLY | O_TRUNC | O_BINARY, 0) < 0) {
315                   Jmsg(jcr, M_ERROR, 0, _("     Cannot open resource fork for %s.\n"), jcr->last_fname);
316                   extract = false;
317                   continue;
318                }
319                alt_size = rsrc_len;
320                Dmsg0(30, "Restoring resource fork\n");
321             }
322             flags = 0;
323             if (extract_data(jcr, &altbfd, sd->msg, sd->msglen, &alt_addr, flags) < 0) {
324                extract = false;
325                bclose(&altbfd);
326                continue;
327             }
328          }
329 #else
330          non_support_rsrc++;
331 #endif
332          break;
333
334       case STREAM_HFSPLUS_ATTRIBUTES:
335 #ifdef HAVE_DARWIN_OS
336          Dmsg0(30, "Restoring Finder Info\n");
337          if (sd->msglen != 32) {
338             Jmsg(jcr, M_ERROR, 0, _("     Invalid length of Finder Info (got %d, not 32)\n"), sd->msglen);
339             continue;
340          }
341          if (setattrlist(jcr->last_fname, &attrList, sd->msg, sd->msglen, 0) != 0) {
342             Jmsg(jcr, M_ERROR, 0, _("     Could not set Finder Info on %s\n"), jcr->last_fname);
343             continue;
344          }
345 #else
346          non_support_finfo++;
347 #endif
348
349       case STREAM_UNIX_ATTRIBUTES_ACCESS_ACL:
350 #ifdef HAVE_ACL
351          pm_strcpy(jcr->acl_text, sd->msg);
352          Dmsg2(400, "Restoring ACL type 0x%2x <%s>\n", BACL_TYPE_ACCESS, jcr->acl_text);
353          if (bacl_set(jcr, BACL_TYPE_ACCESS) != 0) {
354                Jmsg1(jcr, M_WARNING, 0, _("Can't restore ACL of %s\n"), jcr->last_fname);
355          }
356 #else 
357          non_support_acl++;
358 #endif
359          break;
360
361       case STREAM_UNIX_ATTRIBUTES_DEFAULT_ACL:
362 #ifdef HAVE_ACL
363          pm_strcpy(jcr->acl_text, sd->msg);
364          Dmsg2(400, "Restoring ACL type 0x%2x <%s>\n", BACL_TYPE_DEFAULT, jcr->acl_text);
365          if (bacl_set(jcr, BACL_TYPE_DEFAULT) != 0) {
366                Jmsg1(jcr, M_WARNING, 0, _("Can't restore default ACL of %s\n"), jcr->last_fname);
367          }
368 #else 
369          non_support_acl++;
370 #endif
371          break;
372
373       case STREAM_MD5_SIGNATURE:
374       case STREAM_SHA1_SIGNATURE:
375          break;
376
377       case STREAM_PROGRAM_NAMES:
378       case STREAM_PROGRAM_DATA:
379          if (!non_support_progname) {
380             Pmsg0(000, "Got Program Name or Data Stream. Ignored.\n");
381             non_support_progname++;
382          }
383          break;
384
385       default:
386          /* If extracting, wierd stream (not 1 or 2), close output file anyway */
387          if (extract) {
388             Dmsg1(30, "Found wierd stream %d\n", stream);
389             if (size > 0 && !is_bopen(&bfd)) {
390                Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should be open\n"));
391             }
392             set_attributes(jcr, attr, &bfd);
393             extract = false;
394          } else if (is_bopen(&bfd)) {
395             Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should not be open\n"));
396             bclose(&bfd);
397          }
398          Jmsg(jcr, M_ERROR, 0, _("Unknown stream=%d ignored. This shouldn't happen!\n"), stream);
399          Dmsg2(0, "None of above!!! stream=%d data=%s\n", stream,sd->msg);
400          break;
401       } /* end switch(stream) */
402
403    } /* end while get_msg() */
404
405    /* If output file is still open, it was the last one in the
406     * archive since we just hit an end of file, so close the file.
407     */
408    if (is_bopen(&altbfd)) {
409       bclose_chksize(jcr, &altbfd, alt_size);
410    }
411    if (extract) {
412       set_attributes(jcr, attr, &bfd);
413    }
414    if (is_bopen(&bfd)) {
415       bclose(&bfd);
416    }
417    set_jcr_job_status(jcr, JS_Terminated);
418    goto ok_out;
419
420 bail_out:
421    set_jcr_job_status(jcr, JS_ErrorTerminated);
422 ok_out:
423    if (jcr->compress_buf) {
424       free(jcr->compress_buf);
425       jcr->compress_buf = NULL;
426       jcr->compress_buf_size = 0;
427    }
428    bclose(&altbfd);
429    bclose(&bfd);
430    free_attr(attr);
431    free_pool_memory(jcr->acl_text);
432    Dmsg2(10, "End Do Restore. Files=%d Bytes=%s\n", jcr->JobFiles,
433       edit_uint64(jcr->JobBytes, ec1));
434    if (non_support_data > 1 || non_support_attr > 1) {
435       Jmsg(jcr, M_ERROR, 0, _("%d non-supported data streams and %d non-supported attrib streams ignored.\n"),
436          non_support_data, non_support_attr);
437    }
438    if (non_support_rsrc) {
439       Jmsg(jcr, M_INFO, 0, _("%d non-supported resource fork streams ignored.\n"), non_support_rsrc);
440    }
441    if (non_support_finfo) {
442       Jmsg(jcr, M_INFO, 0, _("%d non-supported Finder Info streams ignored.\n"), non_support_rsrc);
443    }
444    if (non_support_acl) {
445       Jmsg(jcr, M_INFO, 0, _("%d non-supported acl streams ignored.\n"), non_support_acl);
446    }
447
448 }
449
450 #ifdef HAVE_LIBZ
451 /*
452  * Convert ZLIB error code into an ASCII message
453  */
454 static const char *zlib_strerror(int stat)
455 {
456    if (stat >= 0) {
457       return _("None");
458    }
459    switch (stat) {
460    case Z_ERRNO:
461       return _("Zlib errno");
462    case Z_STREAM_ERROR:
463       return _("Zlib stream error");
464    case Z_DATA_ERROR:
465       return _("Zlib data error");
466    case Z_MEM_ERROR:
467       return _("Zlib memory error");
468    case Z_BUF_ERROR:
469       return _("Zlib buffer error");
470    case Z_VERSION_ERROR:
471       return _("Zlib version error");
472    default:
473       return _("*none*");
474    }
475 }
476 #endif
477
478 /*
479  * In the context of jcr, write data to bfd.
480  * We write buflen bytes in buf at addr. addr is updated in place.
481  * The flags specify whether to use sparse files or compression.
482  * Return value is the number of bytes written, or -1 on errors.
483  */
484 int32_t extract_data(JCR *jcr, BFILE *bfd, POOLMEM *buf, int32_t buflen,
485       uint64_t *addr, int flags)
486 {
487    int stat;
488    char *wbuf;                        /* write buffer */
489    uint32_t wsize;                    /* write size */
490    uint32_t rsize;                    /* read size */
491    char ec1[50];                      /* Buffer printing huge values */
492
493    if (flags & FO_SPARSE) {
494       ser_declare;
495       uint64_t faddr;
496       char ec1[50];
497       wbuf = buf + SPARSE_FADDR_SIZE;
498       rsize = buflen - SPARSE_FADDR_SIZE;
499       ser_begin(buf, SPARSE_FADDR_SIZE);
500       unser_uint64(faddr);
501       if (*addr != faddr) {
502          *addr = faddr;
503          if (blseek(bfd, (off_t)*addr, SEEK_SET) < 0) {
504             berrno be;
505             Jmsg3(jcr, M_ERROR, 0, _("Seek to %s error on %s: ERR=%s\n"),
506                   edit_uint64(*addr, ec1), jcr->last_fname, 
507                   be.strerror(bfd->berrno));
508             return -1;
509          }
510       }
511    } else {
512       wbuf = buf;
513       rsize = buflen;
514    }
515    wsize = rsize;
516
517    if (flags & FO_GZIP) {
518 #ifdef HAVE_LIBZ
519       uLong compress_len;
520       /* 
521        * NOTE! We only use uLong and Byte because they are
522        *  needed by the zlib routines, they should not otherwise
523        *  be used in Bacula.
524        */
525       compress_len = jcr->compress_buf_size;
526       Dmsg2(100, "Comp_len=%d msglen=%d\n", compress_len, wsize);
527       if ((stat=uncompress((Byte *)jcr->compress_buf, &compress_len,
528                   (const Byte *)wbuf, (uLong)rsize)) != Z_OK) {
529          Jmsg(jcr, M_ERROR, 0, _("Uncompression error on file %s. ERR=%s\n"),
530                jcr->last_fname, zlib_strerror(stat));
531          return -1;
532       }
533       wbuf = jcr->compress_buf;
534       wsize = compress_len;
535       Dmsg2(100, "Write uncompressed %d bytes, total before write=%s\n", compress_len, edit_uint64(jcr->JobBytes, ec1));
536 #else
537       Jmsg(jcr, M_ERROR, 0, _("GZIP data stream found, but GZIP not configured!\n"));
538       return -1;
539 #endif
540    } else {
541       Dmsg2(30, "Write %u bytes, total before write=%s\n", wsize, edit_uint64(jcr->JobBytes, ec1));
542    }
543
544 #ifdef USE_WIN32STREAMEXTRACTION
545    if (flags & FO_WIN32DECOMP) {
546       if (!processWin32BackupAPIBlock(bfd, wbuf, wsize)) {
547          berrno be;
548          Jmsg2(jcr, M_ERROR, 0, _("Write error in Win32 Block Decomposition on %s: %s\n"), 
549                jcr->last_fname, be.strerror(bfd->berrno));
550          return -1;
551       }
552    }
553    else
554 #endif
555    if (bwrite(bfd, wbuf, wsize) != (ssize_t)wsize) {
556       berrno be;
557       Jmsg2(jcr, M_ERROR, 0, _("Write error on %s: %s\n"), 
558             jcr->last_fname, be.strerror(bfd->berrno));
559       return -1;
560    }
561
562    jcr->JobBytes += wsize;
563    jcr->ReadBytes += rsize;
564    *addr += wsize;
565
566    return wsize;
567 }