]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/stored/bextract.c
Massive SD calling sequence reorganization
[bacula/bacula] / bacula / src / stored / bextract.c
index ba9f4443bc5395a89fe5ceeb04128f1580f230d6..fb67da69ae724324b30a3474c2b9b3ef6c1e6100 100644 (file)
@@ -2,13 +2,13 @@
  *
  *  Dumb program to extract files from a Bacula backup.
  *
- *   Kern E. Sibbald
+ *   Kern E. Sibbald, MM
  *
  *   Version $Id$
  *
  */
 /*
-   Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+   Copyright (C) 2000-2004 Kern Sibbald and John Walker
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
 #include "stored.h"
 #include "findlib/find.h"
 
-#ifdef HAVE_CYGWIN
+#if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
 int win32_client = 1;
 #else
 int win32_client = 0;
 #endif
 
-
 static void do_extract(char *fname);
-static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec);
+static bool record_cb(DCR *dcr, DEV_RECORD *rec);
 
 static DEVICE *dev = NULL;
+static DCR *dcr;
 static BFILE bfd;
 static JCR *jcr;
 static FF_PKT my_ff;
 static FF_PKT *ff = &my_ff;
 static BSR *bsr = NULL;
-static int extract = FALSE;
+static bool extract = false;
 static int non_support_data = 0;
-static int non_support_attr = 0;
 static long total = 0;
 static ATTR *attr;
 static char *where;
@@ -66,19 +65,22 @@ static uint64_t fileAddr = 0;             /* file write address */
 
 #define CONFIG_FILE "bacula-sd.conf"
 char *configfile;
-
+bool forge_on = false;
 
 static void usage()
 {
    fprintf(stderr,
+"Copyright (C) 2000-2004 Kern Sibbald and John Walker.\n"
 "\nVersion: " VERSION " (" BDATE ")\n\n"
-"Usage: bextract [-d debug_level] <bacula-archive> <directory-to-store-files>\n"
+"Usage: bextract <options> <bacula-archive-device-name> <directory-to-store-files>\n"
 "       -b <file>       specify a bootstrap file\n"
 "       -c <file>       specify a configuration file\n"
-"       -dnn            set debug level to nn\n"
+"       -d <nn>         set debug level to nn\n"
 "       -e <file>       exclude list\n"
 "       -i <file>       include list\n"
-"       -V              specify Volume names (separated by |)\n"
+"       -p              proceed inspite of I/O errors\n"
+"       -v              verbose\n"
+"       -V <volumes>    specify Volume names (separated by |)\n"
 "       -?              print this message\n\n");
    exit(1);
 }
@@ -99,11 +101,11 @@ int main (int argc, char *argv[])
    init_include_exclude_files(ff);
    binit(&bfd);
 
