]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/filed/job.c
Allow plugin to skip restore if problem
[bacula/bacula] / bacula / src / filed / job.c
index fd45d5da06b4fe6687d673db21bf3177a542774c..368976d2b96dacfa30ca32c90047489627db7047 100644 (file)
@@ -6,7 +6,7 @@
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
    This program is Free Software; you can redistribute it and/or
-   modify it under the terms of version two of the GNU General Public
+   modify it under the terms of version three of the GNU Affero General Public
    License as published by the Free Software Foundation and included
    in the file LICENSE.
 
@@ -15,7 +15,7 @@
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Affero General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
@@ -89,8 +89,12 @@ static int runbefore_cmd(JCR *jcr);
 static int runafter_cmd(JCR *jcr);
 static int runbeforenow_cmd(JCR *jcr);
 static int restore_object_cmd(JCR *jcr);
-static void set_options(findFOPTS *fo, const char *opts);
+static int set_options(findFOPTS *fo, const char *opts);
 static void set_storage_auth_key(JCR *jcr, char *key);
+static int sm_dump_cmd(JCR *jcr);
+#ifdef DEVELOPER
+static int exit_cmd(JCR *jcr);
+#endif
 
 /* Exported functions */
 
@@ -126,6 +130,10 @@ static struct s_cmds cmds[] = {
    {"Run",          runscript_cmd, 0},
    {"accurate",     accurate_cmd,  0},
    {"restoreobject", restore_object_cmd, 0},
+   {"sm_dump",      sm_dump_cmd, 0},
+#ifdef DEVELOPER
+   {"exit",         exit_cmd, 0},
+#endif
    {NULL,       NULL}                  /* list terminator */
 };
 
@@ -137,7 +145,7 @@ static char sessioncmd[]  = "session %127s %ld %ld %ld %ld %ld %ld\n";
 static char restorecmd[]  = "restore replace=%c prelinks=%d where=%s\n";
 static char restorecmd1[] = "restore replace=%c prelinks=%d where=\n";
 static char restorecmdR[] = "restore replace=%c prelinks=%d regexwhere=%s\n";
-static char restoreobjcmd[] = "restoreobject JobId=%u ObjLen=%d ObjInx=%d ObjType=%d FI=%d\n";
+static char restoreobjcmd[] = "restoreobject JobId=%u %d,%d,%d,%d,%d,%d\n";
 static char endrestoreobjectcmd[] = "restoreobject end\n";
 static char verifycmd[]   = "verify level=%30s";
 static char estimatecmd[] = "estimate listing=%d";
@@ -394,9 +402,28 @@ void *handle_client_request(void *dirp)
    free_jcr(jcr);                     /* destroy JCR record */
    Dmsg0(100, "Done with free_jcr\n");
    Dsm_check(1);
+   garbage_collect_memory_pool();
    return NULL;
 }
 
