2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2018 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Bacula File Daemon Windows EFS restore
22 * Kern Sibbald, September MMXIV
34 * This is the test version of the worker routines, which simulates
35 * Windows EFS backup on Linux.
37 * This subroutine is called back from the Windows
38 * WriteEncryptedFileRaw and returns a single buffer of data or
39 * sets ulLength = 0 to indicate the end.
41 static uint32_t test_write_efs_data_cb(char *pbData, void *arctx, uint32_t *len)
43 r_ctx *rctx = (r_ctx *)arctx;
44 worker *wrk = (worker *)rctx->efs;
49 head = (char *)wrk->dequeue(); /* dequeue buffer to write */
50 Dmsg1(200, "dequeue buffer. head=%p\n", head);
53 Dmsg0(200, "cb got NULL.\n");
55 data_len = *(int32_t *)head;
56 Dmsg1(200, "data_len=%d\n", data_len);
58 Dmsg0(200, "Length is zero.\n");
59 wrk->push_free_buffer(head);
60 return ERROR_BUFFER_OVERFLOW;
62 if (data_len > *len) {
63 Dmsg2(200, "Restore data %ld bytes too long for Microsoft buffer %ld bytes.\n",
66 errno = b_errno_win32;
67 wrk->push_free_buffer(head);
68 return ERROR_BUFFER_OVERFLOW;
70 buf = head + sizeof(uint32_t); /* Point to buffer */
71 count = *(int32_t *)buf;
72 buf += sizeof(int32_t);
73 memcpy(pbData, buf, data_len);
75 Dmsg2(200, "Got count=%d len=%d\n", count, data_len);
76 wrk->push_free_buffer(head);
83 * Thread created to run the WriteEncryptedFileRaw code
85 static void *test_efs_write_thread(void *awrk)
88 worker *wrk = (worker *)awrk;
91 uint32_t size = 100000;
92 char *buf = (char *)malloc(size); /* allocate working buffer */
94 rctx = (r_ctx *)wrk->get_ctx();
95 Dmsg2(200, "rctx=%p wrk=%p\n", rctx, wrk);
98 while (!wrk->is_quit_state()) {
99 if (wrk->is_wait_state()) { /* wait if so requested */
100 Dmsg0(200, "Enter wait state\n");
102 Dmsg0(200, "Leave wait state\n");
106 if (test_write_efs_data_cb(buf, rctx, &len) != 0) { /* get a buffer */
108 Qmsg2(rctx->jcr, M_FATAL, 0, _("Restore data %ld bytes too long for Microsoft buffer %ld bytes.\n"),
112 if (len == 0) { /* done? */
113 Dmsg0(200, "Got len 0 set_wait_state.\n");
116 Dmsg2(200, "Write buf=%p len=%d\n", buf, len);
117 if ((wstat=bwrite(&rctx->bfd, buf, len)) != (ssize_t)len) {
118 Dmsg4(000, "bwrite of %d error %d open=%d on file=%s\n",
119 len, wstat, is_bopen(&rctx->bfd), rctx->jcr->last_fname);
123 Dmsg0(200, "worker thread quiting\n");
129 * If the writer thread is not created, create it, then queue
130 * a buffer to be written by the thread.
132 bool test_write_efs_data(r_ctx &rctx, char *data, const int32_t length)
137 rctx.efs = New(worker(10));
138 Dmsg2(200, "Start test_efs_write_thread rctx=%p work=%p\n", &rctx, rctx.efs);
139 rctx.efs->start(test_efs_write_thread, &rctx);
141 head = (POOLMEM *)rctx.efs->pop_free_buffer();
143 head = get_memory(length + 2*sizeof(int32_t)+1);
145 head = check_pool_memory_size(head, length+2*sizeof(int32_t)+1);
148 *(int32_t *)buf = length;
149 buf += sizeof(int32_t);
150 *(int32_t *)buf = ++rctx.count;
151 buf += sizeof(int32_t);
152 memcpy(buf, data, length);
153 Dmsg3(200, "Put count=%d len=%d head=%p\n", rctx.count, length, head);
154 rctx.efs->queue(head);
155 rctx.efs->set_run_state();
163 /* =============================================================
165 * Win EFS functions for restore
167 * =============================================================
171 * This subroutine is called back from the Windows
172 * WriteEncryptedFileRaw.
174 static DWORD WINAPI write_efs_data_cb(PBYTE pbData, PVOID arctx, PULONG ulLength)
176 r_ctx *rctx = (r_ctx *)arctx;
177 worker *wrk = (worker *)rctx->efs;
181 JCR *jcr = rctx->jcr;
183 data = (char *)rctx->efs->dequeue(); /* dequeue buffer to write */
184 Dmsg1(200, "dequeue buffer. head=%p\n", data);
185 if (jcr->is_job_canceled()) {
186 return ERROR_CANCELLED;
190 Dmsg0(200, "cb got NULL.\n");
192 data_len = *(int32_t *)data;
193 if (data_len > *ulLength) {
194 Qmsg2(rctx->jcr, M_FATAL, 0, _("Restore data %ld bytes too long for Microsoft buffer %lld bytes.\n"),
195 data_len, *ulLength);
198 buf = data + sizeof(uint32_t);
199 memcpy(pbData, buf, data_len);
200 *ulLength = (ULONG)data_len;
201 Dmsg1(200, "Got len=%d\n", data_len);
203 wrk->push_free_buffer(data);
205 return ERROR_SUCCESS;
209 * Thread created to run the WriteEncryptedFileRaw code
211 static void *efs_write_thread(void *awrk)
213 worker *wrk = (worker *)awrk;
216 rctx = (r_ctx *)wrk->get_ctx();
219 while (!wrk->is_quit_state() && !rctx->jcr->is_job_canceled()) {
220 if (wrk->is_wait_state()) { /* wait if so requested */
221 Dmsg0(200, "Enter wait state\n");
223 Dmsg0(200, "Leave wait state\n");
226 if (p_WriteEncryptedFileRaw((PFE_IMPORT_FUNC)write_efs_data_cb, rctx,
227 rctx->bfd.pvContext)) {
229 Qmsg1(rctx->jcr, M_FATAL, 0, _("WriteEncryptedFileRaw failure: ERR=%s\n"),
230 be.bstrerror(b_errno_win32));
233 Dmsg0(200, "Got return from WriteEncryptedFileRaw\n");
239 * Called here from Bacula to write a block to a Windows EFS file.
240 * Since the Windows WriteEncryptedFileRaw function uses a callback
241 * subroutine to get the blocks to write, we create a writer thread,
242 * and queue the blocks (buffers) we get in this routine. That
243 * writer thread then hangs on the WriteEncryptedRaw file, calling
244 * back to the callback subroutine which then dequeues the blocks
247 * If the writer thread is not created, create it, then queue
248 * a buffer to be written by the thread.
250 bool win_write_efs_data(r_ctx &rctx, char *data, const int32_t length)
255 rctx.efs = New(worker(10));
256 rctx.efs->start(efs_write_thread, &rctx);
258 buf = (POOLMEM *)rctx.efs->pop_free_buffer();
260 buf = get_memory(length + sizeof(int32_t)+1);
262 buf = check_pool_memory_size(buf, length+sizeof(int32_t)+1);
264 *(int32_t *)buf = length;
265 memcpy(buf+sizeof(int32_t), data, length);
266 Dmsg2(200, "Put len=%d head=%p\n", length, buf);
267 rctx.efs->queue(buf);
268 rctx.efs->set_run_state();
273 * The ReadEncryptedFileRaw from bacula.c calls us back here
275 DWORD WINAPI read_efs_data_cb(PBYTE pbData, PVOID pvCallbackContext, ULONG ulLength)
277 bctx_t *ctx = (bctx_t *)pvCallbackContext; /* get our context */
278 BSOCK *sd = ctx->jcr->store_bsock;
281 if (ctx->jcr->is_job_canceled()) {
282 return ERROR_CANCELLED;
285 Dmsg0(200, "ulLen=0 => done.\n");
286 return ERROR_SUCCESS; /* all done */
288 while (ulLength > 0) {
289 /* Get appropriate block length */
290 if (ulLength <= (ULONG)ctx->rsize) {
291 sd->msglen = ulLength;
293 sd->msglen = (ULONG)ctx->rsize;
295 Dmsg5(200, "ctx->rbuf=%p msg=%p msgbuflen=%d ulSent=%d len=%d\n",
296 ctx->rbuf, sd->msg, ctx->rsize, ulSent, sd->msglen);
297 /* Copy data into Bacula buffer */
298 memcpy(ctx->rbuf, pbData + ulSent, sd->msglen);
299 /* Update sent count and remaining count */
300 ulSent += sd->msglen;
301 ulLength -= sd->msglen;
302 /* Send the data off to the SD */
303 if (!process_and_send_data(*ctx)) {
304 return ERROR_UNEXP_NET_ERR;
307 return ERROR_SUCCESS;