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