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