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