111127Smckusick /* Copyright (c) 1983 Regents of the University of California */ 211127Smckusick 311127Smckusick #ifndef lint 4*11322Smckusick static char sccsid[] = "@(#)dirs.c 3.3 (Berkeley) 83/02/28"; 511127Smckusick #endif 611127Smckusick 711127Smckusick #include "restore.h" 811127Smckusick #include <dumprestor.h> 911309Smckusick #include <sys/file.h> 1011127Smckusick #include <dir.h> 1111127Smckusick 1211127Smckusick #define HASHSIZE 1000 1311127Smckusick 1411127Smckusick #define INOHASH(val) (val % HASHSIZE) 1511127Smckusick struct inotab { 1611127Smckusick struct inotab *t_next; 1711127Smckusick ino_t t_ino; 1811127Smckusick daddr_t t_seekpt; 1911127Smckusick long t_size; 2011309Smckusick }; 2111309Smckusick static struct inotab *inotab[HASHSIZE]; 2211309Smckusick extern struct inotab *inotablookup(); 23*11322Smckusick extern struct inotab *allocinotab(); 2411127Smckusick 2511127Smckusick struct modeinfo { 2611127Smckusick ino_t ino; 2711127Smckusick time_t timep[2]; 2811127Smckusick short mode; 2911127Smckusick short uid; 3011127Smckusick short gid; 3111127Smckusick }; 3211127Smckusick 3311309Smckusick static daddr_t seekpt; 3411309Smckusick static FILE *df, *mf; 3511309Smckusick static DIR *dirp; 3611309Smckusick static char dirfile[] = "/tmp/rstaXXXXXX"; 3711309Smckusick extern ino_t search(); 3811127Smckusick 3911127Smckusick #define ODIRSIZ 14 4011127Smckusick struct odirect { 4111127Smckusick u_short d_ino; 4211127Smckusick char d_name[ODIRSIZ]; 4311127Smckusick }; 4411127Smckusick 4511127Smckusick /* 4611127Smckusick * Extract directory contents, building up a directory structure 4711127Smckusick * on disk for extraction by name. 4811127Smckusick * If modefile is requested, save mode, owner, and times for all 4911127Smckusick * directories on the tape. 5011127Smckusick */ 5111127Smckusick extractdirs(modefile) 5211127Smckusick char *modefile; 5311127Smckusick { 5411127Smckusick register int i; 5511127Smckusick register struct dinode *ip; 56*11322Smckusick struct inotab *itp; 5711127Smckusick struct direct nulldir; 5811127Smckusick int putdir(), null(); 5911127Smckusick 6011127Smckusick vprintf(stdout, "Extract directories from tape\n"); 6111127Smckusick mktemp(dirfile); 6211127Smckusick df = fopen(dirfile, "w"); 6311127Smckusick if (df == 0) { 6411127Smckusick fprintf(stderr, 6511127Smckusick "restor: %s - cannot create directory temporary\n", 6611127Smckusick dirfile); 6711127Smckusick perror("fopen"); 6811127Smckusick done(1); 6911127Smckusick } 7011127Smckusick if (modefile != NULL) { 7111127Smckusick mf = fopen(modefile, "w"); 7211309Smckusick if (mf == 0) { 7311127Smckusick fprintf(stderr, 7411127Smckusick "restor: %s - cannot create modefile \n", 7511127Smckusick modefile); 7611127Smckusick perror("fopen"); 7711127Smckusick done(1); 7811127Smckusick } 7911127Smckusick } 80*11322Smckusick nulldir.d_ino = 0; 8111127Smckusick nulldir.d_namlen = 1; 8211127Smckusick strncpy(nulldir.d_name, "/", nulldir.d_namlen); 8311127Smckusick nulldir.d_reclen = DIRSIZ(&nulldir); 8411127Smckusick for (;;) { 8511127Smckusick curfile.name = "<directory file - name unknown>"; 8611127Smckusick curfile.action = USING; 8711127Smckusick ip = curfile.dip; 8811127Smckusick i = ip->di_mode & IFMT; 8911127Smckusick if (i != IFDIR) { 9011127Smckusick fclose(df); 9111127Smckusick dirp = opendir(dirfile); 9211127Smckusick if (dirp == NULL) 9311127Smckusick perror("opendir"); 9411127Smckusick if (mf != NULL) 9511127Smckusick fclose(mf); 9611127Smckusick return; 9711127Smckusick } 98*11322Smckusick itp = allocinotab(curfile.ino, ip, seekpt); 9911127Smckusick getfile(putdir, null); 10011127Smckusick putent(&nulldir); 10111127Smckusick flushent(); 102*11322Smckusick itp->t_size = seekpt - itp->t_seekpt; 10311127Smckusick } 10411127Smckusick } 10511127Smckusick 10611127Smckusick /* 107*11322Smckusick * skip over all the directories on the tape 108*11322Smckusick */ 109*11322Smckusick skipdirs() 110*11322Smckusick { 111*11322Smckusick 112*11322Smckusick while ((curfile.dip->di_mode & IFMT) == IFDIR) { 113*11322Smckusick skipfile(); 114*11322Smckusick } 115*11322Smckusick } 116*11322Smckusick 117*11322Smckusick /* 11811127Smckusick * Recursively find names and inumbers of all files in subtree 11911127Smckusick * pname and pass them off to be processed. 12011127Smckusick */ 12111127Smckusick treescan(pname, ino, todo) 12211127Smckusick char *pname; 12311127Smckusick ino_t ino; 12411127Smckusick void (*todo)(); 12511127Smckusick { 12611127Smckusick register struct inotab *itp; 12711127Smckusick int namelen; 12811127Smckusick daddr_t bpt; 12911127Smckusick register struct direct *dp; 13011127Smckusick char locname[BUFSIZ + 1]; 13111127Smckusick 13211127Smckusick itp = inotablookup(ino); 13311127Smckusick if (itp == NULL) { 13411127Smckusick /* 13511127Smckusick * Pname is name of a simple file or an unchanged directory. 13611127Smckusick */ 13711127Smckusick (*todo)(pname, ino, LEAF); 13811127Smckusick return; 13911127Smckusick } 14011127Smckusick /* 14111127Smckusick * Pname is a dumped directory name. 14211127Smckusick */ 14311127Smckusick (*todo)(pname, ino, NODE); 14411127Smckusick /* 14511127Smckusick * begin search through the directory 14611127Smckusick * skipping over "." and ".." 14711127Smckusick */ 14811127Smckusick strncpy(locname, pname, BUFSIZ); 14911127Smckusick strncat(locname, "/", BUFSIZ); 15011127Smckusick namelen = strlen(locname); 15111127Smckusick seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 15211127Smckusick dp = readdir(dirp); /* "." */ 15311127Smckusick dp = readdir(dirp); /* ".." */ 15411127Smckusick dp = readdir(dirp); /* first real entry */ 15511127Smckusick bpt = telldir(dirp); 15611127Smckusick /* 15711127Smckusick * "/" signals end of directory 15811127Smckusick */ 15911127Smckusick while (dp != NULL && !(dp->d_namlen == 1 && dp->d_name[0] == '/')) { 16011127Smckusick locname[namelen] = '\0'; 16111127Smckusick if (namelen + dp->d_namlen >= BUFSIZ) { 16211127Smckusick fprintf(stderr, "%s%s: name exceeds %d char\n", 16311127Smckusick locname, dp->d_name, BUFSIZ); 16411127Smckusick } else { 16511127Smckusick strncat(locname, dp->d_name, dp->d_namlen); 16611127Smckusick treescan(locname, dp->d_ino, todo); 16711127Smckusick seekdir(dirp, bpt, itp->t_seekpt); 16811127Smckusick } 16911127Smckusick dp = readdir(dirp); 17011127Smckusick bpt = telldir(dirp); 17111127Smckusick } 17211127Smckusick if (dp == NULL) 17311127Smckusick fprintf(stderr, "corrupted directory: %s.\n", locname); 17411127Smckusick } 17511127Smckusick 17611127Smckusick /* 17711127Smckusick * Search the directory tree rooted at inode ROOTINO 17811127Smckusick * for the path pointed at by n 17911127Smckusick */ 18011127Smckusick ino_t 18111127Smckusick psearch(n) 18211127Smckusick char *n; 18311127Smckusick { 18411127Smckusick register char *cp, *cp1; 18511127Smckusick ino_t ino; 18611127Smckusick char c; 18711127Smckusick 18811127Smckusick ino = ROOTINO; 18911127Smckusick if (*(cp = n) == '/') 19011127Smckusick cp++; 19111127Smckusick next: 19211127Smckusick cp1 = cp + 1; 19311127Smckusick while (*cp1 != '/' && *cp1) 19411127Smckusick cp1++; 19511127Smckusick c = *cp1; 19611127Smckusick *cp1 = 0; 19711127Smckusick ino = search(ino, cp); 19811127Smckusick if (ino == 0) { 19911127Smckusick *cp1 = c; 20011127Smckusick return(0); 20111127Smckusick } 20211127Smckusick *cp1 = c; 20311127Smckusick if (c == '/') { 20411127Smckusick cp = cp1+1; 20511127Smckusick goto next; 20611127Smckusick } 20711127Smckusick return(ino); 20811127Smckusick } 20911127Smckusick 21011127Smckusick /* 21111127Smckusick * search the directory inode ino 21211127Smckusick * looking for entry cp 21311127Smckusick */ 21411127Smckusick ino_t 21511127Smckusick search(inum, cp) 21611127Smckusick ino_t inum; 21711127Smckusick char *cp; 21811127Smckusick { 21911127Smckusick register struct direct *dp; 22011127Smckusick register struct inotab *itp; 22111127Smckusick int len; 22211127Smckusick 22311127Smckusick itp = inotablookup(inum); 22411127Smckusick if (itp == NULL) 22511127Smckusick return(0); 22611127Smckusick seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 22711127Smckusick len = strlen(cp); 22811127Smckusick do { 22911127Smckusick dp = readdir(dirp); 23011127Smckusick if (dp->d_namlen == 1 && dp->d_name[0] == '/') 23111127Smckusick return(0); 23211127Smckusick } while (dp->d_namlen != len || strncmp(dp->d_name, cp, len)); 23311127Smckusick return(dp->d_ino); 23411127Smckusick } 23511127Smckusick 23611127Smckusick /* 23711127Smckusick * Put the directory entries in the directory file 23811127Smckusick */ 23911127Smckusick putdir(buf, size) 24011127Smckusick char *buf; 24111127Smckusick int size; 24211127Smckusick { 24311127Smckusick struct direct cvtbuf; 24411127Smckusick register struct odirect *odp; 24511127Smckusick struct odirect *eodp; 24611127Smckusick register struct direct *dp; 24711127Smckusick long loc, i; 24811127Smckusick 24911127Smckusick if (cvtflag) { 25011127Smckusick eodp = (struct odirect *)&buf[size]; 25111127Smckusick for (odp = (struct odirect *)buf; odp < eodp; odp++) 25211127Smckusick if (odp->d_ino != 0) { 25311127Smckusick dcvt(odp, &cvtbuf); 25411127Smckusick putent(&cvtbuf); 25511127Smckusick } 25611127Smckusick } else { 25711127Smckusick for (loc = 0; loc < size; ) { 25811127Smckusick dp = (struct direct *)(buf + loc); 25911127Smckusick i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1)); 26011127Smckusick if (dp->d_reclen == 0 || dp->d_reclen > i) { 26111127Smckusick loc += i; 26211127Smckusick continue; 26311127Smckusick } 26411127Smckusick loc += dp->d_reclen; 26511127Smckusick if (dp->d_ino != 0) { 26611127Smckusick putent(dp); 26711127Smckusick } 26811127Smckusick } 26911127Smckusick } 27011127Smckusick } 27111127Smckusick 27211127Smckusick /* 27311127Smckusick * These variables are "local" to the following two functions. 27411127Smckusick */ 27511127Smckusick char dirbuf[DIRBLKSIZ]; 27611127Smckusick long dirloc = 0; 27711127Smckusick long prev = 0; 27811127Smckusick 27911127Smckusick /* 28011127Smckusick * add a new directory entry to a file. 28111127Smckusick */ 28211127Smckusick putent(dp) 28311127Smckusick struct direct *dp; 28411127Smckusick { 285*11322Smckusick dp->d_reclen = DIRSIZ(dp); 28611127Smckusick if (dirloc + dp->d_reclen > DIRBLKSIZ) { 28711127Smckusick ((struct direct *)(dirbuf + prev))->d_reclen = 28811127Smckusick DIRBLKSIZ - prev; 28911127Smckusick fwrite(dirbuf, 1, DIRBLKSIZ, df); 29011127Smckusick dirloc = 0; 29111127Smckusick } 29211127Smckusick bcopy((char *)dp, dirbuf + dirloc, (long)dp->d_reclen); 29311127Smckusick prev = dirloc; 29411127Smckusick dirloc += dp->d_reclen; 29511127Smckusick } 29611127Smckusick 29711127Smckusick /* 29811127Smckusick * flush out a directory that is finished. 29911127Smckusick */ 30011127Smckusick flushent() 30111127Smckusick { 30211127Smckusick 30311127Smckusick ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev; 30411127Smckusick fwrite(dirbuf, (int)dirloc, 1, df); 30511127Smckusick seekpt = ftell(df); 30611127Smckusick dirloc = 0; 30711127Smckusick } 30811127Smckusick 30911127Smckusick dcvt(odp, ndp) 31011127Smckusick register struct odirect *odp; 31111127Smckusick register struct direct *ndp; 31211127Smckusick { 31311127Smckusick 31411127Smckusick bzero((char *)ndp, (long)(sizeof *ndp)); 31511127Smckusick ndp->d_ino = odp->d_ino; 31611127Smckusick strncpy(ndp->d_name, odp->d_name, ODIRSIZ); 31711127Smckusick ndp->d_namlen = strlen(ndp->d_name); 31811127Smckusick ndp->d_reclen = DIRSIZ(ndp); 31911127Smckusick /* 32011127Smckusick * this quickly calculates if this inode is a directory. 32111127Smckusick * Currently not maintained. 32211127Smckusick * 32311127Smckusick itp = inotablookup(odp->d_ino); 32411127Smckusick if (itp != NIL) 32511127Smckusick ndp->d_fmt = IFDIR; 32611127Smckusick */ 32711127Smckusick } 32811127Smckusick 32911127Smckusick /* 33011127Smckusick * Open a directory. 33111127Smckusick * Modified to allow any random file to be a legal directory. 33211127Smckusick */ 33311127Smckusick DIR * 33411127Smckusick opendir(name) 33511127Smckusick char *name; 33611127Smckusick { 33711127Smckusick register DIR *dirp; 33811127Smckusick 33911127Smckusick dirp = (DIR *)malloc((unsigned long)sizeof(DIR)); 34011127Smckusick dirp->dd_fd = open(name, 0); 34111127Smckusick if (dirp->dd_fd == -1) { 34211127Smckusick free((char *)dirp); 34311127Smckusick return NULL; 34411127Smckusick } 34511127Smckusick dirp->dd_loc = 0; 34611127Smckusick return dirp; 34711127Smckusick } 34811127Smckusick 34911127Smckusick /* 35011127Smckusick * Seek to an entry in a directory. 35111127Smckusick * Only values returned by ``telldir'' should be passed to seekdir. 35211127Smckusick * Modified to have many directories based in one file. 35311127Smckusick */ 35411127Smckusick void 35511127Smckusick seekdir(dirp, loc, base) 35611127Smckusick register DIR *dirp; 35711127Smckusick daddr_t loc, base; 35811127Smckusick { 35911127Smckusick 36011127Smckusick if (loc == telldir(dirp)) 36111127Smckusick return; 36211127Smckusick loc -= base; 36311127Smckusick if (loc < 0) 36411127Smckusick fprintf(stderr, "bad seek pointer to seekdir %d\n", loc); 36511127Smckusick (void) lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), 0); 36611127Smckusick dirp->dd_loc = loc & (DIRBLKSIZ - 1); 36711127Smckusick if (dirp->dd_loc != 0) 36811127Smckusick dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ); 36911127Smckusick } 37011127Smckusick 37111127Smckusick /* 37211127Smckusick * get next entry in a directory. 37311127Smckusick */ 37411127Smckusick struct direct * 37511127Smckusick readdir(dirp) 37611127Smckusick register DIR *dirp; 37711127Smckusick { 37811127Smckusick register struct direct *dp; 37911127Smckusick 38011127Smckusick for (;;) { 38111127Smckusick if (dirp->dd_loc == 0) { 38211127Smckusick dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, 38311127Smckusick DIRBLKSIZ); 38411127Smckusick if (dirp->dd_size <= 0) 38511127Smckusick return NULL; 38611127Smckusick } 38711127Smckusick if (dirp->dd_loc >= dirp->dd_size) { 38811127Smckusick dirp->dd_loc = 0; 38911127Smckusick continue; 39011127Smckusick } 39111127Smckusick dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc); 39211127Smckusick if (dp->d_reclen == 0 || 39311127Smckusick dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) 39411127Smckusick return NULL; 39511127Smckusick dirp->dd_loc += dp->d_reclen; 39611127Smckusick return (dp); 39711127Smckusick } 39811127Smckusick } 39911127Smckusick 40011127Smckusick /* 40111127Smckusick * Set the mode, owner, and times for all new or changed directories 40211127Smckusick */ 40311127Smckusick setdirmodes(modefile) 40411127Smckusick char *modefile; 40511127Smckusick { 40611127Smckusick FILE *mf; 40711127Smckusick struct modeinfo node; 40811127Smckusick struct entry *ep; 40911127Smckusick char *cp; 41011127Smckusick 41111127Smckusick vprintf(stdout, "Set directory mode, owner, and times.\n"); 41211127Smckusick mf = fopen(modefile, "r"); 41311127Smckusick if (mf == NULL) { 41411127Smckusick perror("fopen"); 41511127Smckusick panic("cannot open mode file %s\n", modefile); 41611127Smckusick } 41711127Smckusick clearerr(mf); 41811309Smckusick for (;;) { 41911309Smckusick fread((char *)&node, 1, sizeof(struct modeinfo), mf); 42011309Smckusick if (feof(mf)) 42111309Smckusick break; 42211127Smckusick ep = lookupino(node.ino); 42311309Smckusick if (ep == NIL) { 42411309Smckusick if (command == 'x') 42511309Smckusick continue; 42611127Smckusick panic("cannot find directory inode %d\n", node.ino); 42711309Smckusick } 42811127Smckusick cp = myname(ep); 42911127Smckusick chown(cp, node.uid, node.gid); 43011127Smckusick chmod(cp, node.mode); 43111127Smckusick utime(cp, node.timep); 43211127Smckusick } 43311127Smckusick if (ferror(mf)) 43411127Smckusick panic("error setting directory modes\n"); 43511127Smckusick fclose(mf); 43611309Smckusick unlink(modefile); 43711127Smckusick } 43811127Smckusick 43911127Smckusick /* 44011127Smckusick * Generate a literal copy of a directory. 44111127Smckusick */ 44211127Smckusick genliteraldir(name, ino) 44311127Smckusick char *name; 44411127Smckusick ino_t ino; 44511127Smckusick { 44611127Smckusick register struct inotab *itp; 44711127Smckusick int ofile, dp, i, size; 44811127Smckusick char buf[BUFSIZ]; 44911127Smckusick 45011127Smckusick itp = inotablookup(ino); 45111127Smckusick if (itp == NULL) 452*11322Smckusick panic("Cannot find directory inode %d named %s\n", ino, name); 45311127Smckusick if ((ofile = open(name, FWRONLY|FCREATE, 0666)) < 0) { 45411127Smckusick fprintf(stderr, "%s: cannot create file\n", name); 45511127Smckusick return (FAIL); 45611127Smckusick } 45711127Smckusick seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 45811127Smckusick dp = dup(dirp->dd_fd); 45911127Smckusick for (i = itp->t_size; i > 0; i -= BUFSIZ) { 46011127Smckusick size = i < BUFSIZ ? i : BUFSIZ; 46111127Smckusick if (read(dp, buf, (int) size) == -1) { 46211127Smckusick fprintf(stderr, 46311127Smckusick "write error extracting inode %d, name %s\n", 46411127Smckusick curfile.ino, curfile.name); 46511127Smckusick perror("read"); 46611127Smckusick done(1); 46711127Smckusick } 46811127Smckusick if (write(ofile, buf, (int) size) == -1) { 46911127Smckusick fprintf(stderr, 47011127Smckusick "write error extracting inode %d, name %s\n", 47111127Smckusick curfile.ino, curfile.name); 47211127Smckusick perror("write"); 47311127Smckusick done(1); 47411127Smckusick } 47511127Smckusick } 47611127Smckusick close(dp); 47711127Smckusick close(ofile); 47811127Smckusick return (GOOD); 47911127Smckusick } 48011127Smckusick 48111127Smckusick /* 482*11322Smckusick * Determine the type of an inode 483*11322Smckusick */ 484*11322Smckusick inodetype(ino) 485*11322Smckusick ino_t ino; 486*11322Smckusick { 487*11322Smckusick struct inotab *itp; 488*11322Smckusick 489*11322Smckusick itp = inotablookup(ino); 490*11322Smckusick if (itp == NULL) 491*11322Smckusick return (LEAF); 492*11322Smckusick return (NODE); 493*11322Smckusick } 494*11322Smckusick 495*11322Smckusick /* 49611127Smckusick * Allocate and initialize a directory inode entry. 49711127Smckusick * If requested, save its pertinent mode, owner, and time info. 49811127Smckusick */ 499*11322Smckusick struct inotab * 50011127Smckusick allocinotab(ino, dip, seekpt) 50111127Smckusick ino_t ino; 50211127Smckusick struct dinode *dip; 50311127Smckusick daddr_t seekpt; 50411127Smckusick { 50511127Smckusick register struct inotab *itp; 50611127Smckusick struct modeinfo node; 50711127Smckusick 50811127Smckusick itp = (struct inotab *)calloc(1, sizeof(struct inotab)); 50911127Smckusick itp->t_next = inotab[INOHASH(ino)]; 51011127Smckusick inotab[INOHASH(ino)] = itp; 51111127Smckusick itp->t_ino = ino; 51211127Smckusick itp->t_seekpt = seekpt; 51311127Smckusick if (mf == NULL) 514*11322Smckusick return(itp); 51511127Smckusick node.ino = ino; 51611127Smckusick node.timep[0] = dip->di_atime; 51711127Smckusick node.timep[1] = dip->di_mtime; 51811127Smckusick node.mode = dip->di_mode; 51911127Smckusick node.uid = dip->di_uid; 52011127Smckusick node.gid = dip->di_gid; 52111127Smckusick fwrite((char *)&node, 1, sizeof(struct modeinfo), mf); 522*11322Smckusick return(itp); 52311127Smckusick } 52411127Smckusick 52511127Smckusick /* 52611127Smckusick * Look up an inode in the table of directories 52711127Smckusick */ 52811127Smckusick struct inotab * 52911127Smckusick inotablookup(ino) 53011127Smckusick ino_t ino; 53111127Smckusick { 53211127Smckusick register struct inotab *itp; 53311127Smckusick 53411127Smckusick for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next) 53511127Smckusick if (itp->t_ino == ino) 53611127Smckusick return(itp); 53711127Smckusick return ((struct inotab *)0); 53811127Smckusick } 53911127Smckusick 54011127Smckusick /* 54111127Smckusick * Clean up and exit 54211127Smckusick */ 54311127Smckusick done(exitcode) 54411127Smckusick int exitcode; 54511127Smckusick { 54611127Smckusick 54711127Smckusick closemt(); 54811127Smckusick unlink(dirfile); 54911127Smckusick exit(exitcode); 55011127Smckusick } 551