-   while ((ch = getopt(argc, argv, "b:c:d:e:i:?")) != -1) {
+   while ((ch = getopt(argc, argv, "b:c:d:e:i:pvV:?")) != -1) {
       switch (ch) {
       case 'b':                    /* bootstrap file */
         bsr = parse_bsr(NULL, optarg);
-//      dump_bsr(bsr);
+//      dump_bsr(bsr, true);
         break;
 
       case 'c':                    /* specify config file */
@@ -121,8 +123,9 @@ int main (int argc, char *argv[])
 
       case 'e':                    /* exclude list */
          if ((fd = fopen(optarg, "r")) == NULL) {
+           berrno be;
             Pmsg2(0, "Could not open exclude file: %s, ERR=%s\n",
-              optarg, strerror(errno));
+              optarg, be.strerror());
            exit(1);
         }
         while (fgets(line, sizeof(line), fd) != NULL) {
@@ -135,8 +138,9 @@ int main (int argc, char *argv[])
 
       case 'i':                    /* include list */
          if ((fd = fopen(optarg, "r")) == NULL) {
+           berrno be;
             Pmsg2(0, "Could not open include file: %s, ERR=%s\n",
-              optarg, strerror(errno));
+              optarg, be.strerror());
            exit(1);
         }
         while (fgets(line, sizeof(line), fd) != NULL) {
@@ -148,6 +152,14 @@ int main (int argc, char *argv[])
         got_inc = TRUE;
         break;
 
+      case 'p':
+        forge_on = true;
+        break;
+
+      case 'v':
+        verbose++;
+        break;
+
       case 'V':                    /* Volume name */
         VolumeName = optarg;
         break;
@@ -196,16 +208,21 @@ int main (int argc, char *argv[])
 static void do_extract(char *devname)
 {
    struct stat statp;
-   jcr = setup_jcr("bextract", devname, bsr, VolumeName);
-   dev = setup_to_access_device(jcr, 1);    /* acquire for read */
+   jcr = setup_jcr("bextract", devname, bsr, VolumeName, 1); /* acquire for read */
+   if (!jcr) {
+      exit(1);
+   }
+   dev = jcr->dcr->dev;
    if (!dev) {
       exit(1);
    }
+   dcr = jcr->dcr;
 
    /* Make sure where directory exists and that it is a directory */
    if (stat(where, &statp) < 0) {
+      berrno be;
       Emsg2(M_ERROR_TERM, 0, "Cannot stat %s. It must exist. ERR=%s\n",
-        where, strerror(errno));
+        where, be.strerror());
    }
    if (!S_ISDIR(statp.st_mode)) {
       Emsg1(M_ERROR_TERM, 0, "%s must be a directory.\n", where);
@@ -217,18 +234,18 @@ static void do_extract(char *devname)
 
    compress_buf = get_memory(compress_buf_size);
 
-   read_records(jcr, dev, record_cb, mount_next_read_volume);
+   read_records(dcr, record_cb, mount_next_read_volume);
    /* If output file is still open, it was the last one in the
     * archive since we just hit an end of file, so close the file. 
     */
    if (is_bopen(&bfd)) {
       set_attributes(jcr, attr, &bfd);
    }
-   release_device(jcr, dev);
-
+   release_device(jcr);
    free_attr(attr);
-   term_dev(dev);
    free_jcr(jcr);
+   term_dev(dev);
+
    printf("%u files restored.\n", num_files);
    return;
 }
@@ -236,12 +253,13 @@ static void do_extract(char *devname)
 /*
  * Called here for each record from read_records()
  */
-static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
+static bool record_cb(DCR *dcr, DEV_RECORD *rec)
 {
    int stat;
+   JCR *jcr = dcr->jcr;
 
    if (rec->FileIndex < 0) {
-      return;                         /* we don't want labels */
+      return true;                    /* we don't want labels */
    }
 
    /* File Attributes stream */
@@ -257,8 +275,8 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
         if (!is_bopen(&bfd)) {
             Emsg0(M_ERROR, 0, _("Logic error output file should be open but is not.\n"));
         }
-        extract = FALSE;
         set_attributes(jcr, attr, &bfd);
+        extract = false;
       }
 
       if (!unpack_attributes_record(jcr, rec->Stream, rec->data, attr)) {
@@ -271,20 +289,28 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
       }
         
       if (file_is_included(ff, attr->fname) && !file_is_excluded(ff, attr->fname)) {
-        uint32_t LinkFI;
 
-        decode_stat(attr->attr, &attr->statp, &LinkFI);
+        attr->data_stream = decode_stat(attr->attr, &attr->statp, &attr->LinkFI);
+        if (!is_stream_supported(attr->data_stream)) {
+           if (!non_support_data++) {
+               Jmsg(jcr, M_ERROR, 0, _("%s stream not supported on this Client.\n"),
+                 stream_to_ascii(attr->data_stream));
+           }
+           extract = false;
+           return true;
+        }
+
 
         build_attr_output_fnames(jcr, attr);
 
-        extract = FALSE;
+        extract = false;
         stat = create_file(jcr, attr, &bfd, REPLACE_ALWAYS);   
         switch (stat) {
         case CF_ERROR:
         case CF_SKIP:
            break;
         case CF_EXTRACT:
-           extract = TRUE;
+           extract = true;
            print_ls_output(jcr, attr);
            num_files++;
            fileAddr = 0;
@@ -297,25 +323,13 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
            break;
         }  
       }
-
-   /* Windows Backup data stream */
-   case STREAM_WIN32_DATA:  
-      if (!is_win32_backup()) {
-        if (!non_support_data) {
-            Jmsg(jcr, M_ERROR, 0, _("Win32 backup data not supported on this Client.\n"));
-        }
-        extract = FALSE;
-        non_support_data++;
-        return;
-      }
-      goto extract_data;
-   
+      break;
 
    /* Data stream and extracting */
    case STREAM_FILE_DATA:
    case STREAM_SPARSE_DATA:
+   case STREAM_WIN32_DATA:  
 
-extract_data:
       if (extract) {
         if (rec->Stream == STREAM_SPARSE_DATA) {
            ser_declare;
@@ -327,8 +341,9 @@ extract_data:
            if (fileAddr != faddr) {
               fileAddr = faddr;
               if (blseek(&bfd, (off_t)fileAddr, SEEK_SET) < 0) {
+                 berrno be;
                   Emsg2(M_ERROR_TERM, 0, _("Seek error on %s: %s\n"), 
-                    attr->ofname, strerror(errno));
+                    attr->ofname, be.strerror());
               }
            }
         } else {
@@ -338,35 +353,27 @@ extract_data:
         total += wsize;
          Dmsg2(8, "Write %u bytes, total=%u\n", wsize, total);
         if ((uint32_t)bwrite(&bfd, wbuf, wsize) != wsize) {
+           berrno be;
             Emsg2(M_ERROR_TERM, 0, _("Write error on %s: %s\n"), 
-              attr->ofname, strerror(errno));
+              attr->ofname, be.strerror());
         }
         fileAddr += wsize;
       }
-
-   /* Windows Backup GZIP data stream */
-   case STREAM_WIN32_GZIP_DATA:  
-      if (!is_win32_backup()) {
-        if (!non_support_attr) {
-            Jmsg(jcr, M_ERROR, 0, _("Win32 GZIP backup data not supported on this Client.\n"));
-        }
-        extract = FALSE;
-        non_support_attr++;
-        return;
-      }
-      /* Fall through desired */
+      break;
 
    /* GZIP data stream */
    case STREAM_GZIP_DATA:
    case STREAM_SPARSE_GZIP_DATA: 
+   case STREAM_WIN32_GZIP_DATA:  
 #ifdef HAVE_LIBZ
       if (extract) {
-        uLongf compress_len;
+        uLong compress_len;
         int stat;
 
         if (rec->Stream == STREAM_SPARSE_GZIP_DATA) {
            ser_declare;
            uint64_t faddr;
+           char ec1[50];
            wbuf = rec->data + SPARSE_FADDR_SIZE;
            wsize = rec->data_len - SPARSE_FADDR_SIZE;
            ser_begin(rec->data, SPARSE_FADDR_SIZE);
@@ -374,8 +381,11 @@ extract_data:
            if (fileAddr != faddr) {
               fileAddr = faddr;
               if (blseek(&bfd, (off_t)fileAddr, SEEK_SET) < 0) {
-                  Emsg2(M_ERROR, 0, _("Seek error on %s: %s\n"), 
-                    attr->ofname, strerror(errno));
+                 berrno be;
+                  Emsg3(M_ERROR, 0, _("Seek to %s error on %s: ERR=%s\n"), 
+                    edit_uint64(fileAddr, ec1), attr->ofname, be.strerror());
+                 extract = false;
+                 return true;
               }
            }
         } else {
@@ -385,14 +395,19 @@ extract_data:
         compress_len = compress_buf_size;
         if ((stat=uncompress((Bytef *)compress_buf, &compress_len, 
               (const Bytef *)wbuf, (uLong)wsize) != Z_OK)) {
-            Emsg1(M_ERROR_TERM, 0, _("Uncompression error. ERR=%d\n"), stat);
+            Emsg1(M_ERROR, 0, _("Uncompression error. ERR=%d\n"), stat);
+           extract = false;
+           return true;
         }
 
          Dmsg2(100, "Write uncompressed %d bytes, total before write=%d\n", compress_len, total);
         if ((uLongf)bwrite(&bfd, compress_buf, (size_t)compress_len) != compress_len) {
+           berrno be;
             Pmsg0(0, "===Write error===\n");
-            Emsg2(M_ERROR_TERM, 0, _("Write error on %s: %s\n"), 
-              attr->ofname, strerror(errno));
+            Emsg2(M_ERROR, 0, _("Write error on %s: %s\n"), 
+              attr->ofname, be.strerror());
+           extract = false;
+           return true;
         }
         total += compress_len;
         fileAddr += compress_len;
@@ -402,10 +417,11 @@ extract_data:
 #else
       if (extract) {
          Emsg0(M_ERROR, 0, "GZIP data stream found, but GZIP not configured!\n");
-        extract = FALSE;
-        return;
+        extract = false;
+        return true;
       }
 #endif
+      break;
 
    case STREAM_MD5_SIGNATURE:
    case STREAM_SHA1_SIGNATURE:
@@ -425,33 +441,32 @@ extract_data:
         if (!is_bopen(&bfd)) {
             Emsg0(M_ERROR, 0, "Logic error output file should be open but is not.\n");
         }
-        extract = FALSE;
         set_attributes(jcr, attr, &bfd);
+        extract = false;
       }
       Jmsg(jcr, M_ERROR, 0, _("Unknown stream=%d ignored. This shouldn't happen!\n"), 
         rec->Stream);
       break;
       
    } /* end switch */
+   return true;
 }
 
-
-
-
 /* Dummies to replace askdir.c */
-int    dir_get_volume_info(JCR *jcr, int writing) { return 1;}
-int    dir_find_next_appendable_volume(JCR *jcr) { return 1;}
-int    dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol, int relabel) { return 1; }
-int    dir_create_jobmedia_record(JCR *jcr) { return 1; }
-int    dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev) { return 1; }
-int    dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec) { return 1;}
-int    dir_send_job_status(JCR *jcr) {return 1;}
+bool   dir_get_volume_info(DCR *dcr, enum get_vol_info_rw  writing) { return 1;}
+bool   dir_find_next_appendable_volume(DCR *dcr) { return 1;}
+bool   dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
+bool   dir_create_jobmedia_record(DCR *dcr) { return 1; }
+bool   dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
+bool   dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
+bool   dir_send_job_status(JCR *jcr) {return 1;}
 
 
-int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev)
+bool dir_ask_sysop_to_mount_volume(DCR *dcr)
 {
-   fprintf(stderr, "Mount Volume %s on device %s and press return when ready: ",
-      jcr->VolumeName, dev_name(dev));
+   DEVICE *dev = dcr->dev;
+   fprintf(stderr, "Mount Volume \"%s\" on device %s and press return when ready: ",
+      dcr->VolumeName, dev_name(dev));
    getchar();  
-   return 1;
+   return true;
 }