1 /* $Copyright: $
2 * Copyright (c) 1996 - 2018 by Steve Baker (ice@mama.indstate.edu)
3 * All Rights reserved
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19 #include "tree.h"
20
21 extern bool dflag, lflag, pflag, sflag, Fflag, aflag, fflag, uflag, gflag;
22 extern bool Dflag, inodeflag, devflag, Rflag, cflag, hflag, siflag;
23 extern bool noindent, force_color, xdev, nolinks, flimit;
24
25 extern const int ifmt[];
26 extern const char fmt[], *ftype[];
27
28 extern struct _info **(*getfulltree)(char *d, u_long lev, dev_t dev, off_t *size, char **err);
29 extern void (*listdir)(char *, int *, int *, u_long, dev_t);
30 extern int (*cmpfunc)();
31 extern FILE *outfile;
32 extern int Level, *dirs, maxdirs;
33
34 extern char *endcode;
35
36 /* JSON code courtesy of Florian Sesser <fs@it-agenten.com>
37 [
38 {"type": "directory", "name": "name", "mode": "0777", "user": "user", "group": "group", "inode": ###, "dev": ####, "time": "00:00 00-00-0000", "contents": [
39 {"type": "link", "name": "name", "target": "name", "contents": [... if link is followed, otherwise this is empty.]}
40 {"type": "file", "name": "name", "mode": "0777", "size": ###, "group": "group", "inode": ###, "dev": ###, "time": "00:00 00-00-0000"}
41 {"type": "socket", "name": "", "error": "some error" ...}
42 {"type": "block", "name": "" ...},
43 {"type": "char", "name": "" ...},
44 {"type": "fifo", "name": "" ...},
45 {"type": "door", "name": "" ...},
46 {"type": "port", "name": "" ...}
47 ]},
48 {"type": "report", "size": ###, "files": ###, "directories": ###}
49 ]
50 */
51
json_listdir(char * d,int * dt,int * ft,u_long lev,dev_t dev)52 off_t json_listdir(char *d, int *dt, int *ft, u_long lev, dev_t dev)
53 {
54 char *path;
55 bool nlf = FALSE;
56 long pathsize = 0;
57 struct _info **dir, **sav;
58 struct stat sb;
59 int t, n, mt;
60
61 if ((Level >= 0) && (lev > Level)) {
62 if (!noindent) fputc('\n',outfile);
63 return 0;
64 }
65
66 if (xdev && lev == 0) {
67 stat(d,&sb);
68 dev = sb.st_dev;
69 }
70
71 sav = dir = read_dir(d,&n);
72 if (!dir && n) {
73 fprintf(outfile,"{\"error\": \"opening dir\"}%s",noindent?"":"\n");
74 return 0;
75 }
76 if (!n) {
77 if (!noindent) fputc('\n', outfile);
78 free_dir(sav);
79 return 0;
80 }
81 if (flimit > 0 && n > flimit) {
82 fprintf(outfile,", \"error\": \"%d entries exceeds filelimit, not opening dir\"\n",n);
83 free_dir(sav);
84 return 0;
85 }
86
87 if (cmpfunc) qsort(dir,n,sizeof(struct _info *),cmpfunc);
88 if (lev >= maxdirs-1) {
89 dirs = xrealloc(dirs,sizeof(int) * (maxdirs += 1024));
90 memset(dirs+(maxdirs-1024), 0, sizeof(int) * 1024);
91 }
92 dirs[lev] = 1;
93 if (!*(dir+1)) dirs[lev] = 2;
94 if (!noindent) fprintf(outfile,"\n");
95
96 path = malloc(pathsize=4096);
97
98 while(*dir) {
99 if (!noindent) json_indent(lev);
100
101 if ((*dir)->lnk) mt = (*dir)->mode & S_IFMT;
102 else mt = (*dir)->mode & S_IFMT;
103 for(t=0;ifmt[t];t++)
104 if (ifmt[t] == mt) break;
105 fprintf(outfile,"{\"type\":\"%s\"", ftype[t]);
106
107 if (fflag) {
108 if (sizeof(char) * (strlen(d)+strlen((*dir)->name)+2) > pathsize)
109 path=xrealloc(path,pathsize=(sizeof(char) * (strlen(d)+strlen((*dir)->name)+1024)));
110 if (!strcmp(d,"/")) sprintf(path,"%s%s",d,(*dir)->name);
111 else sprintf(path,"%s/%s",d,(*dir)->name);
112 } else {
113 if (sizeof(char) * (strlen((*dir)->name)+1) > pathsize)
114 path=xrealloc(path,pathsize=(sizeof(char) * (strlen((*dir)->name)+1024)));
115 sprintf(path,"%s",(*dir)->name);
116 }
117
118 fprintf(outfile, ",\"name\":\"");
119 html_encode(outfile,path);
120 fputc('"',outfile);
121
122 if ((*dir)->lnk) {
123 fprintf(outfile, ",\"target\":\"");
124 html_encode(outfile,(*dir)->lnk);
125 fputc('"',outfile);
126 }
127 json_fillinfo(*dir);
128 if (!(*dir)->isdir && !(*dir)->lnk) {
129 fputc('}',outfile);
130 if (*(dir+1)) fputc(',',outfile);
131 } else
132 fprintf(outfile, ",\"contents\":[");
133
134 if ((*dir)->isdir) {
135 if ((*dir)->lnk) {
136 if (lflag && !(xdev && dev != (*dir)->dev)) {
137 if (findino((*dir)->inode,(*dir)->dev)) {
138 fprintf(outfile,"{\"error\":\"recursive, not followed\"}");
139 } else {
140 saveino((*dir)->inode, (*dir)->dev);
141 if (*(*dir)->lnk == '/')
142 listdir((*dir)->lnk,dt,ft,lev+1,dev);
143 else {
144 if (strlen(d)+strlen((*dir)->lnk)+2 > pathsize) path=xrealloc(path,pathsize=(strlen(d)+strlen((*dir)->name)+1024));
145 if (fflag && !strcmp(d,"/")) sprintf(path,"%s%s",d,(*dir)->lnk);
146 else sprintf(path,"%s/%s",d,(*dir)->lnk);
147 listdir(path,dt,ft,lev+1,dev);
148 }
149 nlf = TRUE;
150 }
151 }
152 } else if (!(xdev && dev != (*dir)->dev)) {
153 if (strlen(d)+strlen((*dir)->name)+2 > pathsize) path=xrealloc(path,pathsize=(strlen(d)+strlen((*dir)->name)+1024));
154 if (fflag && !strcmp(d,"/")) sprintf(path,"%s%s",d,(*dir)->name);
155 else sprintf(path,"%s/%s",d,(*dir)->name);
156 saveino((*dir)->inode, (*dir)->dev);
157 listdir(path,dt,ft,lev+1,dev);
158 nlf = TRUE;
159 }
160 *dt += 1;
161 } else *ft += 1;
162 if (*(dir+1) && !*(dir+2)) dirs[lev] = 2;
163 if (nlf) {
164 nlf = FALSE;
165 if (!noindent) json_indent(lev);
166 }
167 if ((*dir)->isdir || (*dir)->lnk) {
168 fprintf(outfile, "]}");
169 if (*(dir+1)) fputc(',',outfile);
170 }
171 if (!noindent) fputc('\n', outfile);
172 dir++;
173 }
174 dirs[lev] = 0;
175 free(path);
176 free_dir(sav);
177 return 0;
178 }
179
json_rlistdir(char * d,int * dt,int * ft,u_long lev,dev_t dev)180 off_t json_rlistdir(char *d, int *dt, int *ft, u_long lev, dev_t dev)
181 {
182 struct _info **dir;
183 off_t size = 0;
184 char *err;
185
186 dir = getfulltree(d, lev, dev, &size, &err);
187
188 memset(dirs, 0, sizeof(int) * maxdirs);
189
190 jsonr_listdir(dir, d, dt, ft, lev);
191
192 return size;
193 }
194
jsonr_listdir(struct _info ** dir,char * d,int * dt,int * ft,u_long lev)195 void jsonr_listdir(struct _info **dir, char *d, int *dt, int *ft, u_long lev)
196 {
197 char *path;
198 long pathsize = 0;
199 struct _info **sav = dir;
200 bool nlf = FALSE;
201 int mt, t;
202
203 if (dir == NULL) return;
204
205 dirs[lev] = 1;
206 if (!*(dir+1)) dirs[lev] = 2;
207 if (!noindent) fprintf(outfile,"\n");
208
209 path = malloc(pathsize=4096);
210
211 while(*dir) {
212 if (!noindent) json_indent(lev);
213
214 if ((*dir)->lnk) mt = (*dir)->mode & S_IFMT;
215 else mt = (*dir)->mode & S_IFMT;
216 for(t=0;ifmt[t];t++)
217 if (ifmt[t] == mt) break;
218 fprintf(outfile,"{\"type\":\"%s\"", ftype[t]);
219
220 if (fflag) {
221 if (sizeof(char) * (strlen(d)+strlen((*dir)->name)+2) > pathsize)
222 path=xrealloc(path,pathsize=(sizeof(char) * (strlen(d)+strlen((*dir)->name)+1024)));
223 if (!strcmp(d,"/")) sprintf(path,"%s%s",d,(*dir)->name);
224 else sprintf(path,"%s/%s",d,(*dir)->name);
225 } else {
226 if (sizeof(char) * (strlen((*dir)->name)+1) > pathsize)
227 path=xrealloc(path,pathsize=(sizeof(char) * (strlen((*dir)->name)+1024)));
228 sprintf(path,"%s",(*dir)->name);
229 }
230
231 fprintf(outfile, ",\"name\":\"");
232 html_encode(outfile,path);
233 fputc('"',outfile);
234
235 if ((*dir)->lnk) {
236 fprintf(outfile, ",\"target\":\"");
237 html_encode(outfile,(*dir)->lnk);
238 fputc('"',outfile);
239 }
240
241 json_fillinfo(*dir);
242 if (mt != S_IFDIR && mt != S_IFLNK && (*dir)->err == NULL) {
243 fputc('}', outfile);
244 if (*(dir+1)) fputc(',',outfile);
245 } else fprintf(outfile, ",\"contents\":[");
246
247 if ((*dir)->err) {
248 fprintf(outfile,",\"error\":\"%s\"", (*dir)->err);
249 free((*dir)->err);
250 (*dir)->err = NULL;
251 }
252 if ((*dir)->child) {
253 if (fflag) {
254 if (strlen(d)+strlen((*dir)->name)+2 > pathsize) path=xrealloc(path,pathsize=(strlen(d)+strlen((*dir)->name)+1024));
255 if (!strcmp(d,"/")) sprintf(path,"%s%s",d,(*dir)->name);
256 else sprintf(path,"%s/%s",d,(*dir)->name);
257 }
258 jsonr_listdir((*dir)->child, fflag? path : NULL, dt, ft, lev+1);
259 nlf = TRUE;
260 *dt += 1;
261 } else {
262 if ((*dir)->isdir) *dt += 1;
263 else *ft += 1;
264 }
265
266 if (*(dir+1) && !*(dir+2)) dirs[lev] = 2;
267 if (nlf) {
268 nlf = FALSE;
269 if (!noindent) json_indent(lev);
270 }
271 if (mt == S_IFDIR || mt == S_IFLNK || (*dir)->err != NULL) {
272 fprintf(outfile,"]}");
273 if (*(dir+1)) fputc(',',outfile);
274 }
275 if (!noindent) putc('\n',outfile);
276 dir++;
277 }
278 dirs[lev] = 0;
279 free(path);
280 free_dir(sav);
281 }
282
json_indent(int maxlevel)283 void json_indent(int maxlevel)
284 {
285 int i;
286
287 fprintf(outfile, " ");
288 for(i=0; i<maxlevel; i++)
289 fprintf(outfile, " ");
290 }
291
json_fillinfo(struct _info * ent)292 void json_fillinfo(struct _info *ent)
293 {
294 #ifdef __USE_FILE_OFFSET64
295 if (inodeflag) fprintf(outfile,",\"inode\":%lld",(long long)ent->inode);
296 #else
297 if (inodeflag) fprintf(outfile,",\"inode\":%ld",(long int)ent->inode);
298 #endif
299 if (devflag) fprintf(outfile, ",\"dev\":%d", (int)ent->dev);
300 #ifdef __EMX__
301 if (pflag) fprintf(outfile, ",\"mode\":\"%04o\",\"prot\":\"%s\"",ent->attr, prot(ent->attr));
302 #else
303 if (pflag) fprintf(outfile, ",\"mode\":\"%04o\",\"prot\":\"%s\"", ent->mode & (S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID|S_ISVTX), prot(ent->mode));
304 #endif
305 if (uflag) fprintf(outfile, ",\"user\":\"%s\"", uidtoname(ent->uid));
306 if (gflag) fprintf(outfile, ",\"group\":\"%s\"", gidtoname(ent->gid));
307 if (sflag) {
308 if (hflag || siflag) {
309 char nbuf[64];
310 int i;
311 psize(nbuf,ent->size);
312 for(i=0; isspace(nbuf[i]); i++); // trim() hack
313 fprintf(outfile, ",\"size\":\"%s\"", nbuf+i);
314 } else
315 fprintf(outfile, ",\"size\":%lld", (long long int)ent->size);
316 }
317 if (Dflag) fprintf(outfile, ",\"time\":\"%s\"", do_date(cflag? ent->ctime : ent->mtime));
318 }
319