Line data Source code
1 : #include "../burp.h"
2 : #include "../alloc.h"
3 : #include "../asfd.h"
4 : #include "../async.h"
5 : #include "../attribs.h"
6 : #include "../berrno.h"
7 : #include "../cmd.h"
8 : #include "../cntr.h"
9 : #include "../fsops.h"
10 : #include "../handy.h"
11 : #include "../pathcmp.h"
12 : #include "../log.h"
13 : #include "../prepend.h"
14 : #include "../protocol2/blk.h"
15 : #include "cvss.h"
16 : #include "protocol1/restore.h"
17 : #include "protocol2/restore.h"
18 : #include "restore.h"
19 :
20 7 : int restore_interrupt(struct asfd *asfd,
21 : struct sbuf *sb, const char *msg, struct cntr *cntr,
22 : enum protocol protocol)
23 : {
24 7 : int ret=-1;
25 7 : char *path=NULL;
26 7 : struct iobuf *rbuf=asfd->rbuf;
27 :
28 7 : if(cntr)
29 : {
30 0 : cntr_add(cntr, CMD_WARNING, 1);
31 0 : logp("WARNING: %s\n", msg);
32 0 : if(asfd->write_str(asfd, CMD_WARNING, msg))
33 : goto end;
34 : }
35 :
36 7 : if(!iobuf_is_filedata(&sb->path)
37 0 : && !iobuf_is_vssdata(&sb->path))
38 : {
39 : // Do not need to do anything.
40 : ret=0;
41 : goto end;
42 : }
43 :
44 : // If it is file data, get the server
45 : // to interrupt the flow and move on.
46 :
47 7 : if(protocol==PROTO_1)
48 0 : path=sb->protocol1->datapth.buf;
49 7 : else if(protocol==PROTO_2)
50 7 : path=sb->path.buf;
51 :
52 7 : if(!path)
53 : {
54 : ret=0;
55 : goto end;
56 : }
57 :
58 7 : if(asfd->write_str(asfd, CMD_INTERRUPT, path))
59 : goto end;
60 :
61 : // Read to the end file marker.
62 : while(1)
63 : {
64 714 : iobuf_free_content(rbuf);
65 714 : if(asfd->read(asfd))
66 : goto end; // Error.
67 714 : if(!rbuf->len)
68 0 : continue;
69 :
70 714 : switch(rbuf->cmd)
71 : {
72 : case CMD_APPEND:
73 : case CMD_DATA:
74 707 : continue;
75 : case CMD_END_FILE:
76 : ret=0;
77 : goto end;
78 : default:
79 0 : iobuf_log_unexpected(rbuf, __func__);
80 0 : goto end;
81 : }
82 : }
83 : end:
84 7 : iobuf_free_content(rbuf);
85 7 : return ret;
86 : }
87 :
88 6 : static int make_link(
89 : #ifdef HAVE_WIN32
90 : struct asfd *asfd,
91 : struct cntr *cntr,
92 : #endif
93 : const char *fname, const char *lnk,
94 : enum cmd cmd, const char *restore_desired_dir)
95 : {
96 6 : int ret=-1;
97 :
98 : #ifdef HAVE_WIN32
99 : logw(asfd, cntr, "windows seems not to support hardlinks or symlinks\n");
100 : #else
101 6 : unlink(fname);
102 6 : if(cmd==CMD_HARD_LINK)
103 : {
104 1 : char *flnk=NULL;
105 1 : if(!(flnk=prepend_s(restore_desired_dir, lnk)))
106 : {
107 0 : log_out_of_memory(__func__);
108 0 : return -1;
109 : }
110 : //printf("%s -> %s\n", fname, flnk);
111 1 : ret=link(flnk, fname);
112 1 : free_w(&flnk);
113 : }
114 5 : else if(cmd==CMD_SOFT_LINK)
115 : {
116 : //printf("%s -> %s\n", fname, lnk);
117 5 : ret=symlink(lnk, fname);
118 : }
119 : else
120 : {
121 0 : logp("unexpected link command: %c\n", cmd);
122 0 : ret=-1;
123 : }
124 : #endif
125 :
126 6 : if(ret) logp("could not %slink %s -> %s: %s\n",
127 : cmd==CMD_HARD_LINK?"hard":"sym",
128 0 : fname, lnk, strerror(errno));
129 :
130 : return ret;
131 : }
132 :
133 : // FIX THIS: Maybe should be in bfile.c.
134 18 : enum ofr_e open_for_restore(struct asfd *asfd,
135 : struct BFILE *bfd, const char *path,
136 : struct sbuf *sb, enum vss_restore vss_restore, struct cntr *cntr,
137 : enum protocol protocol)
138 : {
139 : static int flags;
140 18 : if(bfd->mode!=BF_CLOSED)
141 : {
142 : #ifdef HAVE_WIN32
143 : if(bfd->path && !strcmp(bfd->path, path))
144 : {
145 : // Already open after restoring the VSS data.
146 : // Time now for the actual file data.
147 : return OFR_OK;
148 : }
149 : else
150 : {
151 : #endif
152 0 : if(bfd->close(bfd, asfd))
153 : {
154 0 : logp("error closing %s in %s()\n",
155 : path, __func__);
156 0 : return OFR_ERROR;
157 : }
158 : #ifdef HAVE_WIN32
159 : }
160 : #endif
161 : }
162 :
163 : #ifdef HAVE_WIN32
164 : // Some massive hacks to work around times that winattr was not
165 : // getting set correctly inside server side backups.
166 : // The EFS one will stop burp segfaulting when restoring affected
167 : // EFS files.
168 : if(sb->path.cmd==CMD_EFS_FILE)
169 : sb->winattr |= FILE_ATTRIBUTE_ENCRYPTED;
170 : if(S_ISDIR(sb->statp.st_mode))
171 : sb->winattr |= FILE_ATTRIBUTE_DIRECTORY;
172 : #endif
173 :
174 18 : bfile_init(bfd, sb->winattr, cntr);
175 18 : bfd->set_attribs_on_close=1;
176 18 : switch(vss_restore)
177 : {
178 : case VSS_RESTORE_OFF:
179 : #ifdef HAVE_WIN32
180 : bfd->set_win32_api(bfd, 0);
181 : #endif
182 0 : bfd->set_vss_strip(bfd, 0);
183 0 : break;
184 : case VSS_RESTORE_OFF_STRIP:
185 : #ifdef HAVE_WIN32
186 : bfd->set_win32_api(bfd, 0);
187 : #endif
188 0 : bfd->set_vss_strip(bfd, 1);
189 0 : break;
190 : case VSS_RESTORE_ON:
191 : #ifdef HAVE_WIN32
192 : bfd->set_win32_api(bfd, 1);
193 : #endif
194 18 : bfd->set_vss_strip(bfd, 0);
195 18 : break;
196 : }
197 18 : flags=O_WRONLY|O_BINARY
198 : #ifdef O_NOFOLLOW
199 : |O_NOFOLLOW
200 : #endif
201 : ;
202 18 : if(S_ISDIR(sb->statp.st_mode))
203 : {
204 : // Windows directories are treated as having file data.
205 0 : mkdir(path, 0777);
206 : }
207 : else
208 18 : flags|=O_CREAT|O_TRUNC;
209 :
210 18 : if(bfd->open(bfd, asfd, path, flags, S_IRUSR | S_IWUSR))
211 : {
212 : struct berrno be;
213 0 : berrno_init(&be);
214 0 : char msg[256]="";
215 0 : snprintf(msg, sizeof(msg), "Could not open for writing %s: %s",
216 0 : path, berrno_bstrerror(&be, errno));
217 0 : if(restore_interrupt(asfd, sb, msg, cntr, protocol))
218 : return OFR_ERROR;
219 0 : return OFR_CONTINUE;
220 : }
221 : // Add attributes to bfd so that they can be set when it is closed.
222 18 : bfd->winattr=sb->winattr;
223 18 : memcpy(&bfd->statp, &sb->statp, sizeof(struct stat));
224 18 : return OFR_OK;
225 : }
226 :
227 : static char *build_msg(const char *text, const char *param)
228 : {
229 : static char msg[256]="";
230 0 : snprintf(msg, sizeof(msg), text, param);
231 : return msg;
232 : }
233 :
234 : #ifndef HAVE_WIN32
235 0 : static void do_logw(struct asfd *asfd, struct cntr *cntr,
236 : const char *text, const char *param)
237 : {
238 0 : logw(asfd, cntr, "%s", build_msg(text, param));
239 0 : }
240 : #endif
241 :
242 : static int warn_and_interrupt(struct asfd *asfd, struct sbuf *sb,
243 : struct cntr *cntr, enum protocol protocol,
244 : const char *text, const char *param)
245 : {
246 0 : return restore_interrupt(asfd, sb, build_msg(text, param), cntr,
247 : protocol);
248 : }
249 :
250 0 : static int restore_special(struct asfd *asfd, struct sbuf *sb,
251 : const char *fname, enum action act, struct cntr *cntr,
252 : enum protocol protocol)
253 : {
254 0 : int ret=0;
255 0 : char *rpath=NULL;
256 : #ifdef HAVE_WIN32
257 : logw(asfd, cntr, "Cannot restore special files to Windows: %s\n", fname);
258 : goto end;
259 : #else
260 0 : struct stat statp=sb->statp;
261 :
262 0 : if(act==ACTION_VERIFY)
263 : {
264 0 : cntr_add(cntr, CMD_SPECIAL, 1);
265 0 : return 0;
266 : }
267 :
268 0 : if(build_path(fname, "", &rpath, NULL))
269 : {
270 : // failed - do a warning
271 0 : if(restore_interrupt(asfd, sb,
272 0 : build_msg("build path failed: %s", fname),
273 : cntr, protocol))
274 0 : ret=-1;
275 : goto end;
276 : }
277 0 : if(S_ISFIFO(statp.st_mode))
278 : {
279 0 : if(mkfifo(rpath, statp.st_mode) && errno!=EEXIST)
280 0 : do_logw(asfd, cntr,
281 0 : "Cannot make fifo: %s\n", strerror(errno));
282 : else
283 : {
284 0 : attribs_set(asfd, rpath, &statp, sb->winattr, cntr);
285 0 : cntr_add(cntr, CMD_SPECIAL, 1);
286 : }
287 : }
288 0 : else if(S_ISSOCK(statp.st_mode))
289 : {
290 0 : if(mksock(rpath))
291 0 : do_logw(asfd, cntr,
292 0 : "Cannot make socket: %s\n", strerror(errno));
293 : else
294 : {
295 0 : attribs_set(asfd, rpath, &statp, sb->winattr, cntr);
296 0 : cntr_add(cntr, CMD_SPECIAL, 1);
297 : }
298 : }
299 : #ifdef S_IFDOOR // Solaris high speed RPC mechanism
300 : else if (S_ISDOOR(statp.st_mode))
301 : do_logw(asfd, cntr,
302 : "Skipping restore of door file: %s\n", fname);
303 : #endif
304 : #ifdef S_IFPORT // Solaris event port for handling AIO
305 : else if (S_ISPORT(statp.st_mode))
306 : do_logw(asfd, cntr,
307 : "Skipping restore of event port file: %s\n", fname);
308 : #endif
309 0 : else if(mknod(fname, statp.st_mode, statp.st_rdev) && errno!=EEXIST)
310 0 : do_logw(asfd, cntr, "Cannot make node: %s\n", strerror(errno));
311 : else
312 : {
313 0 : attribs_set(asfd, rpath, &statp, sb->winattr, cntr);
314 0 : cntr_add(cntr, CMD_SPECIAL, 1);
315 : }
316 : #endif
317 : end:
318 0 : free_w(&rpath);
319 0 : return ret;
320 : }
321 :
322 0 : int restore_dir(struct asfd *asfd, struct sbuf *sb,
323 : const char *dname, enum action act, struct cntr *cntr,
324 : enum protocol protocol)
325 : {
326 0 : int ret=0;
327 0 : char *rpath=NULL;
328 0 : if(act==ACTION_RESTORE)
329 : {
330 0 : if(build_path(dname, "", &rpath, NULL))
331 : {
332 0 : ret=warn_and_interrupt(asfd, sb, cntr, protocol,
333 : "build path failed: %s", dname);
334 0 : goto end;
335 : }
336 0 : else if(is_dir_lstat(rpath)<=0)
337 : {
338 0 : if(mkdir(rpath, 0777))
339 : {
340 0 : ret=warn_and_interrupt(asfd, sb, cntr, protocol,
341 0 : "mkdir error: %s", strerror(errno));
342 0 : goto end;
343 : }
344 : }
345 0 : attribs_set(asfd, rpath, &(sb->statp), sb->winattr, cntr);
346 0 : if(!ret) cntr_add(cntr, sb->path.cmd, 1);
347 : }
348 0 : else cntr_add(cntr, sb->path.cmd, 1);
349 : end:
350 0 : free_w(&rpath);
351 0 : return ret;
352 : }
353 :
354 6 : static int restore_link(struct asfd *asfd, struct sbuf *sb,
355 : const char *fname, enum action act, struct cntr *cntr,
356 : enum protocol protocol, const char *restore_desired_dir)
357 : {
358 6 : int ret=0;
359 :
360 6 : if(act==ACTION_RESTORE)
361 : {
362 6 : char *rpath=NULL;
363 6 : if(build_path(fname, "", &rpath, NULL))
364 : {
365 0 : ret=warn_and_interrupt(asfd, sb, cntr, protocol,
366 : "build path failed: %s", fname);
367 0 : goto end;
368 : }
369 12 : else if(make_link(
370 : #ifdef HAVE_WIN32
371 : asfd,
372 : cntr,
373 : #endif
374 6 : fname, sb->link.buf,
375 : sb->link.cmd, restore_desired_dir))
376 : {
377 0 : ret=warn_and_interrupt(asfd, sb, cntr, protocol,
378 : "could not create link", "");
379 0 : goto end;
380 : }
381 : else if(!ret)
382 : {
383 6 : attribs_set(asfd, fname,
384 : &(sb->statp), sb->winattr, cntr);
385 6 : cntr_add(cntr, sb->path.cmd, 1);
386 : }
387 6 : free_w(&rpath);
388 : }
389 0 : else cntr_add(cntr, sb->path.cmd, 1);
390 : end:
391 6 : return ret;
392 : }
393 :
394 : static void strip_invalid_characters(char **path)
395 : {
396 : #ifdef HAVE_WIN32
397 : char *ch = *path;
398 : if (ch[0] != 0 && ch[1] != 0) {
399 : ch += 2;
400 : while (*ch) {
401 : switch (*ch) {
402 : case ':':
403 : case '<':
404 : case '>':
405 : case '*':
406 : case '?':
407 : case '|':
408 : *ch = '_';
409 : break;
410 : }
411 : ch++;
412 : }
413 : }
414 : #endif
415 : }
416 :
417 : static const char *act_str(enum action act)
418 : {
419 : static const char *ret=NULL;
420 20 : if(act==ACTION_RESTORE) ret="restore";
421 0 : else ret="verify";
422 20 : return ret;
423 : }
424 :
425 : #ifndef UTEST
426 : static
427 : #endif
428 7 : void strip_from_path(char *path, const char *strip)
429 : {
430 : char *p;
431 : char *src;
432 : size_t len;
433 14 : if(!path
434 7 : || !strip
435 6 : || strlen(path)<=strlen(strip)
436 5 : || !(p=strstr(path, strip)))
437 : return;
438 :
439 5 : len=strlen(p)-strlen(strip)+1;
440 5 : src=p+strlen(strip);
441 5 : memmove(p, src, len);
442 : }
443 :
444 :
445 : // Return 1 for ok, -1 for error, 0 for too many components stripped.
446 0 : static int strip_path_components(struct asfd *asfd,
447 : struct sbuf *sb, int strip, struct cntr *cntr, enum protocol protocol)
448 : {
449 0 : int s=0;
450 0 : char *tmp=NULL;
451 0 : char *cp=sb->path.buf;
452 0 : char *dp=NULL;
453 0 : for(s=0; cp && *cp && s<strip; s++)
454 : {
455 0 : if(!(dp=strchr(cp, '/')))
456 : {
457 0 : char msg[256]="";
458 0 : snprintf(msg, sizeof(msg),
459 : "Stripped too many components: %s",
460 : iobuf_to_printable(&sb->path));
461 0 : if(restore_interrupt(asfd, sb, msg, cntr, protocol))
462 : return -1;
463 0 : return 0;
464 : }
465 0 : cp=dp+1;
466 : }
467 0 : if(!cp)
468 : {
469 0 : char msg[256]="";
470 0 : snprintf(msg, sizeof(msg),
471 : "Stripped too many components: %s",
472 : iobuf_to_printable(&sb->path));
473 0 : if(restore_interrupt(asfd, sb, msg, cntr, protocol))
474 : return -1;
475 0 : return 0;
476 : }
477 0 : if(!(tmp=strdup_w(cp, __func__)))
478 : return -1;
479 0 : free_w(&sb->path.buf);
480 0 : sb->path.buf=tmp;
481 0 : return 1;
482 : }
483 :
484 32 : static int overwrite_ok(struct sbuf *sb,
485 : int overwrite,
486 : #ifdef HAVE_WIN32
487 : struct BFILE *bfd,
488 : #endif
489 : const char *fullpath)
490 : {
491 : struct stat checkstat;
492 :
493 : // User specified overwrite is OK.
494 : #ifdef HAVE_WIN32
495 : if(overwrite) return 1;
496 : #else
497 : // User specified overwrite is OK,
498 : // UNLESS we are trying to overwrite the file with trailing VSS data.
499 32 : if(overwrite)
500 0 : return (sb->path.cmd!=CMD_VSS_T
501 0 : && sb->path.cmd!=CMD_ENC_VSS_T);
502 : #endif
503 :
504 32 : if(!S_ISDIR(sb->statp.st_mode)
505 32 : && sb->path.cmd!=CMD_METADATA
506 32 : && sb->path.cmd!=CMD_ENC_METADATA
507 32 : && sb->path.cmd!=CMD_VSS
508 32 : && sb->path.cmd!=CMD_ENC_VSS)
509 : {
510 : #ifdef HAVE_WIN32
511 : // If Windows previously got some VSS data, it needs to append
512 : // the file data to the already open bfd.
513 : // And trailing VSS data.
514 : if(bfd->mode!=BF_CLOSED
515 : && (sb->path.cmd==CMD_FILE || sb->path.cmd==CMD_ENC_FILE
516 : || sb->path.cmd==CMD_VSS_T || sb->path.cmd==CMD_ENC_VSS_T)
517 : && bfd->path && !strcmp(bfd->path, fullpath))
518 : return 1;
519 : #endif
520 : // If we have file data and the destination is
521 : // a fifo, it is OK to write to the fifo.
522 32 : if((sb->path.cmd==CMD_FILE || sb->path.cmd==CMD_ENC_FILE)
523 26 : && S_ISFIFO(sb->statp.st_mode))
524 : return 1;
525 :
526 : // File path exists. Do not overwrite.
527 32 : if(!lstat(fullpath, &checkstat)) return 0;
528 : }
529 :
530 : return 1;
531 : }
532 :
533 : #define RESTORE_STREAM "restore_stream"
534 : // Used to have "restore_spool". Removed for simplicity.
535 :
536 : static char *restore_style=NULL;
537 :
538 2 : static enum asl_ret restore_style_func(struct asfd *asfd,
539 : __attribute__ ((unused)) struct conf **confs,
540 : __attribute__ ((unused)) void *param)
541 : {
542 2 : char msg[32]="";
543 2 : restore_style=NULL;
544 2 : if(strcmp(asfd->rbuf->buf, RESTORE_STREAM))
545 : {
546 0 : iobuf_log_unexpected(asfd->rbuf, __func__);
547 0 : return ASL_END_ERROR;
548 : }
549 2 : snprintf(msg, sizeof(msg), "%s_ok", asfd->rbuf->buf);
550 2 : if(asfd->write_str(asfd, CMD_GEN, msg))
551 : return ASL_END_ERROR;
552 2 : restore_style=asfd->rbuf->buf;
553 2 : iobuf_init(asfd->rbuf);
554 2 : return ASL_END_OK;
555 : }
556 :
557 8 : static char *get_restore_style(struct asfd *asfd, struct conf **confs)
558 : {
559 8 : if(get_protocol(confs)==PROTO_1)
560 5 : return strdup_w(RESTORE_STREAM, __func__);
561 3 : if(asfd->simple_loop(asfd, confs, NULL, __func__,
562 : restore_style_func)) return NULL;
563 2 : return restore_style;
564 : }
565 :
566 : #ifdef HAVE_WIN32
567 : #ifndef PATH_MAX
568 : #define PATH_MAX _MAX_PATH
569 : #endif
570 : #endif
571 :
572 0 : static char *get_restore_desired_dir(
573 : const char *restoreprefix,
574 : struct asfd *asfd,
575 : struct cntr *cntr
576 : ) {
577 0 : char *ret=NULL;
578 0 : char *path=NULL;
579 :
580 0 : if(
581 : #ifdef HAVE_WIN32
582 : isalpha(*restoreprefix) && *(restoreprefix+1)==':'
583 : #else
584 0 : *restoreprefix=='/'
585 : #endif
586 : ) {
587 0 : if(!(path=strdup_w(restoreprefix, __func__)))
588 : return NULL;
589 : }
590 : else
591 : {
592 : static char d[PATH_MAX];
593 0 : if(!getcwd(d, sizeof(d)))
594 : {
595 0 : logw(asfd, cntr,
596 : "Could not get current working directory: %s\n",
597 0 : strerror(errno));
598 0 : return NULL;
599 : }
600 0 : if(!(path=prepend_s(d, restoreprefix)))
601 : return NULL;
602 : }
603 :
604 : // Canonicalise the path so that we can protect against symlinks that
605 : // point outsired of the desired restore directory.
606 0 : if((ret=realpath(path, NULL)))
607 : goto end;
608 0 : if(errno!=ENOENT)
609 : goto realpath_error;
610 : // Try to create the directory if it did not exist, then try again.
611 0 : mkdir(path, 0777);
612 0 : if(!(ret=realpath(path, NULL)))
613 : goto realpath_error;
614 :
615 : end:
616 0 : free_w(&path);
617 0 : return ret;
618 :
619 : realpath_error:
620 0 : logp("%s: Could not get realpath in %s: %s\n",
621 : path, __func__, strerror(errno));
622 0 : free_w(&path);
623 0 : return NULL;
624 : }
625 :
626 : // Seems that windows has no dirname(), so do something similar instead.
627 0 : static int strip_trailing_component(char **path)
628 : {
629 0 : char *cp=NULL;
630 :
631 0 : if(**path=='/' && !*((*path)+1))
632 : return -1;
633 0 : if(!(cp=strrchr(*path, '/')))
634 : return -1;
635 0 : if(*path==cp)
636 0 : *(cp+1)='\0'; // Deal with '/somepath' in root, gives '/'.
637 : else
638 0 : *cp='\0'; // Deal with '/some/path', gives '/some'.
639 : return 0;
640 : }
641 :
642 0 : static int canonicalise(
643 : struct asfd *asfd,
644 : struct sbuf *sb,
645 : struct cntr *cntr,
646 : enum protocol protocol,
647 : const char *restore_desired_dir,
648 : char **fullpath
649 : ) {
650 0 : int ret=-1;
651 0 : char *tmp=NULL;
652 0 : char *copy=NULL;
653 0 : char *canonical=NULL;
654 :
655 0 : if(!(copy=strdup_w(*fullpath, __func__)))
656 : goto end;
657 :
658 : // The realpath function does not work on entries that do not exist,
659 : // so we have to do complicated things.
660 : while(1)
661 : {
662 0 : if(strip_trailing_component(©))
663 : {
664 0 : char msg[512]="";
665 0 : snprintf(msg, sizeof(msg),
666 : "%s: Could not get dirname of '%s'",
667 : *fullpath, copy);
668 0 : if(restore_interrupt(asfd, sb, msg, cntr, protocol))
669 : goto end;
670 0 : ret=1;
671 0 : goto end;
672 : }
673 0 : if((canonical=realpath(copy, NULL)))
674 : break;
675 0 : if(errno!=ENOENT)
676 : {
677 0 : char msg[512]="";
678 0 : snprintf(msg, sizeof(msg),
679 : "%s: Could not get realpath of %s in %s: %s",
680 : *fullpath, copy, __func__, strerror(errno));
681 0 : if(restore_interrupt(asfd, sb, msg, cntr, protocol))
682 : goto end;
683 0 : ret=1;
684 0 : goto end;
685 : }
686 : }
687 :
688 : // Protect against malicious servers trying to install a symlink and
689 : // then files over the top of it to directories outside of the
690 : // desired directory.
691 0 : if(!is_subdir(restore_desired_dir, canonical))
692 : {
693 0 : char msg[512]="";
694 0 : snprintf(msg, sizeof(msg),
695 : "%s: Is not in a subdir of '%s'",
696 : *fullpath,
697 : restore_desired_dir);
698 0 : if(restore_interrupt(asfd, sb, msg, cntr, protocol))
699 : goto end;
700 0 : ret=1;
701 0 : goto end;
702 : }
703 :
704 : // Add the trailing content back onto the canonical path.
705 0 : if(!(tmp=prepend_s(canonical, (*fullpath)+strlen(copy))))
706 : goto end;
707 0 : free_w(fullpath);
708 0 : *fullpath=tmp;
709 :
710 0 : ret=0;
711 : end:
712 : // Cannot use free_w() because it was not allocated by alloc.c, and
713 : // I cannot implement realpath() it in alloc.c because I cannot get
714 : // Windows code to use alloc.c.
715 0 : if(canonical) free(canonical);
716 0 : free_w(©);
717 0 : return ret;
718 : }
719 :
720 8 : int do_restore_client(struct asfd *asfd,
721 : struct conf **confs, enum action act)
722 : {
723 8 : int ret=-1;
724 8 : char msg[512]="";
725 8 : struct sbuf *sb=NULL;
726 8 : struct blk *blk=NULL;
727 8 : struct BFILE *bfd=NULL;
728 8 : char *fullpath=NULL;
729 8 : char *style=NULL;
730 8 : char *restore_desired_dir=NULL;
731 8 : struct cntr *cntr=get_cntr(confs);
732 8 : enum protocol protocol=get_protocol(confs);
733 8 : int strip=get_int(confs[OPT_STRIP]);
734 8 : int overwrite=get_int(confs[OPT_OVERWRITE]);
735 8 : const char *strip_path=get_string(confs[OPT_STRIP_FROM_PATH]);
736 8 : const char *backup=get_string(confs[OPT_BACKUP]);
737 8 : const char *regex=get_string(confs[OPT_REGEX]);
738 8 : const char *encryption_password=
739 8 : get_string(confs[OPT_ENCRYPTION_PASSWORD]);
740 8 : enum vss_restore vss_restore=
741 8 : (enum vss_restore)get_int(confs[OPT_VSS_RESTORE]);
742 :
743 8 : if(act==ACTION_RESTORE)
744 : {
745 8 : const char *restore_prefix=get_string(confs[OPT_RESTOREPREFIX]);
746 8 : if(!restore_prefix)
747 : {
748 0 : logw(NULL, cntr,
749 : "You must specify a restore directory (-d)!\n");
750 0 : goto error;
751 : }
752 8 : if(!strcmp(restore_prefix, "/")) {
753 : // Special case to try to help Windows users that are
754 : // trying to do "bare metal" restores. Let them give
755 : // '/' as the restore prefix, and have it mean that
756 : // everything gets restored back to the original
757 : // locations (this would work on Linux *without* this
758 : // special case anyway, but hey-ho).
759 : }
760 0 : else if(!(restore_desired_dir=get_restore_desired_dir(
761 : restore_prefix, asfd, cntr)))
762 : goto error;
763 : }
764 :
765 8 : if(!(bfd=bfile_alloc()))
766 : goto error;
767 :
768 8 : bfile_init(bfd, 0, cntr);
769 8 : bfd->set_attribs_on_close=1;
770 :
771 16 : snprintf(msg, sizeof(msg), "%s %s:%s", act_str(act),
772 : backup?backup:"", regex?regex:"");
773 8 : logp("doing %s\n", msg);
774 8 : if(asfd->write_str(asfd, CMD_GEN, msg)
775 8 : || asfd_read_expect(asfd, CMD_GEN, "ok"))
776 : goto error;
777 8 : logp("doing %s confirmed\n", act_str(act));
778 8 : if(act==ACTION_RESTORE)
779 8 : logp("Directory: '%s'\n", restore_desired_dir);
780 :
781 : #if defined(HAVE_WIN32)
782 : if(act==ACTION_RESTORE) win32_enable_backup_privileges();
783 : #endif
784 :
785 8 : logfmt("\n");
786 :
787 8 : if(cntr_recv(asfd, confs))
788 : goto error;
789 :
790 8 : if(!(style=get_restore_style(asfd, confs)))
791 : goto error;
792 :
793 7 : if(!(sb=sbuf_alloc(protocol))
794 7 : || (protocol==PROTO_2 && !(blk=blk_alloc())))
795 : {
796 0 : log_and_send_oom(asfd);
797 0 : goto error;
798 : }
799 :
800 : while(1)
801 : {
802 52 : sbuf_free_content(sb);
803 52 : if(protocol==PROTO_1)
804 13 : sb->flags |= SBUF_CLIENT_RESTORE_HACK;
805 :
806 52 : switch(sbuf_fill_from_net(sb, asfd, blk, cntr))
807 : {
808 : case 0: break;
809 4 : case 1: if(asfd->write_str(asfd, CMD_GEN,
810 : "restoreend ok")) goto error;
811 : goto end; // It was OK.
812 : default:
813 : case -1: goto error;
814 : }
815 :
816 46 : if(protocol==PROTO_2)
817 : {
818 37 : if(blk->data)
819 : {
820 14 : int wret=0;
821 14 : if(act==ACTION_VERIFY)
822 0 : cntr_add(cntr, CMD_DATA, 1);
823 : else
824 14 : wret=write_protocol2_data(asfd,
825 : bfd, blk, vss_restore);
826 14 : blk_free_content(blk);
827 14 : blk->data=NULL;
828 14 : if(wret) goto error;
829 14 : continue;
830 : }
831 23 : else if(sb->endfile.buf)
832 : {
833 0 : continue;
834 : }
835 : }
836 :
837 32 : switch(sb->path.cmd)
838 : {
839 : case CMD_DIRECTORY:
840 : case CMD_FILE:
841 : case CMD_ENC_FILE:
842 : case CMD_SOFT_LINK:
843 : case CMD_HARD_LINK:
844 : case CMD_SPECIAL:
845 : case CMD_METADATA:
846 : case CMD_ENC_METADATA:
847 : case CMD_VSS:
848 : case CMD_ENC_VSS:
849 : case CMD_VSS_T:
850 : case CMD_ENC_VSS_T:
851 : case CMD_EFS_FILE:
852 32 : if(strip)
853 : {
854 : int s;
855 0 : s=strip_path_components(asfd,
856 : sb, strip, cntr, protocol);
857 0 : if(s<0) goto error;
858 0 : if(s==0)
859 : {
860 : // Too many components stripped
861 : // - carry on.
862 0 : continue;
863 : }
864 : // It is OK, sb.path is now stripped.
865 : }
866 32 : if(strip_path)
867 : {
868 0 : strip_from_path(sb->path.buf,
869 : strip_path);
870 : // Strip links if their path is absolute
871 0 : if(sb->link.buf && !is_absolute(sb->link.buf))
872 0 : strip_from_path(sb->link.buf,
873 : strip_path);
874 : }
875 32 : free_w(&fullpath);
876 32 : if(!(fullpath=prepend_s(restore_desired_dir,
877 32 : sb->path.buf)))
878 : {
879 0 : log_and_send_oom(asfd);
880 0 : goto error;
881 : }
882 :
883 32 : if(act==ACTION_RESTORE)
884 : {
885 32 : strip_invalid_characters(&fullpath);
886 : // canonicalise will fail on Windows split_vss
887 : // restores if we do not make sure bfd is
888 : // closed first.
889 32 : if(bfd
890 32 : && bfd->mode!=BF_CLOSED
891 19 : && bfd->path
892 19 : && strcmp(bfd->path, fullpath))
893 12 : bfd->close(bfd, asfd);
894 32 : if(restore_desired_dir) {
895 0 : switch(canonicalise(
896 : asfd,
897 : sb,
898 : cntr,
899 : protocol,
900 : restore_desired_dir,
901 : &fullpath
902 : )) {
903 : case 0: break;
904 0 : case 1: continue;
905 : default: goto error;
906 : }
907 : }
908 :
909 32 : if(!overwrite_ok(sb, overwrite,
910 : #ifdef HAVE_WIN32
911 : bfd,
912 : #endif
913 : fullpath))
914 : {
915 7 : char msg[512]="";
916 : // Something exists at that path.
917 7 : snprintf(msg, sizeof(msg),
918 : "Path exists: %s\n", fullpath);
919 7 : if(restore_interrupt(asfd,
920 : sb, msg, cntr, protocol))
921 : goto error;
922 7 : continue;
923 : }
924 : }
925 : break;
926 : case CMD_MESSAGE:
927 : case CMD_WARNING:
928 0 : log_recvd(&sb->path, cntr, 1);
929 0 : logfmt("\n");
930 0 : continue;
931 : default:
932 : break;
933 : }
934 :
935 25 : switch(sb->path.cmd)
936 : {
937 : // These are the same in both protocol1 and protocol2.
938 : case CMD_DIRECTORY:
939 0 : if(restore_dir(asfd, sb, fullpath, act, cntr,
940 : protocol))
941 : goto error;
942 0 : continue;
943 : case CMD_SOFT_LINK:
944 : case CMD_HARD_LINK:
945 6 : if(restore_link(asfd, sb, fullpath, act, cntr,
946 : protocol, restore_desired_dir))
947 : goto error;
948 6 : continue;
949 : case CMD_SPECIAL:
950 0 : if(restore_special(asfd, sb,
951 : fullpath, act, cntr, protocol))
952 : goto error;
953 0 : continue;
954 : default:
955 : break;
956 : }
957 :
958 19 : if(protocol==PROTO_2)
959 : {
960 14 : if(restore_switch_protocol2(asfd, sb, fullpath, act,
961 : bfd, vss_restore, cntr))
962 : goto error;
963 : }
964 : else
965 : {
966 5 : if(restore_switch_protocol1(asfd, sb, fullpath, act,
967 : bfd, vss_restore, cntr, encryption_password))
968 : goto error;
969 : }
970 : }
971 :
972 : end:
973 4 : ret=0;
974 : error:
975 : // It is possible for a fd to still be open.
976 8 : if(bfd)
977 : {
978 8 : bfd->close(bfd, asfd);
979 8 : bfile_free(&bfd);
980 : }
981 :
982 8 : cntr_print_end(cntr);
983 8 : cntr_set_bytes(cntr, asfd);
984 8 : cntr_print(cntr, act);
985 :
986 12 : if(!ret) logp("%s finished\n", act_str(act));
987 4 : else logp("ret: %d\n", ret);
988 :
989 8 : sbuf_free(&sb);
990 8 : free_w(&style);
991 8 : free_w(&fullpath);
992 8 : blk_free(&blk);
993 :
994 : // Cannot use free_w() because it was not allocated by alloc.c, and
995 : // I cannot implement realpath() it in alloc.c because I cannot get
996 : // Windows code to use alloc.c.
997 8 : if(restore_desired_dir)
998 0 : free(restore_desired_dir);
999 :
1000 8 : return ret;
1001 : }
|