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