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