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 "manio.h"
15 :
16 : // Want to make sure that we are listening for reads too - this will let us
17 : // exit promptly if the client was killed.
18 : // FIX THIS: Maybe some of this should go in async.c/asfd.c.
19 0 : static int read_and_write(struct asfd *asfd)
20 : {
21 0 : if(asfd->as->read_write(asfd->as)) return -1;
22 0 : if(!asfd->rbuf->buf) return 0;
23 0 : iobuf_log_unexpected(asfd->rbuf, __func__);
24 0 : return -1;
25 : }
26 :
27 0 : static int flush_asio(struct asfd *asfd)
28 : {
29 0 : while(asfd->writebuflen>0)
30 0 : if(read_and_write(asfd)) return -1;
31 0 : return 0;
32 : }
33 :
34 0 : static int write_wrapper(struct asfd *asfd, struct iobuf *wbuf)
35 : {
36 : while(1)
37 : {
38 0 : switch(asfd->append_all_to_write_buffer(asfd, wbuf))
39 : {
40 0 : case APPEND_OK: return 0;
41 0 : case APPEND_BLOCKED: break;
42 0 : default: return -1;
43 : }
44 0 : if(read_and_write(asfd)) return -1;
45 : }
46 : return 0;
47 : }
48 :
49 0 : static int write_wrapper_str(struct asfd *asfd, enum cmd wcmd, const char *wsrc)
50 : {
51 : static struct iobuf wbuf;
52 0 : wbuf.cmd=wcmd;
53 0 : wbuf.buf=(char *)wsrc;
54 0 : wbuf.len=strlen(wsrc);
55 0 : return write_wrapper(asfd, &wbuf);
56 : }
57 :
58 0 : int check_browsedir(const char *browsedir,
59 : struct sbuf *mb, size_t bdlen, char **last_bd_match)
60 : {
61 0 : char *cp=mb->path.buf;
62 0 : char *copy=NULL;
63 0 : if(bdlen>0)
64 : {
65 0 : if(strncmp(browsedir, cp, bdlen))
66 0 : return 0;
67 0 : cp+=bdlen;
68 0 : if(browsedir[bdlen-1]!='/')
69 : {
70 0 : if(*cp!='\0')
71 : {
72 0 : if(*cp!='/') return 0;
73 0 : cp++;
74 : }
75 : }
76 : }
77 0 : if(*cp=='\0') cp=(char *)".";
78 0 : if(!(copy=strdup_w(cp, __func__))) goto err;
79 0 : if((cp=strchr(copy, '/')))
80 : {
81 0 : if(bdlen==0) cp++;
82 0 : *cp='\0';
83 :
84 0 : if(!S_ISDIR(mb->statp.st_mode))
85 : {
86 : // We are faking a directory entry.
87 : // Make sure the directory bit is set.
88 0 : mb->statp.st_mode &= ~(S_IFMT);
89 0 : mb->statp.st_mode |= S_IFDIR;
90 0 : attribs_encode(mb);
91 : }
92 : }
93 :
94 : // Strip off possible trailing slash.
95 0 : if((cp=strrchr(copy, '/')) && cp>copy) *cp='\0';
96 :
97 0 : if(*last_bd_match)
98 : {
99 0 : if(!strcmp(*last_bd_match, copy))
100 : {
101 : // Got a duplicate match.
102 0 : free(copy);
103 0 : return 0;
104 : }
105 0 : free(*last_bd_match);
106 : }
107 0 : free(mb->path.buf);
108 0 : mb->path.buf=copy;
109 0 : if(!(*last_bd_match=strdup_w(copy, __func__)))
110 0 : goto err;
111 0 : return 1;
112 : err:
113 0 : if(copy) free(copy);
114 0 : log_out_of_memory(__func__);
115 0 : return -1;
116 : }
117 :
118 0 : static int list_manifest(struct asfd *asfd,
119 : const char *fullpath, regex_t *regex,
120 : const char *browsedir, struct cntr *cntr, enum protocol protocol)
121 : {
122 0 : int ret=0;
123 0 : struct sbuf *sb=NULL;
124 0 : struct manio *manio=NULL;
125 0 : char *manifest_dir=NULL;
126 0 : char *last_bd_match=NULL;
127 0 : size_t bdlen=0;
128 :
129 0 : if(!(manifest_dir=prepend_s(fullpath,
130 0 : protocol==PROTO_1?"manifest.gz":"manifest"))
131 0 : || !(manio=manio_open(manifest_dir, "rb", protocol))
132 0 : || !(sb=sbuf_alloc(protocol)))
133 : {
134 0 : log_and_send_oom(asfd, __func__);
135 0 : goto error;
136 : }
137 :
138 0 : if(browsedir) bdlen=strlen(browsedir);
139 :
140 : while(1)
141 : {
142 0 : int show=0;
143 0 : sbuf_free_content(sb);
144 :
145 0 : switch(manio_read(manio, sb))
146 : {
147 0 : case 0: break;
148 0 : case 1: if(browsedir && *browsedir && !last_bd_match)
149 : write_wrapper_str(asfd, CMD_ERROR,
150 0 : "directory not found");
151 0 : goto end; // Finished OK.
152 0 : default: goto error;
153 : }
154 :
155 0 : if(protocol==PROTO_2 && sb->endfile.buf)
156 0 : continue;
157 0 : if(sbuf_is_metadata(sb))
158 0 : continue;
159 :
160 0 : if(write_status(CNTR_STATUS_LISTING, sb->path.buf, cntr))
161 0 : goto error;
162 :
163 0 : if(browsedir)
164 : {
165 : int r;
166 0 : if((r=check_browsedir(browsedir,
167 0 : sb, bdlen, &last_bd_match))<0)
168 0 : goto error;
169 0 : if(!r) continue;
170 0 : show++;
171 : }
172 : else
173 : {
174 0 : if(check_regex(regex, sb->path.buf))
175 0 : show++;
176 : }
177 0 : if(show)
178 : {
179 0 : if(write_wrapper(asfd, &sb->attr)
180 0 : || write_wrapper(asfd, &sb->path))
181 0 : goto error;
182 0 : if(sbuf_is_link(sb)
183 0 : && write_wrapper(asfd, &sb->link))
184 0 : goto error;
185 : }
186 : }
187 :
188 : error:
189 0 : ret=-1;
190 : end:
191 0 : sbuf_free(&sb);
192 0 : free_w(&manifest_dir);
193 0 : manio_close(&manio);
194 0 : free_w(&last_bd_match);
195 0 : return ret;
196 : }
197 :
198 0 : static int send_backup_name_to_client(struct asfd *asfd,
199 : struct bu *bu, enum protocol protocol)
200 : {
201 0 : char msg[64]="";
202 : snprintf(msg, sizeof(msg), "%s%s",
203 : bu->timestamp,
204 : // Protocol2 backups are all deletable, so do not mention it.
205 : protocol==PROTO_1
206 0 : && (bu->flags & BU_DELETABLE)?" (deletable)":"");
207 0 : return write_wrapper_str(asfd, CMD_TIMESTAMP, msg);
208 : }
209 :
210 0 : int do_list_server(struct asfd *asfd, struct sdirs *sdirs, struct cntr *cntr,
211 : enum protocol protocol,
212 : const char *backup, const char *listregex, const char *browsedir)
213 : {
214 0 : int ret=-1;
215 0 : uint8_t found=0;
216 0 : unsigned long bno=0;
217 0 : regex_t *regex=NULL;
218 0 : struct bu *bu=NULL;
219 0 : struct bu *bu_list=NULL;
220 :
221 : //logp("in do_list_server\n");
222 :
223 0 : if(compile_regex(®ex, listregex)
224 0 : || bu_get_list(sdirs, &bu_list)
225 0 : || write_status(CNTR_STATUS_LISTING, NULL, cntr))
226 0 : goto end;
227 :
228 0 : if(backup && *backup) bno=strtoul(backup, NULL, 10);
229 :
230 0 : for(bu=bu_list; bu; bu=bu->next)
231 : {
232 : // Search all backups for things matching the regex.
233 0 : if(listregex && backup && *backup=='a')
234 : {
235 0 : found=1;
236 0 : if(write_wrapper_str(asfd,
237 0 : CMD_TIMESTAMP, bu->timestamp)
238 0 : || list_manifest(asfd, bu->path,
239 0 : regex, browsedir, cntr, protocol)) goto end;
240 : }
241 : // Search or list a particular backup.
242 0 : else if(backup && *backup)
243 : {
244 0 : if(!found
245 0 : && (!strcmp(bu->timestamp, backup)
246 0 : || bu->bno==bno
247 0 : || (*backup=='c' && (bu->flags & BU_CURRENT))))
248 : {
249 0 : found=1;
250 0 : if(send_backup_name_to_client(asfd,
251 0 : bu, protocol)
252 0 : || list_manifest(asfd, bu->path, regex,
253 0 : browsedir, cntr, protocol)) goto end;
254 : }
255 : }
256 : // List the backups.
257 : else
258 : {
259 0 : found=1;
260 0 : if(send_backup_name_to_client(asfd, bu, protocol))
261 0 : goto end;
262 : }
263 : }
264 :
265 0 : if(backup && *backup && !found)
266 : {
267 0 : write_wrapper_str(asfd, CMD_ERROR, "backup not found");
268 0 : flush_asio(asfd);
269 0 : goto end;
270 : }
271 :
272 0 : if(flush_asio(asfd)) goto end;
273 :
274 0 : ret=0;
275 : end:
276 0 : if(regex) { regfree(regex); free(regex); }
277 0 : bu_list_free(&bu);
278 0 : return ret;
279 : }
|