]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/restore.c
Apply Preben 'Peppe' Guldberg <peppe@wielders.org>
[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-2004 Kern Sibbald and John Walker
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 as
14    published by the Free Software Foundation; either version 2 of
15    the License, or (at your option) any later version.
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 GNU
20    General Public License for more details.
21
22    You should have received a copy of the GNU General Public
23    License along with this program; if not, write to the Free
24    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25    MA 02111-1307, USA.
26
27  */
28
29 #include "bacula.h"
30 #include "filed.h"
31
32 #ifdef HAVE_ACL
33 #include <sys/acl.h>
34 #include <acl/libacl.h>
35 #endif
36
37 #ifdef HAVE_DARWIN_OS
38 #include <sys/attr.h>
39 #endif
40
41 /* Data received from Storage Daemon */
42 static char rec_header[] = "rechdr %ld %ld %ld %ld %ld";
43
44 /* Forward referenced functions */
45 #ifdef HAVE_LIBZ
46 static const char *zlib_strerror(int stat);
47 #endif
48
49 #define RETRY 10                      /* retry wait time */
50
51 #ifdef HAVE_DARWIN_OS
52 /* helper routine for closing resource forks */
53 int bclose_chksize(JCR *jcr, BFILE *bfd, off_t osize)
54 {
55    char ec1[50], ec2[50];
56    off_t fsize;
57
58    fsize = blseek(bfd, 0, SEEK_CUR);
59    bclose(bfd);                              /* first close file */
60    if (fsize > 0 && fsize != osize) {
61       Jmsg3(jcr, M_ERROR, 0, _("File size of resource fork for restored file %s not correct. Original %s, restored %s.\n"),
62             jcr->last_fname, edit_uint64(osize, ec1),
63             edit_uint64(fsize, ec2));
64       return -1;
65    }
66    return 0;
67 }
68 #endif
69
70 /*
71  * Restore the requested files.
72  *
73  */
74 void do_restore(JCR *jcr)
75 {
76    BSOCK *sd;
77    int32_t stream;
78    uint32_t size;
79    uint32_t VolSessionId, VolSessionTime;
80    int32_t file_index;
81    bool extract = false;
82    BFILE bfd;
83    int stat;
84    uint32_t total = 0;                /* Job total but only 32 bits for debug */
85    char *wbuf;                        /* write buffer */
86    uint32_t wsize;                    /* write size */
87    uint64_t fileAddr = 0;             /* file write address */
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 prog_name_msg = 0;
94    ATTR *attr;
95 #ifdef HAVE_ACL
96    acl_t acl;
97 #endif
98    BFILE rsrc_bfd;                    /* we often check if it is open */
99 #ifdef HAVE_DARWIN_OS
100    off_t rsrcAddr = 0;
101    off_t rsrc_len;                    /* original length of resource fork */
102
103    /* TODO: initialise attrList once elsewhere? */
104    struct attrlist attrList;
105    memset(&attrList, 0, sizeof(attrList));
106    attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
107    attrList.commonattr = ATTR_CMN_FNDRINFO;
108 #endif
109    binit(&rsrc_bfd);
110
111    binit(&bfd);
112    sd = jcr->store_bsock;
113    set_jcr_job_status(jcr, JS_Running);
114
115    LockRes();
116    CLIENT *client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
117    UnlockRes();
118    uint32_t buf_size;
119    if (client) {
120       buf_size = client->max_network_buffer_size;
121    } else {
122       buf_size = 0;                   /* use default */
123    }
124    if (!bnet_set_buffer_size(sd, buf_size, BNET_SETBUF_WRITE)) {
125       set_jcr_job_status(jcr, JS_ErrorTerminated);
126       return;
127    }
128    jcr->buf_size = sd->msglen;
129
130    attr = new_attr();
131
132 #ifdef HAVE_LIBZ
133    uint32_t compress_buf_size = jcr->buf_size + 12 + ((jcr->buf_size+999) / 1000) + 100;
134    jcr->compress_buf = (char *)bmalloc(compress_buf_size);
135 #endif
136
137    /*
138     * Get a record from the Storage daemon. We are guaranteed to
139     *   receive records in the following order:
140     *   1. Stream record header
141     *   2. Stream data
142     *        a. Attributes (Unix or Win32)
143     *    or  b. File data for the file
144     *    or  c. Resource fork
145     *    or  d. Finder info
146     *    or  e. ACLs
147     *    or  f. Possibly MD5 or SHA1 record
148     *   3. Repeat step 1
149     */
150    while (bget_msg(sd) >= 0 && !job_canceled(jcr)) {
151       /*
152        * First we expect a Stream Record Header
153        */
154       if (sscanf(sd->msg, rec_header, &VolSessionId, &VolSessionTime, &file_index,
155           &stream, &size) != 5) {
156          Jmsg1(jcr, M_FATAL, 0, _("Record header scan error: %s\n"), sd->msg);
157          goto bail_out;
158       }
159       Dmsg2(30, "Got hdr: FilInx=%d Stream=%d.\n", file_index, stream);
160
161       /*
162        * Now we expect the Stream Data
163        */
164       if (bget_msg(sd) < 0) {
165          Jmsg1(jcr, M_FATAL, 0, _("Data record error. ERR=%s\n"), bnet_strerror(sd));
166          goto bail_out;
167       }
168       if (size != (uint32_t)sd->msglen) {
169          Jmsg2(jcr, M_FATAL, 0, _("Actual data size %d not same as header %d\n"), sd->msglen, size);
170          goto bail_out;
171       }
172       Dmsg1(30, "Got stream data, len=%d\n", sd->msglen);
173
174       /* File Attributes stream */
175       switch (stream) {
176       case STREAM_UNIX_ATTRIBUTES:
177       case STREAM_UNIX_ATTRIBUTES_EX:
178          Dmsg1(30, "Stream=Unix Attributes. extract=%d\n", extract);
179          /* If extracting, it was from previous stream, so
180           * close the output file.
181           */
182          if (extract) {
183             if (!is_bopen(&bfd) && !is_bopen(&rsrc_bfd)) {
184                Jmsg0(jcr, M_ERROR, 0, _("Logic error output file should be open\n"));
185             }
186 #ifdef HAVE_DARWIN_OS
187             if (is_bopen(&rsrc_bfd)) {
188                bclose_chksize(jcr, &rsrc_bfd, rsrc_len);
189             }
190 #endif
191             if (is_bopen(&bfd)) {
192                set_attributes(jcr, attr, &bfd);
193             }
194             extract = false;
195             Dmsg0(30, "Stop extracting.\n");
196          }
197
198
199          if (!unpack_attributes_record(jcr, stream, sd->msg, attr)) {
200             goto bail_out;
201          }
202          if (file_index != attr->file_index) {
203             Jmsg(jcr, M_FATAL, 0, _("Record header file index %ld not equal record index %ld\n"),
204                  file_index, attr->file_index);
205             Dmsg0(100, "File index error\n");
206             goto bail_out;
207          }
208
209          Dmsg3(200, "File %s\nattrib=%s\nattribsEx=%s\n", attr->fname,
210                attr->attr, attr->attrEx);
211
212          attr->data_stream = decode_stat(attr->attr, &attr->statp, &attr->LinkFI);
213
214          if (!is_stream_supported(attr->data_stream)) {
215             if (!non_support_data++) {
216                Jmsg(jcr, M_ERROR, 0, _("%s stream not supported on this Client.\n"),
217                   stream_to_ascii(attr->data_stream));
218             }
219             continue;
220          }
221
222          build_attr_output_fnames(jcr, attr);
223
224 #ifdef HAVE_DARWIN_OS
225          from_base64(&rsrc_len, attr->attrEx);
226 #endif
227
228          jcr->num_files_examined++;
229
230          Dmsg1(30, "Outfile=%s\n", attr->ofname);
231          extract = false;
232          stat = create_file(jcr, attr, &bfd, jcr->replace);
233          switch (stat) {
234          case CF_ERROR:
235          case CF_SKIP:
236             break;
237          case CF_EXTRACT:
238             extract = true;
239             /* FALLTHROUGH */
240          case CF_CREATED:
241             P(jcr->mutex);
242             pm_strcpy(jcr->last_fname, attr->ofname);
243             V(jcr->mutex);
244             jcr->JobFiles++;
245             fileAddr = 0;
246             print_ls_output(jcr, attr);
247             if (!extract) {
248                /* set attributes now because file will not be extracted */
249                set_attributes(jcr, attr, &bfd);
250             }
251 #ifdef HAVE_DARWIN_OS
252             if (rsrc_len > 0) {
253                rsrcAddr = 0;
254                if (bopen_rsrc(&rsrc_bfd, jcr->last_fname, O_WRONLY | O_TRUNC | O_BINARY, 0) < 0) {
255                   Jmsg(jcr, M_ERROR, 0, _("     Cannot open resource fork for %s"), jcr->last_fname);
256                } else {
257                   Dmsg0(30, "Restoring resource fork");
258                   extract = true;
259                }
260             }
261 #endif
262             break;
263          }
264          break;
265
266       /* Data stream */
267       case STREAM_FILE_DATA:
268       case STREAM_SPARSE_DATA:
269       case STREAM_WIN32_DATA:
270          if (extract) {
271             if (stream == STREAM_SPARSE_DATA) {
272                ser_declare;
273                uint64_t faddr;
274                char ec1[50];
275
276                wbuf = sd->msg + SPARSE_FADDR_SIZE;
277                wsize = sd->msglen - SPARSE_FADDR_SIZE;
278                ser_begin(sd->msg, SPARSE_FADDR_SIZE);
279                unser_uint64(faddr);
280                if (fileAddr != faddr) {
281                   fileAddr = faddr;
282                   if (blseek(&bfd, (off_t)fileAddr, SEEK_SET) < 0) {
283                      berrno be;
284                      be.set_errno(bfd.berrno);
285                      Jmsg3(jcr, M_ERROR, 0, _("Seek to %s error on %s: ERR=%s\n"),
286                          edit_uint64(fileAddr, ec1), attr->ofname, be.strerror());
287                      extract = false;
288                      bclose(&bfd);
289                      if (is_bopen(&rsrc_bfd)) {
290                         bclose(&rsrc_bfd);
291                      }
292                      continue;
293                   }
294                }
295             } else {
296                wbuf = sd->msg;
297                wsize = sd->msglen;
298             }
299             Dmsg2(30, "Write %u bytes, total before write=%u\n", wsize, total);
300             if ((uint32_t)bwrite(&bfd, wbuf, wsize) != wsize) {
301                Dmsg0(0, "===Write error===\n");
302                berrno be;
303                be.set_errno(bfd.berrno);
304                Jmsg2(jcr, M_ERROR, 0, _("Write error on %s: ERR=%s\n"), attr->ofname,
305                      be.strerror());
306                extract = false;
307                bclose(&bfd);
308                if (is_bopen(&rsrc_bfd)) {
309                   bclose(&rsrc_bfd);
310                }
311                continue;
312             }
313             total += wsize;
314             jcr->JobBytes += wsize;
315             jcr->ReadBytes += wsize;
316             fileAddr += wsize;
317          }
318          break;
319
320       /* GZIP data stream */
321       case STREAM_GZIP_DATA:
322       case STREAM_SPARSE_GZIP_DATA:
323       case STREAM_WIN32_GZIP_DATA:
324 #ifdef HAVE_LIBZ
325          if (extract) {
326             uLong compress_len;
327             int stat;
328
329             if (stream == STREAM_SPARSE_GZIP_DATA) {
330                ser_declare;
331                uint64_t faddr;
332                char ec1[50];
333                wbuf = sd->msg + SPARSE_FADDR_SIZE;
334                wsize = sd->msglen - SPARSE_FADDR_SIZE;
335                ser_begin(sd->msg, SPARSE_FADDR_SIZE);
336                unser_uint64(faddr);
337                if (fileAddr != faddr) {
338                   fileAddr = faddr;
339                   if (blseek(&bfd, (off_t)fileAddr, SEEK_SET) < 0) {
340                      berrno be;
341                      be.set_errno(bfd.berrno);
342                      Jmsg3(jcr, M_ERROR, 0, _("Seek to %s error on %s: ERR=%s\n"),
343                          edit_uint64(fileAddr, ec1), attr->ofname, be.strerror());
344                      extract = false;
345                      bclose(&bfd);
346                      if (is_bopen(&rsrc_bfd)) {
347                         bclose(&rsrc_bfd);
348                      }
349                      continue;
350                   }
351                }
352             } else {
353                wbuf = sd->msg;
354                wsize = sd->msglen;
355             }
356             compress_len = compress_buf_size;
357             Dmsg2(100, "Comp_len=%d msglen=%d\n", compress_len, wsize);
358             if ((stat=uncompress((Byte *)jcr->compress_buf, &compress_len,
359                   (const Byte *)wbuf, (uLong)wsize)) != Z_OK) {
360                Jmsg(jcr, M_ERROR, 0, _("Uncompression error on file %s. ERR=%s\n"),
361                   attr->ofname, zlib_strerror(stat));
362                extract = false;
363                bclose(&bfd);
364                if (is_bopen(&rsrc_bfd)) {
365                   bclose(&rsrc_bfd);
366                }
367                continue;
368             }
369
370             Dmsg2(100, "Write uncompressed %d bytes, total before write=%d\n", compress_len, total);
371             if ((uLong)bwrite(&bfd, jcr->compress_buf, compress_len) != compress_len) {
372                Dmsg0(0, "===Write error===\n");
373                berrno be;
374                be.set_errno(bfd.berrno);
375                Jmsg2(jcr, M_ERROR, 0, _("Write error on %s: %s\n"), attr->ofname, be.strerror());
376                extract = false;
377                bclose(&bfd);
378                if (is_bopen(&rsrc_bfd)) {
379                   bclose(&rsrc_bfd);
380                }
381                continue;
382             }
383             total += compress_len;
384             jcr->JobBytes += compress_len;
385             jcr->ReadBytes += wsize;
386             fileAddr += compress_len;
387          }
388 #else
389          if (extract) {
390             Jmsg(jcr, M_ERROR, 0, _("GZIP data stream found, but GZIP not configured!\n"));
391             extract = false;
392             bclose(&bfd);
393             if (is_bopen(&rsrc_bfd)) {
394                bclose(&rsrc_bfd);
395             }
396             continue;
397          }
398 #endif
399          break;
400
401       /* Resource fork stream - only recorded after a file to be restored */
402       /* Silently ignore if we cannot write - we already reported that */
403       case STREAM_MACOS_FORK_DATA:
404 #ifdef HAVE_DARWIN_OS
405          if (is_bopen(&rsrc_bfd) && sd->msglen) {
406             Dmsg2(30, "Write %u bytes, total before write=%u\n", sd->msglen, total);
407             if (bwrite(&rsrc_bfd, sd->msg, sd->msglen) != sd->msglen) {
408                Dmsg0(0, "===Write error===\n");
409                berrno be;
410                be.set_errno(rsrc_bfd.berrno);
411                Jmsg2(jcr, M_ERROR, 0, _("Write error on resource fork of %s: ERR=%s\n"), jcr->last_fname,
412                      be.strerror());
413                extract = false;
414                if (is_bopen(&bfd)) {
415                   bclose(&bfd);
416                }
417                bclose(&rsrc_bfd);
418                continue;
419             }
420             total += sd->msglen;
421             jcr->JobBytes += sd->msglen;
422             jcr->ReadBytes += sd->msglen;
423             rsrcAddr += sd->msglen;
424          }
425          break;
426 #else
427          non_support_rsrc++;
428 #endif
429
430       case STREAM_HFSPLUS_ATTRIBUTES:
431 #ifdef HAVE_DARWIN_OS
432          Dmsg0(30, "Restoring Finder Info");
433          if (sd->msglen != 32) {
434             Jmsg(jcr, M_ERROR, 0, _("     Invalid length of Finder Info (got %d, not 32)"), sd->msglen);
435             continue;
436          }
437          if (setattrlist(jcr->last_fname, &attrList, sd->msg, sd->msglen, 0) != 0) {
438             Jmsg(jcr, M_ERROR, 0, _("     Could not set Finder Info on %s"), jcr->last_fname);
439             continue;
440          }
441          break;
442 #else
443          non_support_finfo++;
444 #endif
445 /*** FIXME ***/
446 case STREAM_UNIX_ATTRIBUTES_ACCESS_ACL:
447 #ifdef HAVE_ACL
448          /* Recover Acess ACL from stream and check it */
449          acl = acl_from_text(sd->msg);
450          if (acl_valid(acl) != 0) {
451             Jmsg1(jcr, M_WARNING, 0, "Failure in the ACL of %s! FD is not able to restore it!\n", jcr->last_fname);
452             acl_free(acl);
453          }
454
455          /* Try to restore ACL */
456          if (attr->type == FT_DIREND) {
457             /* Directory */
458             if (acl_set_file(jcr->last_fname, ACL_TYPE_ACCESS, acl) != 0) {
459                Jmsg1(jcr, M_WARNING, 0, "Error! Can't restore ACL of directory: %s! Maybe system does not support ACLs!\n", jcr->last_fname);
460             }
461          /* File or Link */
462          } else if (acl_set_file(jcr->last_fname, ACL_TYPE_ACCESS, acl) != 0) {
463             Jmsg1(jcr, M_WARNING, 0, "Error! Can't restore ACL of file: %s! Maybe system does not support ACLs!\n", jcr->last_fname);
464          }
465          acl_free(acl);
466          Dmsg1(200, "ACL of file: %s successfully restored!", jcr->last_fname);
467          break;
468 #else
469          non_support_acl++;
470          break;                       /* unconfigured, ignore */
471 #endif
472       case STREAM_UNIX_ATTRIBUTES_DEFAULT_ACL:
473 #ifdef HAVE_ACL
474       /* Recover Default ACL from stream and check it */
475          acl = acl_from_text(sd->msg);
476          if (acl_valid(acl) != 0) {
477             Jmsg1(jcr, M_WARNING, 0, "Failure in the Default ACL of %s! FD is not able to restore it!\n", jcr->last_fname);
478             acl_free(acl);
479          }
480
481          /* Try to restore ACL */
482          if (attr->type == FT_DIREND) {
483             /* Directory */
484             if (acl_set_file(jcr->last_fname, ACL_TYPE_DEFAULT, acl) != 0) {
485                Jmsg1(jcr, M_WARNING, 0, "Error! Can't restore Default ACL of directory: %s! Maybe system does not support ACLs!\n", jcr->last_fname);
486              }
487          }
488          acl_free(acl);
489          Dmsg1(200, "Default ACL of file: %s successfully restored!", jcr->last_fname);
490          break;
491 #else
492          non_support_acl++;
493          break;                       /* unconfigured, ignore */
494 #endif
495 /*** FIXME ***/
496
497       case STREAM_MD5_SIGNATURE:
498       case STREAM_SHA1_SIGNATURE:
499          break;
500
501       case STREAM_PROGRAM_NAMES:
502       case STREAM_PROGRAM_DATA:
503          if (!prog_name_msg) {
504             Pmsg0(000, "Got Program Name or Data Stream. Ignored.\n");
505             prog_name_msg++;
506          }
507          break;
508
509       default:
510          /* If extracting, wierd stream (not 1 or 2), close output file anyway */
511          if (extract) {
512             Dmsg1(30, "Found wierd stream %d\n", stream);
513             if (!is_bopen(&bfd)) {
514                Jmsg0(jcr, M_ERROR, 0, _("Logic error output file should be open but is not.\n"));
515             }
516             set_attributes(jcr, attr, &bfd);
517             extract = false;
518          }
519          Jmsg(jcr, M_ERROR, 0, _("Unknown stream=%d ignored. This shouldn't happen!\n"), stream);
520          Dmsg2(0, "None of above!!! stream=%d data=%s\n", stream,sd->msg);
521          break;
522       } /* end switch(stream) */
523
524    } /* end while get_msg() */
525
526    /* If output file is still open, it was the last one in the
527     * archive since we just hit an end of file, so close the file.
528     */
529    if (is_bopen(&bfd)) {
530       set_attributes(jcr, attr, &bfd);
531    }
532    set_jcr_job_status(jcr, JS_Terminated);
533    goto ok_out;
534
535 bail_out:
536    set_jcr_job_status(jcr, JS_ErrorTerminated);
537 ok_out:
538    if (jcr->compress_buf) {
539       free(jcr->compress_buf);
540       jcr->compress_buf = NULL;
541    }
542 #ifdef HAVE_DARWIN_OS
543    if (is_bopen(&rsrc_bfd)) {
544       bclose_chksize(jcr, &rsrc_bfd, rsrc_len);
545    }
546 #endif
547    bclose(&bfd);
548    free_attr(attr);
549    Dmsg2(10, "End Do Restore. Files=%d Bytes=%" lld "\n", jcr->JobFiles,
550       jcr->JobBytes);
551    if (non_support_data > 1 || non_support_attr > 1) {
552       Jmsg(jcr, M_ERROR, 0, _("%d non-supported data streams and %d non-supported attrib streams ignored.\n"),
553          non_support_data, non_support_attr);
554    }
555    if (non_support_rsrc) {
556       Jmsg(jcr, M_INFO, 0, _("%d non-supported resource fork streams ignored.\n"), non_support_rsrc);
557    }
558    if (non_support_finfo) {
559       Jmsg(jcr, M_INFO, 0, _("%d non-supported Finder Info streams ignored.\n"), non_support_rsrc);
560    }
561    if (non_support_acl) {
562       Jmsg(jcr, M_INFO, 0, _("%d non-supported acl streams ignored.\n"), non_support_acl);
563    }
564
565 }
566
567 #ifdef HAVE_LIBZ
568 /*
569  * Convert ZLIB error code into an ASCII message
570  */
571 static const char *zlib_strerror(int stat)
572 {
573    if (stat >= 0) {
574       return "None";
575    }
576    switch (stat) {
577    case Z_ERRNO:
578       return "Zlib errno";
579    case Z_STREAM_ERROR:
580       return "Zlib stream error";
581    case Z_DATA_ERROR:
582       return "Zlib data error";
583    case Z_MEM_ERROR:
584       return "Zlib memory error";
585    case Z_BUF_ERROR:
586       return "Zlib buffer error";
587    case Z_VERSION_ERROR:
588       return "Zlib version error";
589    default:
590       return "*none*";
591    }
592 }
593 #endif