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