]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/restore.c
This commit was manufactured by cvs2svn to create tag
[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 int32_t extract_data(JCR *jcr, BFILE *bfd, POOLMEM *buf, int32_t buflen,
39       uint64_t *addr, int flags);
40
41 #define RETRY 10                      /* retry wait time */
42
43 /*
44  * Close a bfd check that we are at the expected file offset.
45  * Makes some code in set_attributes().
46  */
47 int bclose_chksize(JCR *jcr, BFILE *bfd, off_t osize)
48 {
49    char ec1[50], ec2[50];
50    off_t fsize;
51
52    fsize = blseek(bfd, 0, SEEK_CUR);
53    bclose(bfd);                              /* first close file */
54    if (fsize > 0 && fsize != osize) {
55       Qmsg3(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));
58       return -1;
59    }
60    return 0;
61 }
62
63 /*
64  * Restore the requested files.
65  *
66  */
67 void do_restore(JCR *jcr)
68 {
69    BSOCK *sd;
70    int32_t stream = 0;
71    int32_t prev_stream;
72    uint32_t VolSessionId, VolSessionTime;
73    bool extract = false;
74    int32_t file_index;
75    char ec1[50];                      /* Buffer printing huge values */
76
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() */
84    int stat;
85    ATTR *attr;
86
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;
94
95    /* Finally, set up for special configurations */
96 #ifdef HAVE_DARWIN_OS
97    intmax_t rsrc_len = 0;             /* Original length of resource fork */
98    struct attrlist attrList;
99
100    memset(&attrList, 0, sizeof(attrList));
101    attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
102    attrList.commonattr = ATTR_CMN_FNDRINFO;
103 #endif
104
105    sd = jcr->store_bsock;
106    set_jcr_job_status(jcr, JS_Running);
107
108    LockRes();
109    CLIENT *client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
110    UnlockRes();
111    uint32_t buf_size;
112    if (client) {
113       buf_size = client->max_network_buffer_size;
114    } else {
115       buf_size = 0;                   /* use default */
116    }
117    if (!bnet_set_buffer_size(sd, buf_size, BNET_SETBUF_WRITE)) {
118       set_jcr_job_status(jcr, JS_ErrorTerminated);
119       return;
120    }
121    jcr->buf_size = sd->msglen;
122
123 #ifdef HAVE_LIBZ
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;
127 #endif
128
129    /*
130     * Get a record from the Storage daemon. We are guaranteed to
131     *   receive records in the following order:
132     *   1. Stream record header
133     *   2. Stream data
134     *        a. Attributes (Unix or Win32)
135     *    or  b. File data for the file
136     *    or  c. Alternate data stream (e.g. Resource Fork)
137     *    or  d. Finder info
138     *    or  e. ACLs
139     *    or  f. Possibly MD5 or SHA1 record
140     *   3. Repeat step 1
141     *
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
149     *      close it again.
150     *      The expected size of the stream, alt_len, should be set when
151     *      opening the fd.
152     */
153    binit(&bfd);
154    binit(&altbfd);
155    attr = new_attr();
156    jcr->acl_text = get_pool_memory(PM_MESSAGE);
157
158    while (bget_msg(sd) >= 0 && !job_canceled(jcr)) {
159       /* Remember previous stream type */
160       prev_stream = stream;
161
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);
166          goto bail_out;
167       }
168       Dmsg2(30, "Got hdr: FilInx=%d Stream=%d.\n", file_index, stream);
169
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));
173          goto bail_out;
174       }
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);
177          goto bail_out;
178       }
179       Dmsg1(30, "Got stream data, len=%d\n", sd->msglen);
180
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);
185          }
186          alt_size = -1; /* Use an impossible value and set a proper one below */
187          alt_addr = 0;
188       }
189
190       /* File Attributes stream */
191       switch (stream) {
192       case STREAM_UNIX_ATTRIBUTES:
193       case STREAM_UNIX_ATTRIBUTES_EX:
194          Dmsg1(30, "Stream=Unix Attributes. extract=%d\n", extract);
195          /*
196           * If extracting, it was from previous stream, so
197           * close the output file.
198           */
199          if (extract) {
200             if (size > 0 && !is_bopen(&bfd)) {
201                Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should be open\n"));
202             }
203             set_attributes(jcr, attr, &bfd);
204             extract = false;
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"));
208             bclose(&bfd);
209          }
210
211          /*
212           * Unpack and do sanity check fo attributes.
213           */
214          if (!unpack_attributes_record(jcr, stream, sd->msg, attr)) {
215             goto bail_out;
216          }
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");
221             goto bail_out;
222          }
223
224          Dmsg3(200, "File %s\nattrib=%s\nattribsEx=%s\n", attr->fname,
225                attr->attr, attr->attrEx);
226
227          attr->data_stream = decode_stat(attr->attr, &attr->statp, &attr->LinkFI);
228
229          if (!is_restore_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));
233             }
234             continue;
235          }
236
237          build_attr_output_fnames(jcr, attr);
238
239          /*
240           * Now determine if we are extracting or not.
241           */
242          jcr->num_files_examined++;
243          Dmsg1(30, "Outfile=%s\n", attr->ofname);
244          extract = false;
245          stat = create_file(jcr, attr, &bfd, jcr->replace);
246          switch (stat) {
247          case CF_ERROR:
248          case CF_SKIP:
249             break;
250          case CF_EXTRACT:        /* File created and we expect file data */
251             extract = true;
252             /* FALLTHROUGH */
253          case CF_CREATED:        /* File created, but there is no content */
254             jcr->lock();
255             pm_strcpy(jcr->last_fname, attr->ofname);
256             jcr->unlock();
257             jcr->JobFiles++;
258             fileAddr = 0;
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) {
264                extract = true;
265             }
266 #endif
267             if (!extract) {
268                /* set attributes now because file will not be extracted */
269                set_attributes(jcr, attr, &bfd);
270             }
271             break;
272          }
273          break;
274
275       /* Data stream */
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)) {
285             flags = 0;
286             if (stream == STREAM_SPARSE_DATA || stream == STREAM_SPARSE_GZIP_DATA) {
287                flags |= FO_SPARSE;
288             }
289             if (stream == STREAM_GZIP_DATA || stream == STREAM_SPARSE_GZIP_DATA
290                   || stream == STREAM_WIN32_GZIP_DATA) {
291                flags |= FO_GZIP;
292             }
293             if (extract_data(jcr, &bfd, sd->msg, sd->msglen, &fileAddr, flags) < 0) {
294                extract = false;
295                bclose(&bfd);
296                continue;
297             }
298          }
299          break;
300
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
305          if (extract) {
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);
309                   extract = false;
310                   continue;
311                }
312                alt_size = rsrc_len;
313                Dmsg0(30, "Restoring resource fork\n");
314             }
315             flags = 0;
316             if (extract_data(jcr, &altbfd, sd->msg, sd->msglen, &alt_addr, flags) < 0) {
317                extract = false;
318                bclose(&altbfd);
319                continue;
320             }
321          }
322 #else
323          non_support_rsrc++;
324 #endif
325          break;
326
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);
332             continue;
333          }
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);
336             continue;
337          }
338 #else
339          non_support_finfo++;
340 #endif
341
342       case STREAM_UNIX_ATTRIBUTES_ACCESS_ACL:
343 #ifdef HAVE_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);
348          }
349 #else 
350          non_support_acl++;
351 #endif
352          break;
353
354       case STREAM_UNIX_ATTRIBUTES_DEFAULT_ACL:
355 #ifdef HAVE_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);
360          }
361 #else 
362          non_support_acl++;
363 #endif
364          break;
365
366       case STREAM_MD5_SIGNATURE:
367       case STREAM_SHA1_SIGNATURE:
368          break;
369
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++;
375          }
376          break;
377
378       default:
379          /* If extracting, wierd stream (not 1 or 2), close output file anyway */
380          if (extract) {
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"));
384             }
385             set_attributes(jcr, attr, &bfd);
386             extract = false;
387          } else if (is_bopen(&bfd)) {
388             Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should not be open\n"));
389             bclose(&bfd);
390          }
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);
393          break;
394       } /* end switch(stream) */
395
396    } /* end while get_msg() */
397
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.
400     */
401    if (is_bopen(&altbfd)) {
402       bclose_chksize(jcr, &altbfd, alt_size);
403    }
404    if (extract) {
405       set_attributes(jcr, attr, &bfd);
406    }
407    if (is_bopen(&bfd)) {
408       bclose(&bfd);
409    }
410    set_jcr_job_status(jcr, JS_Terminated);
411    goto ok_out;
412
413 bail_out:
414    set_jcr_job_status(jcr, JS_ErrorTerminated);
415 ok_out:
416    if (jcr->compress_buf) {
417       free(jcr->compress_buf);
418       jcr->compress_buf = NULL;
419       jcr->compress_buf_size = 0;
420    }
421    bclose(&altbfd);
422    bclose(&bfd);
423    free_attr(attr);
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);
430    }
431    if (non_support_rsrc) {
432       Jmsg(jcr, M_INFO, 0, _("%d non-supported resource fork streams ignored.\n"), non_support_rsrc);
433    }
434    if (non_support_finfo) {
435       Jmsg(jcr, M_INFO, 0, _("%d non-supported Finder Info streams ignored.\n"), non_support_rsrc);
436    }
437    if (non_support_acl) {
438       Jmsg(jcr, M_INFO, 0, _("%d non-supported acl streams ignored.\n"), non_support_acl);
439    }
440
441 }
442
443 #ifdef HAVE_LIBZ
444 /*
445  * Convert ZLIB error code into an ASCII message
446  */
447 static const char *zlib_strerror(int stat)
448 {
449    if (stat >= 0) {
450       return _("None");
451    }
452    switch (stat) {
453    case Z_ERRNO:
454       return _("Zlib errno");
455    case Z_STREAM_ERROR:
456       return _("Zlib stream error");
457    case Z_DATA_ERROR:
458       return _("Zlib data error");
459    case Z_MEM_ERROR:
460       return _("Zlib memory error");
461    case Z_BUF_ERROR:
462       return _("Zlib buffer error");
463    case Z_VERSION_ERROR:
464       return _("Zlib version error");
465    default:
466       return _("*none*");
467    }
468 }
469 #endif
470
471 /*
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.
476  */
477 int32_t extract_data(JCR *jcr, BFILE *bfd, POOLMEM *buf, int32_t buflen,
478       uint64_t *addr, int flags)
479 {
480    int stat;
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 */
485
486    if (flags & FO_SPARSE) {
487       ser_declare;
488       uint64_t faddr;
489       char ec1[50];
490       wbuf = buf + SPARSE_FADDR_SIZE;
491       rsize = buflen - SPARSE_FADDR_SIZE;
492       ser_begin(buf, SPARSE_FADDR_SIZE);
493       unser_uint64(faddr);
494       if (*addr != faddr) {
495          *addr = faddr;
496          if (blseek(bfd, (off_t)*addr, SEEK_SET) < 0) {
497             berrno be;
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));
501             return -1;
502          }
503       }
504    } else {
505       wbuf = buf;
506       rsize = buflen;
507    }
508    wsize = rsize;
509
510    if (flags & FO_GZIP) {
511 #ifdef HAVE_LIBZ
512       uLong compress_len;
513       /* 
514        * NOTE! We only use uLong and Byte because they are
515        *  needed by the zlib routines, they should not otherwise
516        *  be used in Bacula.
517        */
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));
524          return -1;
525       }
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));
529 #else
530       Jmsg(jcr, M_ERROR, 0, _("GZIP data stream found, but GZIP not configured!\n"));
531       return -1;
532 #endif
533    } else {
534       Dmsg2(30, "Write %u bytes, total before write=%s\n", wsize, edit_uint64(jcr->JobBytes, ec1));
535    }
536
537    if (bwrite(bfd, wbuf, wsize) != (ssize_t)wsize) {
538       berrno be;
539       Jmsg2(jcr, M_ERROR, 0, _("Write error on %s: %s\n"), 
540             jcr->last_fname, be.strerror(bfd->berrno));
541       return -1;
542    }
543
544    jcr->JobBytes += wsize;
545    jcr->ReadBytes += rsize;
546    *addr += wsize;
547
548    return wsize;
549 }