121165Sdist /* 261536Sbostic * Copyright (c) 1983, 1993 361536Sbostic * The Regents of the University of California. All rights reserved. 465767Sbostic * (c) UNIX System Laboratories, Inc. 565767Sbostic * All or some portions of this file are derived from material licensed 665767Sbostic * to the University of California by American Telephone and Telegraph 765767Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with 865767Sbostic * the permission of UNIX System Laboratories, Inc. 936105Sbostic * 1042708Sbostic * %sccs.include.redist.c% 1121165Sdist */ 1221165Sdist 1311127Smckusick #ifndef lint 14*67439Smckusick static char sccsid[] = "@(#)dirs.c 8.3 (Berkeley) 06/20/94"; 1536105Sbostic #endif /* not lint */ 1611127Smckusick 1756567Sbostic #include <sys/param.h> 1811309Smckusick #include <sys/file.h> 1956567Sbostic #include <sys/stat.h> 2056567Sbostic #include <sys/time.h> 2156567Sbostic 2256567Sbostic #include <ufs/ffs/fs.h> 2356567Sbostic #include <ufs/ufs/dinode.h> 2451625Sbostic #include <ufs/ufs/dir.h> 2556567Sbostic #include <protocols/dumprestore.h> 2656567Sbostic 2756567Sbostic #include <errno.h> 2856567Sbostic #include <stdio.h> 2956567Sbostic #include <stdlib.h> 3056567Sbostic #include <string.h> 3156567Sbostic #include <unistd.h> 3256567Sbostic 33*67439Smckusick #include <machine/endian.h> 34*67439Smckusick 3537952Sbostic #include "pathnames.h" 3656567Sbostic #include "restore.h" 3756567Sbostic #include "extern.h" 3811127Smckusick 3911992Smckusick /* 4011992Smckusick * Symbol table of directories read from tape. 4111992Smckusick */ 4211127Smckusick #define HASHSIZE 1000 4311127Smckusick #define INOHASH(val) (val % HASHSIZE) 4411127Smckusick struct inotab { 4550662Smckusick struct inotab *t_next; 4611127Smckusick ino_t t_ino; 4750662Smckusick long t_seekpt; 4850662Smckusick long t_size; 4911309Smckusick }; 5011309Smckusick static struct inotab *inotab[HASHSIZE]; 5111127Smckusick 5211992Smckusick /* 5311992Smckusick * Information retained about directories. 5411992Smckusick */ 5511127Smckusick struct modeinfo { 5611127Smckusick ino_t ino; 5739471Smckusick struct timeval timep[2]; 5811127Smckusick short mode; 5911127Smckusick short uid; 6011127Smckusick short gid; 6111127Smckusick }; 6211127Smckusick 6311992Smckusick /* 6440094Smckusick * Definitions for library routines operating on directories. 6540094Smckusick */ 6646564Smckusick #undef DIRBLKSIZ 6746564Smckusick #define DIRBLKSIZ 1024 6850657Smckusick struct rstdirdesc { 6940094Smckusick int dd_fd; 7040094Smckusick long dd_loc; 7140094Smckusick long dd_size; 7240094Smckusick char dd_buf[DIRBLKSIZ]; 7340094Smckusick }; 7440094Smckusick 7540094Smckusick /* 7611992Smckusick * Global variables for this file. 7711992Smckusick */ 7850662Smckusick static long seekpt; 7911309Smckusick static FILE *df, *mf; 8050657Smckusick static RST_DIR *dirp; 8111992Smckusick static char dirfile[32] = "#"; /* No file */ 8211992Smckusick static char modefile[32] = "#"; /* No file */ 8346566Smckusick static char dot[2] = "."; /* So it can be modified */ 8411127Smckusick 8511992Smckusick /* 8611992Smckusick * Format of old style directories. 8711992Smckusick */ 8811127Smckusick #define ODIRSIZ 14 8911127Smckusick struct odirect { 9011127Smckusick u_short d_ino; 9111127Smckusick char d_name[ODIRSIZ]; 9211127Smckusick }; 9311127Smckusick 9456567Sbostic static struct inotab *allocinotab __P((ino_t, struct dinode *, long)); 9556567Sbostic static void dcvt __P((struct odirect *, struct direct *)); 9656567Sbostic static void flushent __P((void)); 9756567Sbostic static struct inotab *inotablookup __P((ino_t)); 9857896Sbostic static RST_DIR *opendirfile __P((const char *)); 9956567Sbostic static void putdir __P((char *, long)); 10056567Sbostic static void putent __P((struct direct *)); 10156567Sbostic static void rst_seekdir __P((RST_DIR *, long, long)); 10256567Sbostic static long rst_telldir __P((RST_DIR *)); 10356946Smckusick static struct direct *searchdir __P((ino_t, char *)); 10456567Sbostic 10511127Smckusick /* 10611127Smckusick * Extract directory contents, building up a directory structure 10711127Smckusick * on disk for extraction by name. 10811992Smckusick * If genmode is requested, save mode, owner, and times for all 10911127Smckusick * directories on the tape. 11011127Smckusick */ 11156567Sbostic void 11211992Smckusick extractdirs(genmode) 11311992Smckusick int genmode; 11411127Smckusick { 11511127Smckusick register int i; 11611127Smckusick register struct dinode *ip; 11711322Smckusick struct inotab *itp; 11811127Smckusick struct direct nulldir; 11911127Smckusick 12011127Smckusick vprintf(stdout, "Extract directories from tape\n"); 12137952Sbostic (void) sprintf(dirfile, "%s/rstdir%d", _PATH_TMP, dumpdate); 12211127Smckusick df = fopen(dirfile, "w"); 12357930Sbostic if (df == NULL) { 12411127Smckusick fprintf(stderr, 12515779Smckusick "restore: %s - cannot create directory temporary\n", 12611127Smckusick dirfile); 12756567Sbostic fprintf(stderr, "fopen: %s\n", strerror(errno)); 12811127Smckusick done(1); 12911127Smckusick } 13011992Smckusick if (genmode != 0) { 13137952Sbostic (void) sprintf(modefile, "%s/rstmode%d", _PATH_TMP, dumpdate); 13211127Smckusick mf = fopen(modefile, "w"); 13357930Sbostic if (mf == NULL) { 13411127Smckusick fprintf(stderr, 13515779Smckusick "restore: %s - cannot create modefile \n", 13611127Smckusick modefile); 13756567Sbostic fprintf(stderr, "fopen: %s\n", strerror(errno)); 13811127Smckusick done(1); 13911127Smckusick } 14011127Smckusick } 14111322Smckusick nulldir.d_ino = 0; 14254582Smckusick nulldir.d_type = DT_DIR; 14311127Smckusick nulldir.d_namlen = 1; 14412453Smckusick (void) strcpy(nulldir.d_name, "/"); 14554582Smckusick nulldir.d_reclen = DIRSIZ(0, &nulldir); 14611127Smckusick for (;;) { 14711127Smckusick curfile.name = "<directory file - name unknown>"; 14811127Smckusick curfile.action = USING; 14911127Smckusick ip = curfile.dip; 15017948Smckusick if (ip == NULL || (ip->di_mode & IFMT) != IFDIR) { 15111732Smckusick (void) fclose(df); 15240064Smckusick dirp = opendirfile(dirfile); 15311127Smckusick if (dirp == NULL) 15456567Sbostic fprintf(stderr, "opendirfile: %s\n", 15556567Sbostic strerror(errno)); 15611127Smckusick if (mf != NULL) 15711732Smckusick (void) fclose(mf); 15846566Smckusick i = dirlookup(dot); 15911992Smckusick if (i == 0) 16011421Smckusick panic("Root directory is not on tape\n"); 16111127Smckusick return; 16211127Smckusick } 16311322Smckusick itp = allocinotab(curfile.ino, ip, seekpt); 16456434Smckusick getfile(putdir, xtrnull); 16511127Smckusick putent(&nulldir); 16611127Smckusick flushent(); 16711322Smckusick itp->t_size = seekpt - itp->t_seekpt; 16811127Smckusick } 16911127Smckusick } 17011127Smckusick 17111127Smckusick /* 17211322Smckusick * skip over all the directories on the tape 17311322Smckusick */ 17456567Sbostic void 17511322Smckusick skipdirs() 17611322Smckusick { 17711322Smckusick 17811322Smckusick while ((curfile.dip->di_mode & IFMT) == IFDIR) { 17911322Smckusick skipfile(); 18011322Smckusick } 18111322Smckusick } 18211322Smckusick 18311322Smckusick /* 18411127Smckusick * Recursively find names and inumbers of all files in subtree 18511127Smckusick * pname and pass them off to be processed. 18611127Smckusick */ 18756567Sbostic void 18811127Smckusick treescan(pname, ino, todo) 18911127Smckusick char *pname; 19011127Smckusick ino_t ino; 19156567Sbostic long (*todo) __P((char *, ino_t, int)); 19211127Smckusick { 19311127Smckusick register struct inotab *itp; 19412453Smckusick register struct direct *dp; 19511127Smckusick int namelen; 19650662Smckusick long bpt; 19711644Smckusick char locname[MAXPATHLEN + 1]; 19811127Smckusick 19911127Smckusick itp = inotablookup(ino); 20011127Smckusick if (itp == NULL) { 20111127Smckusick /* 20211127Smckusick * Pname is name of a simple file or an unchanged directory. 20311127Smckusick */ 20411744Smckusick (void) (*todo)(pname, ino, LEAF); 20511127Smckusick return; 20611127Smckusick } 20711127Smckusick /* 20811127Smckusick * Pname is a dumped directory name. 20911127Smckusick */ 21011744Smckusick if ((*todo)(pname, ino, NODE) == FAIL) 21111744Smckusick return; 21211127Smckusick /* 21311127Smckusick * begin search through the directory 21411127Smckusick * skipping over "." and ".." 21511127Smckusick */ 21611992Smckusick (void) strncpy(locname, pname, MAXPATHLEN); 21711992Smckusick (void) strncat(locname, "/", MAXPATHLEN); 21811127Smckusick namelen = strlen(locname); 21912556Smckusick rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 22012556Smckusick dp = rst_readdir(dirp); /* "." */ 22127263Smckusick if (dp != NULL && strcmp(dp->d_name, ".") == 0) 22212556Smckusick dp = rst_readdir(dirp); /* ".." */ 22327263Smckusick else 22427263Smckusick fprintf(stderr, "Warning: `.' missing from directory %s\n", 22527263Smckusick pname); 22627263Smckusick if (dp != NULL && strcmp(dp->d_name, "..") == 0) 22712556Smckusick dp = rst_readdir(dirp); /* first real entry */ 22827263Smckusick else 22927263Smckusick fprintf(stderr, "Warning: `..' missing from directory %s\n", 23027263Smckusick pname); 23140064Smckusick bpt = rst_telldir(dirp); 23211127Smckusick /* 23312453Smckusick * a zero inode signals end of directory 23411127Smckusick */ 23512453Smckusick while (dp != NULL && dp->d_ino != 0) { 23611127Smckusick locname[namelen] = '\0'; 23711644Smckusick if (namelen + dp->d_namlen >= MAXPATHLEN) { 23811127Smckusick fprintf(stderr, "%s%s: name exceeds %d char\n", 23911644Smckusick locname, dp->d_name, MAXPATHLEN); 24011127Smckusick } else { 24111992Smckusick (void) strncat(locname, dp->d_name, (int)dp->d_namlen); 24211127Smckusick treescan(locname, dp->d_ino, todo); 24312556Smckusick rst_seekdir(dirp, bpt, itp->t_seekpt); 24411127Smckusick } 24512556Smckusick dp = rst_readdir(dirp); 24640064Smckusick bpt = rst_telldir(dirp); 24711127Smckusick } 24811127Smckusick if (dp == NULL) 24911127Smckusick fprintf(stderr, "corrupted directory: %s.\n", locname); 25011127Smckusick } 25111127Smckusick 25211127Smckusick /* 25356434Smckusick * Lookup a pathname which is always assumed to start from the ROOTINO. 25411127Smckusick */ 25556946Smckusick struct direct * 25656434Smckusick pathsearch(pathname) 25757896Sbostic const char *pathname; 25811127Smckusick { 25911127Smckusick ino_t ino; 26056946Smckusick struct direct *dp; 26157896Sbostic char *path, *name, buffer[MAXPATHLEN]; 26211127Smckusick 26356434Smckusick strcpy(buffer, pathname); 26457896Sbostic path = buffer; 26511127Smckusick ino = ROOTINO; 26657896Sbostic while (*path == '/') 26757896Sbostic path++; 26857930Sbostic dp = NULL; 26957896Sbostic while ((name = strsep(&path, "/")) != NULL && *name != NULL) { 27057930Sbostic if ((dp = searchdir(ino, name)) == NULL) 27156946Smckusick return (NULL); 27256946Smckusick ino = dp->d_ino; 27356946Smckusick } 27456946Smckusick return (dp); 27511127Smckusick } 27611127Smckusick 27711127Smckusick /* 27856434Smckusick * Lookup the requested name in directory inum. 27956434Smckusick * Return its inode number if found, zero if it does not exist. 28011127Smckusick */ 28156946Smckusick static struct direct * 28256434Smckusick searchdir(inum, name) 28311127Smckusick ino_t inum; 28456434Smckusick char *name; 28511127Smckusick { 28611127Smckusick register struct direct *dp; 28711127Smckusick register struct inotab *itp; 28811127Smckusick int len; 28911127Smckusick 29011127Smckusick itp = inotablookup(inum); 29111127Smckusick if (itp == NULL) 29257930Sbostic return (NULL); 29312556Smckusick rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 29456434Smckusick len = strlen(name); 29511127Smckusick do { 29612556Smckusick dp = rst_readdir(dirp); 29712453Smckusick if (dp == NULL || dp->d_ino == 0) 29856946Smckusick return (NULL); 29956434Smckusick } while (dp->d_namlen != len || strncmp(dp->d_name, name, len) != 0); 30056946Smckusick return (dp); 30111127Smckusick } 30211127Smckusick 30311127Smckusick /* 30411127Smckusick * Put the directory entries in the directory file 30511127Smckusick */ 30656567Sbostic static void 30711127Smckusick putdir(buf, size) 30811127Smckusick char *buf; 30956567Sbostic long size; 31011127Smckusick { 31111127Smckusick struct direct cvtbuf; 31211127Smckusick register struct odirect *odp; 31311127Smckusick struct odirect *eodp; 31411127Smckusick register struct direct *dp; 31511127Smckusick long loc, i; 31611127Smckusick 31711127Smckusick if (cvtflag) { 31811127Smckusick eodp = (struct odirect *)&buf[size]; 31911127Smckusick for (odp = (struct odirect *)buf; odp < eodp; odp++) 32011127Smckusick if (odp->d_ino != 0) { 32111127Smckusick dcvt(odp, &cvtbuf); 32211127Smckusick putent(&cvtbuf); 32311127Smckusick } 32411127Smckusick } else { 32511127Smckusick for (loc = 0; loc < size; ) { 32611127Smckusick dp = (struct direct *)(buf + loc); 327*67439Smckusick if (Bcvt) 328*67439Smckusick swabst((u_char *)"ls", (u_char *) dp); 329*67439Smckusick if (oldinofmt && dp->d_ino != 0) { 330*67439Smckusick # if BYTE_ORDER == BIG_ENDIAN 331*67439Smckusick if (Bcvt) 332*67439Smckusick dp->d_namlen = dp->d_type; 333*67439Smckusick # else 334*67439Smckusick if (!Bcvt) 335*67439Smckusick dp->d_namlen = dp->d_type; 336*67439Smckusick # endif 337*67439Smckusick dp->d_type = DT_UNKNOWN; 33826941Ssklower } 33911127Smckusick i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1)); 34046564Smckusick if ((dp->d_reclen & 0x3) != 0 || 34146564Smckusick dp->d_reclen > i || 34254582Smckusick dp->d_reclen < DIRSIZ(0, dp) || 34350662Smckusick dp->d_namlen > NAME_MAX) { 34450662Smckusick vprintf(stdout, "Mangled directory: "); 34550662Smckusick if ((dp->d_reclen & 0x3) != 0) 34650662Smckusick vprintf(stdout, 34750662Smckusick "reclen not multiple of 4 "); 34854582Smckusick if (dp->d_reclen < DIRSIZ(0, dp)) 34950662Smckusick vprintf(stdout, 35050662Smckusick "reclen less than DIRSIZ (%d < %d) ", 35154582Smckusick dp->d_reclen, DIRSIZ(0, dp)); 35250662Smckusick if (dp->d_namlen > NAME_MAX) 35350662Smckusick vprintf(stdout, 35450662Smckusick "reclen name too big (%d > %d) ", 35550662Smckusick dp->d_namlen, NAME_MAX); 35650662Smckusick vprintf(stdout, "\n"); 35711127Smckusick loc += i; 35811127Smckusick continue; 35911127Smckusick } 36011127Smckusick loc += dp->d_reclen; 36111127Smckusick if (dp->d_ino != 0) { 36211127Smckusick putent(dp); 36311127Smckusick } 36411127Smckusick } 36511127Smckusick } 36611127Smckusick } 36711127Smckusick 36811127Smckusick /* 36911127Smckusick * These variables are "local" to the following two functions. 37011127Smckusick */ 37111127Smckusick char dirbuf[DIRBLKSIZ]; 37211127Smckusick long dirloc = 0; 37311127Smckusick long prev = 0; 37411127Smckusick 37511127Smckusick /* 37611127Smckusick * add a new directory entry to a file. 37711127Smckusick */ 37856567Sbostic static void 37911127Smckusick putent(dp) 38011127Smckusick struct direct *dp; 38111127Smckusick { 38254582Smckusick dp->d_reclen = DIRSIZ(0, dp); 38311127Smckusick if (dirloc + dp->d_reclen > DIRBLKSIZ) { 38411127Smckusick ((struct direct *)(dirbuf + prev))->d_reclen = 38511127Smckusick DIRBLKSIZ - prev; 38611732Smckusick (void) fwrite(dirbuf, 1, DIRBLKSIZ, df); 38711127Smckusick dirloc = 0; 38811127Smckusick } 38911127Smckusick bcopy((char *)dp, dirbuf + dirloc, (long)dp->d_reclen); 39011127Smckusick prev = dirloc; 39111127Smckusick dirloc += dp->d_reclen; 39211127Smckusick } 39311127Smckusick 39411127Smckusick /* 39511127Smckusick * flush out a directory that is finished. 39611127Smckusick */ 39756567Sbostic static void 39811127Smckusick flushent() 39911127Smckusick { 40011127Smckusick ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev; 40111732Smckusick (void) fwrite(dirbuf, (int)dirloc, 1, df); 40211127Smckusick seekpt = ftell(df); 40311127Smckusick dirloc = 0; 40411127Smckusick } 40511127Smckusick 40656567Sbostic static void 40711127Smckusick dcvt(odp, ndp) 40811127Smckusick register struct odirect *odp; 40911127Smckusick register struct direct *ndp; 41011127Smckusick { 41111127Smckusick 41211127Smckusick bzero((char *)ndp, (long)(sizeof *ndp)); 41311127Smckusick ndp->d_ino = odp->d_ino; 41454582Smckusick ndp->d_type = DT_UNKNOWN; 41511992Smckusick (void) strncpy(ndp->d_name, odp->d_name, ODIRSIZ); 41611127Smckusick ndp->d_namlen = strlen(ndp->d_name); 41754582Smckusick ndp->d_reclen = DIRSIZ(0, ndp); 41811127Smckusick } 41911127Smckusick 42011127Smckusick /* 42111127Smckusick * Seek to an entry in a directory. 42240064Smckusick * Only values returned by rst_telldir should be passed to rst_seekdir. 42311732Smckusick * This routine handles many directories in a single file. 42411732Smckusick * It takes the base of the directory in the file, plus 42511732Smckusick * the desired seek offset into it. 42611127Smckusick */ 42756567Sbostic static void 42812556Smckusick rst_seekdir(dirp, loc, base) 42950657Smckusick register RST_DIR *dirp; 43050662Smckusick long loc, base; 43111127Smckusick { 43211127Smckusick 43340064Smckusick if (loc == rst_telldir(dirp)) 43411127Smckusick return; 43511127Smckusick loc -= base; 43611127Smckusick if (loc < 0) 43712556Smckusick fprintf(stderr, "bad seek pointer to rst_seekdir %d\n", loc); 43856567Sbostic (void) lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), SEEK_SET); 43911127Smckusick dirp->dd_loc = loc & (DIRBLKSIZ - 1); 44011127Smckusick if (dirp->dd_loc != 0) 44111127Smckusick dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ); 44211127Smckusick } 44311127Smckusick 44411127Smckusick /* 44511127Smckusick * get next entry in a directory. 44611127Smckusick */ 44711127Smckusick struct direct * 44812556Smckusick rst_readdir(dirp) 44950657Smckusick register RST_DIR *dirp; 45011127Smckusick { 45111127Smckusick register struct direct *dp; 45211127Smckusick 45311127Smckusick for (;;) { 45411127Smckusick if (dirp->dd_loc == 0) { 45511127Smckusick dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, 45611127Smckusick DIRBLKSIZ); 45712453Smckusick if (dirp->dd_size <= 0) { 45812453Smckusick dprintf(stderr, "error reading directory\n"); 45956567Sbostic return (NULL); 46012453Smckusick } 46111127Smckusick } 46211127Smckusick if (dirp->dd_loc >= dirp->dd_size) { 46311127Smckusick dirp->dd_loc = 0; 46411127Smckusick continue; 46511127Smckusick } 46611127Smckusick dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc); 46711127Smckusick if (dp->d_reclen == 0 || 46812453Smckusick dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) { 46912453Smckusick dprintf(stderr, "corrupted directory: bad reclen %d\n", 47012453Smckusick dp->d_reclen); 47156567Sbostic return (NULL); 47212453Smckusick } 47311127Smckusick dirp->dd_loc += dp->d_reclen; 47412453Smckusick if (dp->d_ino == 0 && strcmp(dp->d_name, "/") != 0) 47512453Smckusick continue; 47612556Smckusick if (dp->d_ino >= maxino) { 47712453Smckusick dprintf(stderr, "corrupted directory: bad inum %d\n", 47812453Smckusick dp->d_ino); 47912453Smckusick continue; 48012453Smckusick } 48111127Smckusick return (dp); 48211127Smckusick } 48311127Smckusick } 48411127Smckusick 48511127Smckusick /* 48617753Smckusick * Simulate the opening of a directory 48717753Smckusick */ 48850657Smckusick RST_DIR * 48917753Smckusick rst_opendir(name) 49057896Sbostic const char *name; 49117753Smckusick { 49217753Smckusick struct inotab *itp; 49356946Smckusick RST_DIR *dirp; 49417753Smckusick ino_t ino; 49517753Smckusick 49617753Smckusick if ((ino = dirlookup(name)) > 0 && 49717753Smckusick (itp = inotablookup(ino)) != NULL) { 49856946Smckusick dirp = opendirfile(dirfile); 49917753Smckusick rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 50017753Smckusick return (dirp); 50117753Smckusick } 50257930Sbostic return (NULL); 50317753Smckusick } 50417753Smckusick 50517753Smckusick /* 50656946Smckusick * In our case, there is nothing to do when closing a directory. 50756946Smckusick */ 50856946Smckusick void 50956946Smckusick rst_closedir(dirp) 51056946Smckusick RST_DIR *dirp; 51156946Smckusick { 51256946Smckusick 51357896Sbostic (void)close(dirp->dd_fd); 51456946Smckusick free(dirp); 51556946Smckusick return; 51656946Smckusick } 51756946Smckusick 51856946Smckusick /* 51940064Smckusick * Simulate finding the current offset in the directory. 52040064Smckusick */ 52156567Sbostic static long 52240064Smckusick rst_telldir(dirp) 52350657Smckusick RST_DIR *dirp; 52440064Smckusick { 52556567Sbostic return ((long)lseek(dirp->dd_fd, 52656567Sbostic (off_t)0, SEEK_CUR) - dirp->dd_size + dirp->dd_loc); 52740064Smckusick } 52840064Smckusick 52940064Smckusick /* 53040064Smckusick * Open a directory file. 53140064Smckusick */ 53256567Sbostic static RST_DIR * 53340064Smckusick opendirfile(name) 53457896Sbostic const char *name; 53540064Smckusick { 53650657Smckusick register RST_DIR *dirp; 53740064Smckusick register int fd; 53840064Smckusick 53956567Sbostic if ((fd = open(name, O_RDONLY)) == -1) 54056567Sbostic return (NULL); 54156567Sbostic if ((dirp = malloc(sizeof(RST_DIR))) == NULL) { 54256567Sbostic (void)close(fd); 54356567Sbostic return (NULL); 54440064Smckusick } 54540064Smckusick dirp->dd_fd = fd; 54640064Smckusick dirp->dd_loc = 0; 54756567Sbostic return (dirp); 54840064Smckusick } 54940064Smckusick 55040064Smckusick /* 55111127Smckusick * Set the mode, owner, and times for all new or changed directories 55211127Smckusick */ 55356567Sbostic void 55455880Smckusick setdirmodes(flags) 55555880Smckusick int flags; 55611127Smckusick { 55711127Smckusick FILE *mf; 55811127Smckusick struct modeinfo node; 55911127Smckusick struct entry *ep; 56011127Smckusick char *cp; 56111127Smckusick 56211127Smckusick vprintf(stdout, "Set directory mode, owner, and times.\n"); 56337952Sbostic (void) sprintf(modefile, "%s/rstmode%d", _PATH_TMP, dumpdate); 56411127Smckusick mf = fopen(modefile, "r"); 56511127Smckusick if (mf == NULL) { 56656567Sbostic fprintf(stderr, "fopen: %s\n", strerror(errno)); 56715779Smckusick fprintf(stderr, "cannot open mode file %s\n", modefile); 56815779Smckusick fprintf(stderr, "directory mode, owner, and times not set\n"); 56915779Smckusick return; 57011127Smckusick } 57111127Smckusick clearerr(mf); 57211309Smckusick for (;;) { 57311732Smckusick (void) fread((char *)&node, 1, sizeof(struct modeinfo), mf); 57411309Smckusick if (feof(mf)) 57511309Smckusick break; 57611127Smckusick ep = lookupino(node.ino); 57714453Smckusick if (command == 'i' || command == 'x') { 57856567Sbostic if (ep == NULL) 57911309Smckusick continue; 58055880Smckusick if ((flags & FORCE) == 0 && ep->e_flags & EXISTED) { 58118008Smckusick ep->e_flags &= ~NEW; 58218008Smckusick continue; 58318008Smckusick } 58414453Smckusick if (node.ino == ROOTINO && 58514453Smckusick reply("set owner/mode for '.'") == FAIL) 58614453Smckusick continue; 58714453Smckusick } 58856567Sbostic if (ep == NULL) { 58911127Smckusick panic("cannot find directory inode %d\n", node.ino); 59042862Smckusick } else { 59142862Smckusick cp = myname(ep); 59242862Smckusick (void) chown(cp, node.uid, node.gid); 59342862Smckusick (void) chmod(cp, node.mode); 59442862Smckusick utimes(cp, node.timep); 59542862Smckusick ep->e_flags &= ~NEW; 59642862Smckusick } 59711127Smckusick } 59811127Smckusick if (ferror(mf)) 59911127Smckusick panic("error setting directory modes\n"); 60011732Smckusick (void) fclose(mf); 60111127Smckusick } 60211127Smckusick 60311127Smckusick /* 60411127Smckusick * Generate a literal copy of a directory. 60511127Smckusick */ 60656567Sbostic int 60711127Smckusick genliteraldir(name, ino) 60811127Smckusick char *name; 60911127Smckusick ino_t ino; 61011127Smckusick { 61111127Smckusick register struct inotab *itp; 61211127Smckusick int ofile, dp, i, size; 61311127Smckusick char buf[BUFSIZ]; 61411127Smckusick 61511127Smckusick itp = inotablookup(ino); 61611127Smckusick if (itp == NULL) 61711322Smckusick panic("Cannot find directory inode %d named %s\n", ino, name); 61812893Ssam if ((ofile = creat(name, 0666)) < 0) { 61912556Smckusick fprintf(stderr, "%s: ", name); 62012556Smckusick (void) fflush(stderr); 62156567Sbostic fprintf(stderr, "cannot create file: %s\n", strerror(errno)); 62211127Smckusick return (FAIL); 62311127Smckusick } 62412556Smckusick rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 62511127Smckusick dp = dup(dirp->dd_fd); 62611127Smckusick for (i = itp->t_size; i > 0; i -= BUFSIZ) { 62711127Smckusick size = i < BUFSIZ ? i : BUFSIZ; 62811127Smckusick if (read(dp, buf, (int) size) == -1) { 62911127Smckusick fprintf(stderr, 63011127Smckusick "write error extracting inode %d, name %s\n", 63111127Smckusick curfile.ino, curfile.name); 63256567Sbostic fprintf(stderr, "read: %s\n", strerror(errno)); 63311127Smckusick done(1); 63411127Smckusick } 63534268Smckusick if (!Nflag && write(ofile, buf, (int) size) == -1) { 63611127Smckusick fprintf(stderr, 63711127Smckusick "write error extracting inode %d, name %s\n", 63811127Smckusick curfile.ino, curfile.name); 63956567Sbostic fprintf(stderr, "write: %s\n", strerror(errno)); 64011127Smckusick done(1); 64111127Smckusick } 64211127Smckusick } 64311732Smckusick (void) close(dp); 64411732Smckusick (void) close(ofile); 64511127Smckusick return (GOOD); 64611127Smckusick } 64711127Smckusick 64811127Smckusick /* 64911992Smckusick * Determine the type of an inode 65011992Smckusick */ 65156567Sbostic int 65211992Smckusick inodetype(ino) 65311992Smckusick ino_t ino; 65411992Smckusick { 65511992Smckusick struct inotab *itp; 65611992Smckusick 65711992Smckusick itp = inotablookup(ino); 65811992Smckusick if (itp == NULL) 65911992Smckusick return (LEAF); 66011992Smckusick return (NODE); 66111992Smckusick } 66211992Smckusick 66311992Smckusick /* 66411127Smckusick * Allocate and initialize a directory inode entry. 66511127Smckusick * If requested, save its pertinent mode, owner, and time info. 66611127Smckusick */ 66756567Sbostic static struct inotab * 66811127Smckusick allocinotab(ino, dip, seekpt) 66911127Smckusick ino_t ino; 67011127Smckusick struct dinode *dip; 67150662Smckusick long seekpt; 67211127Smckusick { 67311127Smckusick register struct inotab *itp; 67411127Smckusick struct modeinfo node; 67511127Smckusick 67656567Sbostic itp = calloc(1, sizeof(struct inotab)); 67756567Sbostic if (itp == NULL) 67813859Smckusick panic("no memory directory table\n"); 67911127Smckusick itp->t_next = inotab[INOHASH(ino)]; 68011127Smckusick inotab[INOHASH(ino)] = itp; 68111127Smckusick itp->t_ino = ino; 68211127Smckusick itp->t_seekpt = seekpt; 68311127Smckusick if (mf == NULL) 68457930Sbostic return (itp); 68511127Smckusick node.ino = ino; 68654156Smckusick node.timep[0].tv_sec = dip->di_atime.ts_sec; 68754156Smckusick node.timep[0].tv_usec = dip->di_atime.ts_nsec / 1000; 68854156Smckusick node.timep[1].tv_sec = dip->di_mtime.ts_sec; 68954156Smckusick node.timep[1].tv_usec = dip->di_mtime.ts_nsec / 1000; 69011127Smckusick node.mode = dip->di_mode; 69111127Smckusick node.uid = dip->di_uid; 69211127Smckusick node.gid = dip->di_gid; 69311732Smckusick (void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf); 69457930Sbostic return (itp); 69511127Smckusick } 69611127Smckusick 69711127Smckusick /* 69811127Smckusick * Look up an inode in the table of directories 69911127Smckusick */ 70056567Sbostic static struct inotab * 70111127Smckusick inotablookup(ino) 70211127Smckusick ino_t ino; 70311127Smckusick { 70411127Smckusick register struct inotab *itp; 70511127Smckusick 70611127Smckusick for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next) 70711127Smckusick if (itp->t_ino == ino) 70857930Sbostic return (itp); 70956567Sbostic return (NULL); 71011127Smckusick } 71111127Smckusick 71211127Smckusick /* 71311127Smckusick * Clean up and exit 71411127Smckusick */ 71557930Sbostic __dead void 71611127Smckusick done(exitcode) 71711127Smckusick int exitcode; 71811127Smckusick { 71911127Smckusick 72011127Smckusick closemt(); 72111992Smckusick if (modefile[0] != '#') 72211992Smckusick (void) unlink(modefile); 72311992Smckusick if (dirfile[0] != '#') 72411992Smckusick (void) unlink(dirfile); 72511127Smckusick exit(exitcode); 72611127Smckusick } 727