]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/filed/win_efs.c
Restore win32 dir from Branch-5.2 and update it
[bacula/bacula] / bacula / src / filed / win_efs.c
diff --git a/bacula/src/filed/win_efs.c b/bacula/src/filed/win_efs.c
new file mode 100644 (file)
index 0000000..860a21a
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2000-2014 Bacula Systems SA
+   All rights reserved.
+
+   The main author of Bacula is Kern Sibbald, with contributions from many
+   others, a complete list can be found in the file AUTHORS.
+
+   Licensees holding a valid Bacula Systems SA license may use this file
+   and others of this release in accordance with the proprietary license
+   agreement provided in the LICENSE file.  Redistribution of any part of
+   this release is not permitted.
+
+   Bacula® is a registered trademark of Kern Sibbald.
+*/
+/*
+ *  Bacula File Daemon  Windows EFS restore
+ *
+ *    Kern Sibbald, September MMXIV
+ *
+ */
+
+#include "bacula.h"
+#include "filed.h"
+#include "ch.h"
+#include "restore.h"
+#include "backup.h"
+
+#ifdef TEST_WORKER
+/*
+ * This is the test version of the worker routines, which simulates
+ *  Windows EFS backup on Linux.
+ *
+ * This subroutine is called back from the Windows
+ *  WriteEncryptedFileRaw and returns a single buffer of data or
+ *  sets ulLength = 0 to indicate the end.
+ */
+static uint32_t test_write_efs_data_cb(char *pbData, void *arctx, uint32_t *len)
+{
+   r_ctx *rctx = (r_ctx *)arctx;
+   worker *wrk = (worker *)rctx->efs;
+   char *head, *buf;
+   uint32_t data_len;
+   int32_t count;
+
+   head = (char *)wrk->dequeue();      /* dequeue buffer to write */
+   Dmsg1(200, "dequeue buffer. head=%p\n", head);
+   if (!head) {
+      *len = 0;
+      Dmsg0(200, "cb got NULL.\n");
+   } else {
+      data_len = *(int32_t *)head;
+      Dmsg1(200, "data_len=%d\n", data_len);
+      if (data_len == 0) {
+         Dmsg0(200, "Length is zero.\n");
+         wrk->push_free_buffer(head);
+         return ERROR_BUFFER_OVERFLOW;
+      }
+      if (data_len > *len) {
+         Dmsg2(200, "Restore data %ld bytes too long for Microsoft buffer %ld bytes.\n",
+            data_len, *len);
+         *len = 0;
+         errno = b_errno_win32;
+         wrk->push_free_buffer(head);
+         return ERROR_BUFFER_OVERFLOW;
+      } else {
+         buf = head + sizeof(uint32_t);    /* Point to buffer */
+         count = *(int32_t *)buf;
+         buf += sizeof(int32_t);
+         memcpy(pbData, buf, data_len);
+         *len = data_len;
+         Dmsg2(200, "Got count=%d len=%d\n", count, data_len);
+         wrk->push_free_buffer(head);
+      }
+   }
+   return ERROR_SUCCESS;
+}
+
+/*
+ * Thread created to run the WriteEncryptedFileRaw code
+ */
+static void *test_efs_write_thread(void *awrk)
+{
+   ssize_t wstat;
+   worker *wrk = (worker *)awrk;
+   r_ctx *rctx;
+   uint32_t len;
+   uint32_t size = 100000;
+   char *buf = (char *)malloc(size);    /* allocate working buffer */
+
+   rctx = (r_ctx *)wrk->get_ctx();
+   Dmsg2(200, "rctx=%p wrk=%p\n", rctx, wrk);
+   wrk->set_running();
+
+   while (!wrk->is_quit_state()) {
+      if (wrk->is_wait_state()) {      /* wait if so requested */
+         Dmsg0(200, "Enter wait state\n");
+         wrk->wait();
+         Dmsg0(200, "Leave wait state\n");
+         continue;
+      }
+      len = size;
+      if (test_write_efs_data_cb(buf, rctx, &len) != 0) {  /* get a buffer */
+         berrno be;
+         Qmsg2(rctx->jcr, M_FATAL, 0, _("Restore data %ld bytes too long for Microsoft buffer %ld bytes.\n"),
+            len, size);
+         break;
+      }
+      if (len == 0) {       /* done? */
+         Dmsg0(200, "Got len 0 set_wait_state.\n");
+         continue;          /* yes */
+      }
+      Dmsg2(200, "Write buf=%p len=%d\n", buf, len);
+      if ((wstat=bwrite(&rctx->bfd, buf, len)) != (ssize_t)len) {
+         Dmsg4(000, "bwrite of %d error %d open=%d on file=%s\n",
+            len, wstat, is_bopen(&rctx->bfd), rctx->jcr->last_fname);
+         continue;
+      }
+   }
+   Dmsg0(200, "worker thread quiting\n");
+   free(buf);
+   return NULL;
+}
+
+/*
+ * If the writer thread is not created, create it, then queue
+ *  a buffer to be written by the thread.
+ */
+bool test_write_efs_data(r_ctx &rctx, char *data, const int32_t length)
+{
+   POOLMEM *buf, *head;
+
+   if (!rctx.efs) {
+      rctx.efs = New(worker(10));
+      Dmsg2(200, "Start test_efs_write_thread rctx=%p work=%p\n", &rctx, rctx.efs);
+      rctx.efs->start(test_efs_write_thread, &rctx);
+   }
+   head = (POOLMEM *)rctx.efs->pop_free_buffer();
+   if (!head) {
+      head = get_memory(length + 2*sizeof(int32_t)+1);
+   } else {
+      head = check_pool_memory_size(head, length+2*sizeof(int32_t)+1);
+   }
+   buf = head;
+   *(int32_t *)buf = length;
+   buf += sizeof(int32_t);
+   *(int32_t *)buf = ++rctx.count;
+   buf += sizeof(int32_t);
+   memcpy(buf, data, length);
+   Dmsg3(200, "Put count=%d len=%d head=%p\n", rctx.count, length, head);
+   rctx.efs->queue(head);
+   rctx.efs->set_run_state();
+   return true;
+}
+#endif
+
+
+#ifdef HAVE_WIN32
+
+/* =============================================================
+ *
+ *   Win EFS functions for restore
+ *
+ * =============================================================
+ */
+
+/*
+ * This subroutine is called back from the Windows
+ *  WriteEncryptedFileRaw.
+ */
+static DWORD WINAPI write_efs_data_cb(PBYTE pbData, PVOID arctx, PULONG ulLength)
+{
+   r_ctx *rctx = (r_ctx *)arctx;
+   worker *wrk = (worker *)rctx->efs;
+   char *data;
+   char *buf;
+   uint32_t data_len;
+   JCR *jcr = rctx->jcr;
+
+   data = (char *)rctx->efs->dequeue();    /* dequeue buffer to write */
+   Dmsg1(200, "dequeue buffer. head=%p\n", data);
+   if (jcr->is_job_canceled()) {
+      return ERROR_CANCELLED;
+   }
+   if (!data) {
+      *ulLength = 0;
+      Dmsg0(200, "cb got NULL.\n");
+   } else {
+      data_len = *(int32_t *)data;
+      if (data_len > *ulLength) {
+         Qmsg2(rctx->jcr, M_FATAL, 0, _("Restore data %ld bytes too long for Microsoft buffer %lld bytes.\n"),
+            data_len, *ulLength);
+         *ulLength = 0;
+      } else {
+         buf = data + sizeof(uint32_t);
+         memcpy(pbData, buf, data_len);
+         *ulLength = (ULONG)data_len;
+         Dmsg1(200, "Got len=%d\n", data_len);
+      }
+      wrk->push_free_buffer(data);
+   }
+   return ERROR_SUCCESS;
+}
+
+/*
+ * Thread created to run the WriteEncryptedFileRaw code
+ */
+static void *efs_write_thread(void *awrk)
+{
+   worker *wrk = (worker *)awrk;
+   r_ctx *rctx;
+
+   rctx = (r_ctx *)wrk->get_ctx();
+   wrk->set_running();
+
+   while (!wrk->is_quit_state() && !rctx->jcr->is_job_canceled()) {
+      if (wrk->is_wait_state()) {      /* wait if so requested */
+         Dmsg0(200, "Enter wait state\n");
+         wrk->wait();
+         Dmsg0(200, "Leave wait state\n");
+         continue;
+      }
+      if (p_WriteEncryptedFileRaw((PFE_IMPORT_FUNC)write_efs_data_cb, rctx,
+             rctx->bfd.pvContext)) {
+         berrno be;
+         Qmsg1(rctx->jcr, M_FATAL, 0, _("WriteEncryptedFileRaw failure: ERR=%s\n"),
+            be.bstrerror(b_errno_win32));
+         return NULL;
+      }
+      Dmsg0(200, "Got return from WriteEncryptedFileRaw\n");
+   }         
+   return NULL;
+}
+
+/*
+ * Called here from Bacula to write a block to a Windows EFS file.
+ * Since the Windows WriteEncryptedFileRaw function uses a callback
+ *  subroutine to get the blocks to write, we create a writer thread,
+ *  and queue the blocks (buffers) we get in this routine.  That
+ *  writer thread then hangs on the WriteEncryptedRaw file, calling
+ *  back to the callback subroutine which then dequeues the blocks
+ *  we have queued.
+ *
+ * If the writer thread is not created, create it, then queue
+ *  a buffer to be written by the thread.
+ */
+bool win_write_efs_data(r_ctx &rctx, char *data, const int32_t length)
+{
+   POOLMEM *buf;
+
+   if (!rctx.efs) {
+      rctx.efs = New(worker(10));
+      rctx.efs->start(efs_write_thread, &rctx);
+   }
+   buf = (POOLMEM *)rctx.efs->pop_free_buffer();
+   if (!buf) {
+      buf = get_memory(length + sizeof(int32_t)+1);
+   } else {
+      buf = check_pool_memory_size(buf, length+sizeof(int32_t)+1);
+   }
+   *(int32_t *)buf = length;
+   memcpy(buf+sizeof(int32_t), data, length);
+   Dmsg2(200, "Put len=%d head=%p\n", length, buf);
+   rctx.efs->queue(buf);
+   rctx.efs->set_run_state();
+   return true;
+}
+
+/*
+ * The ReadEncryptedFileRaw from bacula.c calls us back here
+ */
+DWORD WINAPI read_efs_data_cb(PBYTE pbData, PVOID pvCallbackContext, ULONG ulLength)
+{
+   bctx_t *ctx = (bctx_t *)pvCallbackContext;  /* get our context */
+   BSOCK *sd = ctx->jcr->store_bsock;
+   ULONG ulSent = 0;
+
+   if (ctx->jcr->is_job_canceled()) {
+      return ERROR_CANCELLED;
+   }
+   if (ulLength == 0) {
+      Dmsg0(200, "ulLen=0 => done.\n");
+      return ERROR_SUCCESS;           /* all done */
+   }
+   while (ulLength > 0) {
+      /* Get appropriate block length */
+      if (ulLength <= (ULONG)ctx->rsize) {
+         sd->msglen = ulLength;
+      } else {
+         sd->msglen = (ULONG)ctx->rsize;
+      }
+      Dmsg5(200, "ctx->rbuf=%p msg=%p msgbuflen=%d ulSent=%d len=%d\n", 
+        ctx->rbuf, sd->msg, ctx->rsize, ulSent, sd->msglen);
+      /* Copy data into Bacula buffer */
+      memcpy(ctx->rbuf, pbData + ulSent, sd->msglen);
+      /* Update sent count and remaining count */
+      ulSent += sd->msglen;
+      ulLength -= sd->msglen;
+      /* Send the data off to the SD */
+      if (!process_and_send_data(*ctx)) {
+         return ERROR_UNEXP_NET_ERR;
+      }
+   }
+   return ERROR_SUCCESS;
+}
+
+#endif