2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2014 Bacula Systems SA
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.
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.
15 Bacula® is a registered trademark of Kern Sibbald.
18 * Bacula File Daemon Windows EFS restore
20 * Kern Sibbald, September MMXIV
32 * This is the test version of the worker routines, which simulates
33 * Windows EFS backup on Linux.
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.
39 static uint32_t test_write_efs_data_cb(char *pbData, void *arctx, uint32_t *len)
41 r_ctx *rctx = (r_ctx *)arctx;
42 worker *wrk = (worker *)rctx->efs;
47 head = (char *)wrk->dequeue(); /* dequeue buffer to write */
48 Dmsg1(200, "dequeue buffer. head=%p\n", head);
51 Dmsg0(200, "cb got NULL.\n");
53 data_len = *(int32_t *)head;
54 Dmsg1(200, "data_len=%d\n", data_len);
56 Dmsg0(200, "Length is zero.\n");
57 wrk->push_free_buffer(head);
58 return ERROR_BUFFER_OVERFLOW;
60 if (data_len > *len) {
61 Dmsg2(200, "Restore data %ld bytes too long for Microsoft buffer %ld bytes.\n",
64 errno = b_errno_win32;
65 wrk->push_free_buffer(head);
66 return ERROR_BUFFER_OVERFLOW;
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);
73 Dmsg2(200, "Got count=%d len=%d\n", count, data_len);
74 wrk->push_free_buffer(head);
81 * Thread created to run the WriteEncryptedFileRaw code
83 static void *test_efs_write_thread(void *awrk)
86 worker *wrk = (worker *)awrk;
89 uint32_t size = 100000;
90 char *buf = (char *)malloc(size); /* allocate working buffer */
92 rctx = (r_ctx *)wrk->get_ctx();
93 Dmsg2(200, "rctx=%p wrk=%p\n", rctx, wrk);
96 while (!wrk->is_quit_state()) {
97 if (wrk->is_wait_state()) { /* wait if so requested */
98 Dmsg0(200, "Enter wait state\n");
100 Dmsg0(200, "Leave wait state\n");
104 if (test_write_efs_data_cb(buf, rctx, &len) != 0) { /* get a buffer */
106 Qmsg2(rctx->jcr, M_FATAL, 0, _("Restore data %ld bytes too long for Microsoft buffer %ld bytes.\n"),
110 if (len == 0) { /* done? */
111 Dmsg0(200, "Got len 0 set_wait_state.\n");
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);
121 Dmsg0(200, "worker thread quiting\n");
127 * If the writer thread is not created, create it, then queue
128 * a buffer to be written by the thread.
130 bool test_write_efs_data(r_ctx &rctx, char *data, const int32_t length)
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);
139 head = (POOLMEM *)rctx.efs->pop_free_buffer();
141 head = get_memory(length + 2*sizeof(int32_t)+1);
143 head = check_pool_memory_size(head, length+2*sizeof(int32_t)+1);
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();
161 /* =============================================================
163 * Win EFS functions for restore
165 * =============================================================
169 * This subroutine is called back from the Windows
170 * WriteEncryptedFileRaw.
172 static DWORD WINAPI write_efs_data_cb(PBYTE pbData, PVOID arctx, PULONG ulLength)
174 r_ctx *rctx = (r_ctx *)arctx;
175 worker *wrk = (worker *)rctx->efs;
179 JCR *jcr = rctx->jcr;
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;
188 Dmsg0(200, "cb got NULL.\n");
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);
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);
201 wrk->push_free_buffer(data);
203 return ERROR_SUCCESS;
207 * Thread created to run the WriteEncryptedFileRaw code
209 static void *efs_write_thread(void *awrk)
211 worker *wrk = (worker *)awrk;
214 rctx = (r_ctx *)wrk->get_ctx();
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");
221 Dmsg0(200, "Leave wait state\n");
224 if (p_WriteEncryptedFileRaw((PFE_IMPORT_FUNC)write_efs_data_cb, rctx,
225 rctx->bfd.pvContext)) {
227 Qmsg1(rctx->jcr, M_FATAL, 0, _("WriteEncryptedFileRaw failure: ERR=%s\n"),
228 be.bstrerror(b_errno_win32));
231 Dmsg0(200, "Got return from WriteEncryptedFileRaw\n");
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
245 * If the writer thread is not created, create it, then queue
246 * a buffer to be written by the thread.
248 bool win_write_efs_data(r_ctx &rctx, char *data, const int32_t length)
253 rctx.efs = New(worker(10));
254 rctx.efs->start(efs_write_thread, &rctx);
256 buf = (POOLMEM *)rctx.efs->pop_free_buffer();
258 buf = get_memory(length + sizeof(int32_t)+1);
260 buf = check_pool_memory_size(buf, length+sizeof(int32_t)+1);
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();
271 * The ReadEncryptedFileRaw from bacula.c calls us back here
273 DWORD WINAPI read_efs_data_cb(PBYTE pbData, PVOID pvCallbackContext, ULONG ulLength)
275 bctx_t *ctx = (bctx_t *)pvCallbackContext; /* get our context */
276 BSOCK *sd = ctx->jcr->store_bsock;
279 if (ctx->jcr->is_job_canceled()) {
280 return ERROR_CANCELLED;
283 Dmsg0(200, "ulLen=0 => done.\n");
284 return ERROR_SUCCESS; /* all done */
286 while (ulLength > 0) {
287 /* Get appropriate block length */
288 if (ulLength <= (ULONG)ctx->rsize) {
289 sd->msglen = ulLength;
291 sd->msglen = (ULONG)ctx->rsize;
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;
305 return ERROR_SUCCESS;