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