]> 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 c602eb4bfad0d880620e80cf3ed6b270ab6b5bcb..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 long total = 0;
 static ATTR *attr;
@@ -65,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);
 }
@@ -98,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 */
@@ -120,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) {
@@ -134,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) {
@@ -147,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;
@@ -195,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);
@@ -216,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;
 }
@@ -235,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,7 +276,7 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
             Emsg0(M_ERROR, 0, _("Logic error output file should be open but is not.\n"));
         }
         set_attributes(jcr, attr, &bfd);
-        extract = FALSE;
+        extract = false;
       }
 
       if (!unpack_attributes_record(jcr, rec->Stream, rec->data, attr)) {
@@ -277,21 +296,21 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
                Jmsg(jcr, M_ERROR, 0, _("%s stream not supported on this Client.\n"),
                  stream_to_ascii(attr->data_stream));
            }
-           extract = FALSE;
-           return;
+           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;
@@ -322,8 +341,9 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
            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 {
@@ -333,8 +353,9 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
         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;
       }
@@ -360,10 +381,11 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
            if (fileAddr != faddr) {
               fileAddr = faddr;
               if (blseek(&bfd, (off_t)fileAddr, SEEK_SET) < 0) {
+                 berrno be;
                   Emsg3(M_ERROR, 0, _("Seek to %s error on %s: ERR=%s\n"), 
-                    edit_uint64(fileAddr, ec1), attr->ofname, berror(&bfd));
-                 extract = FALSE;
-                 return;
+                    edit_uint64(fileAddr, ec1), attr->ofname, be.strerror());
+                 extract = false;
+                 return true;
               }
            }
         } else {
@@ -374,17 +396,18 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
         if ((stat=uncompress((Bytef *)compress_buf, &compress_len, 
               (const Bytef *)wbuf, (uLong)wsize) != Z_OK)) {
             Emsg1(M_ERROR, 0, _("Uncompression error. ERR=%d\n"), stat);
-           extract = FALSE;
-           return;
+           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, 0, _("Write error on %s: %s\n"), 
-              attr->ofname, strerror(errno));
-           extract = FALSE;
-           return;
+              attr->ofname, be.strerror());
+           extract = false;
+           return true;
         }
         total += compress_len;
         fileAddr += compress_len;
@@ -394,8 +417,8 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
 #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;
@@ -419,32 +442,31 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
             Emsg0(M_ERROR, 0, "Logic error output file should be open but is not.\n");
         }
         set_attributes(jcr, attr, &bfd);
-        extract = FALSE;
+        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, enum get_vol_info_rw  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;
 }