]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/filed/backup.c
Permit to get Where/RegexWhere from Plugin and give access to Accurate data
[bacula/bacula] / bacula / src / filed / backup.c
index b2fad4c3028a10ed961840f37445f52bab588bfb..60beddb80c8e233f3062f3e8ee3d0e0825f02545 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.
@@ -61,6 +61,7 @@ bool encode_and_send_attributes(JCR *jcr, FF_PKT *ff_pkt, int &data_stream);
 static bool crypto_session_start(JCR *jcr);
 static void crypto_session_end(JCR *jcr);
 static bool crypto_session_send(JCR *jcr, BSOCK *sd);
+static void close_vss_backup_session(JCR *jcr);
 
 /**
  * Find all the requested files and send them
@@ -172,6 +173,8 @@ bool blast_data_to_storage_daemon(JCR *jcr, char *addr)
            jcr->xattr_data->nr_errors);
    }
 
+   close_vss_backup_session(jcr);
+
    accurate_finish(jcr);              /* send deleted or base file list to SD */
 
    stop_heartbeat_monitor(jcr);
@@ -299,6 +302,7 @@ static bool crypto_session_send(JCR *jcr, BSOCK *sd)
 int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
 {
    bool do_read = false;
+   bool plugin_started = false;
    int stat, data_stream; 
    int rtnstat = 0;
    DIGEST *digest = NULL;
@@ -314,7 +318,7 @@ int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
 #endif
    BSOCK *sd = jcr->store_bsock;
 
-   if (job_canceled(jcr)) {
+   if (jcr->is_job_canceled()) {
       return 0;
    }
 
@@ -335,6 +339,9 @@ int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
    case FT_LNK:
       Dmsg2(130, "FT_LNK saving: %s -> %s\n", ff_pkt->fname, ff_pkt->link);
       break;
+   case FT_RESTORE_FIRST:
+      Dmsg1(100, "FT_RESTORE_FIRST saving: %s\n", ff_pkt->fname);
+      break;
    case FT_DIRBEGIN:
       jcr->num_files_examined--;      /* correct file count */
       return 1;                       /* not used */
@@ -346,8 +353,13 @@ int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
    case FT_NOFSCHG:
       /* Suppress message for /dev filesystems */
       if (!is_in_fileset(ff_pkt)) {
-         Jmsg(jcr, M_INFO, 1, _("     %s is a different filesystem. Will not descend from %s into %s\n"),
-              ff_pkt->fname, ff_pkt->top_fname, ff_pkt->fname);
+#ifdef HAVE_WIN32
+         Jmsg(jcr, M_INFO, 1, _("     %s is a junction point or a different filesystem. Will not descend from %s into it.\n"),
+              ff_pkt->fname, ff_pkt->top_fname);
+#else
+         Jmsg(jcr, M_INFO, 1, _("     %s is a different filesystem. Will not descend from %s into it.\n"),
+              ff_pkt->fname, ff_pkt->top_fname);
+#endif
       }
       ff_pkt->type = FT_DIREND;       /* Backup only the directory entry */
       break;
@@ -489,16 +501,22 @@ int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
       set_portable_backup(&ff_pkt->bfd); /* disable Win32 BackupRead() */
    }
    if (ff_pkt->cmd_plugin) {
+      /* Tell bfile that it needs to call plugin */
       if (!set_cmd_plugin(&ff_pkt->bfd, jcr)) {
          goto bail_out;
       }
       send_plugin_name(jcr, sd, true);      /* signal start of plugin data */
+      plugin_started = true;
    }
 
    /** Send attributes -- must be done after binit() */
    if (!encode_and_send_attributes(jcr, ff_pkt, data_stream)) {
       goto bail_out;
    }
+   /** Meta data only for restore object */
+   if (ff_pkt->type == FT_RESTORE_FIRST) {
+      goto good_rtn;
+   }
 
    /** Set up the encryption context and send the session data to the SD */
    if (has_file_data && jcr->crypto.pki_encrypt) {
@@ -524,11 +542,12 @@ int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
          (!is_portable_backup(&ff_pkt->bfd) && ff_pkt->type == FT_DIREND)) {
       do_read = true;
    }
+
    if (ff_pkt->cmd_plugin) {
       do_read = true;
    }
 
-   Dmsg1(400, "do_read=%d\n", do_read);
+   Dmsg2(150, "type=%d do_read=%d\n", ff_pkt->type, do_read);
    if (do_read) {
       btimer_t *tid;
 
@@ -729,14 +748,14 @@ int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
       sd->send();
       sd->signal(BNET_EOD);              /* end of checksum */
    }
-   if (ff_pkt->cmd_plugin) {
-      send_plugin_name(jcr, sd, false); /* signal end of plugin data */
-   }
 
 good_rtn:
    rtnstat = 1;                       /* good return */
 
 bail_out:
+   if (ff_pkt->cmd_plugin && plugin_started) {
+      send_plugin_name(jcr, sd, false); /* signal end of plugin data */
+   }
    if (digest) {
       crypto_digest_free(digest);
    }
@@ -853,7 +872,7 @@ static int send_data(JCR *jcr, int stream, FF_PKT *ff_pkt, DIGEST *digest,
     *    <file-index> <stream> <info>
     */
    if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
-      if (!job_canceled(jcr)) {
+      if (!jcr->is_job_canceled()) {
          Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
                sd->bstrerror());
       }
@@ -1013,7 +1032,7 @@ static int send_data(JCR *jcr, int stream, FF_PKT *ff_pkt, DIGEST *digest,
       }
       sd->msg = wbuf;              /* set correct write buffer */
       if (!sd->send()) {
-         if (!job_canceled(jcr)) {
+         if (!jcr->is_job_canceled()) {
             Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
                   sd->bstrerror());
          }
@@ -1050,7 +1069,7 @@ static int send_data(JCR *jcr, int stream, FF_PKT *ff_pkt, DIGEST *digest,
          sd->msglen = encrypted_len;      /* set encrypted length */
          sd->msg = jcr->crypto.crypto_buf;       /* set correct write buffer */
          if (!sd->send()) {
-            if (!job_canceled(jcr)) {
+            if (!jcr->is_job_canceled()) {
                Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
                      sd->bstrerror());
             }
@@ -1063,7 +1082,7 @@ static int send_data(JCR *jcr, int stream, FF_PKT *ff_pkt, DIGEST *digest,
    }
 
    if (!sd->signal(BNET_EOD)) {        /* indicate end of file data */
-      if (!job_canceled(jcr)) {
+      if (!jcr->is_job_canceled()) {
          Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
                sd->bstrerror());
       }
@@ -1091,9 +1110,11 @@ bool encode_and_send_attributes(JCR *jcr, FF_PKT *ff_pkt, int &data_stream)
 {
    BSOCK *sd = jcr->store_bsock;
    char attribs[MAXSTRING];
-   char attribsEx[MAXSTRING];
+   char attribsExBuf[MAXSTRING];
+   char *attribsEx = NULL;
    int attr_stream;
-   int stat;
+   int comp_len;
+   bool stat;
 #ifdef FD_NO_SEND_TEST
    return true;
 #endif
@@ -1108,7 +1129,12 @@ bool encode_and_send_attributes(JCR *jcr, FF_PKT *ff_pkt, int &data_stream)
    encode_stat(attribs, &ff_pkt->statp, ff_pkt->LinkFI, data_stream);
 
    /** Now possibly extend the attributes */
-   attr_stream = encode_attribsEx(jcr, attribsEx, ff_pkt);
+   if (ff_pkt->type == FT_RESTORE_FIRST) {
+      attr_stream = STREAM_RESTORE_OBJECT;
+   } else {
+      attribsEx = attribsExBuf;
+      attr_stream = encode_attribsEx(jcr, attribsEx, ff_pkt);
+   }
 
    Dmsg3(300, "File %s\nattribs=%s\nattribsEx=%s\n", ff_pkt->fname, attribs, attribsEx);
 
@@ -1123,7 +1149,7 @@ bool encode_and_send_attributes(JCR *jcr, FF_PKT *ff_pkt, int &data_stream)
     *    <file-index> <stream> <info>
     */
    if (!sd->fsend("%ld %d 0", jcr->JobFiles, attr_stream)) {
-      if (!job_canceled(jcr)) {
+      if (!jcr->is_job_canceled()) {
          Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
                sd->bstrerror());
       }
@@ -1140,39 +1166,84 @@ bool encode_and_send_attributes(JCR *jcr, FF_PKT *ff_pkt, int &data_stream)
     *   Link name (if type==FT_LNK or FT_LNKSAVED)
     *   Encoded extended-attributes (for Win32)
     *
+    * or send Restore Object to Storage daemon
+    *   File_index
+    *   File_type
+    *   Object_index
+    *   Object_len  (possibly compressed)
+    *   Object_full_len (not compressed)
+    *   Object_compression
+    *   Plugin_name
+    *   Object_name
+    *   Binary Object data
+    *
     * For a directory, link is the same as fname, but with trailing
     * slash. For a linked file, link is the link.
     */
    if (ff_pkt->type != FT_DELETED) { /* already stripped */
       strip_path(ff_pkt);
    }
-   if (ff_pkt->type == FT_LNK || ff_pkt->type == FT_LNKSAVED) {
+   switch (ff_pkt->type) {
+   case FT_LNK:
+   case FT_LNKSAVED:
       Dmsg2(300, "Link %s to %s\n", ff_pkt->fname, ff_pkt->link);
       stat = sd->fsend("%ld %d %s%c%s%c%s%c%s%c", jcr->JobFiles,
                ff_pkt->type, ff_pkt->fname, 0, attribs, 0, ff_pkt->link, 0,
                attribsEx, 0);
-   } else if (ff_pkt->type == FT_DIREND || ff_pkt->type == FT_REPARSE) {
+      break;
+   case FT_DIREND:
+   case FT_REPARSE:
       /* Here link is the canonical filename (i.e. with trailing slash) */
       stat = sd->fsend("%ld %d %s%c%s%c%c%s%c", jcr->JobFiles,
                ff_pkt->type, ff_pkt->link, 0, attribs, 0, 0, attribsEx, 0);
-   } else {
+      break;
+   case FT_RESTORE_FIRST:
+      comp_len = ff_pkt->object_len;
+      ff_pkt->object_compression = 0;
+      if (ff_pkt->object_len > 1000) {
+         /* Big object, compress it */
+         int stat;
+         comp_len = ff_pkt->object_len + 1000;
+         POOLMEM *comp_obj = get_memory(comp_len);
+         stat = Zdeflate(ff_pkt->object, ff_pkt->object_len, comp_obj, comp_len);
+         if (comp_len < ff_pkt->object_len) {
+            ff_pkt->object = comp_obj;
+            ff_pkt->object_compression = 1;    /* zlib level 9 compression */
+         } else {
+            /* Uncompressed object smaller, use it */
+            comp_len = ff_pkt->object_len;
+         }
+         Dmsg2(100, "Object compressed from %d to %d bytes\n", ff_pkt->object_len, comp_len);
+      }
+      sd->msglen = Mmsg(sd->msg, "%d %d %d %d %d %d %s%c%s%c", 
+                        jcr->JobFiles, ff_pkt->type, ff_pkt->object_index,
+                        comp_len, ff_pkt->object_len, ff_pkt->object_compression,
+                        ff_pkt->fname, 0, ff_pkt->object_name, 0);
+      sd->msg = check_pool_memory_size(sd->msg, sd->msglen + comp_len + 2);
+      memcpy(sd->msg + sd->msglen, ff_pkt->object, comp_len);
+      /* Note we send one extra byte so Dir can store zero after object */
+      sd->msglen += comp_len + 1;
+      stat = sd->send();
+      if (ff_pkt->object_compression) {
+         free_and_null_pool_memory(ff_pkt->object);
+      }
+      break;
+   default:
       stat = sd->fsend("%ld %d %s%c%s%c%c%s%c", jcr->JobFiles,
                ff_pkt->type, ff_pkt->fname, 0, attribs, 0, 0, attribsEx, 0);
+      break;
    }
    if (ff_pkt->type != FT_DELETED) {
       unstrip_path(ff_pkt);
    }
 
    Dmsg2(300, ">stored: attr len=%d: %s\n", sd->msglen, sd->msg);
-   if (!stat) {
-      if (!job_canceled(jcr)) {
-         Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
-               sd->bstrerror());
-      }
-      return false;
+   if (!stat && !jcr->is_job_canceled()) {
+      Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
+            sd->bstrerror());
    }
    sd->signal(BNET_EOD);            /* indicate end of attributes data */
-   return true;
+   return stat;
 }
 
 /**
@@ -1276,3 +1347,35 @@ void unstrip_path(FF_PKT *ff_pkt)
       sm_check(__FILE__, __LINE__, true);
    }
 }
+
+static void close_vss_backup_session(JCR *jcr)
+{
+#if defined(WIN32_VSS)
+   /* STOP VSS ON WIN32 */
+   /* tell vss to close the backup session */
+   if (jcr->VSS) {
+      if (g_pVSSClient->CloseBackup()) {             
+         /* inform user about writer states */
+         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++;
+            }
+            Jmsg(jcr, msg_type, 0, _("VSS Writer (BackupComplete): %s\n"), g_pVSSClient->GetWriterInfo(i));
+         }
+      }
+      WCHAR *metadata = g_pVSSClient->GetMetadata();
+      if (metadata) {
+         FF_PKT *ff_pkt = jcr->ff;
+         ff_pkt->fname = "job";
+         ff_pkt->type = FT_RESTORE_FIRST;
+         ff_pkt->LinkFI = 0;
+         ff_pkt->object_name = "job_metadata.xml";
+         ff_pkt->object = (char *)metadata;
+         ff_pkt->object_len = (wcslen(metadata) + 1) * sizeof(WCHAR);
+         save_file(jcr, ff_pkt, true);
+     }
+   }
+#endif
+}