121165Sdist /* 236105Sbostic * Copyright (c) 1983 The Regents of the University of California. 336105Sbostic * All rights reserved. 436105Sbostic * 542708Sbostic * %sccs.include.redist.c% 621165Sdist */ 721165Sdist 811127Smckusick #ifndef lint 9*57896Sbostic static char sccsid[] = "@(#)dirs.c 5.26 (Berkeley) 02/10/93"; 1036105Sbostic #endif /* not lint */ 1111127Smckusick 1256567Sbostic #include <sys/param.h> 1311309Smckusick #include <sys/file.h> 1456567Sbostic #include <sys/stat.h> 1556567Sbostic #include <sys/time.h> 1656567Sbostic 1756567Sbostic #include <ufs/ffs/fs.h> 1856567Sbostic #include <ufs/ufs/dinode.h> 1951625Sbostic #include <ufs/ufs/dir.h> 2056567Sbostic #include <protocols/dumprestore.h> 2156567Sbostic 2256567Sbostic #include <errno.h> 2356567Sbostic #include <stdio.h> 2456567Sbostic #include <stdlib.h> 2556567Sbostic #include <string.h> 2656567Sbostic #include <unistd.h> 2756567Sbostic 2837952Sbostic #include "pathnames.h" 2956567Sbostic #include "restore.h" 3056567Sbostic #include "extern.h" 3111127Smckusick 3211992Smckusick /* 3311992Smckusick * Symbol table of directories read from tape. 3411992Smckusick */ 3511127Smckusick #define HASHSIZE 1000 3611127Smckusick #define INOHASH(val) (val % HASHSIZE) 3711127Smckusick struct inotab { 3850662Smckusick struct inotab *t_next; 3911127Smckusick ino_t t_ino; 4050662Smckusick long t_seekpt; 4150662Smckusick long t_size; 4211309Smckusick }; 4311309Smckusick static struct inotab *inotab[HASHSIZE]; 4411127Smckusick 4511992Smckusick /* 4611992Smckusick * Information retained about directories. 4711992Smckusick */ 4811127Smckusick struct modeinfo { 4911127Smckusick ino_t ino; 5039471Smckusick struct timeval timep[2]; 5111127Smckusick short mode; 5211127Smckusick short uid; 5311127Smckusick short gid; 5411127Smckusick }; 5511127Smckusick 5611992Smckusick /* 5740094Smckusick * Definitions for library routines operating on directories. 5840094Smckusick */ 5946564Smckusick #undef DIRBLKSIZ 6046564Smckusick #define DIRBLKSIZ 1024 6150657Smckusick struct rstdirdesc { 6240094Smckusick int dd_fd; 6340094Smckusick long dd_loc; 6440094Smckusick long dd_size; 6540094Smckusick char dd_buf[DIRBLKSIZ]; 6640094Smckusick }; 6740094Smckusick 6840094Smckusick /* 6911992Smckusick * Global variables for this file. 7011992Smckusick */ 7150662Smckusick static long seekpt; 7211309Smckusick static FILE *df, *mf; 7350657Smckusick static RST_DIR *dirp; 7411992Smckusick static char dirfile[32] = "#"; /* No file */ 7511992Smckusick static char modefile[32] = "#"; /* No file */ 7646566Smckusick static char dot[2] = "."; /* So it can be modified */ 7711127Smckusick 7811992Smckusick /* 7911992Smckusick * Format of old style directories. 8011992Smckusick */ 8111127Smckusick #define ODIRSIZ 14 8211127Smckusick struct odirect { 8311127Smckusick u_short d_ino; 8411127Smckusick char d_name[ODIRSIZ]; 8511127Smckusick }; 8611127Smckusick 8756567Sbostic static struct inotab *allocinotab __P((ino_t, struct dinode *, long)); 8856567Sbostic static void dcvt __P((struct odirect *, struct direct *)); 8956567Sbostic static void flushent __P((void)); 9056567Sbostic static struct inotab *inotablookup __P((ino_t)); 91*57896Sbostic static RST_DIR *opendirfile __P((const char *)); 9256567Sbostic static void putdir __P((char *, long)); 9356567Sbostic static void putent __P((struct direct *)); 9456567Sbostic static void rst_seekdir __P((RST_DIR *, long, long)); 9556567Sbostic static long rst_telldir __P((RST_DIR *)); 9656946Smckusick static struct direct *searchdir __P((ino_t, char *)); 9756567Sbostic 9811127Smckusick /* 9911127Smckusick * Extract directory contents, building up a directory structure 10011127Smckusick * on disk for extraction by name. 10111992Smckusick * If genmode is requested, save mode, owner, and times for all 10211127Smckusick * directories on the tape. 10311127Smckusick */ 10456567Sbostic void 10511992Smckusick extractdirs(genmode) 10611992Smckusick int genmode; 10711127Smckusick { 10811127Smckusick register int i; 10911127Smckusick register struct dinode *ip; 11011322Smckusick struct inotab *itp; 11111127Smckusick struct direct nulldir; 11211127Smckusick 11311127Smckusick vprintf(stdout, "Extract directories from tape\n"); 11437952Sbostic (void) sprintf(dirfile, "%s/rstdir%d", _PATH_TMP, dumpdate); 11511127Smckusick df = fopen(dirfile, "w"); 11611127Smckusick if (df == 0) { 11711127Smckusick fprintf(stderr, 11815779Smckusick "restore: %s - cannot create directory temporary\n", 11911127Smckusick dirfile); 12056567Sbostic fprintf(stderr, "fopen: %s\n", strerror(errno)); 12111127Smckusick done(1); 12211127Smckusick } 12311992Smckusick if (genmode != 0) { 12437952Sbostic (void) sprintf(modefile, "%s/rstmode%d", _PATH_TMP, dumpdate); 12511127Smckusick mf = fopen(modefile, "w"); 12611309Smckusick if (mf == 0) { 12711127Smckusick fprintf(stderr, 12815779Smckusick "restore: %s - cannot create modefile \n", 12911127Smckusick modefile); 13056567Sbostic fprintf(stderr, "fopen: %s\n", strerror(errno)); 13111127Smckusick done(1); 13211127Smckusick } 13311127Smckusick } 13411322Smckusick nulldir.d_ino = 0; 13554582Smckusick nulldir.d_type = DT_DIR; 13611127Smckusick nulldir.d_namlen = 1; 13712453Smckusick (void) strcpy(nulldir.d_name, "/"); 13854582Smckusick nulldir.d_reclen = DIRSIZ(0, &nulldir); 13911127Smckusick for (;;) { 14011127Smckusick curfile.name = "<directory file - name unknown>"; 14111127Smckusick curfile.action = USING; 14211127Smckusick ip = curfile.dip; 14317948Smckusick if (ip == NULL || (ip->di_mode & IFMT) != IFDIR) { 14411732Smckusick (void) fclose(df); 14540064Smckusick dirp = opendirfile(dirfile); 14611127Smckusick if (dirp == NULL) 14756567Sbostic fprintf(stderr, "opendirfile: %s\n", 14856567Sbostic strerror(errno)); 14911127Smckusick if (mf != NULL) 15011732Smckusick (void) fclose(mf); 15146566Smckusick i = dirlookup(dot); 15211992Smckusick if (i == 0) 15311421Smckusick panic("Root directory is not on tape\n"); 15411127Smckusick return; 15511127Smckusick } 15611322Smckusick itp = allocinotab(curfile.ino, ip, seekpt); 15756434Smckusick getfile(putdir, xtrnull); 15811127Smckusick putent(&nulldir); 15911127Smckusick flushent(); 16011322Smckusick itp->t_size = seekpt - itp->t_seekpt; 16111127Smckusick } 16211127Smckusick } 16311127Smckusick 16411127Smckusick /* 16511322Smckusick * skip over all the directories on the tape 16611322Smckusick */ 16756567Sbostic void 16811322Smckusick skipdirs() 16911322Smckusick { 17011322Smckusick 17111322Smckusick while ((curfile.dip->di_mode & IFMT) == IFDIR) { 17211322Smckusick skipfile(); 17311322Smckusick } 17411322Smckusick } 17511322Smckusick 17611322Smckusick /* 17711127Smckusick * Recursively find names and inumbers of all files in subtree 17811127Smckusick * pname and pass them off to be processed. 17911127Smckusick */ 18056567Sbostic void 18111127Smckusick treescan(pname, ino, todo) 18211127Smckusick char *pname; 18311127Smckusick ino_t ino; 18456567Sbostic long (*todo) __P((char *, ino_t, int)); 18511127Smckusick { 18611127Smckusick register struct inotab *itp; 18712453Smckusick register struct direct *dp; 18811127Smckusick int namelen; 18950662Smckusick long bpt; 19011644Smckusick char locname[MAXPATHLEN + 1]; 19111127Smckusick 19211127Smckusick itp = inotablookup(ino); 19311127Smckusick if (itp == NULL) { 19411127Smckusick /* 19511127Smckusick * Pname is name of a simple file or an unchanged directory. 19611127Smckusick */ 19711744Smckusick (void) (*todo)(pname, ino, LEAF); 19811127Smckusick return; 19911127Smckusick } 20011127Smckusick /* 20111127Smckusick * Pname is a dumped directory name. 20211127Smckusick */ 20311744Smckusick if ((*todo)(pname, ino, NODE) == FAIL) 20411744Smckusick return; 20511127Smckusick /* 20611127Smckusick * begin search through the directory 20711127Smckusick * skipping over "." and ".." 20811127Smckusick */ 20911992Smckusick (void) strncpy(locname, pname, MAXPATHLEN); 21011992Smckusick (void) strncat(locname, "/", MAXPATHLEN); 21111127Smckusick namelen = strlen(locname); 21212556Smckusick rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 21312556Smckusick dp = rst_readdir(dirp); /* "." */ 21427263Smckusick if (dp != NULL && strcmp(dp->d_name, ".") == 0) 21512556Smckusick dp = rst_readdir(dirp); /* ".." */ 21627263Smckusick else 21727263Smckusick fprintf(stderr, "Warning: `.' missing from directory %s\n", 21827263Smckusick pname); 21927263Smckusick if (dp != NULL && strcmp(dp->d_name, "..") == 0) 22012556Smckusick dp = rst_readdir(dirp); /* first real entry */ 22127263Smckusick else 22227263Smckusick fprintf(stderr, "Warning: `..' missing from directory %s\n", 22327263Smckusick pname); 22440064Smckusick bpt = rst_telldir(dirp); 22511127Smckusick /* 22612453Smckusick * a zero inode signals end of directory 22711127Smckusick */ 22812453Smckusick while (dp != NULL && dp->d_ino != 0) { 22911127Smckusick locname[namelen] = '\0'; 23011644Smckusick if (namelen + dp->d_namlen >= MAXPATHLEN) { 23111127Smckusick fprintf(stderr, "%s%s: name exceeds %d char\n", 23211644Smckusick locname, dp->d_name, MAXPATHLEN); 23311127Smckusick } else { 23411992Smckusick (void) strncat(locname, dp->d_name, (int)dp->d_namlen); 23511127Smckusick treescan(locname, dp->d_ino, todo); 23612556Smckusick rst_seekdir(dirp, bpt, itp->t_seekpt); 23711127Smckusick } 23812556Smckusick dp = rst_readdir(dirp); 23940064Smckusick bpt = rst_telldir(dirp); 24011127Smckusick } 24111127Smckusick if (dp == NULL) 24211127Smckusick fprintf(stderr, "corrupted directory: %s.\n", locname); 24311127Smckusick } 24411127Smckusick 24511127Smckusick /* 24656434Smckusick * Lookup a pathname which is always assumed to start from the ROOTINO. 24711127Smckusick */ 24856946Smckusick struct direct * 24956434Smckusick pathsearch(pathname) 250*57896Sbostic const char *pathname; 25111127Smckusick { 25211127Smckusick ino_t ino; 25356946Smckusick struct direct *dp; 254*57896Sbostic char *path, *name, buffer[MAXPATHLEN]; 25511127Smckusick 25656434Smckusick strcpy(buffer, pathname); 257*57896Sbostic path = buffer; 25811127Smckusick ino = ROOTINO; 259*57896Sbostic while (*path == '/') 260*57896Sbostic path++; 261*57896Sbostic while ((name = strsep(&path, "/")) != NULL && *name != NULL) { 26256946Smckusick if ((dp = searchdir(ino, name)) == 0) 26356946Smckusick return (NULL); 26456946Smckusick ino = dp->d_ino; 26556946Smckusick } 26656946Smckusick return (dp); 26711127Smckusick } 26811127Smckusick 26911127Smckusick /* 27056434Smckusick * Lookup the requested name in directory inum. 27156434Smckusick * Return its inode number if found, zero if it does not exist. 27211127Smckusick */ 27356946Smckusick static struct direct * 27456434Smckusick searchdir(inum, name) 27511127Smckusick ino_t inum; 27656434Smckusick char *name; 27711127Smckusick { 27811127Smckusick register struct direct *dp; 27911127Smckusick register struct inotab *itp; 28011127Smckusick int len; 28111127Smckusick 28211127Smckusick itp = inotablookup(inum); 28311127Smckusick if (itp == NULL) 28411127Smckusick return(0); 28512556Smckusick rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 28656434Smckusick len = strlen(name); 28711127Smckusick do { 28812556Smckusick dp = rst_readdir(dirp); 28912453Smckusick if (dp == NULL || dp->d_ino == 0) 29056946Smckusick return (NULL); 29156434Smckusick } while (dp->d_namlen != len || strncmp(dp->d_name, name, len) != 0); 29256946Smckusick return (dp); 29311127Smckusick } 29411127Smckusick 29511127Smckusick /* 29611127Smckusick * Put the directory entries in the directory file 29711127Smckusick */ 29856567Sbostic static void 29911127Smckusick putdir(buf, size) 30011127Smckusick char *buf; 30156567Sbostic long size; 30211127Smckusick { 30311127Smckusick struct direct cvtbuf; 30411127Smckusick register struct odirect *odp; 30511127Smckusick struct odirect *eodp; 30611127Smckusick register struct direct *dp; 30711127Smckusick long loc, i; 30811127Smckusick 30911127Smckusick if (cvtflag) { 31011127Smckusick eodp = (struct odirect *)&buf[size]; 31111127Smckusick for (odp = (struct odirect *)buf; odp < eodp; odp++) 31211127Smckusick if (odp->d_ino != 0) { 31311127Smckusick dcvt(odp, &cvtbuf); 31411127Smckusick putent(&cvtbuf); 31511127Smckusick } 31611127Smckusick } else { 31711127Smckusick for (loc = 0; loc < size; ) { 31811127Smckusick dp = (struct direct *)(buf + loc); 31954582Smckusick if (oldinofmt) { 32054582Smckusick if (Bcvt) { 32156567Sbostic swabst((u_char *)"l2s", (u_char *) dp); 32254582Smckusick } 32354582Smckusick } else { 32454582Smckusick if (Bcvt) { 32556567Sbostic swabst((u_char *)"ls", (u_char *) dp); 32654582Smckusick } 32726941Ssklower } 32811127Smckusick i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1)); 32946564Smckusick if ((dp->d_reclen & 0x3) != 0 || 33046564Smckusick dp->d_reclen > i || 33154582Smckusick dp->d_reclen < DIRSIZ(0, dp) || 33250662Smckusick dp->d_namlen > NAME_MAX) { 33350662Smckusick vprintf(stdout, "Mangled directory: "); 33450662Smckusick if ((dp->d_reclen & 0x3) != 0) 33550662Smckusick vprintf(stdout, 33650662Smckusick "reclen not multiple of 4 "); 33754582Smckusick if (dp->d_reclen < DIRSIZ(0, dp)) 33850662Smckusick vprintf(stdout, 33950662Smckusick "reclen less than DIRSIZ (%d < %d) ", 34054582Smckusick dp->d_reclen, DIRSIZ(0, dp)); 34150662Smckusick if (dp->d_namlen > NAME_MAX) 34250662Smckusick vprintf(stdout, 34350662Smckusick "reclen name too big (%d > %d) ", 34450662Smckusick dp->d_namlen, NAME_MAX); 34550662Smckusick vprintf(stdout, "\n"); 34611127Smckusick loc += i; 34711127Smckusick continue; 34811127Smckusick } 34911127Smckusick loc += dp->d_reclen; 35011127Smckusick if (dp->d_ino != 0) { 35111127Smckusick putent(dp); 35211127Smckusick } 35311127Smckusick } 35411127Smckusick } 35511127Smckusick } 35611127Smckusick 35711127Smckusick /* 35811127Smckusick * These variables are "local" to the following two functions. 35911127Smckusick */ 36011127Smckusick char dirbuf[DIRBLKSIZ]; 36111127Smckusick long dirloc = 0; 36211127Smckusick long prev = 0; 36311127Smckusick 36411127Smckusick /* 36511127Smckusick * add a new directory entry to a file. 36611127Smckusick */ 36756567Sbostic static void 36811127Smckusick putent(dp) 36911127Smckusick struct direct *dp; 37011127Smckusick { 37154582Smckusick dp->d_reclen = DIRSIZ(0, dp); 37211127Smckusick if (dirloc + dp->d_reclen > DIRBLKSIZ) { 37311127Smckusick ((struct direct *)(dirbuf + prev))->d_reclen = 37411127Smckusick DIRBLKSIZ - prev; 37511732Smckusick (void) fwrite(dirbuf, 1, DIRBLKSIZ, df); 37611127Smckusick dirloc = 0; 37711127Smckusick } 37811127Smckusick bcopy((char *)dp, dirbuf + dirloc, (long)dp->d_reclen); 37911127Smckusick prev = dirloc; 38011127Smckusick dirloc += dp->d_reclen; 38111127Smckusick } 38211127Smckusick 38311127Smckusick /* 38411127Smckusick * flush out a directory that is finished. 38511127Smckusick */ 38656567Sbostic static void 38711127Smckusick flushent() 38811127Smckusick { 38911127Smckusick ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev; 39011732Smckusick (void) fwrite(dirbuf, (int)dirloc, 1, df); 39111127Smckusick seekpt = ftell(df); 39211127Smckusick dirloc = 0; 39311127Smckusick } 39411127Smckusick 39556567Sbostic static void 39611127Smckusick dcvt(odp, ndp) 39711127Smckusick register struct odirect *odp; 39811127Smckusick register struct direct *ndp; 39911127Smckusick { 40011127Smckusick 40111127Smckusick bzero((char *)ndp, (long)(sizeof *ndp)); 40211127Smckusick ndp->d_ino = odp->d_ino; 40354582Smckusick ndp->d_type = DT_UNKNOWN; 40411992Smckusick (void) strncpy(ndp->d_name, odp->d_name, ODIRSIZ); 40511127Smckusick ndp->d_namlen = strlen(ndp->d_name); 40654582Smckusick ndp->d_reclen = DIRSIZ(0, ndp); 40711127Smckusick } 40811127Smckusick 40911127Smckusick /* 41011127Smckusick * Seek to an entry in a directory. 41140064Smckusick * Only values returned by rst_telldir should be passed to rst_seekdir. 41211732Smckusick * This routine handles many directories in a single file. 41311732Smckusick * It takes the base of the directory in the file, plus 41411732Smckusick * the desired seek offset into it. 41511127Smckusick */ 41656567Sbostic static void 41712556Smckusick rst_seekdir(dirp, loc, base) 41850657Smckusick register RST_DIR *dirp; 41950662Smckusick long loc, base; 42011127Smckusick { 42111127Smckusick 42240064Smckusick if (loc == rst_telldir(dirp)) 42311127Smckusick return; 42411127Smckusick loc -= base; 42511127Smckusick if (loc < 0) 42612556Smckusick fprintf(stderr, "bad seek pointer to rst_seekdir %d\n", loc); 42756567Sbostic (void) lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), SEEK_SET); 42811127Smckusick dirp->dd_loc = loc & (DIRBLKSIZ - 1); 42911127Smckusick if (dirp->dd_loc != 0) 43011127Smckusick dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ); 43111127Smckusick } 43211127Smckusick 43311127Smckusick /* 43411127Smckusick * get next entry in a directory. 43511127Smckusick */ 43611127Smckusick struct direct * 43712556Smckusick rst_readdir(dirp) 43850657Smckusick register RST_DIR *dirp; 43911127Smckusick { 44011127Smckusick register struct direct *dp; 44111127Smckusick 44211127Smckusick for (;;) { 44311127Smckusick if (dirp->dd_loc == 0) { 44411127Smckusick dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, 44511127Smckusick DIRBLKSIZ); 44612453Smckusick if (dirp->dd_size <= 0) { 44712453Smckusick dprintf(stderr, "error reading directory\n"); 44856567Sbostic return (NULL); 44912453Smckusick } 45011127Smckusick } 45111127Smckusick if (dirp->dd_loc >= dirp->dd_size) { 45211127Smckusick dirp->dd_loc = 0; 45311127Smckusick continue; 45411127Smckusick } 45511127Smckusick dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc); 45611127Smckusick if (dp->d_reclen == 0 || 45712453Smckusick dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) { 45812453Smckusick dprintf(stderr, "corrupted directory: bad reclen %d\n", 45912453Smckusick dp->d_reclen); 46056567Sbostic return (NULL); 46112453Smckusick } 46211127Smckusick dirp->dd_loc += dp->d_reclen; 46312453Smckusick if (dp->d_ino == 0 && strcmp(dp->d_name, "/") != 0) 46412453Smckusick continue; 46512556Smckusick if (dp->d_ino >= maxino) { 46612453Smckusick dprintf(stderr, "corrupted directory: bad inum %d\n", 46712453Smckusick dp->d_ino); 46812453Smckusick continue; 46912453Smckusick } 47011127Smckusick return (dp); 47111127Smckusick } 47211127Smckusick } 47311127Smckusick 47411127Smckusick /* 47517753Smckusick * Simulate the opening of a directory 47617753Smckusick */ 47750657Smckusick RST_DIR * 47817753Smckusick rst_opendir(name) 479*57896Sbostic const char *name; 48017753Smckusick { 48117753Smckusick struct inotab *itp; 48256946Smckusick RST_DIR *dirp; 48317753Smckusick ino_t ino; 48417753Smckusick 48517753Smckusick if ((ino = dirlookup(name)) > 0 && 48617753Smckusick (itp = inotablookup(ino)) != NULL) { 48756946Smckusick dirp = opendirfile(dirfile); 48817753Smckusick rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 48917753Smckusick return (dirp); 49017753Smckusick } 49117753Smckusick return (0); 49217753Smckusick } 49317753Smckusick 49417753Smckusick /* 49556946Smckusick * In our case, there is nothing to do when closing a directory. 49656946Smckusick */ 49756946Smckusick void 49856946Smckusick rst_closedir(dirp) 49956946Smckusick RST_DIR *dirp; 50056946Smckusick { 50156946Smckusick 502*57896Sbostic (void)close(dirp->dd_fd); 50356946Smckusick free(dirp); 50456946Smckusick return; 50556946Smckusick } 50656946Smckusick 50756946Smckusick /* 50840064Smckusick * Simulate finding the current offset in the directory. 50940064Smckusick */ 51056567Sbostic static long 51140064Smckusick rst_telldir(dirp) 51250657Smckusick RST_DIR *dirp; 51340064Smckusick { 51456567Sbostic return ((long)lseek(dirp->dd_fd, 51556567Sbostic (off_t)0, SEEK_CUR) - dirp->dd_size + dirp->dd_loc); 51640064Smckusick } 51740064Smckusick 51840064Smckusick /* 51940064Smckusick * Open a directory file. 52040064Smckusick */ 52156567Sbostic static RST_DIR * 52240064Smckusick opendirfile(name) 523*57896Sbostic const char *name; 52440064Smckusick { 52550657Smckusick register RST_DIR *dirp; 52640064Smckusick register int fd; 52740064Smckusick 52856567Sbostic if ((fd = open(name, O_RDONLY)) == -1) 52956567Sbostic return (NULL); 53056567Sbostic if ((dirp = malloc(sizeof(RST_DIR))) == NULL) { 53156567Sbostic (void)close(fd); 53256567Sbostic return (NULL); 53340064Smckusick } 53440064Smckusick dirp->dd_fd = fd; 53540064Smckusick dirp->dd_loc = 0; 53656567Sbostic return (dirp); 53740064Smckusick } 53840064Smckusick 53940064Smckusick /* 54011127Smckusick * Set the mode, owner, and times for all new or changed directories 54111127Smckusick */ 54256567Sbostic void 54355880Smckusick setdirmodes(flags) 54455880Smckusick int flags; 54511127Smckusick { 54611127Smckusick FILE *mf; 54711127Smckusick struct modeinfo node; 54811127Smckusick struct entry *ep; 54911127Smckusick char *cp; 55011127Smckusick 55111127Smckusick vprintf(stdout, "Set directory mode, owner, and times.\n"); 55237952Sbostic (void) sprintf(modefile, "%s/rstmode%d", _PATH_TMP, dumpdate); 55311127Smckusick mf = fopen(modefile, "r"); 55411127Smckusick if (mf == NULL) { 55556567Sbostic fprintf(stderr, "fopen: %s\n", strerror(errno)); 55615779Smckusick fprintf(stderr, "cannot open mode file %s\n", modefile); 55715779Smckusick fprintf(stderr, "directory mode, owner, and times not set\n"); 55815779Smckusick return; 55911127Smckusick } 56011127Smckusick clearerr(mf); 56111309Smckusick for (;;) { 56211732Smckusick (void) fread((char *)&node, 1, sizeof(struct modeinfo), mf); 56311309Smckusick if (feof(mf)) 56411309Smckusick break; 56511127Smckusick ep = lookupino(node.ino); 56614453Smckusick if (command == 'i' || command == 'x') { 56756567Sbostic if (ep == NULL) 56811309Smckusick continue; 56955880Smckusick if ((flags & FORCE) == 0 && ep->e_flags & EXISTED) { 57018008Smckusick ep->e_flags &= ~NEW; 57118008Smckusick continue; 57218008Smckusick } 57314453Smckusick if (node.ino == ROOTINO && 57414453Smckusick reply("set owner/mode for '.'") == FAIL) 57514453Smckusick continue; 57614453Smckusick } 57756567Sbostic if (ep == NULL) { 57811127Smckusick panic("cannot find directory inode %d\n", node.ino); 57942862Smckusick } else { 58042862Smckusick cp = myname(ep); 58142862Smckusick (void) chown(cp, node.uid, node.gid); 58242862Smckusick (void) chmod(cp, node.mode); 58342862Smckusick utimes(cp, node.timep); 58442862Smckusick ep->e_flags &= ~NEW; 58542862Smckusick } 58611127Smckusick } 58711127Smckusick if (ferror(mf)) 58811127Smckusick panic("error setting directory modes\n"); 58911732Smckusick (void) fclose(mf); 59011127Smckusick } 59111127Smckusick 59211127Smckusick /* 59311127Smckusick * Generate a literal copy of a directory. 59411127Smckusick */ 59556567Sbostic int 59611127Smckusick genliteraldir(name, ino) 59711127Smckusick char *name; 59811127Smckusick ino_t ino; 59911127Smckusick { 60011127Smckusick register struct inotab *itp; 60111127Smckusick int ofile, dp, i, size; 60211127Smckusick char buf[BUFSIZ]; 60311127Smckusick 60411127Smckusick itp = inotablookup(ino); 60511127Smckusick if (itp == NULL) 60611322Smckusick panic("Cannot find directory inode %d named %s\n", ino, name); 60712893Ssam if ((ofile = creat(name, 0666)) < 0) { 60812556Smckusick fprintf(stderr, "%s: ", name); 60912556Smckusick (void) fflush(stderr); 61056567Sbostic fprintf(stderr, "cannot create file: %s\n", strerror(errno)); 61111127Smckusick return (FAIL); 61211127Smckusick } 61312556Smckusick rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 61411127Smckusick dp = dup(dirp->dd_fd); 61511127Smckusick for (i = itp->t_size; i > 0; i -= BUFSIZ) { 61611127Smckusick size = i < BUFSIZ ? i : BUFSIZ; 61711127Smckusick if (read(dp, buf, (int) size) == -1) { 61811127Smckusick fprintf(stderr, 61911127Smckusick "write error extracting inode %d, name %s\n", 62011127Smckusick curfile.ino, curfile.name); 62156567Sbostic fprintf(stderr, "read: %s\n", strerror(errno)); 62211127Smckusick done(1); 62311127Smckusick } 62434268Smckusick if (!Nflag && write(ofile, buf, (int) size) == -1) { 62511127Smckusick fprintf(stderr, 62611127Smckusick "write error extracting inode %d, name %s\n", 62711127Smckusick curfile.ino, curfile.name); 62856567Sbostic fprintf(stderr, "write: %s\n", strerror(errno)); 62911127Smckusick done(1); 63011127Smckusick } 63111127Smckusick } 63211732Smckusick (void) close(dp); 63311732Smckusick (void) close(ofile); 63411127Smckusick return (GOOD); 63511127Smckusick } 63611127Smckusick 63711127Smckusick /* 63811992Smckusick * Determine the type of an inode 63911992Smckusick */ 64056567Sbostic int 64111992Smckusick inodetype(ino) 64211992Smckusick ino_t ino; 64311992Smckusick { 64411992Smckusick struct inotab *itp; 64511992Smckusick 64611992Smckusick itp = inotablookup(ino); 64711992Smckusick if (itp == NULL) 64811992Smckusick return (LEAF); 64911992Smckusick return (NODE); 65011992Smckusick } 65111992Smckusick 65211992Smckusick /* 65311127Smckusick * Allocate and initialize a directory inode entry. 65411127Smckusick * If requested, save its pertinent mode, owner, and time info. 65511127Smckusick */ 65656567Sbostic static struct inotab * 65711127Smckusick allocinotab(ino, dip, seekpt) 65811127Smckusick ino_t ino; 65911127Smckusick struct dinode *dip; 66050662Smckusick long seekpt; 66111127Smckusick { 66211127Smckusick register struct inotab *itp; 66311127Smckusick struct modeinfo node; 66411127Smckusick 66556567Sbostic itp = calloc(1, sizeof(struct inotab)); 66656567Sbostic if (itp == NULL) 66713859Smckusick panic("no memory directory table\n"); 66811127Smckusick itp->t_next = inotab[INOHASH(ino)]; 66911127Smckusick inotab[INOHASH(ino)] = itp; 67011127Smckusick itp->t_ino = ino; 67111127Smckusick itp->t_seekpt = seekpt; 67211127Smckusick if (mf == NULL) 67311322Smckusick return(itp); 67411127Smckusick node.ino = ino; 67554156Smckusick node.timep[0].tv_sec = dip->di_atime.ts_sec; 67654156Smckusick node.timep[0].tv_usec = dip->di_atime.ts_nsec / 1000; 67754156Smckusick node.timep[1].tv_sec = dip->di_mtime.ts_sec; 67854156Smckusick node.timep[1].tv_usec = dip->di_mtime.ts_nsec / 1000; 67911127Smckusick node.mode = dip->di_mode; 68011127Smckusick node.uid = dip->di_uid; 68111127Smckusick node.gid = dip->di_gid; 68211732Smckusick (void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf); 68311322Smckusick return(itp); 68411127Smckusick } 68511127Smckusick 68611127Smckusick /* 68711127Smckusick * Look up an inode in the table of directories 68811127Smckusick */ 68956567Sbostic static struct inotab * 69011127Smckusick inotablookup(ino) 69111127Smckusick ino_t ino; 69211127Smckusick { 69311127Smckusick register struct inotab *itp; 69411127Smckusick 69511127Smckusick for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next) 69611127Smckusick if (itp->t_ino == ino) 69711127Smckusick return(itp); 69856567Sbostic return (NULL); 69911127Smckusick } 70011127Smckusick 70111127Smckusick /* 70211127Smckusick * Clean up and exit 70311127Smckusick */ 70456567Sbostic void 70511127Smckusick done(exitcode) 70611127Smckusick int exitcode; 70711127Smckusick { 70811127Smckusick 70911127Smckusick closemt(); 71011992Smckusick if (modefile[0] != '#') 71111992Smckusick (void) unlink(modefile); 71211992Smckusick if (dirfile[0] != '#') 71311992Smckusick (void) unlink(dirfile); 71411127Smckusick exit(exitcode); 71511127Smckusick } 716