+static int sm_dump_cmd(JCR *jcr)
+{
+   close_memory_pool();
+   sm_dump(false, true);
+   jcr->dir_bsock->fsend("2000 sm_dump OK\n");
+   return 1;
+}
+
+#ifdef DEVELOPER
+static int exit_cmd(JCR *jcr)
+{
+   jcr->dir_bsock->fsend("2000 exit OK\n");
+   terminate_filed(0);
+   return 0;
+}
+#endif
+
+
 /**
  * Hello from Director he must identify himself and provide his
  *  password.
@@ -428,7 +455,7 @@ static int cancel_cmd(JCR *jcr)
          if (cjcr->store_bsock) {
             cjcr->store_bsock->set_timed_out();
             cjcr->store_bsock->set_terminated();
-            pthread_kill(cjcr->my_thread_id, TIMEOUT_SIGNAL);
+            cjcr->my_thread_send_signal(TIMEOUT_SIGNAL);
          }
          generate_plugin_event(cjcr, bEventCancelCommand, NULL);
          set_jcr_job_status(cjcr, JS_Canceled);
@@ -620,10 +647,15 @@ static int runscript_cmd(JCR *jcr)
    return dir->fsend(OKRunScript);
 }
 
+/*
+ * This reads data sent from the Director from the
+ *   RestoreObject table that allows us to get objects
+ *   that were backed up (VSS .xml data) and are needed
+ *   before starting the restore.
+ */
 static int restore_object_cmd(JCR *jcr)
 {
    BSOCK *dir = jcr->dir_bsock;
-   POOLMEM *msg = get_memory(dir->msglen+1);
    int32_t FileIndex;
    restore_object_pkt rop;
 
@@ -633,20 +665,21 @@ static int restore_object_cmd(JCR *jcr)
    Dmsg1(100, "Enter restoreobject_cmd: %s", dir->msg);
    if (strcmp(dir->msg, endrestoreobjectcmd) == 0) {
       generate_plugin_event(jcr, bEventRestoreObject, NULL);
-      free_memory(msg);
       return dir->fsend(OKRestoreObject);
    }
 
    if (sscanf(dir->msg, restoreobjcmd, &rop.JobId, &rop.object_len, 
-              &rop.object_index, &rop.object_type, &FileIndex) != 5) {
+              &rop.object_full_len, &rop.object_index, 
+              &rop.object_type, &rop.object_compression, &FileIndex) != 7) {
       Dmsg0(5, "Bad restore object command\n");
       pm_strcpy(jcr->errmsg, dir->msg);
       Jmsg1(jcr, M_FATAL, 0, _("Bad RestoreObject command: %s\n"), jcr->errmsg);
       goto bail_out;
    }
 
