121165Sdist /* 236105Sbostic * Copyright (c) 1983 The Regents of the University of California. 336105Sbostic * All rights reserved. 436105Sbostic * 5*42708Sbostic * %sccs.include.redist.c% 621165Sdist */ 721165Sdist 811127Smckusick #ifndef lint 9*42708Sbostic static char sccsid[] = "@(#)dirs.c 5.11 (Berkeley) 06/01/90"; 1036105Sbostic #endif /* not lint */ 1111127Smckusick 1211127Smckusick #include "restore.h" 1323545Smckusick #include <protocols/dumprestore.h> 1411309Smckusick #include <sys/file.h> 1540094Smckusick #include <ufs/dir.h> 1637952Sbostic #include "pathnames.h" 1711127Smckusick 1811992Smckusick /* 1911992Smckusick * Symbol table of directories read from tape. 2011992Smckusick */ 2111127Smckusick #define HASHSIZE 1000 2211127Smckusick #define INOHASH(val) (val % HASHSIZE) 2311127Smckusick struct inotab { 2411127Smckusick struct inotab *t_next; 2511127Smckusick ino_t t_ino; 2611127Smckusick daddr_t t_seekpt; 2711127Smckusick long t_size; 2811309Smckusick }; 2911309Smckusick static struct inotab *inotab[HASHSIZE]; 3011309Smckusick extern struct inotab *inotablookup(); 3111322Smckusick extern struct inotab *allocinotab(); 3211127Smckusick 3311992Smckusick /* 3411992Smckusick * Information retained about directories. 3511992Smckusick */ 3611127Smckusick struct modeinfo { 3711127Smckusick ino_t ino; 3839471Smckusick struct timeval timep[2]; 3911127Smckusick short mode; 4011127Smckusick short uid; 4111127Smckusick short gid; 4211127Smckusick }; 4311127Smckusick 4411992Smckusick /* 4540094Smckusick * Definitions for library routines operating on directories. 4640094Smckusick */ 4740094Smckusick #define DIRBLKSIZ DEV_BSIZE 4840094Smckusick struct dirdesc { 4940094Smckusick int dd_fd; 5040094Smckusick long dd_loc; 5140094Smckusick long dd_size; 5240094Smckusick char dd_buf[DIRBLKSIZ]; 5340094Smckusick }; 5440094Smckusick extern DIR *opendirfile(); 5540094Smckusick extern long rst_telldir(); 5640094Smckusick extern void rst_seekdir(); 5740094Smckusick 5840094Smckusick /* 5911992Smckusick * Global variables for this file. 6011992Smckusick */ 6111309Smckusick static daddr_t seekpt; 6211309Smckusick static FILE *df, *mf; 6311309Smckusick static DIR *dirp; 6411992Smckusick static char dirfile[32] = "#"; /* No file */ 6511992Smckusick static char modefile[32] = "#"; /* No file */ 6611309Smckusick extern ino_t search(); 6712556Smckusick struct direct *rst_readdir(); 6812556Smckusick extern void rst_seekdir(); 6911127Smckusick 7011992Smckusick /* 7111992Smckusick * Format of old style directories. 7211992Smckusick */ 7311127Smckusick #define ODIRSIZ 14 7411127Smckusick struct odirect { 7511127Smckusick u_short d_ino; 7611127Smckusick char d_name[ODIRSIZ]; 7711127Smckusick }; 7811127Smckusick 7911127Smckusick /* 8011127Smckusick * Extract directory contents, building up a directory structure 8111127Smckusick * on disk for extraction by name. 8211992Smckusick * If genmode is requested, save mode, owner, and times for all 8311127Smckusick * directories on the tape. 8411127Smckusick */ 8511992Smckusick extractdirs(genmode) 8611992Smckusick int genmode; 8711127Smckusick { 8811127Smckusick register int i; 8911127Smckusick register struct dinode *ip; 9011322Smckusick struct inotab *itp; 9111127Smckusick struct direct nulldir; 9211127Smckusick int putdir(), null(); 9311127Smckusick 9411127Smckusick vprintf(stdout, "Extract directories from tape\n"); 9537952Sbostic (void) sprintf(dirfile, "%s/rstdir%d", _PATH_TMP, dumpdate); 9611127Smckusick df = fopen(dirfile, "w"); 9711127Smckusick if (df == 0) { 9811127Smckusick fprintf(stderr, 9915779Smckusick "restore: %s - cannot create directory temporary\n", 10011127Smckusick dirfile); 10111127Smckusick perror("fopen"); 10211127Smckusick done(1); 10311127Smckusick } 10411992Smckusick if (genmode != 0) { 10537952Sbostic (void) sprintf(modefile, "%s/rstmode%d", _PATH_TMP, dumpdate); 10611127Smckusick mf = fopen(modefile, "w"); 10711309Smckusick if (mf == 0) { 10811127Smckusick fprintf(stderr, 10915779Smckusick "restore: %s - cannot create modefile \n", 11011127Smckusick modefile); 11111127Smckusick perror("fopen"); 11211127Smckusick done(1); 11311127Smckusick } 11411127Smckusick } 11511322Smckusick nulldir.d_ino = 0; 11611127Smckusick nulldir.d_namlen = 1; 11712453Smckusick (void) strcpy(nulldir.d_name, "/"); 11811127Smckusick nulldir.d_reclen = DIRSIZ(&nulldir); 11911127Smckusick for (;;) { 12011127Smckusick curfile.name = "<directory file - name unknown>"; 12111127Smckusick curfile.action = USING; 12211127Smckusick ip = curfile.dip; 12317948Smckusick if (ip == NULL || (ip->di_mode & IFMT) != IFDIR) { 12411732Smckusick (void) fclose(df); 12540064Smckusick dirp = opendirfile(dirfile); 12611127Smckusick if (dirp == NULL) 12740064Smckusick perror("opendirfile"); 12811127Smckusick if (mf != NULL) 12911732Smckusick (void) fclose(mf); 13011992Smckusick i = dirlookup("."); 13111992Smckusick if (i == 0) 13211421Smckusick panic("Root directory is not on tape\n"); 13311127Smckusick return; 13411127Smckusick } 13511322Smckusick itp = allocinotab(curfile.ino, ip, seekpt); 13611127Smckusick getfile(putdir, null); 13711127Smckusick putent(&nulldir); 13811127Smckusick flushent(); 13911322Smckusick itp->t_size = seekpt - itp->t_seekpt; 14011127Smckusick } 14111127Smckusick } 14211127Smckusick 14311127Smckusick /* 14411322Smckusick * skip over all the directories on the tape 14511322Smckusick */ 14611322Smckusick skipdirs() 14711322Smckusick { 14811322Smckusick 14911322Smckusick while ((curfile.dip->di_mode & IFMT) == IFDIR) { 15011322Smckusick skipfile(); 15111322Smckusick } 15211322Smckusick } 15311322Smckusick 15411322Smckusick /* 15511127Smckusick * Recursively find names and inumbers of all files in subtree 15611127Smckusick * pname and pass them off to be processed. 15711127Smckusick */ 15811127Smckusick treescan(pname, ino, todo) 15911127Smckusick char *pname; 16011127Smckusick ino_t ino; 16111744Smckusick long (*todo)(); 16211127Smckusick { 16311127Smckusick register struct inotab *itp; 16412453Smckusick register struct direct *dp; 16512453Smckusick register struct entry *np; 16611127Smckusick int namelen; 16711127Smckusick daddr_t bpt; 16840064Smckusick off_t rst_telldir(); 16911644Smckusick char locname[MAXPATHLEN + 1]; 17011127Smckusick 17111127Smckusick itp = inotablookup(ino); 17211127Smckusick if (itp == NULL) { 17311127Smckusick /* 17411127Smckusick * Pname is name of a simple file or an unchanged directory. 17511127Smckusick */ 17611744Smckusick (void) (*todo)(pname, ino, LEAF); 17711127Smckusick return; 17811127Smckusick } 17911127Smckusick /* 18011127Smckusick * Pname is a dumped directory name. 18111127Smckusick */ 18211744Smckusick if ((*todo)(pname, ino, NODE) == FAIL) 18311744Smckusick return; 18411127Smckusick /* 18511127Smckusick * begin search through the directory 18611127Smckusick * skipping over "." and ".." 18711127Smckusick */ 18811992Smckusick (void) strncpy(locname, pname, MAXPATHLEN); 18911992Smckusick (void) strncat(locname, "/", MAXPATHLEN); 19011127Smckusick namelen = strlen(locname); 19112556Smckusick rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 19212556Smckusick dp = rst_readdir(dirp); /* "." */ 19327263Smckusick if (dp != NULL && strcmp(dp->d_name, ".") == 0) 19412556Smckusick dp = rst_readdir(dirp); /* ".." */ 19527263Smckusick else 19627263Smckusick fprintf(stderr, "Warning: `.' missing from directory %s\n", 19727263Smckusick pname); 19827263Smckusick if (dp != NULL && strcmp(dp->d_name, "..") == 0) 19912556Smckusick dp = rst_readdir(dirp); /* first real entry */ 20027263Smckusick else 20127263Smckusick fprintf(stderr, "Warning: `..' missing from directory %s\n", 20227263Smckusick pname); 20340064Smckusick bpt = rst_telldir(dirp); 20411127Smckusick /* 20512453Smckusick * a zero inode signals end of directory 20611127Smckusick */ 20712453Smckusick while (dp != NULL && dp->d_ino != 0) { 20811127Smckusick locname[namelen] = '\0'; 20911644Smckusick if (namelen + dp->d_namlen >= MAXPATHLEN) { 21011127Smckusick fprintf(stderr, "%s%s: name exceeds %d char\n", 21111644Smckusick locname, dp->d_name, MAXPATHLEN); 21211127Smckusick } else { 21311992Smckusick (void) strncat(locname, dp->d_name, (int)dp->d_namlen); 21411127Smckusick treescan(locname, dp->d_ino, todo); 21512556Smckusick rst_seekdir(dirp, bpt, itp->t_seekpt); 21611127Smckusick } 21712556Smckusick dp = rst_readdir(dirp); 21840064Smckusick bpt = rst_telldir(dirp); 21911127Smckusick } 22011127Smckusick if (dp == NULL) 22111127Smckusick fprintf(stderr, "corrupted directory: %s.\n", locname); 22211127Smckusick } 22311127Smckusick 22411127Smckusick /* 22511127Smckusick * Search the directory tree rooted at inode ROOTINO 22611127Smckusick * for the path pointed at by n 22711127Smckusick */ 22811127Smckusick ino_t 22911127Smckusick psearch(n) 23011127Smckusick char *n; 23111127Smckusick { 23211127Smckusick register char *cp, *cp1; 23311127Smckusick ino_t ino; 23411127Smckusick char c; 23511127Smckusick 23611127Smckusick ino = ROOTINO; 23711127Smckusick if (*(cp = n) == '/') 23811127Smckusick cp++; 23911127Smckusick next: 24011127Smckusick cp1 = cp + 1; 24111127Smckusick while (*cp1 != '/' && *cp1) 24211127Smckusick cp1++; 24311127Smckusick c = *cp1; 24411127Smckusick *cp1 = 0; 24511127Smckusick ino = search(ino, cp); 24611127Smckusick if (ino == 0) { 24711127Smckusick *cp1 = c; 24811127Smckusick return(0); 24911127Smckusick } 25011127Smckusick *cp1 = c; 25111127Smckusick if (c == '/') { 25211127Smckusick cp = cp1+1; 25311127Smckusick goto next; 25411127Smckusick } 25511127Smckusick return(ino); 25611127Smckusick } 25711127Smckusick 25811127Smckusick /* 25911127Smckusick * search the directory inode ino 26011127Smckusick * looking for entry cp 26111127Smckusick */ 26211127Smckusick ino_t 26311127Smckusick search(inum, cp) 26411127Smckusick ino_t inum; 26511127Smckusick char *cp; 26611127Smckusick { 26711127Smckusick register struct direct *dp; 26811127Smckusick register struct inotab *itp; 26911127Smckusick int len; 27011127Smckusick 27111127Smckusick itp = inotablookup(inum); 27211127Smckusick if (itp == NULL) 27311127Smckusick return(0); 27412556Smckusick rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 27511127Smckusick len = strlen(cp); 27611127Smckusick do { 27712556Smckusick dp = rst_readdir(dirp); 27812453Smckusick if (dp == NULL || dp->d_ino == 0) 27912453Smckusick return (0); 28011992Smckusick } while (dp->d_namlen != len || strncmp(dp->d_name, cp, len) != 0); 28111127Smckusick return(dp->d_ino); 28211127Smckusick } 28311127Smckusick 28411127Smckusick /* 28511127Smckusick * Put the directory entries in the directory file 28611127Smckusick */ 28711127Smckusick putdir(buf, size) 28811127Smckusick char *buf; 28911127Smckusick int size; 29011127Smckusick { 29111127Smckusick struct direct cvtbuf; 29211127Smckusick register struct odirect *odp; 29311127Smckusick struct odirect *eodp; 29411127Smckusick register struct direct *dp; 29511127Smckusick long loc, i; 29626941Ssklower extern int Bcvt; 29711127Smckusick 29811127Smckusick if (cvtflag) { 29911127Smckusick eodp = (struct odirect *)&buf[size]; 30011127Smckusick for (odp = (struct odirect *)buf; odp < eodp; odp++) 30111127Smckusick if (odp->d_ino != 0) { 30211127Smckusick dcvt(odp, &cvtbuf); 30311127Smckusick putent(&cvtbuf); 30411127Smckusick } 30511127Smckusick } else { 30611127Smckusick for (loc = 0; loc < size; ) { 30711127Smckusick dp = (struct direct *)(buf + loc); 30826941Ssklower if (Bcvt) { 30926941Ssklower swabst("l2s", (char *) dp); 31026941Ssklower } 31111127Smckusick i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1)); 31211127Smckusick if (dp->d_reclen == 0 || dp->d_reclen > i) { 31311127Smckusick loc += i; 31411127Smckusick continue; 31511127Smckusick } 31611127Smckusick loc += dp->d_reclen; 31711127Smckusick if (dp->d_ino != 0) { 31811127Smckusick putent(dp); 31911127Smckusick } 32011127Smckusick } 32111127Smckusick } 32211127Smckusick } 32311127Smckusick 32411127Smckusick /* 32511127Smckusick * These variables are "local" to the following two functions. 32611127Smckusick */ 32711127Smckusick char dirbuf[DIRBLKSIZ]; 32811127Smckusick long dirloc = 0; 32911127Smckusick long prev = 0; 33011127Smckusick 33111127Smckusick /* 33211127Smckusick * add a new directory entry to a file. 33311127Smckusick */ 33411127Smckusick putent(dp) 33511127Smckusick struct direct *dp; 33611127Smckusick { 33711322Smckusick dp->d_reclen = DIRSIZ(dp); 33811127Smckusick if (dirloc + dp->d_reclen > DIRBLKSIZ) { 33911127Smckusick ((struct direct *)(dirbuf + prev))->d_reclen = 34011127Smckusick DIRBLKSIZ - prev; 34111732Smckusick (void) fwrite(dirbuf, 1, DIRBLKSIZ, df); 34211127Smckusick dirloc = 0; 34311127Smckusick } 34411127Smckusick bcopy((char *)dp, dirbuf + dirloc, (long)dp->d_reclen); 34511127Smckusick prev = dirloc; 34611127Smckusick dirloc += dp->d_reclen; 34711127Smckusick } 34811127Smckusick 34911127Smckusick /* 35011127Smckusick * flush out a directory that is finished. 35111127Smckusick */ 35211127Smckusick flushent() 35311127Smckusick { 35411127Smckusick 35511127Smckusick ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev; 35611732Smckusick (void) fwrite(dirbuf, (int)dirloc, 1, df); 35711127Smckusick seekpt = ftell(df); 35811127Smckusick dirloc = 0; 35911127Smckusick } 36011127Smckusick 36111127Smckusick dcvt(odp, ndp) 36211127Smckusick register struct odirect *odp; 36311127Smckusick register struct direct *ndp; 36411127Smckusick { 36511127Smckusick 36611127Smckusick bzero((char *)ndp, (long)(sizeof *ndp)); 36711127Smckusick ndp->d_ino = odp->d_ino; 36811992Smckusick (void) strncpy(ndp->d_name, odp->d_name, ODIRSIZ); 36911127Smckusick ndp->d_namlen = strlen(ndp->d_name); 37011127Smckusick ndp->d_reclen = DIRSIZ(ndp); 37111127Smckusick } 37211127Smckusick 37311127Smckusick /* 37411127Smckusick * Seek to an entry in a directory. 37540064Smckusick * Only values returned by rst_telldir should be passed to rst_seekdir. 37611732Smckusick * This routine handles many directories in a single file. 37711732Smckusick * It takes the base of the directory in the file, plus 37811732Smckusick * the desired seek offset into it. 37911127Smckusick */ 38011127Smckusick void 38112556Smckusick rst_seekdir(dirp, loc, base) 38211127Smckusick register DIR *dirp; 38311127Smckusick daddr_t loc, base; 38411127Smckusick { 38540064Smckusick off_t rst_telldir(); 38611127Smckusick 38740064Smckusick if (loc == rst_telldir(dirp)) 38811127Smckusick return; 38911127Smckusick loc -= base; 39011127Smckusick if (loc < 0) 39112556Smckusick fprintf(stderr, "bad seek pointer to rst_seekdir %d\n", loc); 39211127Smckusick (void) lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), 0); 39311127Smckusick dirp->dd_loc = loc & (DIRBLKSIZ - 1); 39411127Smckusick if (dirp->dd_loc != 0) 39511127Smckusick dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ); 39611127Smckusick } 39711127Smckusick 39811127Smckusick /* 39911127Smckusick * get next entry in a directory. 40011127Smckusick */ 40111127Smckusick struct direct * 40212556Smckusick rst_readdir(dirp) 40311127Smckusick register DIR *dirp; 40411127Smckusick { 40511127Smckusick register struct direct *dp; 40611127Smckusick 40711127Smckusick for (;;) { 40811127Smckusick if (dirp->dd_loc == 0) { 40911127Smckusick dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, 41011127Smckusick DIRBLKSIZ); 41112453Smckusick if (dirp->dd_size <= 0) { 41212453Smckusick dprintf(stderr, "error reading directory\n"); 41311127Smckusick return NULL; 41412453Smckusick } 41511127Smckusick } 41611127Smckusick if (dirp->dd_loc >= dirp->dd_size) { 41711127Smckusick dirp->dd_loc = 0; 41811127Smckusick continue; 41911127Smckusick } 42011127Smckusick dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc); 42111127Smckusick if (dp->d_reclen == 0 || 42212453Smckusick dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) { 42312453Smckusick dprintf(stderr, "corrupted directory: bad reclen %d\n", 42412453Smckusick dp->d_reclen); 42511127Smckusick return NULL; 42612453Smckusick } 42711127Smckusick dirp->dd_loc += dp->d_reclen; 42812453Smckusick if (dp->d_ino == 0 && strcmp(dp->d_name, "/") != 0) 42912453Smckusick continue; 43012556Smckusick if (dp->d_ino >= maxino) { 43112453Smckusick dprintf(stderr, "corrupted directory: bad inum %d\n", 43212453Smckusick dp->d_ino); 43312453Smckusick continue; 43412453Smckusick } 43511127Smckusick return (dp); 43611127Smckusick } 43711127Smckusick } 43811127Smckusick 43911127Smckusick /* 44017753Smckusick * Simulate the opening of a directory 44117753Smckusick */ 44217753Smckusick DIR * 44317753Smckusick rst_opendir(name) 44417753Smckusick char *name; 44517753Smckusick { 44617753Smckusick struct inotab *itp; 44717753Smckusick ino_t ino; 44817753Smckusick 44917753Smckusick if ((ino = dirlookup(name)) > 0 && 45017753Smckusick (itp = inotablookup(ino)) != NULL) { 45117753Smckusick rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 45217753Smckusick return (dirp); 45317753Smckusick } 45417753Smckusick return (0); 45517753Smckusick } 45617753Smckusick 45717753Smckusick /* 45840064Smckusick * Simulate finding the current offset in the directory. 45940064Smckusick */ 46040064Smckusick off_t 46140064Smckusick rst_telldir(dirp) 46240064Smckusick DIR *dirp; 46340064Smckusick { 46440064Smckusick off_t lseek(); 46540064Smckusick 46640064Smckusick return (lseek(dirp->dd_fd, 0L, 1) - dirp->dd_size + dirp->dd_loc); 46740064Smckusick } 46840064Smckusick 46940064Smckusick /* 47040064Smckusick * Open a directory file. 47140064Smckusick */ 47240064Smckusick DIR * 47340064Smckusick opendirfile(name) 47440064Smckusick char *name; 47540064Smckusick { 47640064Smckusick register DIR *dirp; 47740064Smckusick register int fd; 47840064Smckusick 47940064Smckusick if ((fd = open(name, 0)) == -1) 48040064Smckusick return NULL; 48140064Smckusick if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) { 48240064Smckusick close (fd); 48340064Smckusick return NULL; 48440064Smckusick } 48540064Smckusick dirp->dd_fd = fd; 48640064Smckusick dirp->dd_loc = 0; 48740064Smckusick return dirp; 48840064Smckusick } 48940064Smckusick 49040064Smckusick /* 49111127Smckusick * Set the mode, owner, and times for all new or changed directories 49211127Smckusick */ 49311992Smckusick setdirmodes() 49411127Smckusick { 49511127Smckusick FILE *mf; 49611127Smckusick struct modeinfo node; 49711127Smckusick struct entry *ep; 49811127Smckusick char *cp; 49911127Smckusick 50011127Smckusick vprintf(stdout, "Set directory mode, owner, and times.\n"); 50137952Sbostic (void) sprintf(modefile, "%s/rstmode%d", _PATH_TMP, dumpdate); 50211127Smckusick mf = fopen(modefile, "r"); 50311127Smckusick if (mf == NULL) { 50411127Smckusick perror("fopen"); 50515779Smckusick fprintf(stderr, "cannot open mode file %s\n", modefile); 50615779Smckusick fprintf(stderr, "directory mode, owner, and times not set\n"); 50715779Smckusick return; 50811127Smckusick } 50911127Smckusick clearerr(mf); 51011309Smckusick for (;;) { 51111732Smckusick (void) fread((char *)&node, 1, sizeof(struct modeinfo), mf); 51211309Smckusick if (feof(mf)) 51311309Smckusick break; 51411127Smckusick ep = lookupino(node.ino); 51514453Smckusick if (command == 'i' || command == 'x') { 51614453Smckusick if (ep == NIL) 51711309Smckusick continue; 51818008Smckusick if (ep->e_flags & EXISTED) { 51918008Smckusick ep->e_flags &= ~NEW; 52018008Smckusick continue; 52118008Smckusick } 52214453Smckusick if (node.ino == ROOTINO && 52314453Smckusick reply("set owner/mode for '.'") == FAIL) 52414453Smckusick continue; 52514453Smckusick } 52614453Smckusick if (ep == NIL) 52711127Smckusick panic("cannot find directory inode %d\n", node.ino); 52811127Smckusick cp = myname(ep); 52911732Smckusick (void) chown(cp, node.uid, node.gid); 53011732Smckusick (void) chmod(cp, node.mode); 53139471Smckusick utimes(cp, node.timep); 53211992Smckusick ep->e_flags &= ~NEW; 53311127Smckusick } 53411127Smckusick if (ferror(mf)) 53511127Smckusick panic("error setting directory modes\n"); 53611732Smckusick (void) fclose(mf); 53711127Smckusick } 53811127Smckusick 53911127Smckusick /* 54011127Smckusick * Generate a literal copy of a directory. 54111127Smckusick */ 54211127Smckusick genliteraldir(name, ino) 54311127Smckusick char *name; 54411127Smckusick ino_t ino; 54511127Smckusick { 54611127Smckusick register struct inotab *itp; 54711127Smckusick int ofile, dp, i, size; 54811127Smckusick char buf[BUFSIZ]; 54911127Smckusick 55011127Smckusick itp = inotablookup(ino); 55111127Smckusick if (itp == NULL) 55211322Smckusick panic("Cannot find directory inode %d named %s\n", ino, name); 55312893Ssam if ((ofile = creat(name, 0666)) < 0) { 55412556Smckusick fprintf(stderr, "%s: ", name); 55512556Smckusick (void) fflush(stderr); 55612556Smckusick perror("cannot create file"); 55711127Smckusick return (FAIL); 55811127Smckusick } 55912556Smckusick rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 56011127Smckusick dp = dup(dirp->dd_fd); 56111127Smckusick for (i = itp->t_size; i > 0; i -= BUFSIZ) { 56211127Smckusick size = i < BUFSIZ ? i : BUFSIZ; 56311127Smckusick if (read(dp, buf, (int) size) == -1) { 56411127Smckusick fprintf(stderr, 56511127Smckusick "write error extracting inode %d, name %s\n", 56611127Smckusick curfile.ino, curfile.name); 56711127Smckusick perror("read"); 56811127Smckusick done(1); 56911127Smckusick } 57034268Smckusick if (!Nflag && write(ofile, buf, (int) size) == -1) { 57111127Smckusick fprintf(stderr, 57211127Smckusick "write error extracting inode %d, name %s\n", 57311127Smckusick curfile.ino, curfile.name); 57411127Smckusick perror("write"); 57511127Smckusick done(1); 57611127Smckusick } 57711127Smckusick } 57811732Smckusick (void) close(dp); 57911732Smckusick (void) close(ofile); 58011127Smckusick return (GOOD); 58111127Smckusick } 58211127Smckusick 58311127Smckusick /* 58411992Smckusick * Determine the type of an inode 58511992Smckusick */ 58611992Smckusick inodetype(ino) 58711992Smckusick ino_t ino; 58811992Smckusick { 58911992Smckusick struct inotab *itp; 59011992Smckusick 59111992Smckusick itp = inotablookup(ino); 59211992Smckusick if (itp == NULL) 59311992Smckusick return (LEAF); 59411992Smckusick return (NODE); 59511992Smckusick } 59611992Smckusick 59711992Smckusick /* 59811127Smckusick * Allocate and initialize a directory inode entry. 59911127Smckusick * If requested, save its pertinent mode, owner, and time info. 60011127Smckusick */ 60111322Smckusick struct inotab * 60211127Smckusick allocinotab(ino, dip, seekpt) 60311127Smckusick ino_t ino; 60411127Smckusick struct dinode *dip; 60511127Smckusick daddr_t seekpt; 60611127Smckusick { 60711127Smckusick register struct inotab *itp; 60811127Smckusick struct modeinfo node; 60911127Smckusick 61011127Smckusick itp = (struct inotab *)calloc(1, sizeof(struct inotab)); 61113859Smckusick if (itp == 0) 61213859Smckusick panic("no memory directory table\n"); 61311127Smckusick itp->t_next = inotab[INOHASH(ino)]; 61411127Smckusick inotab[INOHASH(ino)] = itp; 61511127Smckusick itp->t_ino = ino; 61611127Smckusick itp->t_seekpt = seekpt; 61711127Smckusick if (mf == NULL) 61811322Smckusick return(itp); 61911127Smckusick node.ino = ino; 62039471Smckusick node.timep[0].tv_sec = dip->di_atime; 62139471Smckusick node.timep[0].tv_usec = 0; 62239471Smckusick node.timep[1].tv_sec = dip->di_mtime; 62339471Smckusick node.timep[1].tv_usec = 0; 62411127Smckusick node.mode = dip->di_mode; 62511127Smckusick node.uid = dip->di_uid; 62611127Smckusick node.gid = dip->di_gid; 62711732Smckusick (void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf); 62811322Smckusick return(itp); 62911127Smckusick } 63011127Smckusick 63111127Smckusick /* 63211127Smckusick * Look up an inode in the table of directories 63311127Smckusick */ 63411127Smckusick struct inotab * 63511127Smckusick inotablookup(ino) 63611127Smckusick ino_t ino; 63711127Smckusick { 63811127Smckusick register struct inotab *itp; 63911127Smckusick 64011127Smckusick for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next) 64111127Smckusick if (itp->t_ino == ino) 64211127Smckusick return(itp); 64311127Smckusick return ((struct inotab *)0); 64411127Smckusick } 64511127Smckusick 64611127Smckusick /* 64711127Smckusick * Clean up and exit 64811127Smckusick */ 64911127Smckusick done(exitcode) 65011127Smckusick int exitcode; 65111127Smckusick { 65211127Smckusick 65311127Smckusick closemt(); 65411992Smckusick if (modefile[0] != '#') 65511992Smckusick (void) unlink(modefile); 65611992Smckusick if (dirfile[0] != '#') 65711992Smckusick (void) unlink(dirfile); 65811127Smckusick exit(exitcode); 65911127Smckusick } 660