Line data Source code
1 : #include "../burp.h"
2 : #include "../action.h"
3 : #include "../asfd.h"
4 : #include "../async.h"
5 : #include "../attribs.h"
6 : #include "../cmd.h"
7 : #include "../log.h"
8 : #include "../yajl_gen_w.h"
9 :
10 : static int items_open=0;
11 :
12 0 : static void json_write_all(void)
13 : {
14 : size_t len;
15 : const unsigned char *buf;
16 0 : yajl_gen_get_buf(yajl, &buf, &len);
17 0 : fwrite(buf, 1, len, stdout);
18 0 : yajl_gen_clear(yajl);
19 0 : }
20 :
21 : /* Note: The chars in this function are not the same as in the CMD_ set.
22 : These are for printing to the screen only. */
23 0 : static char *encode_mode(mode_t mode, char *buf)
24 : {
25 0 : char *cp=buf;
26 0 : *cp++=S_ISDIR(mode)?'d':S_ISBLK(mode)?'b':S_ISCHR(mode)?'c':
27 0 : S_ISLNK(mode)?'l':S_ISFIFO(mode)?'p':S_ISSOCK(mode)?'s':'-';
28 0 : *cp++=mode&S_IRUSR?'r':'-';
29 0 : *cp++=mode&S_IWUSR?'w':'-';
30 0 : *cp++=(mode&S_ISUID?(mode&S_IXUSR?'s':'S'):(mode&S_IXUSR?'x':'-'));
31 0 : *cp++=mode&S_IRGRP?'r':'-';
32 0 : *cp++=mode&S_IWGRP?'w':'-';
33 0 : *cp++=(mode&S_ISGID?(mode&S_IXGRP?'s':'S'):(mode&S_IXGRP?'x':'-'));
34 0 : *cp++=mode&S_IROTH?'r':'-';
35 0 : *cp++=mode&S_IWOTH?'w':'-';
36 0 : *cp++=(mode&S_ISVTX?(mode&S_IXOTH?'t':'T'):(mode&S_IXOTH?'x':'-'));
37 0 : *cp='\0';
38 0 : return cp;
39 : }
40 :
41 0 : static char *encode_time(uint64_t utime, char *buf)
42 : {
43 : const struct tm *tm;
44 0 : int n=0;
45 0 : time_t time=utime;
46 :
47 : #ifdef HAVE_WIN32
48 : /* Avoid a seg fault in Microsoft's CRT localtime_r(),
49 : * which incorrectly references a NULL returned from gmtime() if
50 : * time is negative before or after the timezone adjustment. */
51 : struct tm *gtm;
52 :
53 : if(!(gtm=gmtime(&time))) return buf;
54 :
55 : if(gtm->tm_year==1970 && gtm->tm_mon==1 && gtm->tm_mday<3) return buf;
56 : #endif
57 :
58 0 : if((tm=localtime(&time)))
59 : n=sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d",
60 : tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
61 0 : tm->tm_hour, tm->tm_min, tm->tm_sec);
62 0 : return buf+n;
63 : }
64 :
65 0 : void ls_to_buf(char *lsbuf, struct sbuf *sb)
66 : {
67 : int n;
68 : char *p;
69 : time_t time;
70 : const char *f;
71 0 : struct stat *statp=&sb->statp;
72 0 : *lsbuf='\0';
73 :
74 0 : p=encode_mode(statp->st_mode, lsbuf);
75 0 : n=sprintf(p, " %2d ", (uint32_t)statp->st_nlink);
76 0 : p+=n;
77 : n=sprintf(p, "%5d %5d", (uint32_t)statp->st_uid,
78 0 : (uint32_t)statp->st_gid);
79 0 : p+=n;
80 0 : n=sprintf(p, " %7lu ", (unsigned long)statp->st_size);
81 0 : p+=n;
82 0 : if(statp->st_ctime>statp->st_mtime) time=statp->st_ctime;
83 0 : else time=statp->st_mtime;
84 :
85 : // Display most recent time.
86 0 : p=encode_time(time, p);
87 0 : *p++=' ';
88 0 : for(f=sb->path.buf; *f; ) *p++=*f++;
89 0 : *p=0;
90 0 : }
91 :
92 0 : static void ls_long_output(struct sbuf *sb)
93 : {
94 : static char lsbuf[2048];
95 0 : ls_to_buf(lsbuf, sb);
96 0 : printf("%s", lsbuf);
97 0 : if(sb->link.buf) printf(" -> %s", sb->link.buf);
98 0 : printf("\n");
99 0 : }
100 :
101 0 : static void ls_long_output_json(struct sbuf *sb)
102 : {
103 0 : struct stat *statp=&sb->statp;
104 :
105 0 : yajl_map_open_w();
106 0 : yajl_gen_str_pair_w("name", sb->path.buf?sb->path.buf:"");
107 0 : yajl_gen_str_pair_w("link", sb->link.buf?sb->link.buf:"");
108 0 : yajl_gen_int_pair_w("st_dev", (long long)statp->st_dev);
109 0 : yajl_gen_int_pair_w("st_ino", (long long)statp->st_ino);
110 0 : yajl_gen_int_pair_w("st_mode", (long long)statp->st_mode);
111 0 : yajl_gen_int_pair_w("st_nlink", (long long)statp->st_nlink);
112 0 : yajl_gen_int_pair_w("st_uid", (long long)statp->st_uid);
113 0 : yajl_gen_int_pair_w("st_gid", (long long)statp->st_gid);
114 0 : yajl_gen_int_pair_w("st_rdev", (long long)statp->st_rdev);
115 0 : yajl_gen_int_pair_w("st_size", (long long)statp->st_size);
116 0 : yajl_gen_int_pair_w("st_atime", (long long)statp->st_atime);
117 0 : yajl_gen_int_pair_w("st_mtime", (long long)statp->st_mtime);
118 0 : yajl_gen_int_pair_w("st_ctime", (long long)statp->st_ctime);
119 0 : yajl_map_close_w();
120 0 : }
121 :
122 0 : static void json_backup(char *statbuf, struct conf **confs)
123 : {
124 0 : char *cp=NULL;
125 0 : if((cp=strstr(statbuf, " (deletable)")))
126 : {
127 0 : *cp='\0';
128 0 : cp++;
129 : }
130 :
131 0 : if(items_open)
132 : {
133 0 : yajl_array_close_w();
134 0 : yajl_map_close_w();
135 0 : items_open=0;
136 : }
137 :
138 0 : yajl_map_open_w();
139 0 : yajl_gen_str_pair_w("timestamp", statbuf);
140 0 : yajl_gen_int_pair_w("deletable", cp?(long long)1:(long long)0);
141 :
142 0 : if(get_string(confs[OPT_BACKUP]))
143 : {
144 0 : const char *browsedir=get_string(confs[OPT_BROWSEDIR]);
145 0 : const char *regex=get_string(confs[OPT_REGEX]);
146 : yajl_gen_str_pair_w("directory",
147 0 : browsedir?browsedir:"");
148 : yajl_gen_str_pair_w("regex",
149 0 : regex?regex:"");
150 0 : yajl_gen_str_w("items");
151 0 : yajl_array_open_w();
152 0 : items_open=1;
153 : }
154 : else
155 0 : yajl_map_close_w();
156 0 : json_write_all();
157 0 : }
158 :
159 0 : static void ls_short_output(struct sbuf *sb)
160 : {
161 0 : printf("%s\n", sb->path.buf);
162 0 : }
163 :
164 0 : static void ls_short_output_json(struct sbuf *sb)
165 : {
166 0 : yajl_map_open_w();
167 0 : yajl_gen_str_pair_w("name", sb->path.buf);
168 0 : yajl_map_close_w();
169 0 : }
170 :
171 0 : static void list_item(int json, enum action act, struct sbuf *sb)
172 : {
173 0 : if(act==ACTION_LIST_LONG)
174 : {
175 0 : if(json) ls_long_output_json(sb);
176 0 : else ls_long_output(sb);
177 : }
178 : else
179 : {
180 0 : if(json) ls_short_output_json(sb);
181 0 : else ls_short_output(sb);
182 : }
183 0 : if(json) json_write_all();
184 0 : }
185 :
186 0 : int do_list_client(struct asfd *asfd,
187 : enum action act, int json, struct conf **confs)
188 : {
189 0 : int ret=-1;
190 0 : char msg[512]="";
191 0 : char *dpth=NULL;
192 0 : struct sbuf *sb=NULL;
193 0 : struct iobuf *rbuf=asfd->rbuf;
194 0 : const char *backup=get_string(confs[OPT_BACKUP]);
195 0 : const char *browsedir=get_string(confs[OPT_BROWSEDIR]);
196 0 : const char *regex=get_string(confs[OPT_REGEX]);
197 : //logp("in do_list\n");
198 :
199 0 : if(browsedir)
200 : snprintf(msg, sizeof(msg), "listb %s:%s",
201 0 : backup?backup:"", browsedir);
202 : else
203 : snprintf(msg, sizeof(msg), "list %s:%s",
204 0 : backup?backup:"", regex?regex:"");
205 0 : if(asfd->write_str(asfd, CMD_GEN, msg)
206 0 : || asfd->read_expect(asfd, CMD_GEN, "ok"))
207 0 : goto end;
208 :
209 0 : if(!(sb=sbuf_alloc(get_protocol(confs)))) goto end;
210 0 : iobuf_init(&sb->path);
211 0 : iobuf_init(&sb->link);
212 0 : iobuf_init(&sb->attr);
213 :
214 0 : if(json)
215 : {
216 0 : if(!(yajl=yajl_gen_alloc(NULL)))
217 0 : goto end;
218 0 : yajl_gen_config(yajl, yajl_gen_beautify, 1);
219 0 : if(yajl_map_open_w()
220 0 : || yajl_gen_str_w("backups")
221 0 : || yajl_array_open_w())
222 0 : goto end;
223 : }
224 :
225 : // This should probably should use the sbuf stuff.
226 : while(1)
227 : {
228 0 : sbuf_free_content(sb);
229 :
230 0 : iobuf_free_content(rbuf);
231 0 : if(asfd->read(asfd)) break;
232 0 : if(rbuf->cmd==CMD_TIMESTAMP)
233 : {
234 : // A backup timestamp, just print it.
235 0 : if(json) json_backup(rbuf->buf, confs);
236 : else
237 : {
238 0 : printf("Backup: %s\n", rbuf->buf);
239 0 : if(browsedir)
240 : printf("Listing directory: %s\n",
241 0 : browsedir);
242 0 : if(regex)
243 : printf("With regex: %s\n",
244 0 : regex);
245 : }
246 0 : continue;
247 : }
248 0 : else if(rbuf->cmd!=CMD_ATTRIBS)
249 : {
250 0 : iobuf_log_unexpected(rbuf, __func__);
251 0 : goto end;
252 : }
253 0 : iobuf_copy(&sb->attr, rbuf);
254 0 : iobuf_init(rbuf);
255 :
256 0 : attribs_decode(sb);
257 :
258 0 : if(asfd->read(asfd))
259 : {
260 0 : logp("got stat without an object\n");
261 0 : goto end;
262 : }
263 0 : iobuf_copy(&sb->path, rbuf);
264 0 : iobuf_init(rbuf);
265 :
266 0 : if(sb->path.cmd==CMD_DIRECTORY
267 0 : || sb->path.cmd==CMD_FILE
268 0 : || sb->path.cmd==CMD_ENC_FILE
269 0 : || sb->path.cmd==CMD_EFS_FILE
270 0 : || sb->path.cmd==CMD_SPECIAL)
271 : {
272 0 : list_item(json, act, sb);
273 : }
274 0 : else if(cmd_is_link(sb->path.cmd)) // symlink or hardlink
275 : {
276 0 : if(asfd->read(asfd)
277 0 : || rbuf->cmd!=sb->path.cmd)
278 : {
279 : logp("could not get link %c:%s\n",
280 0 : sb->path.cmd, sb->path.buf);
281 0 : goto end;
282 : }
283 0 : iobuf_copy(&sb->link, rbuf);
284 0 : iobuf_init(rbuf);
285 0 : list_item(json, act, sb);
286 : }
287 : else
288 : {
289 : fprintf(stderr, "unlistable %c:%s\n",
290 0 : sb->path.cmd, sb->path.buf?sb->path.buf:"");
291 : }
292 : }
293 :
294 0 : ret=0;
295 : end:
296 0 : if(json && yajl)
297 : {
298 0 : if(items_open)
299 : {
300 0 : yajl_array_close_w();
301 0 : yajl_map_close_w();
302 0 : items_open=0;
303 : }
304 0 : yajl_array_close_w();
305 0 : yajl_map_close_w();
306 0 : json_write_all();
307 0 : yajl_gen_free(yajl);
308 0 : yajl=NULL;
309 : }
310 :
311 0 : if(sb)
312 : {
313 0 : iobuf_free_content(&sb->path);
314 0 : iobuf_free_content(&sb->link);
315 0 : iobuf_free_content(&sb->attr);
316 0 : sbuf_free(&sb);
317 : }
318 0 : if(dpth) free(dpth);
319 0 : if(!ret) logp("List finished ok\n");
320 0 : return ret;
321 : }
|