-   Dmsg5(100, "Recv object: JobId=%u objlen=%d objinx=%d objtype=%d FI=%d\n",
-         rop.JobId, rop.object_len, rop.object_index, rop.object_type, FileIndex);
+   Dmsg6(100, "Recv object: JobId=%u objlen=%d full_len=%d objinx=%d objtype=%d FI=%d\n",
+         rop.JobId, rop.object_len, rop.object_full_len, 
+         rop.object_index, rop.object_type, FileIndex);
    /* Read Object name */
    if (dir->recv() < 0) {
       goto bail_out;
@@ -658,9 +691,28 @@ static int restore_object_cmd(JCR *jcr)
    if (dir->recv() < 0) {
       goto bail_out;
    }
+   /* Transfer object from message buffer, and get new message buffer */
    rop.object = dir->msg;
-   Dmsg2(100, "Recv Object: len=%d Object=%s\n", dir->msglen, dir->msg);
-
+   dir->msg = get_pool_memory(PM_MESSAGE);
+
+   /* If object is compressed, uncompress it */
+   if (rop.object_compression == 1) {   /* zlib level 9 */
+      int stat;
+      int out_len = rop.object_full_len + 100;
+      POOLMEM *obj = get_memory(out_len);
+      Dmsg2(100, "Inflating from %d to %d\n", rop.object_len, rop.object_full_len);
+      stat = Zinflate(rop.object, rop.object_len, obj, out_len);
+      Dmsg1(100, "Zinflate stat=%d\n", stat);
+      if (out_len != rop.object_full_len) {
+         Jmsg3(jcr, M_ERROR, 0, ("Decompression failed. Len wanted=%d got=%d. Object=%s\n"),
+            rop.object_full_len, out_len, rop.object_name);
+      }
+      free_pool_memory(rop.object);   /* release compressed object */
+      rop.object = obj;               /* new uncompressed object */
+      rop.object_len = out_len;
+   }
+   Dmsg2(100, "Recv Object: len=%d Object=%s\n", rop.object_len, rop.object);
+   /* Special Job meta data */
    if (strcmp(rop.object_name, "job_metadata.xml") == 0) {
       Dmsg0(100, "got job metadata\n");
       free_and_null_pool_memory(jcr->job_metadata);
@@ -674,17 +726,15 @@ static int restore_object_cmd(JCR *jcr)
    if (rop.object_name) {
       free(rop.object_name);
    }
-   if (!rop.object) {
-      dir->msg = get_pool_memory(PM_MESSAGE);
+   if (rop.object) {
+      free_pool_memory(rop.object);
    }
 
-   free_memory(msg);
    Dmsg1(100, "Send: %s", OKRestoreObject);
    return 1;
 
 bail_out:
    dir->fsend(_("2909 Bad RestoreObject command.\n"));
-   free_memory(msg);
    return 0;
 
 }
@@ -711,39 +761,30 @@ static bool init_fileset(JCR *jcr)
    return true;
 }
 
-static findFOPTS *start_options(FF_PKT *ff)
+static void append_file(JCR *jcr, findINCEXE *incexe, 
+                        const char *buf, bool is_file)
 {
-   int state = ff->fileset->state;
-   findINCEXE *incexe = ff->fileset->incexe;
+   if (is_file) {
+      incexe->name_list.append(new_dlistString(buf));
 
-   if (state != state_options) {
-      ff->fileset->state = state_options;
-      findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
-      memset(fo, 0, sizeof(findFOPTS));
-      fo->regex.init(1, true);
-      fo->regexdir.init(1, true);
-      fo->regexfile.init(1, true);
-      fo->wild.init(1, true);
-      fo->wilddir.init(1, true);
-      fo->wildfile.init(1, true);
-      fo->wildbase.init(1, true);
-      fo->base.init(1, true);
-      fo->fstype.init(1, true);
-      fo->drivetype.init(1, true);
-      incexe->current_opts = fo;
-      incexe->opts_list.append(fo);
-   }
-   return incexe->current_opts;
+   } else if (me->plugin_directory) {
+      generate_plugin_event(jcr, bEventPluginCommand, (void *)buf);
+      incexe->plugin_list.append(new_dlistString(buf));
 
+   } else {
+      Jmsg(jcr, M_FATAL, 0, 
+           _("Plugin Directory not defined. Cannot use plugin: \"%s\"\n"),
+           buf);
+   }
 }
 
 /**
  * Add fname to include/exclude fileset list. First check for
  * | and < and if necessary perform command.
  */
-void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset,
-                         bool is_file)
+void add_file_to_fileset(JCR *jcr, const char *fname, bool is_file)
 {
+   findFILESET *fileset = jcr->ff->fileset;
    char *p;
    BPIPE *bpipe;
    POOLMEM *fn;
@@ -770,11 +811,7 @@ void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset,
       free_pool_memory(fn);
       while (fgets(buf, sizeof(buf), bpipe->rfd)) {
          strip_trailing_junk(buf);
-         if (is_file) {
-            fileset->incexe->name_list.append(new_dlistString(buf));
-         } else {
-            fileset->incexe->plugin_list.append(new_dlistString(buf));
-         }
+         append_file(jcr, fileset->incexe, buf, is_file);
       }
       if ((stat=close_bpipe(bpipe)) != 0) {
          berrno be;
@@ -788,43 +825,36 @@ void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *fileset,
       p++;                      /* skip over < */
       if ((ffd = fopen(p, "rb")) == NULL) {
          berrno be;
-         Jmsg(jcr, M_FATAL, 0, _("Cannot open FileSet input file: %s. ERR=%s\n"),
+         Jmsg(jcr, M_FATAL, 0, 
+              _("Cannot open FileSet input file: %s. ERR=%s\n"),
             p, be.bstrerror());
          return;
       }
       while (fgets(buf, sizeof(buf), ffd)) {
          strip_trailing_junk(buf);
-         Dmsg1(100, "%s\n", buf);
-         if (is_file) {
-            fileset->incexe->name_list.append(new_dlistString(buf));
-         } else {
-            fileset->incexe->plugin_list.append(new_dlistString(buf));
-         }
+         append_file(jcr, fileset->incexe, buf, is_file);
       }
       fclose(ffd);
       break;
    default:
-      if (is_file) {
-         fileset->incexe->name_list.append(new_dlistString(fname));
-      } else {
-         if (me->plugin_directory) {
-            fileset->incexe->plugin_list.append(new_dlistString(fname));
-         } else {
-            Jmsg(jcr, M_FATAL, 0, _("Plugin Directory not defined. Cannot use plugin: \"%\"\n"),
-               fname);
-         }
-      }
+      append_file(jcr, fileset->incexe, fname, is_file);
       break;
    }
 }
 
+void set_incexe(JCR *jcr, findINCEXE *incexe)
+{
+   findFILESET *fileset = jcr->ff->fileset;
+   fileset->incexe = incexe;
+}
+
+
 /**
  * Define a new Exclude block in the FileSet
  */
-findFILESET *new_exclude(JCR *jcr)
+findINCEXE *new_exclude(JCR *jcr)
 {
-   FF_PKT *ff = jcr->ff;
-   findFILESET *fileset = ff->fileset;
+   findFILESET *fileset = jcr->ff->fileset;
 
    /* New exclude */
    fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
@@ -833,9 +863,162 @@ findFILESET *new_exclude(JCR *jcr)
    fileset->incexe->name_list.init();
    fileset->incexe->plugin_list.init();
    fileset->exclude_list.append(fileset->incexe);
-   return fileset;
+   return fileset->incexe;
+}
+
+/**
+ * Define a new Include block in the FileSet
+ */
+findINCEXE *new_include(JCR *jcr)
+{
+   findFILESET *fileset = jcr->ff->fileset;
+
+   /* New include */
+   fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
+   memset(fileset->incexe, 0, sizeof(findINCEXE));
+   fileset->incexe->opts_list.init(1, true);
+   fileset->incexe->name_list.init(); /* for dlist;  was 1,true for alist */
+   fileset->incexe->plugin_list.init();
+   fileset->include_list.append(fileset->incexe);
+   return fileset->incexe;
+}
+
+/**
+ * Define a new preInclude block in the FileSet
+ *   That is the include is prepended to the other
+ *   Includes.  This is used for plugin exclusions.
+ */
+findINCEXE *new_preinclude(JCR *jcr)
+{
+   findFILESET *fileset = jcr->ff->fileset;
+
+   /* New pre-include */
+   fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
+   memset(fileset->incexe, 0, sizeof(findINCEXE));
+   fileset->incexe->opts_list.init(1, true);
+   fileset->incexe->name_list.init(); /* for dlist;  was 1,true for alist */
+   fileset->incexe->plugin_list.init();
+   fileset->include_list.prepend(fileset->incexe);
+   return fileset->incexe;
+}
+
+static findFOPTS *start_options(FF_PKT *ff)
+{
+   int state = ff->fileset->state;
+   findINCEXE *incexe = ff->fileset->incexe;
+
+   if (state != state_options) {
+      ff->fileset->state = state_options;
+      findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
+      memset(fo, 0, sizeof(findFOPTS));
+      fo->regex.init(1, true);
+      fo->regexdir.init(1, true);
+      fo->regexfile.init(1, true);
+      fo->wild.init(1, true);
+      fo->wilddir.init(1, true);
+      fo->wildfile.init(1, true);
+      fo->wildbase.init(1, true);
+      fo->base.init(1, true);
+      fo->fstype.init(1, true);
+      fo->drivetype.init(1, true);
+      incexe->current_opts = fo;
+      incexe->opts_list.append(fo);
+   }
+   return incexe->current_opts;
+}
+
+/*
+ * Used by plugins to define a new options block
+ */
+void new_options(JCR *jcr, findINCEXE *incexe)
+{
+   if (!incexe) {
+      incexe = jcr->ff->fileset->incexe;
+   }
+   findFOPTS *fo = (findFOPTS *)malloc(sizeof(findFOPTS));
+   memset(fo, 0, sizeof(findFOPTS));
+   fo->regex.init(1, true);
+   fo->regexdir.init(1, true);
+   fo->regexfile.init(1, true);
+   fo->wild.init(1, true);
+   fo->wilddir.init(1, true);
+   fo->wildfile.init(1, true);
+   fo->wildbase.init(1, true);
+   fo->base.init(1, true);
+   fo->fstype.init(1, true);
+   fo->drivetype.init(1, true);
+   incexe->current_opts = fo;
+   incexe->opts_list.prepend(fo);
+   jcr->ff->fileset->state = state_options;
 }
 
+/**
+ * Add a regex to the current fileset
+ */
+int add_regex_to_fileset(JCR *jcr, const char *item, int type)
+{
+   findFOPTS *current_opts = start_options(jcr->ff);
+   regex_t *preg;
+   int rc;
+   char prbuf[500];
+
+   preg = (regex_t *)malloc(sizeof(regex_t));
+   if (current_opts->flags & FO_IGNORECASE) {
+      rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
+   } else {
+      rc = regcomp(preg, item, REG_EXTENDED);
+   }
+   if (rc != 0) {
+      regerror(rc, preg, prbuf, sizeof(prbuf));
+      regfree(preg);
+      free(preg);
+      Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
+      return state_error;
+   }
+   if (type == ' ') {
+      current_opts->regex.append(preg);
+   } else if (type == 'D') {
+      current_opts->regexdir.append(preg);
+   } else if (type == 'F') {
+      current_opts->regexfile.append(preg);
+   } else {
+      return state_error;
+   }
+   return state_options;
+}
+
+/**
+ * Add a wild card to the current fileset
+ */
+int add_wild_to_fileset(JCR *jcr, const char *item, int type)
+{
+   findFOPTS *current_opts = start_options(jcr->ff);
+
+   if (type == ' ') {
+      current_opts->wild.append(bstrdup(item));
+   } else if (type == 'D') {
+      current_opts->wilddir.append(bstrdup(item));
+   } else if (type == 'F') {
+      current_opts->wildfile.append(bstrdup(item));
+   } else if (type == 'B') {
+      current_opts->wildbase.append(bstrdup(item));
+   } else {
+      return state_error;
+   }
+   return state_options;
+}
+
+
+/**
+ * Add options to the current fileset
+ */
+int add_options_to_fileset(JCR *jcr, const char *item)
+{
+   findFOPTS *current_opts = start_options(jcr->ff);
+
+   set_options(current_opts, item);
+   return state_options;
+}
 
 static void add_fileset(JCR *jcr, const char *item)
 {
@@ -877,66 +1060,33 @@ static void add_fileset(JCR *jcr, const char *item)
    }
    switch (code) {
    case 'I':
-      /* New include */
-      fileset->incexe = (findINCEXE *)malloc(sizeof(findINCEXE));
-      memset(fileset->incexe, 0, sizeof(findINCEXE));
-      fileset->incexe->opts_list.init(1, true);
-      fileset->incexe->name_list.init(); /* for dlist;  was 1,true for alist */
-      fileset->incexe->plugin_list.init();
-      fileset->include_list.append(fileset->incexe);
+      (void)new_include(jcr);
       break;
    case 'E':
-      fileset = new_exclude(jcr);
+      (void)new_exclude(jcr);
       break;
-   case 'N':
+   case 'N':                             /* null */
       state = state_none;
       break;
-   case 'F':
+   case 'F':                             /* file = */
       /* File item to include or exclude list */
       state = state_include;
-      add_file_to_fileset(jcr, item, fileset, true);
+      add_file_to_fileset(jcr, item, true);
       break;
-   case 'P':
+   case 'P':                              /* plugin */
       /* Plugin item to include list */
       state = state_include;
-      add_file_to_fileset(jcr, item, fileset, false);
+      add_file_to_fileset(jcr, item, false);
       break;
-   case 'R':
-      current_opts = start_options(ff);
-      regex_t *preg;
-      int rc;
-      char prbuf[500];
-      preg = (regex_t *)malloc(sizeof(regex_t));
-      if (current_opts->flags & FO_IGNORECASE) {
-         rc = regcomp(preg, item, REG_EXTENDED|REG_ICASE);
-      } else {
-         rc = regcomp(preg, item, REG_EXTENDED);
-      }
-      if (rc != 0) {
-         regerror(rc, preg, prbuf, sizeof(prbuf));
-         regfree(preg);
-         free(preg);
-         Jmsg(jcr, M_FATAL, 0, _("REGEX %s compile error. ERR=%s\n"), item, prbuf);
-         state = state_error;
-         break;
-      }
-      state = state_options;
-      if (subcode == ' ') {
-         current_opts->regex.append(preg);
-      } else if (subcode == 'D') {
-         current_opts->regexdir.append(preg);
-      } else if (subcode == 'F') {
-         current_opts->regexfile.append(preg);
-      } else {
-         state = state_error;
-      }
+   case 'R':                              /* regex */
+      state = add_regex_to_fileset(jcr, item, subcode);
       break;
    case 'B':
       current_opts = start_options(ff);
       current_opts->base.append(bstrdup(item));
       state = state_options;
       break;
-   case 'X':
+   case 'X':                             /* Filetype or Drive type */
       current_opts = start_options(ff);
       state = state_options;
       if (subcode == ' ') {
@@ -947,38 +1097,24 @@ static void add_fileset(JCR *jcr, const char *item)
          state = state_error;
       }
       break;
-   case 'W':
-      current_opts = start_options(ff);
-      state = state_options;
-      if (subcode == ' ') {
-         current_opts->wild.append(bstrdup(item));
-      } else if (subcode == 'D') {
-         current_opts->wilddir.append(bstrdup(item));
-      } else if (subcode == 'F') {
-         current_opts->wildfile.append(bstrdup(item));
-      } else if (subcode == 'B') {
-         current_opts->wildbase.append(bstrdup(item));
-      } else {
-         state = state_error;
-      }
+   case 'W':                               /* wild cards */
+      state = add_wild_to_fileset(jcr, item, subcode);
       break;
-   case 'O':
-      current_opts = start_options(ff);
-      set_options(current_opts, item);
-      state = state_options;
+   case 'O':                                /* Options */
+      state = add_options_to_fileset(jcr, item);
       break;
-   case 'Z':
+   case 'Z':                                /* ignore dir */
       state = state_include;
       fileset->incexe->ignoredir = bstrdup(item);
       break;
    case 'D':
       current_opts = start_options(ff);
-//    current_opts->reader = bstrdup(item);
+//    current_opts->reader = bstrdup(item); /* deprecated */
       state = state_options;
       break;
    case 'T':
       current_opts = start_options(ff);
-//    current_opts->writer = bstrdup(item);
+//    current_opts->writer = bstrdup(item); /* deprecated */
       state = state_options;
       break;
    default:
@@ -1098,7 +1234,7 @@ static bool term_fileset(JCR *jcr)
  *  "compile" time in filed/job.c, and keep only a bit mask
  *  and the Verify options.
  */
-static void set_options(findFOPTS *fo, const char *opts)
+static int set_options(findFOPTS *fo, const char *opts)
 {
    int j;
    const char *p;
@@ -1140,6 +1276,7 @@ static void set_options(findFOPTS *fo, const char *opts)
          break;
       case 'R':                 /* Resource forks and Finder Info */
          fo->flags |= FO_HFSPLUS;
+         break;
       case 'r':                 /* read fifo */
          fo->flags |= FO_READFIFO;
          break;
@@ -1254,6 +1391,7 @@ static void set_options(findFOPTS *fo, const char *opts)
          break;
       }
    }
+   return state_options;
 }
 
 
