Line data Source code
1 : #include "../burp.h"
2 : #include "../alloc.h"
3 : #include "../asfd.h"
4 : #include "../async.h"
5 : #include "../attribs.h"
6 : #include "../bu.h"
7 : #include "../cmd.h"
8 : #include "../cntr.h"
9 : #include "../cstat.h"
10 : #include "../log.h"
11 : #include "../prepend.h"
12 : #include "../regexp.h"
13 : #include "bu_get.h"
14 : #include "child.h"
15 : #include "list.h"
16 : #include "manio.h"
17 :
18 : enum list_mode
19 : {
20 : LIST_MODE_BACKUPS=0,
21 : LIST_MODE_CONTENTS_ONE,
22 : LIST_MODE_CONTENTS_MANY,
23 : };
24 :
25 : static struct asfd *asfd;
26 : static struct conf **confs;
27 : static struct cntr *cntr;
28 : static enum protocol protocol;
29 : static const char *backup;
30 : static regex_t *regex=NULL;
31 : static const char *browsedir;
32 : static struct bu *bu_list=NULL;
33 : static enum list_mode list_mode;
34 : static unsigned long bno=0;
35 :
36 57 : int list_server_init(
37 : struct asfd *a,
38 : struct sdirs *s,
39 : struct conf **c,
40 : enum protocol p,
41 : const char *backup_str,
42 : const char *regex_str,
43 : const char *browsedir_str)
44 : {
45 57 : asfd=a;
46 57 : confs=c;
47 57 : protocol=p;
48 57 : backup=backup_str;
49 57 : browsedir=browsedir_str;
50 57 : if (confs)
51 1 : cntr=get_cntr(confs);
52 :
53 57 : if(bu_get_list_with_working(s, &bu_list))
54 : goto error;
55 57 : if(regex_str
56 9 : && *regex_str
57 9 : && !(regex=regex_compile(regex_str)))
58 : {
59 1 : char msg[256]="";
60 1 : snprintf(msg, sizeof(msg), "unable to compile regex: %s\n",
61 : regex_str);
62 1 : log_and_send(asfd, msg);
63 : goto error;
64 : }
65 56 : list_mode=LIST_MODE_BACKUPS;
66 56 : if(regex || browsedir)
67 16 : list_mode=LIST_MODE_CONTENTS_MANY;
68 56 : if(backup && *backup)
69 : {
70 42 : if((bno=strtoul(backup, NULL, 10))>0)
71 19 : list_mode=LIST_MODE_CONTENTS_ONE;
72 23 : else if(*backup=='c')
73 8 : list_mode=LIST_MODE_CONTENTS_ONE;
74 15 : else if(*backup=='a')
75 11 : list_mode=LIST_MODE_CONTENTS_MANY;
76 : else
77 4 : list_mode=LIST_MODE_CONTENTS_ONE;
78 : }
79 : return 0;
80 : error:
81 : list_server_free();
82 1 : return -1;
83 : }
84 :
85 57 : void list_server_free(void)
86 : {
87 58 : bu_list_free(&bu_list);
88 58 : regex_free(®ex);
89 57 : }
90 :
91 : #ifndef UTEST
92 : static
93 : #endif
94 51 : void maybe_fake_directory(struct sbuf *mb)
95 : {
96 51 : if(S_ISDIR(mb->statp.st_mode))
97 : return;
98 : // We are faking a directory entry.
99 : // Make sure the directory bit is set.
100 49 : mb->statp.st_mode &= ~(S_IFMT);
101 49 : mb->statp.st_mode |= S_IFDIR;
102 :
103 : // Need to free attr so that it is reallocated, because it may get
104 : // longer than what we initially had.
105 49 : iobuf_free_content(&mb->attr);
106 49 : attribs_encode(mb);
107 : }
108 :
109 77 : int check_browsedir(const char *browsedir,
110 : struct sbuf *mb, size_t bdlen, char **last_bd_match)
111 : {
112 77 : char *cp=mb->path.buf;
113 77 : char *copy=NULL;
114 77 : if(bdlen>0)
115 : {
116 42 : if(strncmp(browsedir, cp, bdlen))
117 : return 0;
118 30 : cp+=bdlen;
119 30 : if(browsedir[bdlen-1]!='/')
120 : {
121 24 : if(*cp!='\0')
122 : {
123 20 : if(*cp!='/')
124 : return 0;
125 18 : cp++;
126 : }
127 : }
128 : }
129 63 : if(*cp=='\0')
130 8 : cp=(char *)".";
131 63 : if(!(copy=strdup_w(cp, __func__)))
132 : goto error;
133 62 : if((cp=strchr(copy, '/')))
134 : {
135 40 : if(bdlen==0) cp++;
136 40 : *cp='\0';
137 :
138 40 : maybe_fake_directory(mb);
139 : }
140 22 : else if(!strcmp(mb->path.buf, "/")
141 2 : && !strcmp(browsedir, "/"))
142 2 : maybe_fake_directory(mb);
143 20 : else if(mb->path.cmd==CMD_DIRECTORY)
144 8 : maybe_fake_directory(mb);
145 :
146 : // Strip off possible trailing slash.
147 62 : if((cp=strrchr(copy, '/')) && cp>copy)
148 14 : *cp='\0';
149 :
150 62 : if(*last_bd_match
151 50 : && !strcmp(*last_bd_match, copy))
152 : {
153 : // Got a duplicate match.
154 22 : free_w(©);
155 22 : return 0;
156 : }
157 40 : free_w(&mb->path.buf);
158 40 : mb->path.buf=copy;
159 40 : free_w(last_bd_match);
160 40 : if(!(*last_bd_match=strdup_w(copy, __func__)))
161 : goto error;
162 : return 1;
163 : error:
164 1 : free_w(©);
165 1 : log_out_of_memory(__func__);
166 1 : return -1;
167 : }
168 :
169 0 : static int list_manifest(const char *fullpath)
170 : {
171 0 : int ret=0;
172 0 : struct sbuf *sb=NULL;
173 0 : struct manio *manio=NULL;
174 0 : char *manifest_dir=NULL;
175 0 : char *last_bd_match=NULL;
176 0 : size_t bdlen=0;
177 :
178 0 : if(!(manifest_dir=prepend_s(fullpath,
179 0 : protocol==PROTO_1?"manifest.gz":"manifest"))
180 0 : || !(manio=manio_open(manifest_dir, "rb", protocol))
181 0 : || !(sb=sbuf_alloc(protocol)))
182 : {
183 0 : log_and_send_oom(asfd);
184 0 : goto error;
185 : }
186 :
187 0 : if(browsedir) bdlen=strlen(browsedir);
188 :
189 : while(1)
190 : {
191 0 : sbuf_free_content(sb);
192 :
193 0 : switch(manio_read(manio, sb))
194 : {
195 : case 0: break;
196 0 : case 1: if(browsedir && *browsedir && !last_bd_match)
197 0 : asfd_write_wrapper_str(asfd,
198 : CMD_ERROR,
199 : "directory not found");
200 : goto end; // Finished OK.
201 : default: goto error;
202 : }
203 :
204 0 : if(protocol==PROTO_2 && sb->endfile.buf)
205 0 : continue;
206 0 : if(sbuf_is_metadata(sb))
207 0 : continue;
208 :
209 0 : if(timed_operation_status_only(CNTR_STATUS_LISTING,
210 0 : sb->path.buf, confs)) goto error;
211 :
212 0 : if(browsedir)
213 : {
214 : int r;
215 0 : if((r=check_browsedir(browsedir,
216 : sb, bdlen, &last_bd_match))<0)
217 : goto error;
218 0 : if(!r) continue;
219 : }
220 :
221 0 : if(regex && !regex_check(regex, sb->path.buf))
222 0 : continue;
223 :
224 0 : if(asfd_write_wrapper(asfd, &sb->attr)
225 0 : || asfd_write_wrapper(asfd, &sb->path))
226 : goto error;
227 0 : if(sbuf_is_link(sb)
228 0 : && asfd_write_wrapper(asfd, &sb->link))
229 : goto error;
230 : }
231 :
232 : error:
233 : ret=-1;
234 : end:
235 0 : sbuf_free(&sb);
236 0 : free_w(&manifest_dir);
237 0 : manio_close(&manio);
238 0 : free_w(&last_bd_match);
239 0 : return ret;
240 : }
241 :
242 73 : static char *get_extradesc(struct bu *bu)
243 : {
244 73 : if(bu->flags & BU_WORKING)
245 0 : return strdup_w(" (working)", __func__);
246 73 : else if(bu->flags & BU_FINISHING)
247 0 : return strdup_w(" (finishing)", __func__);
248 : // Protocol2 backups are all deletable, so do not mention it.
249 73 : else if(bu->flags & BU_DELETABLE && protocol==1)
250 19 : return strdup_w(" (deletable)", __func__);
251 54 : return strdup_w("", __func__);
252 : }
253 :
254 73 : static int send_backup_name_to_client(struct bu *bu)
255 : {
256 : int ret;
257 73 : char msg[64]="";
258 : char *extradesc;
259 73 : if(!(extradesc=get_extradesc(bu)))
260 : return -1;
261 73 : snprintf(msg, sizeof(msg), "%s%s", bu->timestamp, extradesc);
262 73 : ret=asfd_write_wrapper_str(asfd, CMD_TIMESTAMP, msg);
263 73 : free_w(&extradesc);
264 73 : return ret;
265 : }
266 :
267 : static int list_all_backups(void)
268 : {
269 10 : int found=0;
270 10 : struct bu *bu=NULL;
271 24 : for(bu=bu_list; bu; bu=bu->next)
272 : {
273 15 : found=1;
274 15 : if(send_backup_name_to_client(bu))
275 : return -1;
276 : }
277 : return found;
278 : }
279 :
280 31 : static int list_contents_one(
281 : int list_server_callback(const char *fullpath))
282 : {
283 31 : struct bu *bu=NULL;
284 73 : for(bu=bu_list; bu; bu=bu->next)
285 : {
286 65 : if(!strcmp(bu->timestamp, backup)
287 65 : || bu->bno==bno
288 50 : || (*backup=='c' && (bu->flags & BU_CURRENT)))
289 : {
290 23 : if(cntr)
291 0 : cntr->bno=bu->bno;
292 23 : if(send_backup_name_to_client(bu)
293 22 : || list_server_callback(bu->path))
294 : return -1;
295 : return 1;
296 : }
297 : }
298 : return 0;
299 : }
300 :
301 15 : static int list_contents_many(
302 : int list_server_callback(const char *fullpath))
303 : {
304 15 : int found=0;
305 15 : struct bu *bu=NULL;
306 47 : for(bu=bu_list; bu; bu=bu->next)
307 : {
308 35 : found=1;
309 35 : if(cntr)
310 0 : cntr->bno=bu->bno;
311 35 : if(send_backup_name_to_client(bu)
312 34 : || list_server_callback(bu->path))
313 : return -1;
314 : }
315 : return found;
316 : }
317 :
318 : #ifndef UTEST
319 : static
320 : #endif
321 56 : int do_list_server_work(
322 : int list_server_callback(const char *fullpath))
323 : {
324 56 : int ret=-1;
325 56 : int found=0;
326 :
327 : //logp("in do_list_server\n");
328 :
329 56 : if(timed_operation_status_only(CNTR_STATUS_LISTING, NULL, confs))
330 : goto end;
331 :
332 56 : switch(list_mode)
333 : {
334 : case LIST_MODE_BACKUPS:
335 10 : if((found=list_all_backups())<0)
336 : goto end;
337 : break;
338 : case LIST_MODE_CONTENTS_ONE:
339 31 : if((found=list_contents_one(list_server_callback))<0)
340 : goto end;
341 : break;
342 : case LIST_MODE_CONTENTS_MANY:
343 15 : if((found=list_contents_many(list_server_callback))<0)
344 : goto end;
345 : break;
346 : }
347 :
348 49 : if(!found)
349 : {
350 11 : if(list_mode==LIST_MODE_BACKUPS)
351 : {
352 3 : asfd_write_wrapper_str(asfd,
353 : CMD_MESSAGE, "no backups");
354 : // Success.
355 : }
356 : else
357 : {
358 8 : asfd_write_wrapper_str(asfd,
359 : CMD_MESSAGE, "backup not found");
360 8 : goto end;
361 : }
362 : }
363 :
364 : ret=0;
365 : end:
366 56 : bu_list_free(&bu_list);
367 56 : return ret;
368 : }
369 :
370 1 : int do_list_server(void)
371 : {
372 1 : return do_list_server_work(list_manifest);
373 : }
|