Line data Source code
1 : #include "../burp.h"
2 : #include "../action.h"
3 : #include "../alloc.h"
4 : #include "../asfd.h"
5 : #include "../async.h"
6 : #include "../attribs.h"
7 : #include "../cmd.h"
8 : #include "../cntr.h"
9 : #include "../conf.h"
10 : #include "../handy_extra.h"
11 : #include "../log.h"
12 : #include "../md5.h"
13 : #include "../transfer.h"
14 : #include "cvss.h"
15 : #include "extrameta.h"
16 : #include "find.h"
17 : #include "backup_phase2.h"
18 :
19 2 : static int rs_loadsig_network_run(struct asfd *asfd,
20 : rs_job_t *job, struct cntr *cntr)
21 : {
22 2 : int ret=-1;
23 : rs_buffers_t buf;
24 : rs_result result;
25 2 : rs_filebuf_t *in_fb=NULL;
26 2 : memset(&buf, 0, sizeof(buf));
27 :
28 2 : if(!(in_fb=rs_filebuf_new(NULL,
29 : NULL, asfd, ASYNC_BUF_LEN, -1)))
30 : goto end;
31 :
32 : while(1)
33 : {
34 4 : iobuf_free_content(asfd->rbuf);
35 4 : if(asfd->read(asfd)) goto end;
36 8 : if(asfd->rbuf->cmd==CMD_MESSAGE
37 4 : || asfd->rbuf->cmd==CMD_WARNING)
38 : {
39 0 : log_recvd(asfd->rbuf, cntr, 0);
40 0 : continue;
41 : }
42 4 : switch((result=rs_async(job, &buf, in_fb, NULL)))
43 : {
44 : case RS_BLOCKED:
45 : case RS_RUNNING:
46 2 : continue;
47 : case RS_DONE:
48 : ret=0;
49 : goto end;
50 : default:
51 0 : logp("error in rs_async for sig: %d\n",
52 : result);
53 0 : goto end;
54 : }
55 : }
56 :
57 : end:
58 2 : iobuf_free_content(asfd->rbuf);
59 2 : rs_filebuf_free(&in_fb);
60 2 : return ret;
61 : }
62 :
63 2 : static int load_signature(struct asfd *asfd,
64 : rs_signature_t **sumset, struct cntr *cntr)
65 : {
66 : rs_job_t *job;
67 :
68 2 : if(!(job=rs_loadsig_begin(sumset)))
69 : {
70 0 : logp("could not start sig job.\n");
71 0 : return -1;
72 : }
73 2 : if(rs_loadsig_network_run(asfd, job, cntr))
74 : return -1;
75 2 : if(rs_build_hash_table(*sumset))
76 : return -1;
77 2 : rs_job_free(job);
78 2 : return 0;
79 : }
80 :
81 2 : static int load_signature_and_send_delta(struct asfd *asfd,
82 : struct BFILE *bfd, uint64_t *bytes, uint64_t *sentbytes,
83 : struct cntr *cntr)
84 : {
85 2 : int ret=-1;
86 2 : rs_job_t *job=NULL;
87 2 : rs_signature_t *sumset=NULL;
88 : uint8_t checksum[MD5_DIGEST_LENGTH];
89 2 : rs_filebuf_t *infb=NULL;
90 2 : rs_filebuf_t *outfb=NULL;
91 : rs_buffers_t rsbuf;
92 2 : memset(&rsbuf, 0, sizeof(rsbuf));
93 :
94 2 : if(load_signature(asfd, &sumset, cntr))
95 : goto end;
96 :
97 2 : if(!(job=rs_delta_begin(sumset)))
98 : {
99 0 : logp("could not start delta job.\n");
100 0 : goto end;
101 : }
102 :
103 2 : if(!(infb=rs_filebuf_new(bfd,
104 : NULL, NULL, ASYNC_BUF_LEN, bfd->datalen))
105 2 : || !(outfb=rs_filebuf_new(NULL,
106 : NULL, asfd, ASYNC_BUF_LEN, -1)))
107 : {
108 0 : logp("could not rs_filebuf_new for delta\n");
109 0 : goto end;
110 : }
111 :
112 : while(1)
113 4 : {
114 : rs_result result;
115 6 : switch((result=rs_async(job, &rsbuf, infb, outfb)))
116 : {
117 : case RS_DONE:
118 2 : *bytes=infb->bytes;
119 2 : *sentbytes=outfb->bytes;
120 2 : if(!md5_final(infb->md5, checksum))
121 : {
122 0 : logp("md5_final() failed\n");
123 0 : goto end;
124 : }
125 2 : if(write_endfile(asfd, *bytes, checksum))
126 : goto end;
127 2 : ret=0;
128 2 : goto end;
129 : case RS_BLOCKED:
130 : case RS_RUNNING:
131 : // FIX ME: get it to read stuff here too.
132 : // (errors, for example)
133 4 : if(asfd->as->write(asfd->as))
134 : goto end;
135 4 : continue;
136 : default:
137 0 : logp("error in rs_async for delta: %d\n",
138 : result);
139 0 : goto end;
140 : }
141 : }
142 : end:
143 2 : rs_filebuf_free(&infb);
144 2 : rs_filebuf_free(&outfb);
145 2 : if(job) rs_job_free(job);
146 2 : if(sumset) rs_free_sumset(sumset);
147 2 : return ret;
148 : }
149 :
150 6 : static enum send_e send_whole_file_w(struct asfd *asfd,
151 : struct sbuf *sb, const char *datapth,
152 : int quick_read, uint64_t *bytes, const char *encpassword,
153 : struct cntr *cntr, int compression, struct BFILE *bfd,
154 : const char *extrameta, size_t elen)
155 : {
156 6 : if((compression || encpassword) && sb->path.cmd!=CMD_EFS_FILE)
157 : {
158 0 : int key_deriv=sb->encryption;
159 0 : return send_whole_file_gzl(asfd, datapth, quick_read, bytes,
160 : encpassword, cntr, compression, bfd, extrameta, elen,
161 : key_deriv, sb->salt);
162 : }
163 : else
164 6 : return send_whole_filel(asfd,
165 : #ifdef HAVE_WIN32
166 : sb->path.cmd,
167 : #endif
168 : datapth, quick_read, bytes,
169 : cntr, bfd, extrameta, elen);
170 : }
171 :
172 0 : static int forget_file(struct asfd *asfd, struct sbuf *sb, struct conf **confs)
173 : {
174 : // Tell the server to forget about this
175 : // file, otherwise it might get stuck
176 : // on a select waiting for it to arrive.
177 0 : if(asfd->write_str(asfd, CMD_INTERRUPT, sb->path.buf))
178 : return 0;
179 :
180 0 : if(sb->path.cmd==CMD_FILE && sb->datapth.buf)
181 : {
182 0 : rs_signature_t *sumset=NULL;
183 : // The server will be sending us a signature.
184 : // Munch it up then carry on.
185 0 : if(load_signature(asfd, &sumset, get_cntr(confs))) return -1;
186 0 : else rs_free_sumset(sumset);
187 : }
188 : return 0;
189 : }
190 :
191 8 : static int size_checks(struct asfd *asfd, struct sbuf *sb, struct conf **confs)
192 : {
193 16 : if(sb->path.cmd!=CMD_FILE
194 8 : && sb->path.cmd!=CMD_ENC_FILE
195 0 : && sb->path.cmd!=CMD_EFS_FILE)
196 : return 0;
197 8 : if(get_uint64_t(confs[OPT_MIN_FILE_SIZE])
198 0 : && (uint64_t)sb->statp.st_size<get_uint64_t(confs[OPT_MIN_FILE_SIZE]))
199 : {
200 0 : logw(asfd, get_cntr(confs), "File size decreased below min_file_size after initial scan: %s\n", iobuf_to_printable(&sb->path));
201 0 : return -1;
202 : }
203 8 : if(get_uint64_t(confs[OPT_MAX_FILE_SIZE])
204 0 : && (uint64_t)sb->statp.st_size>get_uint64_t(confs[OPT_MAX_FILE_SIZE]))
205 : {
206 0 : logw(asfd, get_cntr(confs), "File size increased above max_file_size after initial scan: %s\n", iobuf_to_printable(&sb->path));
207 0 : return -1;
208 : }
209 : return 0;
210 : }
211 :
212 8 : static int deal_with_data(struct asfd *asfd, struct sbuf *sb,
213 : struct BFILE *bfd, struct conf **confs)
214 : {
215 8 : int ret=-1;
216 8 : int forget=0;
217 8 : size_t elen=0;
218 8 : char *extrameta=NULL;
219 8 : uint64_t bytes=0;
220 8 : int conf_compression=get_int(confs[OPT_COMPRESSION]);
221 8 : struct cntr *cntr=get_cntr(confs);
222 8 : const char *enc_password=get_string(confs[OPT_ENCRYPTION_PASSWORD]);
223 :
224 8 : sb->compression=conf_compression;
225 8 : if(enc_password)
226 : {
227 0 : sb->encryption=ENCRYPTION_KEY_DERIVED_AES_CBC_256;
228 0 : if(!RAND_bytes((uint8_t *)&sb->salt, 8))
229 : {
230 0 : logp("RAND_bytes() failed\n");
231 0 : return -1;
232 : }
233 : }
234 :
235 8 : iobuf_copy(&sb->path, asfd->rbuf);
236 8 : iobuf_init(asfd->rbuf);
237 :
238 : #ifdef HAVE_WIN32
239 : sb->use_winapi=get_use_winapi(
240 : get_string(confs[OPT_REMOTE_DRIVES]),
241 : sb->path.buf[0]
242 : );
243 : if(win32_lstat(sb->path.buf, &sb->statp, &sb->winattr))
244 : #else
245 16 : if(lstat(sb->path.buf, &sb->statp))
246 : #endif
247 : {
248 0 : logw(asfd, cntr, "Path has vanished: %s\n",
249 : iobuf_to_printable(&sb->path));
250 0 : forget++;
251 0 : goto end;
252 : }
253 :
254 8 : if(size_checks(asfd, sb, confs))
255 : {
256 : forget++;
257 : goto end;
258 : }
259 :
260 8 : sb->compression=in_exclude_comp(get_strlist(confs[OPT_EXCOM]),
261 8 : sb->path.buf, conf_compression);
262 8 : if(attribs_encode(sb)) goto error;
263 :
264 16 : if(sb->path.cmd!=CMD_METADATA
265 8 : && sb->path.cmd!=CMD_ENC_METADATA)
266 : {
267 32 : if(bfd->open_for_send(
268 : bfd,
269 : asfd,
270 8 : sb->path.buf,
271 8 : sb->use_winapi,
272 8 : sb->winattr,
273 : get_int(confs[OPT_ATIME]),
274 : cntr
275 : )) {
276 : forget++;
277 : goto end;
278 : }
279 : }
280 :
281 16 : if(sb->path.cmd==CMD_METADATA
282 : || sb->path.cmd==CMD_ENC_METADATA
283 8 : || sb->path.cmd==CMD_VSS
284 8 : || sb->path.cmd==CMD_ENC_VSS
285 : #ifdef HAVE_WIN32
286 : || get_int(confs[OPT_STRIP_VSS])
287 : #endif
288 : )
289 : {
290 0 : if(get_extrameta(asfd,
291 : #ifdef HAVE_WIN32
292 : bfd,
293 : #endif
294 0 : sb->path.buf,
295 0 : S_ISDIR(sb->statp.st_mode),
296 : &extrameta, &elen, cntr))
297 : {
298 0 : logw(asfd, cntr,
299 : "Meta data error for %s\n",
300 : iobuf_to_printable(&sb->path));
301 0 : forget++;
302 0 : goto end;
303 : }
304 0 : if(extrameta)
305 : {
306 : #ifdef HAVE_WIN32
307 : if(get_int(confs[OPT_STRIP_VSS]))
308 : {
309 : free_w(&extrameta);
310 : elen=0;
311 : }
312 : #endif
313 : }
314 : else
315 : {
316 0 : logw(asfd, cntr,
317 : "No meta data after all: %s\n",
318 : iobuf_to_printable(&sb->path));
319 0 : forget++;
320 0 : goto end;
321 : }
322 : }
323 :
324 8 : if(sb->path.cmd==CMD_FILE
325 4 : && sb->datapth.buf)
326 2 : {
327 2 : uint64_t sentbytes=0;
328 : // Need to do sig/delta stuff.
329 2 : if(asfd->write(asfd, &(sb->datapth))
330 2 : || asfd->write(asfd, &sb->attr)
331 2 : || asfd->write(asfd, &sb->path)
332 2 : || load_signature_and_send_delta(asfd, bfd,
333 : &bytes, &sentbytes, cntr))
334 : {
335 0 : logp("error in sig/delta for %s (%s)\n",
336 : iobuf_to_printable(&sb->path),
337 : iobuf_to_printable(&sb->datapth));
338 0 : forget++;
339 0 : goto end;
340 : }
341 2 : cntr_add(cntr, CMD_FILE_CHANGED, 1);
342 : }
343 : else
344 : {
345 : //logp("need to send whole file: %s\n", sb.path);
346 : // send the whole file.
347 :
348 6 : if(asfd->write(asfd, &sb->attr)
349 6 : || asfd->write(asfd, &sb->path))
350 : goto end;
351 :
352 6 : switch(send_whole_file_w(asfd, sb, NULL, 0, &bytes,
353 : enc_password,
354 : cntr, sb->compression,
355 : bfd, extrameta, elen))
356 : {
357 : case SEND_OK:
358 : break;
359 : case SEND_ERROR:
360 0 : forget++;
361 0 : break;
362 : case SEND_FATAL:
363 : default:
364 : goto error;
365 : }
366 6 : cntr_add(cntr, sb->path.cmd, 1);
367 : }
368 8 : cntr_add_bytes(cntr, bytes);
369 :
370 : end:
371 8 : ret=0;
372 8 : if(forget && forget_file(asfd, sb, confs))
373 0 : ret=-1;
374 : error:
375 : #ifdef HAVE_WIN32
376 : // If using Windows do not close bfd - it needs
377 : // to stay open to read VSS/file data/VSS.
378 : // It will get closed either when given a
379 : // different file path, or when this function
380 : // exits.
381 : #else
382 8 : bfd->close(bfd, asfd);
383 : #endif
384 8 : sbuf_free_content(sb);
385 8 : free_w(&extrameta);
386 8 : return ret;
387 : }
388 :
389 19 : static int parse_rbuf(struct asfd *asfd, struct sbuf *sb,
390 : struct BFILE *bfd, struct conf **confs)
391 : {
392 : static struct iobuf *rbuf;
393 19 : rbuf=asfd->rbuf;
394 19 : if(rbuf->cmd==CMD_DATAPTH)
395 : {
396 2 : iobuf_move(&(sb->datapth), rbuf);
397 : }
398 17 : else if(rbuf->cmd==CMD_ATTRIBS)
399 : {
400 : // Ignore the stat data - we will fill it
401 : // in again. Some time may have passed by now,
402 : // and it is best to make it as fresh as
403 : // possible.
404 : }
405 9 : else if(iobuf_is_filedata(rbuf)
406 1 : || iobuf_is_vssdata(rbuf))
407 : {
408 8 : if(deal_with_data(asfd, sb, bfd, confs))
409 : return -1;
410 : }
411 2 : else if(rbuf->cmd==CMD_MESSAGE
412 1 : || rbuf->cmd==CMD_WARNING)
413 : {
414 1 : struct cntr *cntr=NULL;
415 1 : if(confs) cntr=get_cntr(confs);
416 1 : log_recvd(rbuf, cntr, 0);
417 : }
418 : else
419 : {
420 0 : iobuf_log_unexpected(rbuf, __func__);
421 0 : return -1;
422 : }
423 : return 0;
424 : }
425 :
426 6 : static int do_backup_phase2_client(struct asfd *asfd,
427 : struct conf **confs, int resume)
428 : {
429 6 : int ret=-1;
430 : // For efficiency, open Windows files for the VSS data, and do not
431 : // close them until another time around the loop, when the actual
432 : // data is read.
433 6 : struct BFILE *bfd=NULL;
434 6 : struct sbuf *sb=NULL;
435 6 : struct iobuf *rbuf=NULL;
436 6 : struct cntr *cntr=NULL;
437 6 : if(confs) cntr=get_cntr(confs);
438 :
439 6 : if(!asfd)
440 : {
441 1 : logp("%s() called without asfd!\n", __func__);
442 1 : goto end;
443 : }
444 5 : rbuf=asfd->rbuf;
445 :
446 5 : if(!(bfd=bfile_alloc())
447 5 : || !(sb=sbuf_alloc()))
448 : goto end;
449 5 : bfile_init(bfd, 0, 0, cntr);
450 :
451 5 : if(!resume)
452 : {
453 : // Only do this bit if the server did not tell us to resume.
454 5 : if(asfd->write_str(asfd, CMD_GEN, "backupphase2")
455 5 : || asfd_read_expect(asfd, CMD_GEN, "ok"))
456 : goto end;
457 : }
458 : else
459 : {
460 : // On resume, the server might update the client with cntr.
461 0 : if(cntr_recv(asfd, confs))
462 : goto end;
463 : }
464 :
465 : while(1)
466 : {
467 24 : iobuf_free_content(rbuf);
468 24 : if(asfd->read(asfd)) goto end;
469 23 : else if(!rbuf->buf) continue;
470 :
471 23 : if(rbuf->cmd==CMD_GEN && !strcmp(rbuf->buf, "backupphase2end"))
472 : {
473 4 : if(asfd->write_str(asfd, CMD_GEN, "okbackupphase2end"))
474 : goto end;
475 4 : ret=0;
476 4 : break;
477 : }
478 :
479 19 : if(parse_rbuf(asfd, sb, bfd, confs))
480 : goto end;
481 : }
482 :
483 : end:
484 : // It is possible for a bfd to still be open.
485 6 : if(bfd) bfd->close(bfd, asfd);
486 6 : bfile_free(&bfd);
487 6 : iobuf_free_content(rbuf);
488 6 : sbuf_free(&sb);
489 6 : return ret;
490 : }
491 :
492 6 : int backup_phase2_client(struct asfd *asfd,
493 : struct conf **confs, int resume)
494 : {
495 6 : int ret=0;
496 6 : struct cntr *cntr=NULL;
497 6 : if(confs) cntr=get_cntr(confs);
498 :
499 6 : logp("Phase 2 begin (send backup data)\n");
500 6 : logfmt("\n");
501 :
502 6 : ret=do_backup_phase2_client(asfd, confs, resume);
503 :
504 6 : cntr_print_end(cntr);
505 6 : cntr_set_bytes(cntr, asfd);
506 6 : cntr_print(cntr, ACTION_BACKUP);
507 :
508 6 : if(ret) logp("Error in phase 2\n");
509 6 : logp("Phase 2 end (send file data)\n");
510 :
511 6 : return ret;
512 : }
|