/* * The author of this software is Eric Grosse. Copyright (c) 2000 by Lucent. * Permission to use, copy, modify, and distribute this software for any * purpose without fee is hereby granted, provided that this entire notice * is included in all copies of any software which is or includes a copy * or modification of this software and in all copies of the supporting * documentation for such software. * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. */ /* recursive ls. Does not follow symbolic links. Does not use ftw for portability reasons. According to pixie, half the execution time is spent in printf; according to prof, 90 percent of the time is in lstat. Anyway, don't bother with trivial optimizations. 28 Dec 91 ehg first version 13 Sep 92 ehg keep going after bad opendir 20 Sep 92 ehg -t option to print Unixtime 1 Jan 93 ehg follow crc format for -t (but still only stat file) 5 Apr 93 ehg sort. strip off leading ./ 5 Jan 94 ehg keep going if stat fails 29 Dec 94 ehg complain about nonprinting characters in filenames 24 Feb 96 ehg skip naughty files, quietly unless -v 2 May 00 rsc -d option to print directories For Plan 9, the best way to do the recursion is different; see lsr-plan9.c. */ // Ubuntu 64bit moved /usr/include/sys #define _POSIX_SOURCE #include #include #include #include #include #include #include #include #ifdef NOSYMLINK #define lstat(f,s) stat(f,s) #endif typedef unsigned char uchar; uchar *path, **component; int ncomp; int verbose = 0; int prunixtime = 0; int printdirs = 0; void * Malloc(size_t n) { void *p; if (!(p = malloc((size_t)n))){ fprintf(stderr,"unable to allocate %ld bytes\n",n); exit(1); } return p; } void * Realloc(void *ReallocP, int ReallocN) { if(!(ReallocP = realloc(ReallocP, ReallocN))){ fprintf(stderr,"unable to reallocate %d bytes\n",ReallocN); exit(1); } return(ReallocP); } char* Strdup(char* s) { int l; if (!s) return 0; l = strlen(s)+1; return strcpy((char *)Malloc((size_t)l), s); } int cmp(const void *a, const void *b) { return strcmp(*(char**)a,*(char**)b); } int unsafe(char *s) { char c, *file = s; /* check for shell specials or whitespace, which would confuse later tools */ for (c = (*s); c != '\0'; c = (*++s)){ if (!isgraph(c) || strchr("\"'`$#;&|^<>()\\",c)){ strcpy((char*)component[ncomp-1],file); if(verbose) fprintf(stderr,"%s: dangerous filename\n",path); return(1); } } return(0); } char ** sorted_names(DIR *dir) { int maxnames = 250; /* starting guess at size of directory */ int nnames = 0; char **names = (char **)Malloc(maxnames*sizeof(*names)); char *file, *s; struct dirent *entry; while( entry = readdir(dir) ){ file = entry->d_name; if(strcmp(file,".")!=0 && strcmp(file,"..")!=0 && !unsafe(file)){ names[nnames++] = Strdup(file); if(nnames>=maxnames){ maxnames += 200; names = (char **)Realloc(names,maxnames*sizeof(char*)); } } } qsort((void*)names,nnames,sizeof(*names),cmp); names[nnames] = 0; return(names); } void free_names(char **names) { char **name; for(name = names; *name; name++) free(*name); free(names); } void prname(uchar *p, struct stat s) { if(p[0]=='.' && p[1]=='/') p += 2; /* chop off leading ./ */ if(prunixtime) printf("%s %lu %lu 0\n",p,(unsigned long)s.st_mtime, (unsigned long)s.st_size); else if(S_ISDIR(s.st_mode)) printf("%s/\n",p); else printf("%s\n",p); } void pr(void) { struct stat s; DIR *dir; char buf[BUFSIZ]; int cc; char **names, **name; if(lstat((char*)path,&s)){ if(verbose){ fprintf(stderr,"%s: ",path); perror("can't stat"); } return; } if(access((char*)path,R_OK)){ if(verbose) fprintf(stderr,"can't access %s\n",path); return; } #ifndef NOSYMLINK if(S_ISLNK(s.st_mode)){ if(verbose){ printf("%s -> ",path); cc = readlink((char*)path,buf,BUFSIZ); if (cc >= 0) { buf[cc] = 0; printf("%s\n",buf); }else{ perror("can't readlink\n"); exit(1); } } }else #endif if(S_ISREG(s.st_mode)){ prname(path, s); }else if(S_ISDIR(s.st_mode)){ if(printdirs) prname(path, s); if(dir = opendir((char*)path)){ cc = strlen((char*)component[ncomp-1]); component[ncomp] = cc+component[ncomp-1]+1; component[ncomp][-1] = '/'; ncomp++; names = sorted_names(dir); for(name = names; *name; name++){ strcpy((char*)component[ncomp-1],*name); pr(); } free_names(names); ncomp--; component[ncomp][-1] = '\0'; closedir(dir); }else{ fflush(stdout); fprintf(stderr,"can't opendir %s\n",(char*)path); } }else{ fprintf(stderr,"%s mode %o\n",(char*)path,s.st_mode); } } void main(int argc, char **argv) { while(argc > 1) { if(argv[1][0]=='-' && (argv[1][1]=='s'||argv[1][1]=='v')){ verbose = 1; prunixtime = 0; argc--; argv++; } else if(!strcmp(argv[1],"-t")){ prunixtime = 1; verbose = 0; argc--; argv++; } else if(!strcmp(argv[1], "-d")){ printdirs = 1; argc--; argv++; } else break; } component = (uchar**)Malloc(1000*sizeof(uchar*)); /* should check against depth */ path = (uchar *)Malloc(4096); /* should be _POSIX_PATH_MAX */ component[0] = path; ncomp = 1; if(argc>1){ while(--argc){ strcpy((char*)path,*++argv); pr(); } }else{ strcpy((char*)path,"."); pr(); } }