111127Smckusick /* Copyright (c) 1983 Regents of the University of California */ 211127Smckusick 311127Smckusick #ifndef lint 4*11992Smckusick static char sccsid[] = "@(#)dirs.c 3.8 (Berkeley) 83/04/19"; 511127Smckusick #endif 611127Smckusick 711127Smckusick #include "restore.h" 811127Smckusick #include <dumprestor.h> 911309Smckusick #include <sys/file.h> 1011127Smckusick #include <dir.h> 1111127Smckusick 12*11992Smckusick /* 13*11992Smckusick * Symbol table of directories read from tape. 14*11992Smckusick */ 1511127Smckusick #define HASHSIZE 1000 1611127Smckusick #define INOHASH(val) (val % HASHSIZE) 1711127Smckusick struct inotab { 1811127Smckusick struct inotab *t_next; 1911127Smckusick ino_t t_ino; 2011127Smckusick daddr_t t_seekpt; 2111127Smckusick long t_size; 2211309Smckusick }; 2311309Smckusick static struct inotab *inotab[HASHSIZE]; 2411309Smckusick extern struct inotab *inotablookup(); 2511322Smckusick extern struct inotab *allocinotab(); 2611127Smckusick 27*11992Smckusick /* 28*11992Smckusick * Information retained about directories. 29*11992Smckusick */ 3011127Smckusick struct modeinfo { 3111127Smckusick ino_t ino; 3211127Smckusick time_t timep[2]; 3311127Smckusick short mode; 3411127Smckusick short uid; 3511127Smckusick short gid; 3611127Smckusick }; 3711127Smckusick 38*11992Smckusick /* 39*11992Smckusick * Global variables for this file. 40*11992Smckusick */ 4111309Smckusick static daddr_t seekpt; 4211309Smckusick static FILE *df, *mf; 4311309Smckusick static DIR *dirp; 44*11992Smckusick static char dirfile[32] = "#"; /* No file */ 45*11992Smckusick static char modefile[32] = "#"; /* No file */ 4611309Smckusick extern ino_t search(); 4711127Smckusick 48*11992Smckusick /* 49*11992Smckusick * Format of old style directories. 50*11992Smckusick */ 5111127Smckusick #define ODIRSIZ 14 5211127Smckusick struct odirect { 5311127Smckusick u_short d_ino; 5411127Smckusick char d_name[ODIRSIZ]; 5511127Smckusick }; 5611127Smckusick 5711127Smckusick /* 58*11992Smckusick * Structure and routines associated with listing directories. 59*11992Smckusick */ 60*11992Smckusick struct afile { 61*11992Smckusick ino_t fnum; /* inode number of file */ 62*11992Smckusick char *fname; /* file name */ 63*11992Smckusick short fflags; /* extraction flags, if any */ 64*11992Smckusick char ftype; /* file type, e.g. LEAF or NODE */ 65*11992Smckusick }; 66*11992Smckusick extern int fcmp(); 67*11992Smckusick extern char *fmtentry(); 68*11992Smckusick 69*11992Smckusick /* 7011127Smckusick * Extract directory contents, building up a directory structure 7111127Smckusick * on disk for extraction by name. 72*11992Smckusick * If genmode is requested, save mode, owner, and times for all 7311127Smckusick * directories on the tape. 7411127Smckusick */ 75*11992Smckusick extractdirs(genmode) 76*11992Smckusick int genmode; 7711127Smckusick { 7811127Smckusick register int i; 7911127Smckusick register struct dinode *ip; 8011322Smckusick struct inotab *itp; 8111127Smckusick struct direct nulldir; 8211127Smckusick int putdir(), null(); 8311127Smckusick 8411127Smckusick vprintf(stdout, "Extract directories from tape\n"); 85*11992Smckusick (void) sprintf(dirfile, "/tmp/rstdir%d", dumpdate); 8611127Smckusick df = fopen(dirfile, "w"); 8711127Smckusick if (df == 0) { 8811127Smckusick fprintf(stderr, 8911127Smckusick "restor: %s - cannot create directory temporary\n", 9011127Smckusick dirfile); 9111127Smckusick perror("fopen"); 9211127Smckusick done(1); 9311127Smckusick } 94*11992Smckusick if (genmode != 0) { 95*11992Smckusick (void) sprintf(modefile, "/tmp/rstmode%d", dumpdate); 9611127Smckusick mf = fopen(modefile, "w"); 9711309Smckusick if (mf == 0) { 9811127Smckusick fprintf(stderr, 9911127Smckusick "restor: %s - cannot create modefile \n", 10011127Smckusick modefile); 10111127Smckusick perror("fopen"); 10211127Smckusick done(1); 10311127Smckusick } 10411127Smckusick } 10511322Smckusick nulldir.d_ino = 0; 10611127Smckusick nulldir.d_namlen = 1; 107*11992Smckusick (void) strncpy(nulldir.d_name, "/", (int)nulldir.d_namlen); 10811127Smckusick nulldir.d_reclen = DIRSIZ(&nulldir); 10911127Smckusick for (;;) { 11011127Smckusick curfile.name = "<directory file - name unknown>"; 11111127Smckusick curfile.action = USING; 11211127Smckusick ip = curfile.dip; 11311127Smckusick i = ip->di_mode & IFMT; 11411127Smckusick if (i != IFDIR) { 11511732Smckusick (void) fclose(df); 11611127Smckusick dirp = opendir(dirfile); 11711127Smckusick if (dirp == NULL) 11811127Smckusick perror("opendir"); 11911127Smckusick if (mf != NULL) 12011732Smckusick (void) fclose(mf); 121*11992Smckusick i = dirlookup("."); 122*11992Smckusick if (i == 0) 12311421Smckusick panic("Root directory is not on tape\n"); 12411127Smckusick return; 12511127Smckusick } 12611322Smckusick itp = allocinotab(curfile.ino, ip, seekpt); 12711127Smckusick getfile(putdir, null); 12811127Smckusick putent(&nulldir); 12911127Smckusick flushent(); 13011322Smckusick itp->t_size = seekpt - itp->t_seekpt; 13111127Smckusick } 13211127Smckusick } 13311127Smckusick 13411127Smckusick /* 13511322Smckusick * skip over all the directories on the tape 13611322Smckusick */ 13711322Smckusick skipdirs() 13811322Smckusick { 13911322Smckusick 14011322Smckusick while ((curfile.dip->di_mode & IFMT) == IFDIR) { 14111322Smckusick skipfile(); 14211322Smckusick } 14311322Smckusick } 14411322Smckusick 14511322Smckusick /* 14611127Smckusick * Recursively find names and inumbers of all files in subtree 14711127Smckusick * pname and pass them off to be processed. 14811127Smckusick */ 14911127Smckusick treescan(pname, ino, todo) 15011127Smckusick char *pname; 15111127Smckusick ino_t ino; 15211744Smckusick long (*todo)(); 15311127Smckusick { 15411127Smckusick register struct inotab *itp; 15511127Smckusick int namelen; 15611127Smckusick daddr_t bpt; 15711127Smckusick register struct direct *dp; 15811644Smckusick char locname[MAXPATHLEN + 1]; 15911127Smckusick 16011127Smckusick itp = inotablookup(ino); 16111127Smckusick if (itp == NULL) { 16211127Smckusick /* 16311127Smckusick * Pname is name of a simple file or an unchanged directory. 16411127Smckusick */ 16511744Smckusick (void) (*todo)(pname, ino, LEAF); 16611127Smckusick return; 16711127Smckusick } 16811127Smckusick /* 16911127Smckusick * Pname is a dumped directory name. 17011127Smckusick */ 17111744Smckusick if ((*todo)(pname, ino, NODE) == FAIL) 17211744Smckusick return; 17311127Smckusick /* 17411127Smckusick * begin search through the directory 17511127Smckusick * skipping over "." and ".." 17611127Smckusick */ 177*11992Smckusick (void) strncpy(locname, pname, MAXPATHLEN); 178*11992Smckusick (void) strncat(locname, "/", MAXPATHLEN); 17911127Smckusick namelen = strlen(locname); 18011127Smckusick seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 18111127Smckusick dp = readdir(dirp); /* "." */ 18211127Smckusick dp = readdir(dirp); /* ".." */ 18311127Smckusick dp = readdir(dirp); /* first real entry */ 18411127Smckusick bpt = telldir(dirp); 18511127Smckusick /* 18611127Smckusick * "/" signals end of directory 18711127Smckusick */ 18811127Smckusick while (dp != NULL && !(dp->d_namlen == 1 && dp->d_name[0] == '/')) { 18911127Smckusick locname[namelen] = '\0'; 19011644Smckusick if (namelen + dp->d_namlen >= MAXPATHLEN) { 19111127Smckusick fprintf(stderr, "%s%s: name exceeds %d char\n", 19211644Smckusick locname, dp->d_name, MAXPATHLEN); 19311127Smckusick } else { 194*11992Smckusick (void) strncat(locname, dp->d_name, (int)dp->d_namlen); 19511127Smckusick treescan(locname, dp->d_ino, todo); 19611127Smckusick seekdir(dirp, bpt, itp->t_seekpt); 19711127Smckusick } 19811127Smckusick dp = readdir(dirp); 19911127Smckusick bpt = telldir(dirp); 20011127Smckusick } 20111127Smckusick if (dp == NULL) 20211127Smckusick fprintf(stderr, "corrupted directory: %s.\n", locname); 20311127Smckusick } 20411127Smckusick 20511127Smckusick /* 20611127Smckusick * Search the directory tree rooted at inode ROOTINO 20711127Smckusick * for the path pointed at by n 20811127Smckusick */ 20911127Smckusick ino_t 21011127Smckusick psearch(n) 21111127Smckusick char *n; 21211127Smckusick { 21311127Smckusick register char *cp, *cp1; 21411127Smckusick ino_t ino; 21511127Smckusick char c; 21611127Smckusick 21711127Smckusick ino = ROOTINO; 21811127Smckusick if (*(cp = n) == '/') 21911127Smckusick cp++; 22011127Smckusick next: 22111127Smckusick cp1 = cp + 1; 22211127Smckusick while (*cp1 != '/' && *cp1) 22311127Smckusick cp1++; 22411127Smckusick c = *cp1; 22511127Smckusick *cp1 = 0; 22611127Smckusick ino = search(ino, cp); 22711127Smckusick if (ino == 0) { 22811127Smckusick *cp1 = c; 22911127Smckusick return(0); 23011127Smckusick } 23111127Smckusick *cp1 = c; 23211127Smckusick if (c == '/') { 23311127Smckusick cp = cp1+1; 23411127Smckusick goto next; 23511127Smckusick } 23611127Smckusick return(ino); 23711127Smckusick } 23811127Smckusick 23911127Smckusick /* 24011127Smckusick * search the directory inode ino 24111127Smckusick * looking for entry cp 24211127Smckusick */ 24311127Smckusick ino_t 24411127Smckusick search(inum, cp) 24511127Smckusick ino_t inum; 24611127Smckusick char *cp; 24711127Smckusick { 24811127Smckusick register struct direct *dp; 24911127Smckusick register struct inotab *itp; 25011127Smckusick int len; 25111127Smckusick 25211127Smckusick itp = inotablookup(inum); 25311127Smckusick if (itp == NULL) 25411127Smckusick return(0); 25511127Smckusick seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 25611127Smckusick len = strlen(cp); 25711127Smckusick do { 25811127Smckusick dp = readdir(dirp); 25911127Smckusick if (dp->d_namlen == 1 && dp->d_name[0] == '/') 26011127Smckusick return(0); 261*11992Smckusick } while (dp->d_namlen != len || strncmp(dp->d_name, cp, len) != 0); 26211127Smckusick return(dp->d_ino); 26311127Smckusick } 26411127Smckusick 26511127Smckusick /* 26611127Smckusick * Put the directory entries in the directory file 26711127Smckusick */ 26811127Smckusick putdir(buf, size) 26911127Smckusick char *buf; 27011127Smckusick int size; 27111127Smckusick { 27211127Smckusick struct direct cvtbuf; 27311127Smckusick register struct odirect *odp; 27411127Smckusick struct odirect *eodp; 27511127Smckusick register struct direct *dp; 27611127Smckusick long loc, i; 27711127Smckusick 27811127Smckusick if (cvtflag) { 27911127Smckusick eodp = (struct odirect *)&buf[size]; 28011127Smckusick for (odp = (struct odirect *)buf; odp < eodp; odp++) 28111127Smckusick if (odp->d_ino != 0) { 28211127Smckusick dcvt(odp, &cvtbuf); 28311127Smckusick putent(&cvtbuf); 28411127Smckusick } 28511127Smckusick } else { 28611127Smckusick for (loc = 0; loc < size; ) { 28711127Smckusick dp = (struct direct *)(buf + loc); 28811127Smckusick i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1)); 28911127Smckusick if (dp->d_reclen == 0 || dp->d_reclen > i) { 29011127Smckusick loc += i; 29111127Smckusick continue; 29211127Smckusick } 29311127Smckusick loc += dp->d_reclen; 29411127Smckusick if (dp->d_ino != 0) { 29511127Smckusick putent(dp); 29611127Smckusick } 29711127Smckusick } 29811127Smckusick } 29911127Smckusick } 30011127Smckusick 30111127Smckusick /* 30211127Smckusick * These variables are "local" to the following two functions. 30311127Smckusick */ 30411127Smckusick char dirbuf[DIRBLKSIZ]; 30511127Smckusick long dirloc = 0; 30611127Smckusick long prev = 0; 30711127Smckusick 30811127Smckusick /* 30911127Smckusick * add a new directory entry to a file. 31011127Smckusick */ 31111127Smckusick putent(dp) 31211127Smckusick struct direct *dp; 31311127Smckusick { 31411322Smckusick dp->d_reclen = DIRSIZ(dp); 31511127Smckusick if (dirloc + dp->d_reclen > DIRBLKSIZ) { 31611127Smckusick ((struct direct *)(dirbuf + prev))->d_reclen = 31711127Smckusick DIRBLKSIZ - prev; 31811732Smckusick (void) fwrite(dirbuf, 1, DIRBLKSIZ, df); 31911127Smckusick dirloc = 0; 32011127Smckusick } 32111127Smckusick bcopy((char *)dp, dirbuf + dirloc, (long)dp->d_reclen); 32211127Smckusick prev = dirloc; 32311127Smckusick dirloc += dp->d_reclen; 32411127Smckusick } 32511127Smckusick 32611127Smckusick /* 32711127Smckusick * flush out a directory that is finished. 32811127Smckusick */ 32911127Smckusick flushent() 33011127Smckusick { 33111127Smckusick 33211127Smckusick ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev; 33311732Smckusick (void) fwrite(dirbuf, (int)dirloc, 1, df); 33411127Smckusick seekpt = ftell(df); 33511127Smckusick dirloc = 0; 33611127Smckusick } 33711127Smckusick 33811127Smckusick dcvt(odp, ndp) 33911127Smckusick register struct odirect *odp; 34011127Smckusick register struct direct *ndp; 34111127Smckusick { 34211127Smckusick 34311127Smckusick bzero((char *)ndp, (long)(sizeof *ndp)); 34411127Smckusick ndp->d_ino = odp->d_ino; 345*11992Smckusick (void) strncpy(ndp->d_name, odp->d_name, ODIRSIZ); 34611127Smckusick ndp->d_namlen = strlen(ndp->d_name); 34711127Smckusick ndp->d_reclen = DIRSIZ(ndp); 34811127Smckusick } 34911127Smckusick 35011127Smckusick /* 35111127Smckusick * Seek to an entry in a directory. 35211127Smckusick * Only values returned by ``telldir'' should be passed to seekdir. 35311732Smckusick * This routine handles many directories in a single file. 35411732Smckusick * It takes the base of the directory in the file, plus 35511732Smckusick * the desired seek offset into it. 35611127Smckusick */ 35711127Smckusick void 35811127Smckusick seekdir(dirp, loc, base) 35911127Smckusick register DIR *dirp; 36011127Smckusick daddr_t loc, base; 36111127Smckusick { 36211127Smckusick 36311127Smckusick if (loc == telldir(dirp)) 36411127Smckusick return; 36511127Smckusick loc -= base; 36611127Smckusick if (loc < 0) 36711127Smckusick fprintf(stderr, "bad seek pointer to seekdir %d\n", loc); 36811127Smckusick (void) lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), 0); 36911127Smckusick dirp->dd_loc = loc & (DIRBLKSIZ - 1); 37011127Smckusick if (dirp->dd_loc != 0) 37111127Smckusick dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ); 37211127Smckusick } 37311127Smckusick 37411127Smckusick /* 37511127Smckusick * get next entry in a directory. 37611127Smckusick */ 37711127Smckusick struct direct * 37811127Smckusick readdir(dirp) 37911127Smckusick register DIR *dirp; 38011127Smckusick { 38111127Smckusick register struct direct *dp; 38211127Smckusick 38311127Smckusick for (;;) { 38411127Smckusick if (dirp->dd_loc == 0) { 38511127Smckusick dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, 38611127Smckusick DIRBLKSIZ); 38711127Smckusick if (dirp->dd_size <= 0) 38811127Smckusick return NULL; 38911127Smckusick } 39011127Smckusick if (dirp->dd_loc >= dirp->dd_size) { 39111127Smckusick dirp->dd_loc = 0; 39211127Smckusick continue; 39311127Smckusick } 39411127Smckusick dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc); 39511127Smckusick if (dp->d_reclen == 0 || 39611127Smckusick dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) 39711127Smckusick return NULL; 39811127Smckusick dirp->dd_loc += dp->d_reclen; 39911127Smckusick return (dp); 40011127Smckusick } 40111127Smckusick } 40211127Smckusick 40311127Smckusick /* 40411127Smckusick * Set the mode, owner, and times for all new or changed directories 40511127Smckusick */ 406*11992Smckusick setdirmodes() 40711127Smckusick { 40811127Smckusick FILE *mf; 40911127Smckusick struct modeinfo node; 41011127Smckusick struct entry *ep; 41111127Smckusick char *cp; 41211127Smckusick 41311127Smckusick vprintf(stdout, "Set directory mode, owner, and times.\n"); 41411127Smckusick mf = fopen(modefile, "r"); 41511127Smckusick if (mf == NULL) { 41611127Smckusick perror("fopen"); 41711127Smckusick panic("cannot open mode file %s\n", modefile); 41811127Smckusick } 41911127Smckusick clearerr(mf); 42011309Smckusick for (;;) { 42111732Smckusick (void) fread((char *)&node, 1, sizeof(struct modeinfo), mf); 42211309Smckusick if (feof(mf)) 42311309Smckusick break; 42411127Smckusick ep = lookupino(node.ino); 425*11992Smckusick if (ep == NIL || (ep->e_flags & NEW) == 0) { 426*11992Smckusick if (command != 'r' && command != 'R') 42711309Smckusick continue; 42811127Smckusick panic("cannot find directory inode %d\n", node.ino); 42911309Smckusick } 43011127Smckusick cp = myname(ep); 43111732Smckusick (void) chown(cp, node.uid, node.gid); 43211732Smckusick (void) chmod(cp, node.mode); 43311127Smckusick utime(cp, node.timep); 434*11992Smckusick ep->e_flags &= ~NEW; 43511127Smckusick } 43611127Smckusick if (ferror(mf)) 43711127Smckusick panic("error setting directory modes\n"); 43811732Smckusick (void) fclose(mf); 43911127Smckusick } 44011127Smckusick 44111127Smckusick /* 44211127Smckusick * Generate a literal copy of a directory. 44311127Smckusick */ 44411127Smckusick genliteraldir(name, ino) 44511127Smckusick char *name; 44611127Smckusick ino_t ino; 44711127Smckusick { 44811127Smckusick register struct inotab *itp; 44911127Smckusick int ofile, dp, i, size; 45011127Smckusick char buf[BUFSIZ]; 45111127Smckusick 45211127Smckusick itp = inotablookup(ino); 45311127Smckusick if (itp == NULL) 45411322Smckusick panic("Cannot find directory inode %d named %s\n", ino, name); 45511127Smckusick if ((ofile = open(name, FWRONLY|FCREATE, 0666)) < 0) { 45611127Smckusick fprintf(stderr, "%s: cannot create file\n", name); 45711127Smckusick return (FAIL); 45811127Smckusick } 45911127Smckusick seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 46011127Smckusick dp = dup(dirp->dd_fd); 46111127Smckusick for (i = itp->t_size; i > 0; i -= BUFSIZ) { 46211127Smckusick size = i < BUFSIZ ? i : BUFSIZ; 46311127Smckusick if (read(dp, buf, (int) size) == -1) { 46411127Smckusick fprintf(stderr, 46511127Smckusick "write error extracting inode %d, name %s\n", 46611127Smckusick curfile.ino, curfile.name); 46711127Smckusick perror("read"); 46811127Smckusick done(1); 46911127Smckusick } 47011127Smckusick if (write(ofile, buf, (int) size) == -1) { 47111127Smckusick fprintf(stderr, 47211127Smckusick "write error extracting inode %d, name %s\n", 47311127Smckusick curfile.ino, curfile.name); 47411127Smckusick perror("write"); 47511127Smckusick done(1); 47611127Smckusick } 47711127Smckusick } 47811732Smckusick (void) close(dp); 47911732Smckusick (void) close(ofile); 48011127Smckusick return (GOOD); 48111127Smckusick } 48211127Smckusick 48311127Smckusick /* 484*11992Smckusick * Do an "ls" style listing of a directory 485*11992Smckusick */ 486*11992Smckusick printlist(name, ino) 487*11992Smckusick char *name; 488*11992Smckusick ino_t ino; 489*11992Smckusick { 490*11992Smckusick register struct afile *fp; 491*11992Smckusick register struct inotab *itp; 492*11992Smckusick struct afile *dfp0, *dfplast; 493*11992Smckusick struct afile single; 494*11992Smckusick 495*11992Smckusick itp = inotablookup(ino); 496*11992Smckusick if (itp == NULL) { 497*11992Smckusick single.fnum = ino; 498*11992Smckusick single.fname = savename(rindex(name, '/') + 1); 499*11992Smckusick dfp0 = &single; 500*11992Smckusick dfplast = dfp0 + 1; 501*11992Smckusick } else { 502*11992Smckusick seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 503*11992Smckusick if (getdir(dirp, &dfp0, &dfplast) == FAIL) 504*11992Smckusick return; 505*11992Smckusick } 506*11992Smckusick qsort((char *)dfp0, dfplast - dfp0, sizeof (struct afile), fcmp); 507*11992Smckusick formatf(dfp0, dfplast); 508*11992Smckusick for (fp = dfp0; fp < dfplast; fp++) 509*11992Smckusick freename(fp->fname); 510*11992Smckusick } 511*11992Smckusick 512*11992Smckusick /* 513*11992Smckusick * Read the contents of a directory. 514*11992Smckusick */ 515*11992Smckusick getdir(dirp, pfp0, pfplast) 516*11992Smckusick DIR *dirp; 517*11992Smckusick struct afile **pfp0, **pfplast; 518*11992Smckusick { 519*11992Smckusick register struct afile *fp; 520*11992Smckusick register struct direct *dp; 521*11992Smckusick static struct afile *basefp = NULL; 522*11992Smckusick static long nent = 20; 523*11992Smckusick 524*11992Smckusick if (basefp == NULL) 525*11992Smckusick basefp = (struct afile *)calloc((unsigned)nent, 526*11992Smckusick sizeof (struct afile)); 527*11992Smckusick fp = *pfp0 = basefp; 528*11992Smckusick *pfplast = *pfp0 + nent; 529*11992Smckusick while (dp = readdir(dirp)) { 530*11992Smckusick if (dp->d_ino == 0 && strcmp(dp->d_name, "/") == 0) 531*11992Smckusick break; 532*11992Smckusick if (BIT(dp->d_ino, dumpmap) == 0) 533*11992Smckusick continue; 534*11992Smckusick if (vflag == 0 && 535*11992Smckusick (strcmp(dp->d_name, ".") == 0 || 536*11992Smckusick strcmp(dp->d_name, "..") == 0)) 537*11992Smckusick continue; 538*11992Smckusick fp->fnum = dp->d_ino; 539*11992Smckusick fp->fname = savename(dp->d_name); 540*11992Smckusick fp++; 541*11992Smckusick if (fp == *pfplast) { 542*11992Smckusick basefp = (struct afile *)realloc((char *)basefp, 543*11992Smckusick (unsigned)(2 * nent * sizeof (struct afile))); 544*11992Smckusick if (basefp == 0) { 545*11992Smckusick fprintf(stderr, "ls: out of memory\n"); 546*11992Smckusick return (FAIL); 547*11992Smckusick } 548*11992Smckusick *pfp0 = basefp; 549*11992Smckusick fp = *pfp0 + nent; 550*11992Smckusick *pfplast = fp + nent; 551*11992Smckusick nent *= 2; 552*11992Smckusick } 553*11992Smckusick } 554*11992Smckusick *pfplast = fp; 555*11992Smckusick return (GOOD); 556*11992Smckusick } 557*11992Smckusick 558*11992Smckusick /* 559*11992Smckusick * Print out a pretty listing of a directory 560*11992Smckusick */ 561*11992Smckusick formatf(fp0, fplast) 562*11992Smckusick struct afile *fp0, *fplast; 563*11992Smckusick { 564*11992Smckusick register struct afile *fp; 565*11992Smckusick struct entry *np; 566*11992Smckusick int width = 0, w, nentry = fplast - fp0; 567*11992Smckusick int i, j, len, columns, lines; 568*11992Smckusick char *cp; 569*11992Smckusick 570*11992Smckusick if (fp0 == fplast) 571*11992Smckusick return; 572*11992Smckusick for (fp = fp0; fp < fplast; fp++) { 573*11992Smckusick fp->ftype = inodetype(fp->fnum); 574*11992Smckusick np = lookupino(fp->fnum); 575*11992Smckusick if (np != NIL) 576*11992Smckusick fp->fflags = np->e_flags; 577*11992Smckusick else 578*11992Smckusick fp->fflags = 0; 579*11992Smckusick len = strlen(fmtentry(fp)); 580*11992Smckusick if (len > width) 581*11992Smckusick width = len; 582*11992Smckusick } 583*11992Smckusick width += 2; 584*11992Smckusick columns = 80 / width; 585*11992Smckusick if (columns == 0) 586*11992Smckusick columns = 1; 587*11992Smckusick lines = (nentry + columns - 1) / columns; 588*11992Smckusick for (i = 0; i < lines; i++) { 589*11992Smckusick for (j = 0; j < columns; j++) { 590*11992Smckusick fp = fp0 + j * lines + i; 591*11992Smckusick cp = fmtentry(fp); 592*11992Smckusick fprintf(stderr, "%s", cp); 593*11992Smckusick if (fp + lines >= fplast) { 594*11992Smckusick fprintf(stderr, "\n"); 595*11992Smckusick break; 596*11992Smckusick } 597*11992Smckusick w = strlen(cp); 598*11992Smckusick while (w < width) { 599*11992Smckusick w++; 600*11992Smckusick fprintf(stderr, " "); 601*11992Smckusick } 602*11992Smckusick } 603*11992Smckusick } 604*11992Smckusick } 605*11992Smckusick 606*11992Smckusick /* 607*11992Smckusick * Comparison routine for qsort. 608*11992Smckusick */ 609*11992Smckusick fcmp(f1, f2) 610*11992Smckusick register struct afile *f1, *f2; 611*11992Smckusick { 612*11992Smckusick 613*11992Smckusick return (strcmp(f1->fname, f2->fname)); 614*11992Smckusick } 615*11992Smckusick 616*11992Smckusick /* 617*11992Smckusick * Format a directory entry. 618*11992Smckusick */ 619*11992Smckusick char * 620*11992Smckusick fmtentry(fp) 621*11992Smckusick register struct afile *fp; 622*11992Smckusick { 623*11992Smckusick static char fmtres[BUFSIZ]; 624*11992Smckusick register char *cp, *dp; 625*11992Smckusick 626*11992Smckusick if (vflag) 627*11992Smckusick (void) sprintf(fmtres, "%5d ", fp->fnum); 628*11992Smckusick else 629*11992Smckusick fmtres[0] = '\0'; 630*11992Smckusick dp = &fmtres[strlen(fmtres)]; 631*11992Smckusick if ((fp->fflags & NEW) != 0) 632*11992Smckusick *dp++ = '*'; 633*11992Smckusick else 634*11992Smckusick *dp++ = ' '; 635*11992Smckusick for (cp = fp->fname; *cp; cp++) 636*11992Smckusick if (!vflag && (*cp < ' ' || *cp >= 0177)) 637*11992Smckusick *dp++ = '?'; 638*11992Smckusick else 639*11992Smckusick *dp++ = *cp; 640*11992Smckusick if (fp->ftype == NODE) 641*11992Smckusick *dp++ = '/'; 642*11992Smckusick *dp++ = 0; 643*11992Smckusick return (fmtres); 644*11992Smckusick } 645*11992Smckusick 646*11992Smckusick /* 647*11992Smckusick * Determine the type of an inode 648*11992Smckusick */ 649*11992Smckusick inodetype(ino) 650*11992Smckusick ino_t ino; 651*11992Smckusick { 652*11992Smckusick struct inotab *itp; 653*11992Smckusick 654*11992Smckusick itp = inotablookup(ino); 655*11992Smckusick if (itp == NULL) 656*11992Smckusick return (LEAF); 657*11992Smckusick return (NODE); 658*11992Smckusick } 659*11992Smckusick 660*11992Smckusick /* 66111127Smckusick * Allocate and initialize a directory inode entry. 66211127Smckusick * If requested, save its pertinent mode, owner, and time info. 66311127Smckusick */ 66411322Smckusick struct inotab * 66511127Smckusick allocinotab(ino, dip, seekpt) 66611127Smckusick ino_t ino; 66711127Smckusick struct dinode *dip; 66811127Smckusick daddr_t seekpt; 66911127Smckusick { 67011127Smckusick register struct inotab *itp; 67111127Smckusick struct modeinfo node; 67211127Smckusick 67311127Smckusick itp = (struct inotab *)calloc(1, sizeof(struct inotab)); 67411127Smckusick itp->t_next = inotab[INOHASH(ino)]; 67511127Smckusick inotab[INOHASH(ino)] = itp; 67611127Smckusick itp->t_ino = ino; 67711127Smckusick itp->t_seekpt = seekpt; 67811127Smckusick if (mf == NULL) 67911322Smckusick return(itp); 68011127Smckusick node.ino = ino; 68111127Smckusick node.timep[0] = dip->di_atime; 68211127Smckusick node.timep[1] = dip->di_mtime; 68311127Smckusick node.mode = dip->di_mode; 68411127Smckusick node.uid = dip->di_uid; 68511127Smckusick node.gid = dip->di_gid; 68611732Smckusick (void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf); 68711322Smckusick return(itp); 68811127Smckusick } 68911127Smckusick 69011127Smckusick /* 69111127Smckusick * Look up an inode in the table of directories 69211127Smckusick */ 69311127Smckusick struct inotab * 69411127Smckusick inotablookup(ino) 69511127Smckusick ino_t ino; 69611127Smckusick { 69711127Smckusick register struct inotab *itp; 69811127Smckusick 69911127Smckusick for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next) 70011127Smckusick if (itp->t_ino == ino) 70111127Smckusick return(itp); 70211127Smckusick return ((struct inotab *)0); 70311127Smckusick } 70411127Smckusick 70511127Smckusick /* 70611127Smckusick * Clean up and exit 70711127Smckusick */ 70811127Smckusick done(exitcode) 70911127Smckusick int exitcode; 71011127Smckusick { 71111127Smckusick 71211127Smckusick closemt(); 713*11992Smckusick if (modefile[0] != '#') 714*11992Smckusick (void) unlink(modefile); 715*11992Smckusick if (dirfile[0] != '#') 716*11992Smckusick (void) unlink(dirfile); 71711127Smckusick exit(exitcode); 71811127Smckusick } 719