/* find COMPILE: cc -o find -s -O -i find.c -lS */ #include #include #include #include #define A_DAY 86400L /* a day full of seconds */ #define EQ(x, y) (strcmp(x, y)==0) int Randlast; char Pathname[200]; struct anode { int (*F)(); struct anode *L, *R; } Node[100]; int Nn; /* number of nodes */ char *Fname; long Now; int Argc, Ai, Pi; char **Argv; /* cpio stuff */ int Cpio; short *Buf, *Dbuf, *Wp; int Bufsize = 5120; int Wct = 2560; long Newer; struct stat Statb; struct anode *exp(), *e1(), *e2(), *e3(), *mk(); char *nxtarg(); char Home[128]; long Blocks; char *rindex(); char *sbrk(); main(argc, argv) char *argv[]; { struct anode *exlist; int paths; register char *cp, *sp = 0; FILE *pwd, *popen(); time(&Now); pwd = popen("pwd", "r"); fgets(Home, 128, pwd); pclose(pwd); Home[strlen(Home) - 1] = '\0'; Argc = argc; Argv = argv; if(argc<3) { usage: pr("Usage: find path-list predicate-list\n"); exit(1); } for(Ai = paths = 1; Ai < (argc-1); ++Ai, ++paths) if(*Argv[Ai] == '-' || EQ(Argv[Ai], "(") || EQ(Argv[Ai], "!")) break; if(paths == 1) /* no path-list */ goto usage; if(!(exlist = exp())) { /* parse and compile the arguments */ pr("find: parsing error\n"); exit(1); } if(Ai=Argc) { strikes++; Ai = Argc + 1; return(""); } return(Argv[Ai++]); } /* execution time functions */ and(p) register struct anode *p; { return(((*p->L->F)(p->L)) && ((*p->R->F)(p->R))?1:0); } or(p) register struct anode *p; { return(((*p->L->F)(p->L)) || ((*p->R->F)(p->R))?1:0); } not(p) register struct anode *p; { return( !((*p->L->F)(p->L))); } glob(p) register struct { int f; char *pat; } *p; { return(gmatch(Fname, p->pat)); } print() { puts(Pathname); return(1); } mtime(p) register struct { int f, t, s; } *p; { return(scomp((int)((Now - Statb.st_mtime) / A_DAY), p->t, p->s)); } atime(p) register struct { int f, t, s; } *p; { return(scomp((int)((Now - Statb.st_atime) / A_DAY), p->t, p->s)); } ctime(p) register struct { int f, t, s; } *p; { return(scomp((int)((Now - Statb.st_ctime) / A_DAY), p->t, p->s)); } user(p) register struct { int f, u, s; } *p; { return(scomp(Statb.st_uid, p->u, p->s)); } ino(p) register struct { int f, u, s; } *p; { return(scomp((int)Statb.st_ino, p->u, p->s)); } group(p) register struct { int f, u; } *p; { return(p->u == Statb.st_gid); } links(p) register struct { int f, link, s; } *p; { return(scomp(Statb.st_nlink, p->link, p->s)); } size(p) register struct { int f, sz, s; } *p; { return(scomp((int)((Statb.st_size+511)>>9), p->sz, p->s)); } perm(p) register struct { int f, per, s; } *p; { register i; i = (p->s=='-') ? p->per : 07777; /* '-' means only arg bits */ return((Statb.st_mode & i & 07777) == p->per); } type(p) register struct { int f, per, s; } *p; { return((Statb.st_mode&S_IFMT)==p->per); } exeq(p) register struct { int f, com; } *p; { fflush(stdout); /* to flush possible `-print' */ return(doex(p->com)); } ok(p) struct { int f, com; } *p; { int c; int yes; yes = 0; fflush(stdout); /* to flush possible `-print' */ pr("< "), pr(Argv[p->com]), pr(" ... "), pr(Pathname), pr(" >? "); fflush(stderr); if((c=getchar())=='y') yes = 1; while(c!='\n') if(c==EOF) exit(2); else c = getchar(); if(yes) return(doex(p->com)); return(0); } #define MKSHORT(v, lv) {U.l=1L;if(U.c[0]) U.l=lv, v[0]=U.s[1], v[1]=U.s[0]; else U.l=lv, v[0]=U.s[0], v[1]=U.s[1];} union { long l; short s[2]; char c[4]; } U; long mklong(v) short v[]; { U.l = 1; if(U.c[0] /* VAX */) U.s[0] = v[1], U.s[1] = v[0]; else U.s[0] = v[0], U.s[1] = v[1]; return U.l; } cpio() { #define MAGIC 070707 struct header { short h_magic, h_dev, h_ino, h_mode, h_uid, h_gid, h_nlink, h_rdev; short h_mtime[2]; short h_namesize; short h_filesize[2]; char h_name[256]; } hdr; register ifile, ct; static long fsz; register i; hdr.h_magic = MAGIC; strcpy(hdr.h_name, !strncmp(Pathname, "./", 2)? Pathname+2: Pathname); hdr.h_namesize = strlen(hdr.h_name) + 1; hdr.h_uid = Statb.st_uid; hdr.h_gid = Statb.st_gid; hdr.h_dev = Statb.st_dev; hdr.h_ino = Statb.st_ino; hdr.h_mode = Statb.st_mode; MKSHORT(hdr.h_mtime, Statb.st_mtime); hdr.h_nlink = Statb.st_nlink; fsz = hdr.h_mode & S_IFREG? Statb.st_size: 0L; MKSHORT(hdr.h_filesize, fsz); hdr.h_rdev = Statb.st_rdev; if(EQ(hdr.h_name, "TRAILER!!!")) { bwrite((short *)&hdr, (sizeof hdr-256)+hdr.h_namesize); for(i = 0; i < 10; ++i) bwrite(Buf, 512); return; } if(!mklong(hdr.h_filesize)) { bwrite((short *)&hdr, (sizeof hdr-256)+hdr.h_namesize); return; } if((ifile = open(Fname, 0)) < 0) { cerror: pr("find: cannot copy "), pr(hdr.h_name), pr("\n"); return; } bwrite((short *)&hdr, (sizeof hdr-256)+hdr.h_namesize); for(fsz = mklong(hdr.h_filesize); fsz > 0; fsz -= 512) { ct = fsz>512? 512: fsz; if(read(ifile, (char *)Buf, ct) < 0) goto cerror; bwrite(Buf, ct); } close(ifile); return; } newer() { return Statb.st_mtime > Newer; } /* support functions */ scomp(a, b, s) /* funny signed compare */ register a, b; register char s; { if(s == '+') return(a > b); if(s == '-') return(a < (b * -1)); return(a == b); } doex(com) { register np; register char *na; static char *nargv[50]; static ccode; ccode = np = 0; while (na=Argv[com++]) { if(strcmp(na, ";")==0) break; if(strcmp(na, "{}")==0) nargv[np++] = Pathname; else nargv[np++] = na; } nargv[np] = 0; if (np==0) return(9); if(fork()) /*parent*/ wait(&ccode); else { /*child*/ chdir(Home); execvp(nargv[0], nargv, np); exit(1); } return(ccode ? 0:1); } getunum(f, s) char *f, *s; { /* find user/group name and return number */ register i; register char *sp; register c; char str[20]; FILE *pin; i = -1; pin = fopen(f, "r"); c = '\n'; /* prime with a CR */ do { if(c=='\n') { sp = str; while((c = *sp++ = getc(pin)) != ':') if(c == EOF) goto RET; *--sp = '\0'; if(EQ(str, s)) { while((c=getc(pin)) != ':') if(c == EOF) goto RET; sp = str; while((*sp = getc(pin)) != ':') sp++; *sp = '\0'; i = atoi(str); goto RET; } } } while((c = getc(pin)) != EOF); RET: fclose(pin); return(i); } descend(name, fname, exlist) struct anode *exlist; char *name, *fname; { int dir = 0, /* open directory */ offset, dsize, entries, dirsize; struct direct dentry[32]; register struct direct *dp; register char *c1, *c2; int i; int rv = 0; char *endofname; if(stat(fname, &Statb)<0) { pr("find: bad status-- "), pr(name), pr("\n"); return(0); } (*exlist->F)(exlist); if((Statb.st_mode&S_IFMT)!=S_IFDIR) return(1); for(c1 = name; *c1; ++c1); if(*(c1-1) == '/') --c1; endofname = c1; dirsize = Statb.st_size; if(chdir(fname) == -1) return(0); for(offset=0 ; offset < dirsize ; offset += 512) { /* each block */ dsize = 512<(dirsize-offset)? 512: (dirsize-offset); if(!dir) { if((dir=open(".", 0))<0) { pr("find: cannot open "), pr(name), pr("\n"); rv = 0; goto ret; } if(offset) lseek(dir, (long)offset, 0); if(read(dir, (char *)dentry, dsize)<0) { pr("find: cannot read "), pr(name), pr("\n"); rv = 0; goto ret; } if(dir > 10) { close(dir); dir = 0; } } else if(read(dir, (char *)dentry, dsize)<0) { pr("find: cannot read "), pr(name), pr("\n"); rv = 0; goto ret; } for(dp=dentry, entries=dsize>>4; entries; --entries, ++dp) { /* each directory entry */ if(dp->d_ino==0 || (dp->d_name[0]=='.' && dp->d_name[1]=='\0') || (dp->d_name[0]=='.' && dp->d_name[1]=='.' && dp->d_name[2]=='\0')) continue; c1 = endofname; *c1++ = '/'; c2 = dp->d_name; for(i=0; i<14; ++i) if(*c2) *c1++ = *c2++; else break; *c1 = '\0'; if(c1 == endofname) { /* ?? */ rv = 0; goto ret; } Fname = endofname+1; if(!descend(name, Fname, exlist)) { *endofname = '\0'; chdir(Home); if(chdir(Pathname) == -1) { pr("find: bad directory tree\n"); exit(1); } } } } rv = 1; ret: if(dir) close(dir); if(chdir("..") == -1) { *endofname = '\0'; pr("find: bad directory "), pr(name), pr("\n"); rv = 1; } return(rv); } gmatch(s, p) /* string match as in glob */ register char *s, *p; { if (*s=='.' && *p!='.') return(0); return amatch(s, p); } amatch(s, p) register char *s, *p; { register cc; int scc, k; int c, lc; scc = *s; lc = 077777; switch (c = *p) { case '[': k = 0; while (cc = *++p) { switch (cc) { case ']': if (k) return(amatch(++s, ++p)); else return(0); case '-': k |= lc <= scc & scc <= (cc=p[1]); } if (scc==(lc=cc)) k++; } return(0); case '?': caseq: if(scc) return(amatch(++s, ++p)); return(0); case '*': return(umatch(s, ++p)); case 0: return(!scc); } if (c==scc) goto caseq; return(0); } umatch(s, p) register char *s, *p; { if(*p==0) return(1); while(*s) if (amatch(s++, p)) return(1); return(0); } bwrite(rp, c) register short *rp; register c; { register short *wp = Wp; c = (c+1) >> 1; while(c--) { if(!Wct) { again: if(write(Cpio, (char *)Dbuf, Bufsize)<0) { Cpio = chgreel(1, Cpio); goto again; } Wct = Bufsize >> 1; wp = Dbuf; ++Blocks; } *wp++ = *rp++; --Wct; } Wp = wp; } chgreel(x, fl) { register f; char str[22]; FILE *devtty; struct stat statb; pr("find: can't "), pr(x? "write output": "read input"), pr("\n"); fstat(fl, &statb); if((statb.st_mode&S_IFMT) != S_IFCHR) exit(1); again: pr("If you want to go on, type device/file name when ready\n"); devtty = fopen("/dev/tty", "r"); fgets(str, 20, devtty); str[strlen(str) - 1] = '\0'; if(!*str) exit(1); close(fl); if((f = open(str, x? 1: 0)) < 0) { pr("That didn't work"); fclose(devtty); goto again; } return f; } pr(s) char *s; { fputs(s, stderr); }