Line data Source code
1 : #include "../../burp.h"
2 : #include "../../alloc.h"
3 : #include "../../asfd.h"
4 : #include "../../async.h"
5 : #include "../../bu.h"
6 : #include "../../cmd.h"
7 : #include "../../cntr.h"
8 : #include "../../handy.h"
9 : #include "../../hexmap.h"
10 : #include "../../log.h"
11 : #include "../../prepend.h"
12 : #include "../../protocol1/handy.h"
13 : #include "../../server/protocol1/backup_phase4.h"
14 : #include "../../server/protocol1/link.h"
15 : #include "../../server/protocol1/zlibio.h"
16 : #include "../../server/protocol2/restore.h"
17 : #include "../../sbuf.h"
18 : #include "../../slist.h"
19 : #include "../sdirs.h"
20 : #include "dpth.h"
21 : #include "restore.h"
22 :
23 : #include <librsync.h>
24 :
25 0 : static int create_zero_length_file(const char *path)
26 : {
27 0 : int ret=0;
28 : struct fzp *dest;
29 0 : if(!(dest=fzp_open(path, "wb")))
30 0 : ret=-1;
31 0 : ret|=fzp_close(&dest);
32 0 : return ret;
33 : }
34 :
35 0 : static int inflate_or_link_oldfile(struct asfd *asfd, const char *oldpath,
36 : const char *infpath, struct conf **cconfs, int compression)
37 : {
38 0 : int ret=0;
39 : struct stat statp;
40 :
41 0 : if(lstat(oldpath, &statp))
42 : {
43 0 : logp("could not lstat %s\n", oldpath);
44 0 : return -1;
45 : }
46 :
47 0 : if(dpth_protocol1_is_compressed(compression, oldpath))
48 : {
49 : //logp("inflating...\n");
50 :
51 0 : if(!statp.st_size)
52 : {
53 : // Empty file - cannot inflate.
54 0 : logp("asked to inflate zero length file: %s\n",
55 : oldpath);
56 0 : return create_zero_length_file(infpath);
57 : }
58 :
59 0 : if((ret=zlib_inflate(asfd, oldpath, infpath, get_cntr(cconfs))))
60 0 : logp("zlib_inflate returned: %d\n", ret);
61 : }
62 : else
63 : {
64 : // Not compressed - just hard link it.
65 0 : if(do_link(oldpath, infpath, &statp, cconfs,
66 : 1 /* allow overwrite of infpath */))
67 : return -1;
68 : }
69 : return ret;
70 : }
71 :
72 4 : static int do_send_file(struct asfd *asfd, struct sbuf *sb,
73 : int patches, const char *best, struct cntr *cntr)
74 : {
75 4 : enum send_e ret=SEND_FATAL;
76 : struct BFILE bfd;
77 4 : uint64_t bytes=0; // Unused.
78 :
79 4 : bfile_init(&bfd, 0, cntr);
80 4 : if(bfd.open_for_send(&bfd, asfd, best, sb->winattr,
81 : 1 /* no O_NOATIME */, cntr, PROTO_1))
82 : return SEND_FATAL;
83 4 : if(asfd->write(asfd, &sb->path))
84 : ret=SEND_FATAL;
85 4 : else if(patches)
86 : {
87 : // If we did some patches, the resulting file
88 : // is not gzipped. Gzip it during the send.
89 0 : ret=send_whole_file_gzl(
90 : asfd,
91 0 : sb->protocol1->datapth.buf,
92 : /*quick_read*/1,
93 : &bytes,
94 : /*encpassword*/NULL,
95 : cntr,
96 : /*compression*/9,
97 : &bfd,
98 : /*extrameta*/NULL,
99 : /*elen*/0,
100 : /*key_deriv*/ENCRYPTION_UNSET,
101 : /*salt*/0
102 : );
103 : }
104 : else
105 : {
106 : // If it was encrypted, it may or may not have been compressed
107 : // before encryption. Send it as it as, and let the client
108 : // sort it out.
109 4 : if(sbuf_is_encrypted(sb))
110 : {
111 2 : ret=send_whole_filel(asfd,
112 : #ifdef HAVE_WIN32
113 : sb->path.cmd
114 : #endif
115 2 : sb->protocol1->datapth.buf,
116 : 1, &bytes, cntr, &bfd, NULL, 0);
117 : }
118 : // It might have been stored uncompressed. Gzip it during
119 : // the send. If the client knew what kind of file it would be
120 : // receiving, this step could disappear.
121 2 : else if(!dpth_protocol1_is_compressed(sb->compression,
122 2 : sb->protocol1->datapth.buf))
123 : {
124 2 : ret=send_whole_file_gzl(
125 : asfd,
126 2 : sb->protocol1->datapth.buf,
127 : /*quick_read*/1,
128 : &bytes,
129 : /*encpassword*/NULL,
130 : cntr,
131 : /*compression*/9,
132 : &bfd,
133 : /*extrameta*/NULL,
134 : /*elen*/0,
135 : /*key_deriv*/ENCRYPTION_UNSET,
136 : /*salt*/0
137 : );
138 : }
139 : else
140 : {
141 : // If we did not do some patches, the resulting
142 : // file might already be gzipped. Send it as it is.
143 0 : ret=send_whole_filel(asfd,
144 : #ifdef HAVE_WIN32
145 : sb->path.cmd
146 : #endif
147 0 : sb->protocol1->datapth.buf,
148 : 1, &bytes, cntr, &bfd, NULL, 0);
149 : }
150 : }
151 4 : bfd.close(&bfd, asfd);
152 :
153 4 : switch(ret)
154 : {
155 : case SEND_OK:
156 : case SEND_ERROR: // Carry on.
157 : return 0;
158 : case SEND_FATAL:
159 : default:
160 0 : return -1;
161 : }
162 : }
163 :
164 : #ifndef UTEST
165 : static
166 : #endif
167 5 : int verify_file(struct asfd *asfd, struct sbuf *sb,
168 : int patches, const char *best, struct cntr *cntr)
169 : {
170 : MD5_CTX md5;
171 5 : int b=0;
172 5 : const char *cp=NULL;
173 5 : const char *newsum=NULL;
174 : uint8_t in[ZCHUNK];
175 : uint8_t checksum[MD5_DIGEST_LENGTH];
176 5 : uint64_t cbytes=0;
177 5 : struct fzp *fzp=NULL;
178 :
179 5 : if(!sb->endfile.buf
180 5 : || !(cp=strrchr(sb->endfile.buf, ':')))
181 : {
182 1 : logw(asfd, cntr,
183 : "%s has no md5sum!\n",
184 1 : iobuf_to_printable(&sb->protocol1->datapth));
185 1 : return 0;
186 : }
187 4 : cp++;
188 4 : if(!MD5_Init(&md5))
189 : {
190 0 : logp("MD5_Init() failed\n");
191 0 : return -1;
192 : }
193 4 : if(patches
194 4 : || sb->path.cmd==CMD_ENC_FILE
195 4 : || sb->path.cmd==CMD_ENC_METADATA
196 4 : || sb->path.cmd==CMD_EFS_FILE
197 4 : || sb->path.cmd==CMD_ENC_VSS
198 4 : || sb->path.cmd==CMD_ENC_VSS_T
199 4 : || (!patches && !dpth_protocol1_is_compressed(sb->compression, best)))
200 2 : fzp=fzp_open(best, "rb");
201 : else
202 2 : fzp=fzp_gzopen(best, "rb");
203 :
204 4 : if(!fzp)
205 : {
206 1 : logw(asfd, cntr, "could not open %s\n", best);
207 1 : return 0;
208 : }
209 5 : while((b=fzp_read(fzp, in, ZCHUNK))>0)
210 : {
211 2 : cbytes+=b;
212 2 : if(!MD5_Update(&md5, in, b))
213 : {
214 0 : logp("MD5_Update() failed\n");
215 0 : fzp_close(&fzp);
216 0 : return -1;
217 : }
218 : }
219 3 : if(!fzp_eof(fzp))
220 : {
221 1 : logw(asfd, cntr, "error while reading %s\n", best);
222 1 : fzp_close(&fzp);
223 1 : return 0;
224 : }
225 2 : fzp_close(&fzp);
226 2 : if(!MD5_Final(checksum, &md5))
227 : {
228 0 : logp("MD5_Final() failed\n");
229 0 : return -1;
230 : }
231 2 : newsum=bytes_to_md5str(checksum);
232 :
233 2 : if(strcmp(newsum, cp))
234 : {
235 1 : logp("%s %s\n", newsum, cp);
236 1 : logw(asfd, cntr, "md5sum for '%s (%s)' did not match!\n",
237 : iobuf_to_printable(&sb->path),
238 1 : iobuf_to_printable(&sb->protocol1->datapth));
239 1 : logp("md5sum for '%s (%s)' did not match!\n",
240 : iobuf_to_printable(&sb->path),
241 1 : iobuf_to_printable(&sb->protocol1->datapth));
242 1 : return 0;
243 : }
244 :
245 : // Just send the file name to the client, so that it can show cntr.
246 1 : if(asfd->write(asfd, &sb->path)) return -1;
247 1 : return 0;
248 : }
249 :
250 4 : static int process_data_dir_file(struct asfd *asfd,
251 : struct bu *bu, struct bu *b, const char *path,
252 : struct sbuf *sb, enum action act, struct sdirs *sdirs,
253 : struct conf **cconfs)
254 : {
255 4 : int ret=-1;
256 4 : int patches=0;
257 4 : char *dpath=NULL;
258 : struct stat dstatp;
259 4 : const char *tmp=NULL;
260 4 : const char *best=NULL;
261 : static char *tmppath1=NULL;
262 : static char *tmppath2=NULL;
263 4 : struct cntr *cntr=NULL;
264 4 : if(cconfs) cntr=get_cntr(cconfs);
265 :
266 4 : if((!tmppath1 && !(tmppath1=prepend_s(bu->path, "tmp1")))
267 4 : || (!tmppath2 && !(tmppath2=prepend_s(bu->path, "tmp2"))))
268 : goto end;
269 :
270 4 : best=path;
271 4 : tmp=tmppath1;
272 : // Now go down the list, applying any deltas.
273 4 : for(b=b->prev; b && b->next!=bu; b=b->prev)
274 : {
275 0 : free_w(&dpath);
276 0 : if(!(dpath=prepend_s(b->delta, sb->protocol1->datapth.buf)))
277 : goto end;
278 :
279 0 : if(lstat(dpath, &dstatp) || !S_ISREG(dstatp.st_mode))
280 0 : continue;
281 :
282 0 : if(!patches)
283 : {
284 : // Need to gunzip the first one.
285 0 : if(inflate_or_link_oldfile(asfd, best, tmp,
286 : cconfs, sb->compression))
287 : {
288 0 : logw(asfd, cntr,
289 : "problem when inflating %s\n", best);
290 0 : ret=0;
291 : goto end;
292 : }
293 0 : best=tmp;
294 0 : if(tmp==tmppath1) tmp=tmppath2;
295 : else tmp=tmppath1;
296 : }
297 :
298 0 : if(do_patch(best, dpath, tmp,
299 : 0 /* do not gzip the result */,
300 : sb->compression /* from the manifest */))
301 : {
302 0 : logw(asfd, cntr, "problem when patching %s with %s\n", path, b->timestamp);
303 0 : ret=0;
304 : goto end;
305 : }
306 :
307 0 : best=tmp;
308 0 : if(tmp==tmppath1) tmp=tmppath2;
309 : else tmp=tmppath1;
310 0 : unlink(tmp);
311 0 : patches++;
312 : }
313 :
314 4 : switch(act)
315 : {
316 : case ACTION_RESTORE:
317 4 : if(do_send_file(asfd, sb, patches, best, cntr))
318 : goto end;
319 : break;
320 : case ACTION_VERIFY:
321 0 : if(verify_file(asfd, sb, patches, best, cntr))
322 : goto end;
323 : break;
324 : default:
325 0 : logp("Unknown action: %d\n", act);
326 : goto end;
327 : }
328 4 : cntr_add(cntr, sb->path.cmd, 0);
329 4 : cntr_add_bytes(cntr, strtoull(sb->endfile.buf, NULL, 10));
330 :
331 4 : ret=0;
332 : end:
333 4 : free_w(&dpath);
334 4 : if(tmppath1) unlink(tmppath1);
335 4 : if(tmppath2) unlink(tmppath2);
336 4 : free_w(&tmppath1);
337 4 : free_w(&tmppath2);
338 4 : return ret;
339 : }
340 :
341 : // a = length of struct bu array
342 : // i = position to restore from
343 : #ifndef UTEST
344 : static
345 : #endif
346 5 : int restore_file(struct asfd *asfd, struct bu *bu,
347 : struct sbuf *sb, enum action act,
348 : struct sdirs *sdirs, struct conf **cconfs)
349 : {
350 5 : int ret=-1;
351 5 : char *path=NULL;
352 : struct bu *b;
353 5 : struct bu *hlwarn=NULL;
354 : struct stat statp;
355 5 : struct cntr *cntr=NULL;
356 5 : if(cconfs) cntr=get_cntr(cconfs);
357 :
358 : // Go up the array until we find the file in the data directory.
359 10 : for(b=bu; b; b=b->next)
360 : {
361 4 : free_w(&path);
362 4 : if(!(path=prepend_s(b->data, sb->protocol1->datapth.buf)))
363 : goto end;
364 :
365 8 : if(lstat(path, &statp) || !S_ISREG(statp.st_mode))
366 0 : continue;
367 :
368 4 : if(b!=bu && (bu->flags & BU_HARDLINKED)) hlwarn=b;
369 :
370 4 : if(process_data_dir_file(asfd, bu, b,
371 : path, sb, act, sdirs, cconfs))
372 : goto end;
373 :
374 : // This warning must be done after everything else,
375 : // Because the client does not expect another cmd after
376 : // the warning.
377 4 : if(hlwarn) logw(asfd, cntr, "restore found %s in %s\n",
378 : iobuf_to_printable(&sb->path),
379 : hlwarn->basename);
380 : ret=0; // All OK.
381 : break;
382 : }
383 :
384 5 : if(!b)
385 : {
386 1 : logw(asfd, cntr, "restore could not find %s (%s)\n",
387 : iobuf_to_printable(&sb->path),
388 1 : iobuf_to_printable(&sb->protocol1->datapth));
389 1 : ret=0; // Carry on to subsequent files.
390 : }
391 : end:
392 5 : free_w(&path);
393 5 : return ret;
394 : }
395 :
396 10 : int restore_sbuf_protocol1(struct asfd *asfd, struct sbuf *sb, struct bu *bu,
397 : enum action act, struct sdirs *sdirs, struct conf **cconfs)
398 : {
399 10 : if((sb->protocol1->datapth.buf
400 4 : && asfd->write(asfd, &(sb->protocol1->datapth)))
401 10 : || asfd->write(asfd, &sb->attr))
402 : return -1;
403 10 : else if(sbuf_is_filedata(sb)
404 6 : || sbuf_is_vssdata(sb))
405 : {
406 4 : if(!sb->protocol1->datapth.buf)
407 : {
408 0 : logw(asfd, get_cntr(cconfs),
409 : "Got filedata entry with no datapth: %s\n",
410 : iobuf_to_printable(&sb->path));
411 0 : return 0;
412 : }
413 4 : return restore_file(asfd, bu, sb, act, sdirs, cconfs);
414 : }
415 : else
416 : {
417 6 : if(asfd->write(asfd, &sb->path))
418 : return -1;
419 : // If it is a link, send what
420 : // it points to.
421 6 : else if(sbuf_is_link(sb)
422 4 : && asfd->write(asfd, &sb->link)) return -1;
423 6 : cntr_add(get_cntr(cconfs), sb->path.cmd, 0);
424 : }
425 6 : return 0;
426 : }
|