@@ -1263,6 +1401,7 @@ static void set_options(findFOPTS *fo, const char *opts)
 static int fileset_cmd(JCR *jcr)
 {
    BSOCK *dir = jcr->dir_bsock;
+   int rtnstat;
 
 #if defined(WIN32_VSS)
    int vss = 0;
@@ -1282,7 +1421,9 @@ static int fileset_cmd(JCR *jcr)
    if (!term_fileset(jcr)) {
       return 0;
    }
-   return dir->fsend(OKinc);
+   rtnstat = dir->fsend(OKinc);
+   generate_plugin_event(jcr, bEventEndFileSet);
+   return rtnstat;
 }
 
 static void free_bootstrap(JCR *jcr)
@@ -1681,8 +1822,8 @@ static int backup_cmd(JCR *jcr)
         if (get_win32_driveletters(jcr->ff, szWinDriveLetters)) {
             Jmsg(jcr, M_INFO, 0, _("Generate VSS snapshots. Driver=\"%s\", Drive(s)=\"%s\"\n"), g_pVSSClient->GetDriverName(), szWinDriveLetters);
             if (!g_pVSSClient->CreateSnapshots(szWinDriveLetters)) {               
-               Jmsg(jcr, M_WARNING, 0, _("Generate VSS snapshots failed.\n"));
-               jcr->JobErrors++;
+               berrno be;
+               Jmsg(jcr, M_FATAL, 0, _("Generate VSS snapshots failed. ERR=%s\n"), be.bstrerror());
             } else {
                /* tell user if snapshot creation of a specific drive failed */
                int i;
@@ -1695,8 +1836,8 @@ static int backup_cmd(JCR *jcr)
                /* inform user about writer states */
                for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++)                
                   if (g_pVSSClient->GetWriterState(i) < 1) {
-                     Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));                    
-                     jcr->JobErrors++;
+                     Jmsg(jcr, M_INFO, 0, _("VSS Writer (PrepareForBackup): %s\n"), g_pVSSClient->GetWriterInfo(i));                    
+                     //jcr->JobErrors++;
                   }                            
             }
         } else {
@@ -1888,8 +2029,11 @@ static int restore_cmd(JCR *jcr)
    Dmsg0(100, "restore command\n");
 #if defined(WIN32_VSS)
 
-   /* TODO: this should be given from the director */
-   enable_vss = 1;
+   /**
+    * No need to enable VSS for restore if we do not have plugin
+    *  data to restore 
+    */
+   enable_vss = jcr->job_metadata != NULL;
 
    Dmsg2(50, "g_pVSSClient = %p, enable_vss = %d\n", g_pVSSClient, enable_vss);
    // capture state here, if client is backed up by multiple directors
@@ -1965,20 +2109,21 @@ static int restore_cmd(JCR *jcr)
    if (jcr->VSS) {
       if (g_pVSSClient->InitializeForRestore(jcr, vss_restore_init_callback,
             (WCHAR *)jcr->job_metadata)) {
+
          /* inform user about writer states */
          int i;
          for (i=0; i < (int)g_pVSSClient->GetWriterCount(); i++) {
-            int msg_type = M_INFO;
             if (g_pVSSClient->GetWriterState(i) < 1) {
-               msg_type = M_WARNING;
-               jcr->JobErrors++;
-            }
-            if (g_pVSSClient->GetWriterState(i) < 1) {
-               Jmsg(jcr, M_WARNING, 0, _("VSS Writer (PreRestore): %s\n"), g_pVSSClient->GetWriterInfo(i));
-               jcr->JobErrors++;
+               Jmsg(jcr, M_INFO, 0, _("VSS Writer (PreRestore): %s\n"), g_pVSSClient->GetWriterInfo(i));
+               //jcr->JobErrors++;
             }
          }
       } else {
+/*
+   int fd = open("C:\\eric.xml", O_CREAT | O_WRONLY | O_TRUNC, 0777);
+   write(fd, (WCHAR *)jcr->job_metadata, wcslen((WCHAR *)jcr->job_metadata) * sizeof(WCHAR));
+   close(fd);
+*/
          berrno be;
          Jmsg(jcr, M_WARNING, 0, _("VSS was not initialized properly. VSS support is disabled. ERR=%s\n"), be.bstrerror());
       }
@@ -2018,8 +2163,8 @@ static int restore_cmd(JCR *jcr)
          for (int i=0; i<(int)g_pVSSClient->GetWriterCount(); i++) {
             int msg_type = M_INFO;
             if (g_pVSSClient->GetWriterState(i) < 1) {
-               msg_type = M_WARNING;
-               jcr->JobErrors++;
+               //msg_type = M_WARNING;
+               //jcr->JobErrors++;
             }
             Jmsg(jcr, msg_type, 0, _("VSS Writer (RestoreComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
          }