off_t xml_listdir(char *d, int *dt, int *ft, u_long lev, dev_t dev) { char *path; bool nlf = FALSE; long pathsize = 0; struct _info **dir, **sav; struct stat sb; int t, n, mt; if ((Level >= 0) && (lev > Level)) { if (!noindent) fputc('\n',outfile); return 0; } if (xdev && lev == 0) { stat(d,&sb); dev = sb.st_dev; } sav = dir = read_dir(d,&n); if (!dir && n) { fprintf(outfile,"<error>opening dir</error>\n"); return 0; } if (!n) { if (!noindent) fputc('\n', outfile); free_dir(sav); return 0; } if (flimit > 0 && n > flimit) { fprintf(outfile,"<error>%d entries exceeds filelimit, not opening dir</error>%s",n,noindent?"":"\n"); free_dir(sav); return 0; } if (cmpfunc) qsort(dir,n,sizeof(struct _info *), cmpfunc); if (lev >= maxdirs-1) { dirs = xrealloc(dirs,sizeof(int) * (maxdirs += 1024)); memset(dirs+(maxdirs-1024), 0, sizeof(int) * 1024); } dirs[lev] = 1; if (!*(dir+1)) dirs[lev] = 2; if (!noindent) fprintf(outfile,"\n"); path = malloc(pathsize=4096); while(*dir) { if (!noindent) xml_indent(lev); if ((*dir)->lnk) mt = (*dir)->mode & S_IFMT; else mt = (*dir)->mode & S_IFMT; for(t=0;ifmt[t];t++) if (ifmt[t] == mt) break; fprintf(outfile,"<%s", ftype[t]); if (fflag) { if (sizeof(char) * (strlen(d)+strlen((*dir)->name)+2) > pathsize) path=xrealloc(path,pathsize=(sizeof(char) * (strlen(d)+strlen((*dir)->name)+1024))); if (!strcmp(d,"/")) sprintf(path,"%s%s",d,(*dir)->name); else sprintf(path,"%s/%s",d,(*dir)->name); } else { if (sizeof(char) * (strlen((*dir)->name)+1) > pathsize) path=xrealloc(path,pathsize=(sizeof(char) * (strlen((*dir)->name)+1024))); sprintf(path,"%s",(*dir)->name); } fprintf(outfile, " name=\""); html_encode(outfile,path); fputc('"',outfile); if ((*dir)->lnk) { fprintf(outfile, " target=\""); html_encode(outfile,(*dir)->lnk); fputc('"',outfile); } xml_fillinfo(*dir); fputc('>',outfile); if ((*dir)->isdir) { if ((*dir)->lnk) { if (lflag && !(xdev && dev != (*dir)->dev)) { if (findino((*dir)->inode,(*dir)->dev)) { fprintf(outfile,"<error>recursive, not followed</error>"); } else { saveino((*dir)->inode, (*dir)->dev); if (*(*dir)->lnk == '/') listdir((*dir)->lnk,dt,ft,lev+1,dev); else { if (strlen(d)+strlen((*dir)->lnk)+2 > pathsize) path=xrealloc(path,pathsize=(strlen(d)+strlen((*dir)->name)+1024)); if (fflag && !strcmp(d,"/")) sprintf(path,"%s%s",d,(*dir)->lnk); else sprintf(path,"%s/%s",d,(*dir)->lnk); listdir(path,dt,ft,lev+1,dev); } nlf = TRUE; } } } else if (!(xdev && dev != (*dir)->dev)) { if (strlen(d)+strlen((*dir)->name)+2 > pathsize) path=xrealloc(path,pathsize=(strlen(d)+strlen((*dir)->name)+1024)); if (fflag && !strcmp(d,"/")) sprintf(path,"%s%s",d,(*dir)->name); else sprintf(path,"%s/%s",d,(*dir)->name); saveino((*dir)->inode, (*dir)->dev); listdir(path,dt,ft,lev+1,dev); nlf = TRUE; } *dt += 1; } else *ft += 1; if (*(dir+1) && !*(dir+2)) dirs[lev] = 2; if (nlf) { nlf = FALSE; if (!noindent) xml_indent(lev); } fprintf(outfile,"</%s>%s",ftype[t],noindent?"":"\n"); dir++; } dirs[lev] = 0; free(path); free_dir(sav); return 0; }
int main(int argc, char **argv) { char **dirname = NULL; int i,j=0,k,n,optf,p,q,dtotal,ftotal,colored = FALSE; struct stat st; char sizebuf[64], *stmp; off_t size = 0; mode_t mt; bool needfulltree; q = p = dtotal = ftotal = 0; aflag = dflag = fflag = lflag = pflag = sflag = Fflag = uflag = gflag = FALSE; Dflag = qflag = Nflag = Qflag = Rflag = hflag = Hflag = siflag = cflag = FALSE; noindent = force_color = nocolor = xdev = noreport = nolinks = reverse = FALSE; ignorecase = matchdirs = dirsfirst = inodeflag = devflag = Xflag = Jflag = FALSE; duflag = pruneflag = FALSE; flimit = 0; dirs = xmalloc(sizeof(int) * (maxdirs=4096)); memset(dirs, 0, sizeof(int) * maxdirs); dirs[0] = 0; Level = -1; setlocale(LC_CTYPE, ""); setlocale(LC_COLLATE, ""); charset = getcharset(); if (charset == NULL) { charset = "UTF-8"; } /* Until I get rid of this hack, make it linux/cygwin/HP nonstop only: */ #if defined (LINUX) || defined (CYGWIN) || defined (__TANDEM) mb_cur_max = (int)MB_CUR_MAX; #else mb_cur_max = 1; #endif memset(utable,0,sizeof(utable)); memset(gtable,0,sizeof(gtable)); memset(itable,0,sizeof(itable)); optf = TRUE; for(n=i=1;i<argc;i=n) { n++; if (optf && argv[i][0] == '-' && argv[i][1]) { for(j=1;argv[i][j];j++) { switch(argv[i][j]) { case 'N': Nflag = TRUE; break; case 'q': qflag = TRUE; break; case 'Q': Qflag = TRUE; break; case 'd': dflag = TRUE; break; case 'l': lflag = TRUE; break; case 's': sflag = TRUE; break; case 'h': hflag = TRUE; sflag = TRUE; /* Assume they also want -s */ break; case 'u': uflag = TRUE; break; case 'g': gflag = TRUE; break; case 'f': fflag = TRUE; break; case 'F': Fflag = TRUE; break; case 'a': aflag = TRUE; break; case 'p': pflag = TRUE; break; case 'i': noindent = TRUE; _nl = ""; break; case 'C': force_color = TRUE; break; case 'n': nocolor = TRUE; break; case 'x': xdev = TRUE; break; case 'P': if (argv[n] == NULL) { fprintf(stderr,"tree: missing argument to -P option.\n"); exit(1); } pattern = argv[n++]; break; case 'I': if (argv[n] == NULL) { fprintf(stderr,"tree: missing argument to -I option.\n"); exit(1); } ipattern = argv[n++]; break; case 'A': ansilines = TRUE; break; case 'S': charset = "IBM437"; break; case 'D': Dflag = TRUE; break; case 't': cmpfunc = mtimesort; break; case 'c': cmpfunc = ctimesort; cflag = TRUE; break; case 'r': reverse = TRUE; break; case 'v': cmpfunc = versort; break; case 'U': cmpfunc = NULL; break; case 'X': Hflag = FALSE; Xflag = TRUE; break; case 'J': Jflag = TRUE; break; case 'H': Hflag = TRUE; Xflag = FALSE; if (argv[n] == NULL) { fprintf(stderr,"tree: missing argument to -H option.\n"); exit(1); } host = argv[n++]; sp = " "; break; case 'T': if (argv[n] == NULL) { fprintf(stderr,"tree: missing argument to -T option.\n"); exit(1); } title = argv[n++]; break; case 'R': Rflag = TRUE; break; case 'L': if ((sLevel = argv[n++]) == NULL) { fprintf(stderr,"tree: Missing argument to -L option.\n"); exit(1); } Level = strtoul(sLevel,NULL,0)-1; if (Level < 0) { fprintf(stderr,"tree: Invalid level, must be greater than 0.\n"); exit(1); } break; case 'o': if (argv[n] == NULL) { fprintf(stderr,"tree: missing argument to -o option.\n"); exit(1); } outfilename = argv[n++]; break; case '-': if (j == 1) { if (!strcmp("--", argv[i])) { optf = FALSE; break; } if (!strcmp("--help",argv[i])) { usage(2); exit(0); } if (!strcmp("--version",argv[i])) { char *v = version+12; printf("%.*s\n",(int)strlen(v)-1,v); exit(0); } if (!strcmp("--inodes",argv[i])) { j = strlen(argv[i])-1; inodeflag=TRUE; break; } if (!strcmp("--device",argv[i])) { j = strlen(argv[i])-1; devflag=TRUE; break; } if (!strcmp("--noreport",argv[i])) { j = strlen(argv[i])-1; noreport = TRUE; break; } if (!strcmp("--nolinks",argv[i])) { j = strlen(argv[i])-1; nolinks = TRUE; break; } if (!strcmp("--dirsfirst",argv[i])) { j = strlen(argv[i])-1; dirsfirst = TRUE; break; } if (!strncmp("--filelimit",argv[i],11)) { j = 11; if (*(argv[i]+11) == '=') { if (*(argv[i]+12)) { flimit=atoi(argv[i]+12); j = strlen(argv[i])-1; break; } } if (argv[n] != NULL) { flimit = atoi(argv[n++]); j = strlen(argv[i])-1; } else { fprintf(stderr,"tree: missing argument to --filelimit\n"); exit(1); } break; } if (!strncmp("--charset",argv[i],9)){ j = 9; if (*(argv[i]+j) == '=') { if (*(charset = (argv[i]+10))) { j = strlen(argv[i])-1; break; } } if (argv[n] != NULL) { charset = argv[n++]; j = strlen(argv[i])-1; } else { initlinedraw(1); exit(1); } break; } if (!strncmp("--si", argv[i], 4)) { j = strlen(argv[i])-1; sflag = TRUE; hflag = TRUE; siflag = TRUE; break; } if (!strncmp("--du",argv[i],4)) { j = strlen(argv[i])-1; sflag = TRUE; duflag = TRUE; break; } if (!strncmp("--prune",argv[i],7)) { j = strlen(argv[i])-1; pruneflag = TRUE; break; } if (!strncmp("--timefmt",argv[i],9)) { j = 9; if (*(argv[i]+j) == '=') { if (*(argv[i]+ (++j))) { timefmt=scopy(argv[i]+j); j = strlen(argv[i])-1; break; } } else if (argv[n] != NULL) { timefmt = scopy(argv[n]); n++; j = strlen(argv[i])-1; } else { fprintf(stderr,"tree: missing argument to --timefmt\n"); exit(1); } Dflag = TRUE; break; } if (!strncmp("--ignore-case",argv[i],13)) { j = strlen(argv[i])-1; ignorecase = TRUE; break; } if (!strncmp("--matchdirs",argv[i],11)) { j = strlen(argv[i])-1; matchdirs = TRUE; break; } if (!strncmp("--sort",argv[i],6)) { j = 6; if (*(argv[i]+j) == '=') { if (*(argv[i]+(++j))) { stmp = argv[i]+j; j = strlen(argv[i])-1; } else { fprintf(stderr,"tree: missing argument to --sort=\n"); exit(1); } } else if (argv[n] != NULL) { stmp = argv[n++]; } else { fprintf(stderr,"tree: missing argument to --sort\n"); exit(1); } cmpfunc = (void *)1; for(k=0;sorts[k].name;k++) { if (strcasecmp(sorts[k].name,stmp) == 0) { cmpfunc = sorts[k].cmpfunc; break; } } if (cmpfunc == (void *)1) { fprintf(stderr,"tree: sort type '%s' not valid, should be one of: ", stmp); for(k=0; sorts[k].name; k++) printf("%s%c", sorts[k].name, sorts[k+1].name? ',': '\n'); exit(1); } break; } } default: fprintf(stderr,"tree: Invalid argument -`%c'.\n",argv[i][j]); usage(1); exit(1); break; } } } else { if (!dirname) dirname = (char **)xmalloc(sizeof(char *) * (q=MINIT)); else if (p == (q-2)) dirname = (char **)xrealloc(dirname,sizeof(char *) * (q+=MINC)); dirname[p++] = scopy(argv[i]); } } if (p) dirname[p] = NULL; if (outfilename == NULL) { #ifdef __EMX__ _fsetmode(outfile=stdout,Hflag?"b":"t"); #else outfile = stdout; #endif } else { #ifdef __EMX__ outfile = fopen(outfilename,Hflag?"wb":"wt"); #else outfile = fopen(outfilename,"w"); #endif if (outfile == NULL) { fprintf(stderr,"tree: invalid filename '%s'\n",outfilename); exit(1); } } parse_dir_colors(); initlinedraw(0); needfulltree = duflag || pruneflag || matchdirs; /* Set our listdir function and sanity check options. */ if (Hflag) { listdir = needfulltree ? html_rlistdir : html_listdir; Xflag = FALSE; } else if (Xflag) { listdir = needfulltree ? xml_rlistdir : xml_listdir; colorize = FALSE; colored = FALSE; /* Do people want colored XML output? */ } else if (Jflag) { listdir = needfulltree ? json_rlistdir : json_listdir; colorize = FALSE; colored = FALSE; /* Do people want colored JSON output? */ } else { listdir = needfulltree ? unix_rlistdir : unix_listdir; } if (dflag) pruneflag = FALSE; /* You'll just get nothing otherwise. */ if (Rflag && (Level == -1)) Rflag = FALSE; if (Hflag) { emit_html_header(charset, title, version); fflag = FALSE; if (nolinks) { if (force_color) fprintf(outfile, "<b class=\"NORM\">%s</b>",host); else fprintf(outfile,"%s",host); } else { if (force_color) fprintf(outfile,"<a class=\"NORM\" href=\"%s\">%s</a>",host,host); else fprintf(outfile,"<a href=\"%s\">%s</a>",host,host); } curdir = gnu_getcwd(); } else if (Xflag) { fprintf(outfile,"<?xml version=\"1.0\""); if (charset) fprintf(outfile," encoding=\"%s\"",charset); fprintf(outfile,"?>%s<tree>%s",_nl,_nl); } else if (Jflag) fputc('[',outfile); if (dirname) { for(colored=i=0;dirname[i];i++,colored=0) { if (fflag) { do { j=strlen(dirname[i]); if (j > 1 && dirname[i][j-1] == '/') dirname[i][--j] = 0; } while (j > 1 && dirname[i][j-1] == '/'); } if ((n = lstat(dirname[i],&st)) >= 0) { saveino(st.st_ino, st.st_dev); if (colorize) colored = color(st.st_mode,dirname[i],n<0,FALSE); size += st.st_size; } if (Xflag || Jflag) { mt = st.st_mode & S_IFMT; for(j=0;ifmt[j];j++) if (ifmt[j] == mt) break; if (Xflag) fprintf(outfile,"%s<%s name=\"%s\">", noindent?"":" ", ftype[j], dirname[i]); else if (Jflag) { if (i) fprintf(outfile, ","); fprintf(outfile,"%s{\"type\":\"%s\",\"name\":\"%s\",\"contents\":[", noindent?"":"\n ", ftype[j], dirname[i]); } } else if (!Hflag) printit(dirname[i]); if (colored) fprintf(outfile,"%s",endcode); if (!Hflag) size += listdir(dirname[i],&dtotal,&ftotal,0,0); else { if (chdir(dirname[i])) { fprintf(outfile,"%s [error opening dir]\n",dirname[i]); exit(1); } else { size += listdir(".",&dtotal,&ftotal,0,0); chdir(curdir); } } if (Xflag) fprintf(outfile,"%s</%s>\n",noindent?"":" ", ftype[j]); if (Jflag) fprintf(outfile,"%s]}",noindent?"":" "); } } else { if ((n = lstat(".",&st)) >= 0) { saveino(st.st_ino, st.st_dev); if (colorize) colored = color(st.st_mode,".",n<0,FALSE); size = st.st_size; } if (Xflag) fprintf(outfile,"%s<directory name=\".\">",noindent?"":" "); else if (Jflag) fprintf(outfile, "{\"type\":\"directory\",\"name\": \".\",\"contents\":["); else if (!Hflag) fprintf(outfile,"."); if (colored) fprintf(outfile,"%s",endcode); size += listdir(".",&dtotal,&ftotal,0,0); if (Xflag) fprintf(outfile,"%s</directory>%s",noindent?"":" ", _nl); if (Jflag) fprintf(outfile,"%s]}",noindent?"":" "); } if (Hflag) fprintf(outfile,"\t<br><br>\n\t</p>\n\t<p>\n"); if (!noreport) { if (Xflag) { fprintf(outfile,"%s<report>%s",noindent?"":" ", _nl); if (duflag) fprintf(outfile,"%s<size>%lld</size>%s", noindent?"":" ", (long long int)size, _nl); fprintf(outfile,"%s<directories>%d</directories>%s", noindent?"":" ", dtotal, _nl); if (!dflag) fprintf(outfile,"%s<files>%d</files>%s", noindent?"":" ", ftotal, _nl); fprintf(outfile,"%s</report>%s",noindent?"":" ", _nl); } else if (Jflag) { fprintf(outfile, ",%s{\"type\":\"report\"",noindent?"":"\n "); if (duflag) fprintf(outfile,",\"size\":%lld", (long long int)size); fprintf(outfile,",\"directories\":%d", dtotal); if (!dflag) fprintf(outfile,",\"files\":%d", ftotal); fprintf(outfile, "}"); } else { if (duflag) { psize(sizebuf, size); fprintf(outfile,"\n%s%s used in ", sizebuf, hflag || siflag? "" : " bytes"); } else fputc('\n', outfile); if (dflag) fprintf(outfile,"%d director%s\n",dtotal,(dtotal==1? "y":"ies")); else fprintf(outfile,"%d director%s, %d file%s\n",dtotal,(dtotal==1? "y":"ies"),ftotal,(ftotal==1? "":"s")); } } if (Hflag) { fprintf(outfile,"\t<br><br>\n\t</p>\n"); fprintf(outfile,"\t<hr>\n"); fprintf(outfile,"\t<p class=\"VERSION\">\n"); fprintf(outfile,hversion,linedraw->copy, linedraw->copy, linedraw->copy, linedraw->copy); fprintf(outfile,"\t</p>\n"); fprintf(outfile,"</body>\n"); fprintf(outfile,"</html>\n"); } else if (Xflag) { fprintf(outfile,"</tree>\n"); } else if (Jflag) { fprintf(outfile, "%s]\n",_nl); } if (outfilename != NULL) fclose(outfile); return 0; }