Line data Source code
1 : #include "burp.h"
2 : #include "sbuf.h"
3 : #include "alloc.h"
4 : #include "asfd.h"
5 : #include "attribs.h"
6 : #include "cmd.h"
7 : #include "conf.h"
8 : #include "handy.h"
9 : #include "log.h"
10 : #include "msg.h"
11 : #include "protocol2/blk.h"
12 : #include "server/protocol2/rblk.h"
13 :
14 132384 : struct sbuf *sbuf_alloc(enum protocol protocol)
15 : {
16 : struct sbuf *sb;
17 132384 : if(!(sb=(struct sbuf *)calloc_w(1, sizeof(struct sbuf), __func__)))
18 : return NULL;
19 132384 : iobuf_init(&sb->path);
20 132384 : iobuf_init(&sb->attr);
21 132384 : sb->attr.cmd=CMD_ATTRIBS;
22 132384 : iobuf_init(&sb->link);
23 132384 : iobuf_init(&sb->endfile);
24 132384 : sb->compression=-1;
25 132384 : if(protocol==PROTO_1)
26 : {
27 31950 : if(!(sb->protocol1=sbuf_protocol1_alloc())) return NULL;
28 : }
29 : else
30 : {
31 100434 : if(!(sb->protocol2=sbuf_protocol2_alloc())) return NULL;
32 : }
33 132384 : return sb;
34 : }
35 :
36 228160 : void sbuf_free_content(struct sbuf *sb)
37 : {
38 228160 : iobuf_free_content(&sb->path);
39 228160 : iobuf_free_content(&sb->attr);
40 228160 : iobuf_free_content(&sb->link);
41 228160 : iobuf_free_content(&sb->endfile);
42 228160 : memset(&(sb->statp), 0, sizeof(sb->statp));
43 228160 : sb->compression=-1;
44 228160 : sb->winattr=0;
45 228160 : sb->flags=0;
46 228160 : sbuf_protocol1_free_content(sb->protocol1);
47 228160 : sbuf_protocol2_free_content(sb->protocol2);
48 228160 : }
49 :
50 387101 : void sbuf_free(struct sbuf **sb)
51 : {
52 774202 : if(!sb || !*sb) return;
53 132384 : sbuf_free_content(*sb);
54 132384 : free_v((void **)&((*sb)->protocol1));
55 132384 : free_v((void **)&((*sb)->protocol2));
56 132384 : free_v((void **)sb);
57 : }
58 :
59 108 : int sbuf_is_link(struct sbuf *sb)
60 : {
61 108 : return iobuf_is_link(&sb->path);
62 : }
63 :
64 218385 : int sbuf_is_filedata(struct sbuf *sb)
65 : {
66 226555 : return iobuf_is_filedata(&sb->path);
67 : }
68 :
69 10453 : int sbuf_is_vssdata(struct sbuf *sb)
70 : {
71 10551 : return iobuf_is_vssdata(&sb->path);
72 : }
73 :
74 85249 : int sbuf_is_encrypted(struct sbuf *sb)
75 : {
76 85249 : return iobuf_is_encrypted(&sb->path);
77 : }
78 :
79 0 : int sbuf_is_metadata(struct sbuf *sb)
80 : {
81 0 : return iobuf_is_metadata(&sb->path);
82 : }
83 :
84 91632 : int sbuf_to_manifest(struct sbuf *sb, struct fzp *fzp)
85 : {
86 91632 : if(!sb->path.buf) return 0;
87 :
88 91632 : if(sb->protocol1)
89 : {
90 11704 : if(sb->protocol1->datapth.buf
91 11704 : && iobuf_send_msg_fzp(&(sb->protocol1->datapth), fzp))
92 : return -1;
93 :
94 11704 : if(iobuf_send_msg_fzp(&sb->attr, fzp))
95 : return -1;
96 : }
97 : else
98 : {
99 : // Hackity hack: Strip the file index from the beginning of
100 : // the attribs so that manifests where nothing changed are
101 : // identical to each other. Better would be to preserve the
102 : // index.
103 : char *cp;
104 159856 : if(!(cp=strchr(sb->attr.buf, ' ')))
105 : {
106 0 : logp("Strange attributes: %s\n", sb->attr.buf);
107 0 : return -1;
108 : }
109 79928 : if(send_msg_fzp(fzp, CMD_ATTRIBS,
110 79928 : cp, sb->attr.len-(cp-sb->attr.buf)))
111 : return -1;
112 : }
113 91632 : if(iobuf_send_msg_fzp(&sb->path, fzp))
114 : return -1;
115 91632 : if(sb->link.buf
116 91632 : && iobuf_send_msg_fzp(&sb->link, fzp))
117 : return -1;
118 91632 : if(sb->endfile.buf
119 91632 : && iobuf_send_msg_fzp(&sb->endfile, fzp))
120 : return -1;
121 :
122 91632 : return 0;
123 : }
124 :
125 : // Like pathcmp, but sort entries that have the same paths so that metadata
126 : // comes later, and vss comes earlier, and trailing vss comes later.
127 10 : int sbuf_pathcmp(struct sbuf *a, struct sbuf *b)
128 : {
129 10 : return iobuf_pathcmp(&a->path, &b->path);
130 : }
131 :
132 : // Return -1 for error, 0 for could not open file, 1 for success.
133 22 : int sbuf_open_file(struct sbuf *sb, struct asfd *asfd, struct cntr *cntr,
134 : struct conf **confs)
135 : {
136 22 : BFILE *bfd=&sb->protocol2->bfd;
137 : #ifdef HAVE_WIN32
138 : if(win32_lstat(sb->path.buf, &sb->statp, &sb->winattr))
139 : #else
140 44 : if(lstat(sb->path.buf, &sb->statp))
141 : #endif
142 : {
143 : // This file is no longer available.
144 3 : logw(asfd, cntr, "%s has vanished\n", sb->path.buf);
145 3 : return 0;
146 : }
147 19 : sb->compression=get_int(confs[OPT_COMPRESSION]);
148 : // Encryption not yet implemented in protocol2.
149 : //sb->protocol2->encryption=conf->protocol2->encryption_password?1:0;
150 19 : if(attribs_encode(sb)) return -1;
151 :
152 19 : if(bfd->open_for_send(bfd, asfd,
153 : sb->path.buf, sb->winattr,
154 19 : get_int(confs[OPT_ATIME]), cntr, PROTO_2))
155 : {
156 : logw(asfd, get_cntr(confs),
157 0 : "Could not open %s\n", sb->path.buf);
158 0 : return 0;
159 : }
160 : return 1;
161 : }
162 :
163 19 : void sbuf_close_file(struct sbuf *sb, struct asfd *asfd)
164 : {
165 19 : BFILE *bfd=&sb->protocol2->bfd;
166 19 : bfd->close(bfd, asfd);
167 19 : }
168 :
169 38 : ssize_t sbuf_read(struct sbuf *sb, char *buf, size_t bufsize)
170 : {
171 38 : BFILE *bfd=&sb->protocol2->bfd;
172 38 : return (ssize_t)bfd->read(bfd, buf, bufsize);
173 : }
174 :
175 : enum parse_ret
176 : {
177 : PARSE_RET_ERROR=-1,
178 : PARSE_RET_NEED_MORE=0,
179 : PARSE_RET_COMPLETE=1,
180 : PARSE_RET_FINISHED=2,
181 : };
182 :
183 353136 : static parse_ret parse_cmd(struct sbuf *sb, struct asfd *asfd,
184 : struct iobuf *rbuf, struct blk *blk,
185 : const char *datpath, struct cntr *cntr)
186 : {
187 353136 : switch(rbuf->cmd)
188 : {
189 : case CMD_ATTRIBS:
190 60512 : if(sb->protocol2)
191 47063 : sbuf_free_content(sb);
192 : else
193 : {
194 13449 : if(sb->protocol1->datapth.buf)
195 : // protocol 1 phase 2+ file data
196 : // starts with datapth.
197 8204 : iobuf_free_content(&sb->attr);
198 : else
199 : // protocol 1 phase 1 or non file data
200 : // starts with attribs
201 5245 : sbuf_free_content(sb);
202 : }
203 60512 : iobuf_move(&sb->attr, rbuf);
204 60512 : attribs_decode(sb);
205 60512 : return PARSE_RET_NEED_MORE;
206 :
207 : case CMD_FILE:
208 : case CMD_DIRECTORY:
209 : case CMD_SOFT_LINK:
210 : case CMD_HARD_LINK:
211 : case CMD_SPECIAL:
212 : // Stuff not currently supported in burp-2, but OK
213 : // to find in burp-1.
214 : case CMD_ENC_FILE:
215 : case CMD_METADATA:
216 : case CMD_ENC_METADATA:
217 : case CMD_EFS_FILE:
218 : case CMD_VSS:
219 : case CMD_ENC_VSS:
220 : case CMD_VSS_T:
221 : case CMD_ENC_VSS_T:
222 69576 : if(!sb->attr.buf)
223 : {
224 1 : log_and_send(asfd, "read cmd with no attribs");
225 1 : return PARSE_RET_ERROR;
226 : }
227 69575 : if(sb->flags & SBUF_NEED_LINK)
228 : {
229 9083 : if(cmd_is_link(rbuf->cmd))
230 : {
231 9083 : iobuf_free_content(&sb->link);
232 9083 : iobuf_move(&sb->link, rbuf);
233 9083 : sb->flags &= ~SBUF_NEED_LINK;
234 9083 : return PARSE_RET_COMPLETE;
235 : }
236 : else
237 : {
238 0 : log_and_send(asfd, "got non-link after link in manifest");
239 0 : return PARSE_RET_NEED_MORE;
240 : }
241 : }
242 : else
243 : {
244 60492 : iobuf_free_content(&sb->path);
245 60492 : iobuf_move(&sb->path, rbuf);
246 60492 : if(cmd_is_link(rbuf->cmd))
247 : {
248 9083 : sb->flags |= SBUF_NEED_LINK;
249 9083 : return PARSE_RET_NEED_MORE;
250 : }
251 51409 : else if(sb->protocol1
252 12085 : && sb->protocol1->datapth.buf)
253 : {
254 : // Protocol1 client restore reads
255 : // CMD_APPEND and CMD_END_FILE in the
256 : // calling function, so pretend it is
257 : // complete if we have the hack flag.
258 8204 : if(sb->flags & SBUF_CLIENT_RESTORE_HACK)
259 : return PARSE_RET_COMPLETE;
260 8200 : return PARSE_RET_NEED_MORE;
261 : }
262 : return PARSE_RET_COMPLETE;
263 : }
264 : #ifndef HAVE_WIN32
265 : case CMD_SIG:
266 : // Fill in the sig/block, if the caller provided
267 : // a pointer for one. Server only.
268 198406 : if(!blk) return PARSE_RET_NEED_MORE;
269 :
270 : // Just fill in the sig details.
271 46452 : if(blk_set_from_iobuf_sig_and_savepath(blk, rbuf))
272 : return PARSE_RET_ERROR;
273 46452 : blk->got_save_path=1;
274 46452 : iobuf_free_content(rbuf);
275 46452 : if(datpath && rblk_retrieve_data(datpath, blk))
276 : {
277 0 : logp("Could not retrieve blk data.\n");
278 0 : return PARSE_RET_ERROR;
279 : }
280 : return PARSE_RET_COMPLETE;
281 : #endif
282 : case CMD_DATA:
283 : // Need to write the block to disk.
284 : // Client only.
285 14 : if(!blk) return PARSE_RET_NEED_MORE;
286 14 : blk->data=rbuf->buf;
287 14 : blk->length=rbuf->len;
288 14 : rbuf->buf=NULL;
289 14 : return PARSE_RET_COMPLETE;
290 : case CMD_MESSAGE:
291 : case CMD_WARNING:
292 0 : log_recvd(rbuf, cntr, 1);
293 0 : return PARSE_RET_NEED_MORE;
294 : case CMD_GEN:
295 42 : if(!strcmp(rbuf->buf, "restoreend")
296 38 : || !strcmp(rbuf->buf, "phase1end")
297 0 : || !strcmp(rbuf->buf, "backupphase2")
298 : // Think these are protocol1 things.
299 0 : || !strcmp(rbuf->buf, "backupend")
300 0 : || !strcmp(rbuf->buf, "estimateend"))
301 : return PARSE_RET_FINISHED;
302 0 : iobuf_log_unexpected(rbuf, __func__);
303 0 : return PARSE_RET_ERROR;
304 : case CMD_FINGERPRINT:
305 36 : if(blk && blk_set_from_iobuf_fingerprint(blk, rbuf))
306 : return PARSE_RET_ERROR;
307 : // Fall through.
308 : case CMD_MANIFEST:
309 52 : iobuf_free_content(&sb->path);
310 52 : iobuf_move(&sb->path, rbuf);
311 52 : return PARSE_RET_COMPLETE;
312 : case CMD_ERROR:
313 0 : logp("got error: %s\n", rbuf->buf);
314 0 : return PARSE_RET_ERROR;
315 : case CMD_DATAPTH:
316 8205 : if(!sb->protocol1)
317 : {
318 0 : iobuf_log_unexpected(rbuf, __func__);
319 0 : return PARSE_RET_ERROR;
320 : }
321 8205 : if(sb->flags & SBUF_CLIENT_RESTORE_HACK)
322 : {
323 5 : sbuf_free_content(sb);
324 5 : sb->flags |= SBUF_CLIENT_RESTORE_HACK;
325 : }
326 : else
327 8200 : sbuf_free_content(sb);
328 :
329 8205 : iobuf_move(&sb->protocol1->datapth, rbuf);
330 8205 : return PARSE_RET_NEED_MORE;
331 : case CMD_END_FILE:
332 16329 : iobuf_free_content(&sb->endfile);
333 16329 : iobuf_move(&sb->endfile, rbuf);
334 16329 : if(sb->protocol1)
335 : {
336 16340 : if(!sb->attr.buf
337 8170 : || !sb->protocol1->datapth.buf
338 16340 : || (!sbuf_is_filedata(sb)
339 98 : && !sbuf_is_vssdata(sb)))
340 : {
341 0 : logp("got unexpected cmd_endfile");
342 0 : return PARSE_RET_ERROR;
343 : }
344 : }
345 : return PARSE_RET_COMPLETE;
346 : default:
347 0 : iobuf_log_unexpected(rbuf, __func__);
348 0 : return PARSE_RET_ERROR;
349 : }
350 : logp("Fell out of switch unexpectedly in %s()\n", __func__);
351 : return PARSE_RET_ERROR;
352 : }
353 :
354 115527 : static int sbuf_fill(struct sbuf *sb, struct asfd *asfd, struct fzp *fzp,
355 : struct blk *blk, const char *datpath, struct cntr *cntr)
356 : {
357 : static struct iobuf *rbuf;
358 : static struct iobuf localrbuf;
359 115527 : int ret=-1;
360 :
361 115527 : if(asfd) rbuf=asfd->rbuf;
362 : else
363 : {
364 : // If not given asfd, use our own iobuf.
365 : memset(&localrbuf, 0, sizeof(struct iobuf));
366 115475 : rbuf=&localrbuf;
367 : }
368 : while(1)
369 : {
370 353481 : iobuf_free_content(rbuf);
371 353481 : if(fzp)
372 : {
373 353386 : if((ret=iobuf_fill_from_fzp(rbuf, fzp)))
374 : goto end;
375 : }
376 : else
377 : {
378 95 : if(asfd->read(asfd))
379 : {
380 1 : logp("error in async_read\n");
381 1 : break;
382 : }
383 : }
384 353136 : switch(parse_cmd(sb, asfd, rbuf, blk, datpath, cntr))
385 : {
386 : case PARSE_RET_NEED_MORE:
387 : continue;
388 : case PARSE_RET_COMPLETE:
389 : return 0;
390 : case PARSE_RET_FINISHED:
391 : ret=1;
392 : goto end;
393 : case PARSE_RET_ERROR:
394 : default:
395 1 : ret=-1;
396 1 : goto end;
397 : }
398 : }
399 : end:
400 388 : iobuf_free_content(rbuf);
401 388 : return ret;
402 : }
403 :
404 52 : int sbuf_fill_from_net(struct sbuf *sb, struct asfd *asfd,
405 : struct blk *blk, const char *datpath, struct cntr *cntr)
406 : {
407 52 : return sbuf_fill(sb, asfd, NULL, blk, datpath, cntr);
408 : }
409 :
410 115475 : int sbuf_fill_from_file(struct sbuf *sb, struct fzp *fzp,
411 : struct blk *blk, const char *datpath)
412 : {
413 115475 : return sbuf_fill(sb, NULL, fzp, blk, datpath, NULL);
414 : }
|