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