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