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 0 : return ret;
70 : }
71 :
72 4 : static int send_file(struct asfd *asfd, struct sbuf *sb,
73 : int patches, const char *best, struct cntr *cntr)
74 : {
75 4 : int ret=-1;
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)) return -1;
82 : //logp("sending: %s\n", best);
83 4 : if(asfd->write(asfd, &sb->path))
84 : ret=-1;
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(asfd, sb->protocol1->datapth.buf,
90 : 1, &bytes, NULL, cntr, 9, &bfd, NULL, 0);
91 : }
92 : else
93 : {
94 : // If it was encrypted, it may or may not have been compressed
95 : // before encryption. Send it as it as, and let the client
96 : // sort it out.
97 4 : if(sbuf_is_encrypted(sb))
98 : {
99 2 : ret=send_whole_filel(asfd,
100 : #ifdef HAVE_WIN32
101 : sb->path.cmd
102 : #endif
103 2 : sb->protocol1->datapth.buf,
104 : 1, &bytes, cntr, &bfd, NULL, 0);
105 : }
106 : // It might have been stored uncompressed. Gzip it during
107 : // the send. If the client knew what kind of file it would be
108 : // receiving, this step could disappear.
109 2 : else if(!dpth_protocol1_is_compressed(sb->compression,
110 2 : sb->protocol1->datapth.buf))
111 : {
112 2 : ret=send_whole_file_gzl(asfd,
113 2 : sb->protocol1->datapth.buf, 1, &bytes,
114 : NULL, cntr, 9, &bfd, NULL, 0);
115 : }
116 : else
117 : {
118 : // If we did not do some patches, the resulting
119 : // file might already be gzipped. Send it as it is.
120 0 : ret=send_whole_filel(asfd,
121 : #ifdef HAVE_WIN32
122 : sb->path.cmd
123 : #endif
124 0 : sb->protocol1->datapth.buf,
125 : 1, &bytes, cntr, &bfd, NULL, 0);
126 : }
127 : }
128 4 : bfd.close(&bfd, asfd);
129 4 : return ret;
130 : }
131 :
132 0 : static int verify_file(struct asfd *asfd, struct sbuf *sb,
133 : int patches, const char *best, struct cntr *cntr)
134 : {
135 : MD5_CTX md5;
136 0 : size_t b=0;
137 0 : const char *cp=NULL;
138 0 : const char *newsum=NULL;
139 : uint8_t in[ZCHUNK];
140 : uint8_t checksum[MD5_DIGEST_LENGTH];
141 0 : uint64_t cbytes=0;
142 0 : struct fzp *fzp=NULL;
143 :
144 0 : if(!(cp=strrchr(sb->endfile.buf, ':')))
145 : {
146 0 : logw(asfd, cntr,
147 0 : "%s has no md5sum!\n", sb->protocol1->datapth.buf);
148 0 : return 0;
149 : }
150 0 : cp++;
151 0 : if(!MD5_Init(&md5))
152 : {
153 0 : logp("MD5_Init() failed\n");
154 0 : return -1;
155 : }
156 0 : if(patches
157 0 : || sb->path.cmd==CMD_ENC_FILE
158 0 : || sb->path.cmd==CMD_ENC_METADATA
159 0 : || sb->path.cmd==CMD_EFS_FILE
160 0 : || sb->path.cmd==CMD_ENC_VSS
161 0 : || (!patches && !dpth_protocol1_is_compressed(sb->compression, best)))
162 0 : fzp=fzp_open(best, "rb");
163 : else
164 0 : fzp=fzp_gzopen(best, "rb");
165 :
166 0 : if(!fzp)
167 : {
168 0 : logw(asfd, cntr, "could not open %s\n", best);
169 0 : return 0;
170 : }
171 0 : while((b=fzp_read(fzp, in, ZCHUNK))>0)
172 : {
173 0 : cbytes+=b;
174 0 : if(!MD5_Update(&md5, in, b))
175 : {
176 0 : logp("MD5_Update() failed\n");
177 0 : fzp_close(&fzp);
178 0 : return -1;
179 : }
180 : }
181 0 : if(!fzp_eof(fzp))
182 : {
183 0 : logw(asfd, cntr, "error while reading %s\n", best);
184 0 : fzp_close(&fzp);
185 0 : return 0;
186 : }
187 0 : fzp_close(&fzp);
188 0 : if(!MD5_Final(checksum, &md5))
189 : {
190 0 : logp("MD5_Final() failed\n");
191 0 : return -1;
192 : }
193 0 : newsum=bytes_to_md5str(checksum);
194 :
195 0 : if(strcmp(newsum, cp))
196 : {
197 0 : logp("%s %s\n", newsum, cp);
198 0 : logw(asfd, cntr, "md5sum for '%s (%s)' did not match!\n",
199 0 : sb->path.buf, sb->protocol1->datapth.buf);
200 0 : logp("md5sum for '%s (%s)' did not match!\n",
201 0 : sb->path.buf, sb->protocol1->datapth.buf);
202 0 : return 0;
203 : }
204 :
205 : // Just send the file name to the client, so that it can show cntr.
206 0 : if(asfd->write(asfd, &sb->path)) return -1;
207 0 : return 0;
208 : }
209 :
210 4 : static int process_data_dir_file(struct asfd *asfd,
211 : struct bu *bu, struct bu *b, const char *path,
212 : struct sbuf *sb, enum action act, struct sdirs *sdirs,
213 : struct conf **cconfs)
214 : {
215 4 : int ret=-1;
216 4 : int patches=0;
217 4 : char *dpath=NULL;
218 : struct stat dstatp;
219 4 : const char *tmp=NULL;
220 4 : const char *best=NULL;
221 : static char *tmppath1=NULL;
222 : static char *tmppath2=NULL;
223 4 : struct cntr *cntr=NULL;
224 4 : if(cconfs) cntr=get_cntr(cconfs);
225 :
226 4 : if((!tmppath1 && !(tmppath1=prepend_s(sdirs->client, "tmp1")))
227 4 : || (!tmppath2 && !(tmppath2=prepend_s(sdirs->client, "tmp2"))))
228 : goto end;
229 :
230 4 : best=path;
231 4 : tmp=tmppath1;
232 : // Now go down the list, applying any deltas.
233 4 : for(b=b->prev; b && b->next!=bu; b=b->prev)
234 : {
235 0 : free_w(&dpath);
236 0 : if(!(dpath=prepend_s(b->delta, sb->protocol1->datapth.buf)))
237 : goto end;
238 :
239 0 : if(lstat(dpath, &dstatp) || !S_ISREG(dstatp.st_mode))
240 0 : continue;
241 :
242 0 : if(!patches)
243 : {
244 : // Need to gunzip the first one.
245 0 : if(inflate_or_link_oldfile(asfd, best, tmp,
246 : cconfs, sb->compression))
247 : {
248 0 : logw(asfd, cntr,
249 : "problem when inflating %s\n", best);
250 0 : ret=0;
251 : goto end;
252 : }
253 0 : best=tmp;
254 0 : if(tmp==tmppath1) tmp=tmppath2;
255 : else tmp=tmppath1;
256 : }
257 :
258 0 : if(do_patch(best, dpath, tmp,
259 : 0 /* do not gzip the result */,
260 : sb->compression /* from the manifest */))
261 : {
262 0 : logw(asfd, cntr, "problem when patching %s with %s\n", path, b->timestamp);
263 0 : ret=0;
264 : goto end;
265 : }
266 :
267 0 : best=tmp;
268 0 : if(tmp==tmppath1) tmp=tmppath2;
269 : else tmp=tmppath1;
270 0 : unlink(tmp);
271 0 : patches++;
272 : }
273 :
274 4 : switch(act)
275 : {
276 : case ACTION_RESTORE:
277 4 : if(send_file(asfd, sb, patches, best, cntr))
278 : goto end;
279 : break;
280 : case ACTION_VERIFY:
281 0 : if(verify_file(asfd, sb, patches, best, cntr))
282 : goto end;
283 : break;
284 : default:
285 0 : logp("Unknown action: %d\n", act);
286 : goto end;
287 : }
288 4 : cntr_add(cntr, sb->path.cmd, 0);
289 4 : cntr_add_bytes(cntr, strtoull(sb->endfile.buf, NULL, 10));
290 :
291 4 : ret=0;
292 : end:
293 4 : free_w(&dpath);
294 4 : free_w(&tmppath1);
295 4 : free_w(&tmppath2);
296 4 : return ret;
297 : }
298 :
299 : // a = length of struct bu array
300 : // i = position to restore from
301 4 : static int restore_file(struct asfd *asfd, struct bu *bu,
302 : struct sbuf *sb, enum action act,
303 : struct sdirs *sdirs, struct conf **cconfs)
304 : {
305 4 : int ret=-1;
306 4 : char *path=NULL;
307 : struct bu *b;
308 4 : struct bu *hlwarn=NULL;
309 : struct stat statp;
310 4 : struct cntr *cntr=NULL;
311 4 : if(cconfs) cntr=get_cntr(cconfs);
312 :
313 : // Go up the array until we find the file in the data directory.
314 8 : for(b=bu; b; b=b->next)
315 : {
316 4 : free_w(&path);
317 4 : if(!(path=prepend_s(b->data, sb->protocol1->datapth.buf)))
318 : goto end;
319 :
320 8 : if(lstat(path, &statp) || !S_ISREG(statp.st_mode))
321 0 : continue;
322 :
323 4 : if(b!=bu && (bu->flags & BU_HARDLINKED)) hlwarn=b;
324 :
325 4 : if(process_data_dir_file(asfd, bu, b,
326 : path, sb, act, sdirs, cconfs)) goto end;
327 :
328 : // This warning must be done after everything else,
329 : // Because the client does not expect another cmd after
330 : // the warning.
331 4 : if(hlwarn) logw(asfd, cntr, "restore found %s in %s\n",
332 : sb->path.buf, hlwarn->basename);
333 : ret=0; // All OK.
334 : break;
335 : }
336 :
337 4 : if(!b) logw(asfd, cntr, "restore could not find %s (%s)\n",
338 0 : sb->path.buf, sb->protocol1->datapth.buf);
339 : end:
340 4 : free_w(&path);
341 4 : return ret;
342 : }
343 :
344 10 : int restore_sbuf_protocol1(struct asfd *asfd, struct sbuf *sb, struct bu *bu,
345 : enum action act, struct sdirs *sdirs, struct conf **cconfs)
346 : {
347 10 : if((sb->protocol1->datapth.buf
348 4 : && asfd->write(asfd, &(sb->protocol1->datapth)))
349 10 : || asfd->write(asfd, &sb->attr))
350 : return -1;
351 10 : else if(sbuf_is_filedata(sb)
352 6 : || sbuf_is_vssdata(sb))
353 : {
354 4 : if(!sb->protocol1->datapth.buf)
355 : {
356 0 : logw(asfd, get_cntr(cconfs),
357 : "Got filedata entry with no datapth: %c:%s\n",
358 0 : sb->path.cmd, sb->path.buf);
359 0 : return 0;
360 : }
361 4 : return restore_file(asfd, bu, sb, act, sdirs, cconfs);
362 : }
363 : else
364 : {
365 6 : if(asfd->write(asfd, &sb->path))
366 : return -1;
367 : // If it is a link, send what
368 : // it points to.
369 6 : else if(sbuf_is_link(sb)
370 4 : && asfd->write(asfd, &sb->link)) return -1;
371 6 : cntr_add(get_cntr(cconfs), sb->path.cmd, 0);
372 : }
373 6 : return 0;
374 : }
|