]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/win_efs.c
Restore win32 dir from Branch-5.2 and update it
[bacula/bacula] / bacula / src / filed / win_efs.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2014 Bacula Systems SA
5    All rights reserved.
6
7    The main author of Bacula is Kern Sibbald, with contributions from many
8    others, a complete list can be found in the file AUTHORS.
9
10    Licensees holding a valid Bacula Systems SA license may use this file
11    and others of this release in accordance with the proprietary license
12    agreement provided in the LICENSE file.  Redistribution of any part of
13    this release is not permitted.
14
15    Bacula® is a registered trademark of Kern Sibbald.
16 */
17 /*
18  *  Bacula File Daemon  Windows EFS restore
19  *
20  *    Kern Sibbald, September MMXIV
21  *
22  */
23
24 #include "bacula.h"
25 #include "filed.h"
26 #include "ch.h"
27 #include "restore.h"
28 #include "backup.h"
29
30 #ifdef TEST_WORKER
31 /*
32  * This is the test version of the worker routines, which simulates
33  *  Windows EFS backup on Linux.
34  *
35  * This subroutine is called back from the Windows
36  *  WriteEncryptedFileRaw and returns a single buffer of data or
37  *  sets ulLength = 0 to indicate the end.
38  */
39 static uint32_t test_write_efs_data_cb(char *pbData, void *arctx, uint32_t *len)
40 {
41    r_ctx *rctx = (r_ctx *)arctx;
42    worker *wrk = (worker *)rctx->efs;
43    char *head, *buf;
44    uint32_t data_len;
45    int32_t count;
46
47    head = (char *)wrk->dequeue();      /* dequeue buffer to write */
48    Dmsg1(200, "dequeue buffer. head=%p\n", head);
49    if (!head) {
50       *len = 0;
51       Dmsg0(200, "cb got NULL.\n");
52    } else {
53       data_len = *(int32_t *)head;
54       Dmsg1(200, "data_len=%d\n", data_len);
55       if (data_len == 0) {
56          Dmsg0(200, "Length is zero.\n");
57          wrk->push_free_buffer(head);
58          return ERROR_BUFFER_OVERFLOW;
59       }
60       if (data_len > *len) {
61          Dmsg2(200, "Restore data %ld bytes too long for Microsoft buffer %ld bytes.\n",
62             data_len, *len);
63          *len = 0;
64          errno = b_errno_win32;
65          wrk->push_free_buffer(head);
66          return ERROR_BUFFER_OVERFLOW;
67       } else {
68          buf = head + sizeof(uint32_t);    /* Point to buffer */
69          count = *(int32_t *)buf;
70          buf += sizeof(int32_t);
71          memcpy(pbData, buf, data_len);
72          *len = data_len;
73          Dmsg2(200, "Got count=%d len=%d\n", count, data_len);
74          wrk->push_free_buffer(head);
75       }
76    }
77    return ERROR_SUCCESS;
78 }
79
80 /*
81  * Thread created to run the WriteEncryptedFileRaw code
82  */
83 static void *test_efs_write_thread(void *awrk)
84 {
85    ssize_t wstat;
86    worker *wrk = (worker *)awrk;
87    r_ctx *rctx;
88    uint32_t len;
89    uint32_t size = 100000;
90    char *buf = (char *)malloc(size);    /* allocate working buffer */
91
92    rctx = (r_ctx *)wrk->get_ctx();
93    Dmsg2(200, "rctx=%p wrk=%p\n", rctx, wrk);
94    wrk->set_running();
95
96    while (!wrk->is_quit_state()) {
97       if (wrk->is_wait_state()) {      /* wait if so requested */
98          Dmsg0(200, "Enter wait state\n");
99          wrk->wait();
100          Dmsg0(200, "Leave wait state\n");
101          continue;
102       }
103       len = size;
104       if (test_write_efs_data_cb(buf, rctx, &len) != 0) {  /* get a buffer */
105          berrno be;
106          Qmsg2(rctx->jcr, M_FATAL, 0, _("Restore data %ld bytes too long for Microsoft buffer %ld bytes.\n"),
107             len, size);
108          break;
109       }
110       if (len == 0) {       /* done? */
111          Dmsg0(200, "Got len 0 set_wait_state.\n");
112          continue;          /* yes */
113       }
114       Dmsg2(200, "Write buf=%p len=%d\n", buf, len);
115       if ((wstat=bwrite(&rctx->bfd, buf, len)) != (ssize_t)len) {
116          Dmsg4(000, "bwrite of %d error %d open=%d on file=%s\n",
117             len, wstat, is_bopen(&rctx->bfd), rctx->jcr->last_fname);
118          continue;
119       }
120    }
121    Dmsg0(200, "worker thread quiting\n");
122    free(buf);
123    return NULL;
124 }
125
126 /*
127  * If the writer thread is not created, create it, then queue
128  *  a buffer to be written by the thread.
129  */
130 bool test_write_efs_data(r_ctx &rctx, char *data, const int32_t length)
131 {
132    POOLMEM *buf, *head;
133
134    if (!rctx.efs) {
135       rctx.efs = New(worker(10));
136       Dmsg2(200, "Start test_efs_write_thread rctx=%p work=%p\n", &rctx, rctx.efs);
137       rctx.efs->start(test_efs_write_thread, &rctx);
138    }
139    head = (POOLMEM *)rctx.efs->pop_free_buffer();
140    if (!head) {
141       head = get_memory(length + 2*sizeof(int32_t)+1);
142    } else {
143       head = check_pool_memory_size(head, length+2*sizeof(int32_t)+1);
144    }
145    buf = head;
146    *(int32_t *)buf = length;
147    buf += sizeof(int32_t);
148    *(int32_t *)buf = ++rctx.count;
149    buf += sizeof(int32_t);
150    memcpy(buf, data, length);
151    Dmsg3(200, "Put count=%d len=%d head=%p\n", rctx.count, length, head);
152    rctx.efs->queue(head);
153    rctx.efs->set_run_state();
154    return true;
155 }
156 #endif
157
158
159 #ifdef HAVE_WIN32
160
161 /* =============================================================
162  *
163  *   Win EFS functions for restore
164  *
165  * =============================================================
166  */
167
168 /*
169  * This subroutine is called back from the Windows
170  *  WriteEncryptedFileRaw.
171  */
172 static DWORD WINAPI write_efs_data_cb(PBYTE pbData, PVOID arctx, PULONG ulLength)
173 {
174    r_ctx *rctx = (r_ctx *)arctx;
175    worker *wrk = (worker *)rctx->efs;
176    char *data;
177    char *buf;
178    uint32_t data_len;
179    JCR *jcr = rctx->jcr;
180
181    data = (char *)rctx->efs->dequeue();    /* dequeue buffer to write */
182    Dmsg1(200, "dequeue buffer. head=%p\n", data);
183    if (jcr->is_job_canceled()) {
184       return ERROR_CANCELLED;
185    }
186    if (!data) {
187       *ulLength = 0;
188       Dmsg0(200, "cb got NULL.\n");
189    } else {
190       data_len = *(int32_t *)data;
191       if (data_len > *ulLength) {
192          Qmsg2(rctx->jcr, M_FATAL, 0, _("Restore data %ld bytes too long for Microsoft buffer %lld bytes.\n"),
193             data_len, *ulLength);
194          *ulLength = 0;
195       } else {
196          buf = data + sizeof(uint32_t);
197          memcpy(pbData, buf, data_len);
198          *ulLength = (ULONG)data_len;
199          Dmsg1(200, "Got len=%d\n", data_len);
200       }
201       wrk->push_free_buffer(data);
202    }
203    return ERROR_SUCCESS;
204 }
205
206 /*
207  * Thread created to run the WriteEncryptedFileRaw code
208  */
209 static void *efs_write_thread(void *awrk)
210 {
211    worker *wrk = (worker *)awrk;
212    r_ctx *rctx;
213
214    rctx = (r_ctx *)wrk->get_ctx();
215    wrk->set_running();
216
217    while (!wrk->is_quit_state() && !rctx->jcr->is_job_canceled()) {
218       if (wrk->is_wait_state()) {      /* wait if so requested */
219          Dmsg0(200, "Enter wait state\n");
220          wrk->wait();
221          Dmsg0(200, "Leave wait state\n");
222          continue;
223       }
224       if (p_WriteEncryptedFileRaw((PFE_IMPORT_FUNC)write_efs_data_cb, rctx,
225              rctx->bfd.pvContext)) {
226          berrno be;
227          Qmsg1(rctx->jcr, M_FATAL, 0, _("WriteEncryptedFileRaw failure: ERR=%s\n"),
228             be.bstrerror(b_errno_win32));
229          return NULL;
230       }
231       Dmsg0(200, "Got return from WriteEncryptedFileRaw\n");
232    }         
233    return NULL;
234 }
235
236 /*
237  * Called here from Bacula to write a block to a Windows EFS file.
238  * Since the Windows WriteEncryptedFileRaw function uses a callback
239  *  subroutine to get the blocks to write, we create a writer thread,
240  *  and queue the blocks (buffers) we get in this routine.  That
241  *  writer thread then hangs on the WriteEncryptedRaw file, calling
242  *  back to the callback subroutine which then dequeues the blocks
243  *  we have queued.
244  *
245  * If the writer thread is not created, create it, then queue
246  *  a buffer to be written by the thread.
247  */
248 bool win_write_efs_data(r_ctx &rctx, char *data, const int32_t length)
249 {
250    POOLMEM *buf;
251
252    if (!rctx.efs) {
253       rctx.efs = New(worker(10));
254       rctx.efs->start(efs_write_thread, &rctx);
255    }
256    buf = (POOLMEM *)rctx.efs->pop_free_buffer();
257    if (!buf) {
258       buf = get_memory(length + sizeof(int32_t)+1);
259    } else {
260       buf = check_pool_memory_size(buf, length+sizeof(int32_t)+1);
261    }
262    *(int32_t *)buf = length;
263    memcpy(buf+sizeof(int32_t), data, length);
264    Dmsg2(200, "Put len=%d head=%p\n", length, buf);
265    rctx.efs->queue(buf);
266    rctx.efs->set_run_state();
267    return true;
268 }
269
270 /*
271  * The ReadEncryptedFileRaw from bacula.c calls us back here
272  */
273 DWORD WINAPI read_efs_data_cb(PBYTE pbData, PVOID pvCallbackContext, ULONG ulLength)
274 {
275    bctx_t *ctx = (bctx_t *)pvCallbackContext;  /* get our context */
276    BSOCK *sd = ctx->jcr->store_bsock;
277    ULONG ulSent = 0;
278
279    if (ctx->jcr->is_job_canceled()) {
280       return ERROR_CANCELLED;
281    }
282    if (ulLength == 0) {
283       Dmsg0(200, "ulLen=0 => done.\n");
284       return ERROR_SUCCESS;           /* all done */
285    }
286    while (ulLength > 0) {
287       /* Get appropriate block length */
288       if (ulLength <= (ULONG)ctx->rsize) {
289          sd->msglen = ulLength;
290       } else {
291          sd->msglen = (ULONG)ctx->rsize;
292       }
293       Dmsg5(200, "ctx->rbuf=%p msg=%p msgbuflen=%d ulSent=%d len=%d\n", 
294         ctx->rbuf, sd->msg, ctx->rsize, ulSent, sd->msglen);
295       /* Copy data into Bacula buffer */
296       memcpy(ctx->rbuf, pbData + ulSent, sd->msglen);
297       /* Update sent count and remaining count */
298       ulSent += sd->msglen;
299       ulLength -= sd->msglen;
300       /* Send the data off to the SD */
301       if (!process_and_send_data(*ctx)) {
302          return ERROR_UNEXP_NET_ERR;
303       }
304    }
305    return ERROR_SUCCESS;
306 }
307
308 #endif