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