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