121165Sdist /* 236105Sbostic * Copyright (c) 1983 The Regents of the University of California. 336105Sbostic * All rights reserved. 436105Sbostic * 536105Sbostic * Redistribution and use in source and binary forms are permitted 636105Sbostic * provided that the above copyright notice and this paragraph are 736105Sbostic * duplicated in all such forms and that any documentation, 836105Sbostic * advertising materials, and other materials related to such 936105Sbostic * distribution and use acknowledge that the software was developed 1036105Sbostic * by the University of California, Berkeley. The name of the 1136105Sbostic * University may not be used to endorse or promote products derived 1236105Sbostic * from this software without specific prior written permission. 1336105Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1436105Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1536105Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621165Sdist */ 1721165Sdist 1811127Smckusick #ifndef lint 19*40094Smckusick static char sccsid[] = "@(#)dirs.c 5.10 (Berkeley) 02/15/90"; 2036105Sbostic #endif /* not lint */ 2111127Smckusick 2211127Smckusick #include "restore.h" 2323545Smckusick #include <protocols/dumprestore.h> 2411309Smckusick #include <sys/file.h> 25*40094Smckusick #include <ufs/dir.h> 2637952Sbostic #include "pathnames.h" 2711127Smckusick 2811992Smckusick /* 2911992Smckusick * Symbol table of directories read from tape. 3011992Smckusick */ 3111127Smckusick #define HASHSIZE 1000 3211127Smckusick #define INOHASH(val) (val % HASHSIZE) 3311127Smckusick struct inotab { 3411127Smckusick struct inotab *t_next; 3511127Smckusick ino_t t_ino; 3611127Smckusick daddr_t t_seekpt; 3711127Smckusick long t_size; 3811309Smckusick }; 3911309Smckusick static struct inotab *inotab[HASHSIZE]; 4011309Smckusick extern struct inotab *inotablookup(); 4111322Smckusick extern struct inotab *allocinotab(); 4211127Smckusick 4311992Smckusick /* 4411992Smckusick * Information retained about directories. 4511992Smckusick */ 4611127Smckusick struct modeinfo { 4711127Smckusick ino_t ino; 4839471Smckusick struct timeval timep[2]; 4911127Smckusick short mode; 5011127Smckusick short uid; 5111127Smckusick short gid; 5211127Smckusick }; 5311127Smckusick 5411992Smckusick /* 55*40094Smckusick * Definitions for library routines operating on directories. 56*40094Smckusick */ 57*40094Smckusick #define DIRBLKSIZ DEV_BSIZE 58*40094Smckusick struct dirdesc { 59*40094Smckusick int dd_fd; 60*40094Smckusick long dd_loc; 61*40094Smckusick long dd_size; 62*40094Smckusick char dd_buf[DIRBLKSIZ]; 63*40094Smckusick }; 64*40094Smckusick extern DIR *opendirfile(); 65*40094Smckusick extern long rst_telldir(); 66*40094Smckusick extern void rst_seekdir(); 67*40094Smckusick 68*40094Smckusick /* 6911992Smckusick * Global variables for this file. 7011992Smckusick */ 7111309Smckusick static daddr_t seekpt; 7211309Smckusick static FILE *df, *mf; 7311309Smckusick static DIR *dirp; 7411992Smckusick static char dirfile[32] = "#"; /* No file */ 7511992Smckusick static char modefile[32] = "#"; /* No file */ 7611309Smckusick extern ino_t search(); 7712556Smckusick struct direct *rst_readdir(); 7812556Smckusick extern void rst_seekdir(); 7911127Smckusick 8011992Smckusick /* 8111992Smckusick * Format of old style directories. 8211992Smckusick */ 8311127Smckusick #define ODIRSIZ 14 8411127Smckusick struct odirect { 8511127Smckusick u_short d_ino; 8611127Smckusick char d_name[ODIRSIZ]; 8711127Smckusick }; 8811127Smckusick 8911127Smckusick /* 9011127Smckusick * Extract directory contents, building up a directory structure 9111127Smckusick * on disk for extraction by name. 9211992Smckusick * If genmode is requested, save mode, owner, and times for all 9311127Smckusick * directories on the tape. 9411127Smckusick */ 9511992Smckusick extractdirs(genmode) 9611992Smckusick int genmode; 9711127Smckusick { 9811127Smckusick register int i; 9911127Smckusick register struct dinode *ip; 10011322Smckusick struct inotab *itp; 10111127Smckusick struct direct nulldir; 10211127Smckusick int putdir(), null(); 10311127Smckusick 10411127Smckusick vprintf(stdout, "Extract directories from tape\n"); 10537952Sbostic (void) sprintf(dirfile, "%s/rstdir%d", _PATH_TMP, dumpdate); 10611127Smckusick df = fopen(dirfile, "w"); 10711127Smckusick if (df == 0) { 10811127Smckusick fprintf(stderr, 10915779Smckusick "restore: %s - cannot create directory temporary\n", 11011127Smckusick dirfile); 11111127Smckusick perror("fopen"); 11211127Smckusick done(1); 11311127Smckusick } 11411992Smckusick if (genmode != 0) { 11537952Sbostic (void) sprintf(modefile, "%s/rstmode%d", _PATH_TMP, dumpdate); 11611127Smckusick mf = fopen(modefile, "w"); 11711309Smckusick if (mf == 0) { 11811127Smckusick fprintf(stderr, 11915779Smckusick "restore: %s - cannot create modefile \n", 12011127Smckusick modefile); 12111127Smckusick perror("fopen"); 12211127Smckusick done(1); 12311127Smckusick } 12411127Smckusick } 12511322Smckusick nulldir.d_ino = 0; 12611127Smckusick nulldir.d_namlen = 1; 12712453Smckusick (void) strcpy(nulldir.d_name, "/"); 12811127Smckusick nulldir.d_reclen = DIRSIZ(&nulldir); 12911127Smckusick for (;;) { 13011127Smckusick curfile.name = "<directory file - name unknown>"; 13111127Smckusick curfile.action = USING; 13211127Smckusick ip = curfile.dip; 13317948Smckusick if (ip == NULL || (ip->di_mode & IFMT) != IFDIR) { 13411732Smckusick (void) fclose(df); 13540064Smckusick dirp = opendirfile(dirfile); 13611127Smckusick if (dirp == NULL) 13740064Smckusick perror("opendirfile"); 13811127Smckusick if (mf != NULL) 13911732Smckusick (void) fclose(mf); 14011992Smckusick i = dirlookup("."); 14111992Smckusick if (i == 0) 14211421Smckusick panic("Root directory is not on tape\n"); 14311127Smckusick return; 14411127Smckusick } 14511322Smckusick itp = allocinotab(curfile.ino, ip, seekpt); 14611127Smckusick getfile(putdir, null); 14711127Smckusick putent(&nulldir); 14811127Smckusick flushent(); 14911322Smckusick itp->t_size = seekpt - itp->t_seekpt; 15011127Smckusick } 15111127Smckusick } 15211127Smckusick 15311127Smckusick /* 15411322Smckusick * skip over all the directories on the tape 15511322Smckusick */ 15611322Smckusick skipdirs() 15711322Smckusick { 15811322Smckusick 15911322Smckusick while ((curfile.dip->di_mode & IFMT) == IFDIR) { 16011322Smckusick skipfile(); 16111322Smckusick } 16211322Smckusick } 16311322Smckusick 16411322Smckusick /* 16511127Smckusick * Recursively find names and inumbers of all files in subtree 16611127Smckusick * pname and pass them off to be processed. 16711127Smckusick */ 16811127Smckusick treescan(pname, ino, todo) 16911127Smckusick char *pname; 17011127Smckusick ino_t ino; 17111744Smckusick long (*todo)(); 17211127Smckusick { 17311127Smckusick register struct inotab *itp; 17412453Smckusick register struct direct *dp; 17512453Smckusick register struct entry *np; 17611127Smckusick int namelen; 17711127Smckusick daddr_t bpt; 17840064Smckusick off_t rst_telldir(); 17911644Smckusick char locname[MAXPATHLEN + 1]; 18011127Smckusick 18111127Smckusick itp = inotablookup(ino); 18211127Smckusick if (itp == NULL) { 18311127Smckusick /* 18411127Smckusick * Pname is name of a simple file or an unchanged directory. 18511127Smckusick */ 18611744Smckusick (void) (*todo)(pname, ino, LEAF); 18711127Smckusick return; 18811127Smckusick } 18911127Smckusick /* 19011127Smckusick * Pname is a dumped directory name. 19111127Smckusick */ 19211744Smckusick if ((*todo)(pname, ino, NODE) == FAIL) 19311744Smckusick return; 19411127Smckusick /* 19511127Smckusick * begin search through the directory 19611127Smckusick * skipping over "." and ".." 19711127Smckusick */ 19811992Smckusick (void) strncpy(locname, pname, MAXPATHLEN); 19911992Smckusick (void) strncat(locname, "/", MAXPATHLEN); 20011127Smckusick namelen = strlen(locname); 20112556Smckusick rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 20212556Smckusick dp = rst_readdir(dirp); /* "." */ 20327263Smckusick if (dp != NULL && strcmp(dp->d_name, ".") == 0) 20412556Smckusick dp = rst_readdir(dirp); /* ".." */ 20527263Smckusick else 20627263Smckusick fprintf(stderr, "Warning: `.' missing from directory %s\n", 20727263Smckusick pname); 20827263Smckusick if (dp != NULL && strcmp(dp->d_name, "..") == 0) 20912556Smckusick dp = rst_readdir(dirp); /* first real entry */ 21027263Smckusick else 21127263Smckusick fprintf(stderr, "Warning: `..' missing from directory %s\n", 21227263Smckusick pname); 21340064Smckusick bpt = rst_telldir(dirp); 21411127Smckusick /* 21512453Smckusick * a zero inode signals end of directory 21611127Smckusick */ 21712453Smckusick while (dp != NULL && dp->d_ino != 0) { 21811127Smckusick locname[namelen] = '\0'; 21911644Smckusick if (namelen + dp->d_namlen >= MAXPATHLEN) { 22011127Smckusick fprintf(stderr, "%s%s: name exceeds %d char\n", 22111644Smckusick locname, dp->d_name, MAXPATHLEN); 22211127Smckusick } else { 22311992Smckusick (void) strncat(locname, dp->d_name, (int)dp->d_namlen); 22411127Smckusick treescan(locname, dp->d_ino, todo); 22512556Smckusick rst_seekdir(dirp, bpt, itp->t_seekpt); 22611127Smckusick } 22712556Smckusick dp = rst_readdir(dirp); 22840064Smckusick bpt = rst_telldir(dirp); 22911127Smckusick } 23011127Smckusick if (dp == NULL) 23111127Smckusick fprintf(stderr, "corrupted directory: %s.\n", locname); 23211127Smckusick } 23311127Smckusick 23411127Smckusick /* 23511127Smckusick * Search the directory tree rooted at inode ROOTINO 23611127Smckusick * for the path pointed at by n 23711127Smckusick */ 23811127Smckusick ino_t 23911127Smckusick psearch(n) 24011127Smckusick char *n; 24111127Smckusick { 24211127Smckusick register char *cp, *cp1; 24311127Smckusick ino_t ino; 24411127Smckusick char c; 24511127Smckusick 24611127Smckusick ino = ROOTINO; 24711127Smckusick if (*(cp = n) == '/') 24811127Smckusick cp++; 24911127Smckusick next: 25011127Smckusick cp1 = cp + 1; 25111127Smckusick while (*cp1 != '/' && *cp1) 25211127Smckusick cp1++; 25311127Smckusick c = *cp1; 25411127Smckusick *cp1 = 0; 25511127Smckusick ino = search(ino, cp); 25611127Smckusick if (ino == 0) { 25711127Smckusick *cp1 = c; 25811127Smckusick return(0); 25911127Smckusick } 26011127Smckusick *cp1 = c; 26111127Smckusick if (c == '/') { 26211127Smckusick cp = cp1+1; 26311127Smckusick goto next; 26411127Smckusick } 26511127Smckusick return(ino); 26611127Smckusick } 26711127Smckusick 26811127Smckusick /* 26911127Smckusick * search the directory inode ino 27011127Smckusick * looking for entry cp 27111127Smckusick */ 27211127Smckusick ino_t 27311127Smckusick search(inum, cp) 27411127Smckusick ino_t inum; 27511127Smckusick char *cp; 27611127Smckusick { 27711127Smckusick register struct direct *dp; 27811127Smckusick register struct inotab *itp; 27911127Smckusick int len; 28011127Smckusick 28111127Smckusick itp = inotablookup(inum); 28211127Smckusick if (itp == NULL) 28311127Smckusick return(0); 28412556Smckusick rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 28511127Smckusick len = strlen(cp); 28611127Smckusick do { 28712556Smckusick dp = rst_readdir(dirp); 28812453Smckusick if (dp == NULL || dp->d_ino == 0) 28912453Smckusick return (0); 29011992Smckusick } while (dp->d_namlen != len || strncmp(dp->d_name, cp, len) != 0); 29111127Smckusick return(dp->d_ino); 29211127Smckusick } 29311127Smckusick 29411127Smckusick /* 29511127Smckusick * Put the directory entries in the directory file 29611127Smckusick */ 29711127Smckusick putdir(buf, size) 29811127Smckusick char *buf; 29911127Smckusick int size; 30011127Smckusick { 30111127Smckusick struct direct cvtbuf; 30211127Smckusick register struct odirect *odp; 30311127Smckusick struct odirect *eodp; 30411127Smckusick register struct direct *dp; 30511127Smckusick long loc, i; 30626941Ssklower extern int Bcvt; 30711127Smckusick 30811127Smckusick if (cvtflag) { 30911127Smckusick eodp = (struct odirect *)&buf[size]; 31011127Smckusick for (odp = (struct odirect *)buf; odp < eodp; odp++) 31111127Smckusick if (odp->d_ino != 0) { 31211127Smckusick dcvt(odp, &cvtbuf); 31311127Smckusick putent(&cvtbuf); 31411127Smckusick } 31511127Smckusick } else { 31611127Smckusick for (loc = 0; loc < size; ) { 31711127Smckusick dp = (struct direct *)(buf + loc); 31826941Ssklower if (Bcvt) { 31926941Ssklower swabst("l2s", (char *) dp); 32026941Ssklower } 32111127Smckusick i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1)); 32211127Smckusick if (dp->d_reclen == 0 || dp->d_reclen > i) { 32311127Smckusick loc += i; 32411127Smckusick continue; 32511127Smckusick } 32611127Smckusick loc += dp->d_reclen; 32711127Smckusick if (dp->d_ino != 0) { 32811127Smckusick putent(dp); 32911127Smckusick } 33011127Smckusick } 33111127Smckusick } 33211127Smckusick } 33311127Smckusick 33411127Smckusick /* 33511127Smckusick * These variables are "local" to the following two functions. 33611127Smckusick */ 33711127Smckusick char dirbuf[DIRBLKSIZ]; 33811127Smckusick long dirloc = 0; 33911127Smckusick long prev = 0; 34011127Smckusick 34111127Smckusick /* 34211127Smckusick * add a new directory entry to a file. 34311127Smckusick */ 34411127Smckusick putent(dp) 34511127Smckusick struct direct *dp; 34611127Smckusick { 34711322Smckusick dp->d_reclen = DIRSIZ(dp); 34811127Smckusick if (dirloc + dp->d_reclen > DIRBLKSIZ) { 34911127Smckusick ((struct direct *)(dirbuf + prev))->d_reclen = 35011127Smckusick DIRBLKSIZ - prev; 35111732Smckusick (void) fwrite(dirbuf, 1, DIRBLKSIZ, df); 35211127Smckusick dirloc = 0; 35311127Smckusick } 35411127Smckusick bcopy((char *)dp, dirbuf + dirloc, (long)dp->d_reclen); 35511127Smckusick prev = dirloc; 35611127Smckusick dirloc += dp->d_reclen; 35711127Smckusick } 35811127Smckusick 35911127Smckusick /* 36011127Smckusick * flush out a directory that is finished. 36111127Smckusick */ 36211127Smckusick flushent() 36311127Smckusick { 36411127Smckusick 36511127Smckusick ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev; 36611732Smckusick (void) fwrite(dirbuf, (int)dirloc, 1, df); 36711127Smckusick seekpt = ftell(df); 36811127Smckusick dirloc = 0; 36911127Smckusick } 37011127Smckusick 37111127Smckusick dcvt(odp, ndp) 37211127Smckusick register struct odirect *odp; 37311127Smckusick register struct direct *ndp; 37411127Smckusick { 37511127Smckusick 37611127Smckusick bzero((char *)ndp, (long)(sizeof *ndp)); 37711127Smckusick ndp->d_ino = odp->d_ino; 37811992Smckusick (void) strncpy(ndp->d_name, odp->d_name, ODIRSIZ); 37911127Smckusick ndp->d_namlen = strlen(ndp->d_name); 38011127Smckusick ndp->d_reclen = DIRSIZ(ndp); 38111127Smckusick } 38211127Smckusick 38311127Smckusick /* 38411127Smckusick * Seek to an entry in a directory. 38540064Smckusick * Only values returned by rst_telldir should be passed to rst_seekdir. 38611732Smckusick * This routine handles many directories in a single file. 38711732Smckusick * It takes the base of the directory in the file, plus 38811732Smckusick * the desired seek offset into it. 38911127Smckusick */ 39011127Smckusick void 39112556Smckusick rst_seekdir(dirp, loc, base) 39211127Smckusick register DIR *dirp; 39311127Smckusick daddr_t loc, base; 39411127Smckusick { 39540064Smckusick off_t rst_telldir(); 39611127Smckusick 39740064Smckusick if (loc == rst_telldir(dirp)) 39811127Smckusick return; 39911127Smckusick loc -= base; 40011127Smckusick if (loc < 0) 40112556Smckusick fprintf(stderr, "bad seek pointer to rst_seekdir %d\n", loc); 40211127Smckusick (void) lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), 0); 40311127Smckusick dirp->dd_loc = loc & (DIRBLKSIZ - 1); 40411127Smckusick if (dirp->dd_loc != 0) 40511127Smckusick dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ); 40611127Smckusick } 40711127Smckusick 40811127Smckusick /* 40911127Smckusick * get next entry in a directory. 41011127Smckusick */ 41111127Smckusick struct direct * 41212556Smckusick rst_readdir(dirp) 41311127Smckusick register DIR *dirp; 41411127Smckusick { 41511127Smckusick register struct direct *dp; 41611127Smckusick 41711127Smckusick for (;;) { 41811127Smckusick if (dirp->dd_loc == 0) { 41911127Smckusick dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, 42011127Smckusick DIRBLKSIZ); 42112453Smckusick if (dirp->dd_size <= 0) { 42212453Smckusick dprintf(stderr, "error reading directory\n"); 42311127Smckusick return NULL; 42412453Smckusick } 42511127Smckusick } 42611127Smckusick if (dirp->dd_loc >= dirp->dd_size) { 42711127Smckusick dirp->dd_loc = 0; 42811127Smckusick continue; 42911127Smckusick } 43011127Smckusick dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc); 43111127Smckusick if (dp->d_reclen == 0 || 43212453Smckusick dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) { 43312453Smckusick dprintf(stderr, "corrupted directory: bad reclen %d\n", 43412453Smckusick dp->d_reclen); 43511127Smckusick return NULL; 43612453Smckusick } 43711127Smckusick dirp->dd_loc += dp->d_reclen; 43812453Smckusick if (dp->d_ino == 0 && strcmp(dp->d_name, "/") != 0) 43912453Smckusick continue; 44012556Smckusick if (dp->d_ino >= maxino) { 44112453Smckusick dprintf(stderr, "corrupted directory: bad inum %d\n", 44212453Smckusick dp->d_ino); 44312453Smckusick continue; 44412453Smckusick } 44511127Smckusick return (dp); 44611127Smckusick } 44711127Smckusick } 44811127Smckusick 44911127Smckusick /* 45017753Smckusick * Simulate the opening of a directory 45117753Smckusick */ 45217753Smckusick DIR * 45317753Smckusick rst_opendir(name) 45417753Smckusick char *name; 45517753Smckusick { 45617753Smckusick struct inotab *itp; 45717753Smckusick ino_t ino; 45817753Smckusick 45917753Smckusick if ((ino = dirlookup(name)) > 0 && 46017753Smckusick (itp = inotablookup(ino)) != NULL) { 46117753Smckusick rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 46217753Smckusick return (dirp); 46317753Smckusick } 46417753Smckusick return (0); 46517753Smckusick } 46617753Smckusick 46717753Smckusick /* 46840064Smckusick * Simulate finding the current offset in the directory. 46940064Smckusick */ 47040064Smckusick off_t 47140064Smckusick rst_telldir(dirp) 47240064Smckusick DIR *dirp; 47340064Smckusick { 47440064Smckusick off_t lseek(); 47540064Smckusick 47640064Smckusick return (lseek(dirp->dd_fd, 0L, 1) - dirp->dd_size + dirp->dd_loc); 47740064Smckusick } 47840064Smckusick 47940064Smckusick /* 48040064Smckusick * Open a directory file. 48140064Smckusick */ 48240064Smckusick DIR * 48340064Smckusick opendirfile(name) 48440064Smckusick char *name; 48540064Smckusick { 48640064Smckusick register DIR *dirp; 48740064Smckusick register int fd; 48840064Smckusick 48940064Smckusick if ((fd = open(name, 0)) == -1) 49040064Smckusick return NULL; 49140064Smckusick if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) { 49240064Smckusick close (fd); 49340064Smckusick return NULL; 49440064Smckusick } 49540064Smckusick dirp->dd_fd = fd; 49640064Smckusick dirp->dd_loc = 0; 49740064Smckusick return dirp; 49840064Smckusick } 49940064Smckusick 50040064Smckusick /* 50111127Smckusick * Set the mode, owner, and times for all new or changed directories 50211127Smckusick */ 50311992Smckusick setdirmodes() 50411127Smckusick { 50511127Smckusick FILE *mf; 50611127Smckusick struct modeinfo node; 50711127Smckusick struct entry *ep; 50811127Smckusick char *cp; 50911127Smckusick 51011127Smckusick vprintf(stdout, "Set directory mode, owner, and times.\n"); 51137952Sbostic (void) sprintf(modefile, "%s/rstmode%d", _PATH_TMP, dumpdate); 51211127Smckusick mf = fopen(modefile, "r"); 51311127Smckusick if (mf == NULL) { 51411127Smckusick perror("fopen"); 51515779Smckusick fprintf(stderr, "cannot open mode file %s\n", modefile); 51615779Smckusick fprintf(stderr, "directory mode, owner, and times not set\n"); 51715779Smckusick return; 51811127Smckusick } 51911127Smckusick clearerr(mf); 52011309Smckusick for (;;) { 52111732Smckusick (void) fread((char *)&node, 1, sizeof(struct modeinfo), mf); 52211309Smckusick if (feof(mf)) 52311309Smckusick break; 52411127Smckusick ep = lookupino(node.ino); 52514453Smckusick if (command == 'i' || command == 'x') { 52614453Smckusick if (ep == NIL) 52711309Smckusick continue; 52818008Smckusick if (ep->e_flags & EXISTED) { 52918008Smckusick ep->e_flags &= ~NEW; 53018008Smckusick continue; 53118008Smckusick } 53214453Smckusick if (node.ino == ROOTINO && 53314453Smckusick reply("set owner/mode for '.'") == FAIL) 53414453Smckusick continue; 53514453Smckusick } 53614453Smckusick if (ep == NIL) 53711127Smckusick panic("cannot find directory inode %d\n", node.ino); 53811127Smckusick cp = myname(ep); 53911732Smckusick (void) chown(cp, node.uid, node.gid); 54011732Smckusick (void) chmod(cp, node.mode); 54139471Smckusick utimes(cp, node.timep); 54211992Smckusick ep->e_flags &= ~NEW; 54311127Smckusick } 54411127Smckusick if (ferror(mf)) 54511127Smckusick panic("error setting directory modes\n"); 54611732Smckusick (void) fclose(mf); 54711127Smckusick } 54811127Smckusick 54911127Smckusick /* 55011127Smckusick * Generate a literal copy of a directory. 55111127Smckusick */ 55211127Smckusick genliteraldir(name, ino) 55311127Smckusick char *name; 55411127Smckusick ino_t ino; 55511127Smckusick { 55611127Smckusick register struct inotab *itp; 55711127Smckusick int ofile, dp, i, size; 55811127Smckusick char buf[BUFSIZ]; 55911127Smckusick 56011127Smckusick itp = inotablookup(ino); 56111127Smckusick if (itp == NULL) 56211322Smckusick panic("Cannot find directory inode %d named %s\n", ino, name); 56312893Ssam if ((ofile = creat(name, 0666)) < 0) { 56412556Smckusick fprintf(stderr, "%s: ", name); 56512556Smckusick (void) fflush(stderr); 56612556Smckusick perror("cannot create file"); 56711127Smckusick return (FAIL); 56811127Smckusick } 56912556Smckusick rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 57011127Smckusick dp = dup(dirp->dd_fd); 57111127Smckusick for (i = itp->t_size; i > 0; i -= BUFSIZ) { 57211127Smckusick size = i < BUFSIZ ? i : BUFSIZ; 57311127Smckusick if (read(dp, buf, (int) size) == -1) { 57411127Smckusick fprintf(stderr, 57511127Smckusick "write error extracting inode %d, name %s\n", 57611127Smckusick curfile.ino, curfile.name); 57711127Smckusick perror("read"); 57811127Smckusick done(1); 57911127Smckusick } 58034268Smckusick if (!Nflag && write(ofile, buf, (int) size) == -1) { 58111127Smckusick fprintf(stderr, 58211127Smckusick "write error extracting inode %d, name %s\n", 58311127Smckusick curfile.ino, curfile.name); 58411127Smckusick perror("write"); 58511127Smckusick done(1); 58611127Smckusick } 58711127Smckusick } 58811732Smckusick (void) close(dp); 58911732Smckusick (void) close(ofile); 59011127Smckusick return (GOOD); 59111127Smckusick } 59211127Smckusick 59311127Smckusick /* 59411992Smckusick * Determine the type of an inode 59511992Smckusick */ 59611992Smckusick inodetype(ino) 59711992Smckusick ino_t ino; 59811992Smckusick { 59911992Smckusick struct inotab *itp; 60011992Smckusick 60111992Smckusick itp = inotablookup(ino); 60211992Smckusick if (itp == NULL) 60311992Smckusick return (LEAF); 60411992Smckusick return (NODE); 60511992Smckusick } 60611992Smckusick 60711992Smckusick /* 60811127Smckusick * Allocate and initialize a directory inode entry. 60911127Smckusick * If requested, save its pertinent mode, owner, and time info. 61011127Smckusick */ 61111322Smckusick struct inotab * 61211127Smckusick allocinotab(ino, dip, seekpt) 61311127Smckusick ino_t ino; 61411127Smckusick struct dinode *dip; 61511127Smckusick daddr_t seekpt; 61611127Smckusick { 61711127Smckusick register struct inotab *itp; 61811127Smckusick struct modeinfo node; 61911127Smckusick 62011127Smckusick itp = (struct inotab *)calloc(1, sizeof(struct inotab)); 62113859Smckusick if (itp == 0) 62213859Smckusick panic("no memory directory table\n"); 62311127Smckusick itp->t_next = inotab[INOHASH(ino)]; 62411127Smckusick inotab[INOHASH(ino)] = itp; 62511127Smckusick itp->t_ino = ino; 62611127Smckusick itp->t_seekpt = seekpt; 62711127Smckusick if (mf == NULL) 62811322Smckusick return(itp); 62911127Smckusick node.ino = ino; 63039471Smckusick node.timep[0].tv_sec = dip->di_atime; 63139471Smckusick node.timep[0].tv_usec = 0; 63239471Smckusick node.timep[1].tv_sec = dip->di_mtime; 63339471Smckusick node.timep[1].tv_usec = 0; 63411127Smckusick node.mode = dip->di_mode; 63511127Smckusick node.uid = dip->di_uid; 63611127Smckusick node.gid = dip->di_gid; 63711732Smckusick (void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf); 63811322Smckusick return(itp); 63911127Smckusick } 64011127Smckusick 64111127Smckusick /* 64211127Smckusick * Look up an inode in the table of directories 64311127Smckusick */ 64411127Smckusick struct inotab * 64511127Smckusick inotablookup(ino) 64611127Smckusick ino_t ino; 64711127Smckusick { 64811127Smckusick register struct inotab *itp; 64911127Smckusick 65011127Smckusick for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next) 65111127Smckusick if (itp->t_ino == ino) 65211127Smckusick return(itp); 65311127Smckusick return ((struct inotab *)0); 65411127Smckusick } 65511127Smckusick 65611127Smckusick /* 65711127Smckusick * Clean up and exit 65811127Smckusick */ 65911127Smckusick done(exitcode) 66011127Smckusick int exitcode; 66111127Smckusick { 66211127Smckusick 66311127Smckusick closemt(); 66411992Smckusick if (modefile[0] != '#') 66511992Smckusick (void) unlink(modefile); 66611992Smckusick if (dirfile[0] != '#') 66711992Smckusick (void) unlink(dirfile); 66811127Smckusick exit(exitcode); 66911127Smckusick } 670