dirs.c revision 8871
1187706Sgonzo/* 2187706Sgonzo * Copyright (c) 1983, 1993 3187706Sgonzo * The Regents of the University of California. All rights reserved. 4187706Sgonzo * (c) UNIX System Laboratories, Inc. 5187706Sgonzo * All or some portions of this file are derived from material licensed 6187706Sgonzo * to the University of California by American Telephone and Telegraph 7187706Sgonzo * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8187706Sgonzo * the permission of UNIX System Laboratories, Inc. 9187706Sgonzo * 10187706Sgonzo * Redistribution and use in source and binary forms, with or without 11187706Sgonzo * modification, are permitted provided that the following conditions 12187706Sgonzo * are met: 13187706Sgonzo * 1. Redistributions of source code must retain the above copyright 14187706Sgonzo * notice, this list of conditions and the following disclaimer. 15187706Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 16187706Sgonzo * notice, this list of conditions and the following disclaimer in the 17187706Sgonzo * documentation and/or other materials provided with the distribution. 18187706Sgonzo * 3. All advertising materials mentioning features or use of this software 19187706Sgonzo * must display the following acknowledgement: 20187706Sgonzo * This product includes software developed by the University of 21187706Sgonzo * California, Berkeley and its contributors. 22187706Sgonzo * 4. Neither the name of the University nor the names of its contributors 23187706Sgonzo * may be used to endorse or promote products derived from this software 24187706Sgonzo * without specific prior written permission. 25187706Sgonzo * 26187706Sgonzo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27187706Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28187706Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29187706Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30187706Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31187706Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32187706Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33187706Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34187706Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35187706Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36187706Sgonzo * SUCH DAMAGE. 37187706Sgonzo */ 38187706Sgonzo 39187706Sgonzo#ifndef lint 40187706Sgonzostatic char sccsid[] = "@(#)dirs.c 8.2 (Berkeley) 1/21/94"; 41187706Sgonzo#endif /* not lint */ 42187706Sgonzo 43187706Sgonzo#include <sys/param.h> 44187706Sgonzo#include <sys/file.h> 45187706Sgonzo#include <sys/stat.h> 46187706Sgonzo#include <sys/time.h> 47210900Sgonzo 48187706Sgonzo#include <ufs/ffs/fs.h> 49187706Sgonzo#include <ufs/ufs/dinode.h> 50187706Sgonzo#include <ufs/ufs/dir.h> 51187706Sgonzo#include <protocols/dumprestore.h> 52187706Sgonzo 53187706Sgonzo#include <errno.h> 54187706Sgonzo#include <stdio.h> 55187706Sgonzo#include <stdlib.h> 56192161Sgonzo#include <string.h> 57192161Sgonzo#include <unistd.h> 58187706Sgonzo 59211478Sadrian#include <machine/endian.h> 60211478Sadrian 61187706Sgonzo#include "pathnames.h" 62187706Sgonzo#include "restore.h" 63187706Sgonzo#include "extern.h" 64187706Sgonzo 65187706Sgonzo/* 66187706Sgonzo * Symbol table of directories read from tape. 67187706Sgonzo */ 68187706Sgonzo#define HASHSIZE 1000 69187706Sgonzo#define INOHASH(val) (val % HASHSIZE) 70187706Sgonzostruct inotab { 71187706Sgonzo struct inotab *t_next; 72187706Sgonzo ino_t t_ino; 73187706Sgonzo long t_seekpt; 74187706Sgonzo long t_size; 75191872Sgonzo}; 76210900Sgonzostatic struct inotab *inotab[HASHSIZE]; 77187706Sgonzo 78187706Sgonzo/* 79187706Sgonzo * Information retained about directories. 80187706Sgonzo */ 81191872Sgonzostruct modeinfo { 82191872Sgonzo ino_t ino; 83191872Sgonzo struct timeval timep[2]; 84191872Sgonzo short mode; 85191872Sgonzo short uid; 86191872Sgonzo short gid; 87192822Sgonzo}; 88192822Sgonzo 89191872Sgonzo/* 90191872Sgonzo * Definitions for library routines operating on directories. 91192822Sgonzo */ 92191872Sgonzo#undef DIRBLKSIZ 93191872Sgonzo#define DIRBLKSIZ 1024 94194273Sgonzostruct rstdirdesc { 95194273Sgonzo int dd_fd; 96191872Sgonzo long dd_loc; 97191872Sgonzo long dd_size; 98191872Sgonzo char dd_buf[DIRBLKSIZ]; 99192822Sgonzo}; 100192822Sgonzo 101191872Sgonzo/* 102191872Sgonzo * Global variables for this file. 103192822Sgonzo */ 104191872Sgonzostatic long seekpt; 105191872Sgonzostatic FILE *df, *mf; 106191872Sgonzostatic RST_DIR *dirp; 107194273Sgonzostatic char dirfile[32] = "#"; /* No file */ 108194273Sgonzostatic char modefile[32] = "#"; /* No file */ 109191872Sgonzostatic char dot[2] = "."; /* So it can be modified */ 110191872Sgonzo 111187706Sgonzo/* 112187706Sgonzo * Format of old style directories. 113187706Sgonzo */ 114187706Sgonzo#define ODIRSIZ 14 115187706Sgonzostruct odirect { 116187706Sgonzo u_short d_ino; 117187706Sgonzo char d_name[ODIRSIZ]; 118187706Sgonzo}; 119187706Sgonzo 120187706Sgonzostatic struct inotab *allocinotab __P((ino_t, struct dinode *, long)); 121187706Sgonzostatic void dcvt __P((struct odirect *, struct direct *)); 122187706Sgonzostatic void flushent __P((void)); 123187706Sgonzostatic struct inotab *inotablookup __P((ino_t)); 124187706Sgonzostatic RST_DIR *opendirfile __P((const char *)); 125187706Sgonzostatic void putdir __P((char *, long)); 126187706Sgonzostatic void putent __P((struct direct *)); 127187706Sgonzostatic void rst_seekdir __P((RST_DIR *, long, long)); 128187706Sgonzostatic long rst_telldir __P((RST_DIR *)); 129187706Sgonzostatic struct direct *searchdir __P((ino_t, char *)); 130187706Sgonzo 131187706Sgonzo/* 132187706Sgonzo * Extract directory contents, building up a directory structure 133187706Sgonzo * on disk for extraction by name. 134187706Sgonzo * If genmode is requested, save mode, owner, and times for all 135187706Sgonzo * directories on the tape. 136187706Sgonzo */ 137187706Sgonzovoid 138187706Sgonzoextractdirs(genmode) 139187706Sgonzo int genmode; 140187706Sgonzo{ 141187706Sgonzo register int i; 142187706Sgonzo register struct dinode *ip; 143187706Sgonzo struct inotab *itp; 144187706Sgonzo struct direct nulldir; 145187706Sgonzo 146187706Sgonzo vprintf(stdout, "Extract directories from tape\n"); 147187706Sgonzo (void) sprintf(dirfile, "%s/rstdir%d", _PATH_TMP, dumpdate); 148187706Sgonzo df = fopen(dirfile, "w"); 149187706Sgonzo if (df == NULL) { 150187706Sgonzo fprintf(stderr, 151187706Sgonzo "restore: %s - cannot create directory temporary\n", 152187706Sgonzo dirfile); 153187706Sgonzo fprintf(stderr, "fopen: %s\n", strerror(errno)); 154187706Sgonzo done(1); 155187706Sgonzo } 156187706Sgonzo if (genmode != 0) { 157187706Sgonzo (void) sprintf(modefile, "%s/rstmode%d", _PATH_TMP, dumpdate); 158187706Sgonzo mf = fopen(modefile, "w"); 159187706Sgonzo if (mf == NULL) { 160187706Sgonzo fprintf(stderr, 161187706Sgonzo "restore: %s - cannot create modefile \n", 162187706Sgonzo modefile); 163187706Sgonzo fprintf(stderr, "fopen: %s\n", strerror(errno)); 164187706Sgonzo done(1); 165187706Sgonzo } 166187706Sgonzo } 167187706Sgonzo nulldir.d_ino = 0; 168187706Sgonzo nulldir.d_type = DT_DIR; 169187706Sgonzo nulldir.d_namlen = 1; 170187706Sgonzo (void) strcpy(nulldir.d_name, "/"); 171187706Sgonzo nulldir.d_reclen = DIRSIZ(0, &nulldir); 172187706Sgonzo for (;;) { 173187706Sgonzo curfile.name = "<directory file - name unknown>"; 174187706Sgonzo curfile.action = USING; 175187706Sgonzo ip = curfile.dip; 176187706Sgonzo if (ip == NULL || (ip->di_mode & IFMT) != IFDIR) { 177187706Sgonzo (void) fclose(df); 178187706Sgonzo dirp = opendirfile(dirfile); 179187706Sgonzo if (dirp == NULL) 180187706Sgonzo fprintf(stderr, "opendirfile: %s\n", 181187706Sgonzo strerror(errno)); 182187706Sgonzo if (mf != NULL) 183187706Sgonzo (void) fclose(mf); 184187706Sgonzo i = dirlookup(dot); 185187706Sgonzo if (i == 0) 186187706Sgonzo panic("Root directory is not on tape\n"); 187187706Sgonzo return; 188187706Sgonzo } 189187706Sgonzo itp = allocinotab(curfile.ino, ip, seekpt); 190187706Sgonzo getfile(putdir, xtrnull); 191187706Sgonzo putent(&nulldir); 192194059Sgonzo flushent(); 193194059Sgonzo itp->t_size = seekpt - itp->t_seekpt; 194187706Sgonzo } 195187706Sgonzo} 196187706Sgonzo 197187706Sgonzo/* 198187706Sgonzo * skip over all the directories on the tape 199187706Sgonzo */ 200187706Sgonzovoid 201187706Sgonzoskipdirs() 202187706Sgonzo{ 203187706Sgonzo 204187706Sgonzo while ((curfile.dip->di_mode & IFMT) == IFDIR) { 205187706Sgonzo skipfile(); 206187706Sgonzo } 207187706Sgonzo} 208187706Sgonzo 209187706Sgonzo/* 210187706Sgonzo * Recursively find names and inumbers of all files in subtree 211187706Sgonzo * pname and pass them off to be processed. 212187706Sgonzo */ 213187706Sgonzovoid 214187706Sgonzotreescan(pname, ino, todo) 215187706Sgonzo char *pname; 216187706Sgonzo ino_t ino; 217187706Sgonzo long (*todo) __P((char *, ino_t, int)); 218187706Sgonzo{ 219187706Sgonzo register struct inotab *itp; 220187706Sgonzo register struct direct *dp; 221187706Sgonzo int namelen; 222187706Sgonzo long bpt; 223187706Sgonzo char locname[MAXPATHLEN + 1]; 224187706Sgonzo 225187706Sgonzo itp = inotablookup(ino); 226187706Sgonzo if (itp == NULL) { 227187706Sgonzo /* 228187706Sgonzo * Pname is name of a simple file or an unchanged directory. 229194059Sgonzo */ 230194059Sgonzo (void) (*todo)(pname, ino, LEAF); 231187706Sgonzo return; 232187706Sgonzo } 233187706Sgonzo /* 234187706Sgonzo * Pname is a dumped directory name. 235187706Sgonzo */ 236187706Sgonzo if ((*todo)(pname, ino, NODE) == FAIL) 237187706Sgonzo return; 238187706Sgonzo /* 239187706Sgonzo * begin search through the directory 240187706Sgonzo * skipping over "." and ".." 241187706Sgonzo */ 242187706Sgonzo (void) strncpy(locname, pname, MAXPATHLEN); 243187706Sgonzo (void) strncat(locname, "/", MAXPATHLEN); 244187706Sgonzo namelen = strlen(locname); 245187706Sgonzo rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 246187706Sgonzo dp = rst_readdir(dirp); /* "." */ 247187706Sgonzo if (dp != NULL && strcmp(dp->d_name, ".") == 0) 248187706Sgonzo dp = rst_readdir(dirp); /* ".." */ 249187706Sgonzo else 250187706Sgonzo fprintf(stderr, "Warning: `.' missing from directory %s\n", 251187706Sgonzo pname); 252187706Sgonzo if (dp != NULL && strcmp(dp->d_name, "..") == 0) 253187706Sgonzo dp = rst_readdir(dirp); /* first real entry */ 254187706Sgonzo else 255187706Sgonzo fprintf(stderr, "Warning: `..' missing from directory %s\n", 256187706Sgonzo pname); 257187706Sgonzo bpt = rst_telldir(dirp); 258187706Sgonzo /* 259187706Sgonzo * a zero inode signals end of directory 260187706Sgonzo */ 261187706Sgonzo while (dp != NULL && dp->d_ino != 0) { 262187706Sgonzo locname[namelen] = '\0'; 263187706Sgonzo if (namelen + dp->d_namlen >= MAXPATHLEN) { 264187706Sgonzo fprintf(stderr, "%s%s: name exceeds %d char\n", 265187706Sgonzo locname, dp->d_name, MAXPATHLEN); 266187706Sgonzo } else { 267187706Sgonzo (void) strncat(locname, dp->d_name, (int)dp->d_namlen); 268187706Sgonzo treescan(locname, dp->d_ino, todo); 269187706Sgonzo rst_seekdir(dirp, bpt, itp->t_seekpt); 270187706Sgonzo } 271187706Sgonzo dp = rst_readdir(dirp); 272187706Sgonzo bpt = rst_telldir(dirp); 273187706Sgonzo } 274187706Sgonzo if (dp == NULL) 275187706Sgonzo fprintf(stderr, "corrupted directory: %s.\n", locname); 276187706Sgonzo} 277187706Sgonzo 278187706Sgonzo/* 279187706Sgonzo * Lookup a pathname which is always assumed to start from the ROOTINO. 280187706Sgonzo */ 281187706Sgonzostruct direct * 282187706Sgonzopathsearch(pathname) 283187706Sgonzo const char *pathname; 284187706Sgonzo{ 285187706Sgonzo ino_t ino; 286187706Sgonzo struct direct *dp; 287187706Sgonzo char *path, *name, buffer[MAXPATHLEN]; 288187706Sgonzo 289187706Sgonzo strcpy(buffer, pathname); 290187706Sgonzo path = buffer; 291187706Sgonzo ino = ROOTINO; 292191872Sgonzo while (*path == '/') 293187706Sgonzo path++; 294187706Sgonzo dp = NULL; 295187706Sgonzo while ((name = strsep(&path, "/")) != NULL && *name != NULL) { 296187706Sgonzo if ((dp = searchdir(ino, name)) == NULL) 297187706Sgonzo return (NULL); 298187706Sgonzo ino = dp->d_ino; 299211478Sadrian } 300203132Sgonzo return (dp); 301187706Sgonzo} 302211478Sadrian 303203132Sgonzo/* 304187706Sgonzo * Lookup the requested name in directory inum. 305187706Sgonzo * Return its inode number if found, zero if it does not exist. 306187706Sgonzo */ 307187706Sgonzostatic struct direct * 308187706Sgonzosearchdir(inum, name) 309187706Sgonzo ino_t inum; 310187706Sgonzo char *name; 311187706Sgonzo{ 312187706Sgonzo register struct direct *dp; 313187706Sgonzo register struct inotab *itp; 314203132Sgonzo int len; 315187706Sgonzo 316187706Sgonzo itp = inotablookup(inum); 317187706Sgonzo if (itp == NULL) 318187706Sgonzo return (NULL); 319187706Sgonzo rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 320187706Sgonzo len = strlen(name); 321187706Sgonzo do { 322187706Sgonzo dp = rst_readdir(dirp); 323187706Sgonzo if (dp == NULL || dp->d_ino == 0) 324187706Sgonzo return (NULL); 325187706Sgonzo } while (dp->d_namlen != len || strncmp(dp->d_name, name, len) != 0); 326187706Sgonzo return (dp); 327187706Sgonzo} 328187706Sgonzo 329187706Sgonzo/* 330187706Sgonzo * Put the directory entries in the directory file 331187706Sgonzo */ 332187706Sgonzostatic void 333187706Sgonzoputdir(buf, size) 334187706Sgonzo char *buf; 335187706Sgonzo long size; 336187706Sgonzo{ 337187706Sgonzo struct direct cvtbuf; 338187706Sgonzo register struct odirect *odp; 339187706Sgonzo struct odirect *eodp; 340187706Sgonzo register struct direct *dp; 341187706Sgonzo long loc, i; 342187706Sgonzo 343187706Sgonzo if (cvtflag) { 344187706Sgonzo eodp = (struct odirect *)&buf[size]; 345187706Sgonzo for (odp = (struct odirect *)buf; odp < eodp; odp++) 346187706Sgonzo if (odp->d_ino != 0) { 347187706Sgonzo dcvt(odp, &cvtbuf); 348187706Sgonzo putent(&cvtbuf); 349187706Sgonzo } 350187706Sgonzo } else { 351187706Sgonzo for (loc = 0; loc < size; ) { 352187706Sgonzo dp = (struct direct *)(buf + loc); 353187706Sgonzo if (Bcvt) 354187706Sgonzo swabst((u_char *)"ls", (u_char *) dp); 355187706Sgonzo if (oldinofmt && dp->d_ino != 0) { 356187706Sgonzo#if BYTE_ORDER == BIG_ENDIAN 357187706Sgonzo if (Bcvt) 358187706Sgonzo#else 359187706Sgonzo if (!Bcvt) 360187706Sgonzo#endif 361187706Sgonzo dp->d_namlen = dp->d_type; 362187706Sgonzo dp->d_type = DT_UNKNOWN; 363187706Sgonzo } 364187706Sgonzo i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1)); 365192161Sgonzo if ((dp->d_reclen & 0x3) != 0 || 366187706Sgonzo dp->d_reclen > i || 367187706Sgonzo dp->d_reclen < DIRSIZ(0, dp) || 368187706Sgonzo dp->d_namlen > NAME_MAX) { 369187706Sgonzo vprintf(stdout, "Mangled directory: "); 370187706Sgonzo if ((dp->d_reclen & 0x3) != 0) 371187706Sgonzo vprintf(stdout, 372187706Sgonzo "reclen not multiple of 4 "); 373187706Sgonzo if (dp->d_reclen < DIRSIZ(0, dp)) 374187706Sgonzo vprintf(stdout, 375187706Sgonzo "reclen less than DIRSIZ (%d < %d) ", 376187706Sgonzo dp->d_reclen, DIRSIZ(0, dp)); 377187706Sgonzo if (dp->d_namlen > NAME_MAX) 378187706Sgonzo vprintf(stdout, 379187706Sgonzo "reclen name too big (%d > %d) ", 380187706Sgonzo dp->d_namlen, NAME_MAX); 381187706Sgonzo vprintf(stdout, "\n"); 382187706Sgonzo loc += i; 383187706Sgonzo continue; 384187706Sgonzo } 385187706Sgonzo loc += dp->d_reclen; 386187706Sgonzo if (dp->d_ino != 0) { 387187706Sgonzo putent(dp); 388187706Sgonzo } 389187706Sgonzo } 390187706Sgonzo } 391187706Sgonzo} 392187706Sgonzo 393192161Sgonzo/* 394187706Sgonzo * These variables are "local" to the following two functions. 395187706Sgonzo */ 396187706Sgonzochar dirbuf[DIRBLKSIZ]; 397192161Sgonzolong dirloc = 0; 398187706Sgonzolong prev = 0; 399192161Sgonzo 400192161Sgonzo/* 401192161Sgonzo * add a new directory entry to a file. 402192161Sgonzo */ 403192161Sgonzostatic void 404192161Sgonzoputent(dp) 405192161Sgonzo struct direct *dp; 406192161Sgonzo{ 407192161Sgonzo dp->d_reclen = DIRSIZ(0, dp); 408192161Sgonzo if (dirloc + dp->d_reclen > DIRBLKSIZ) { 409192161Sgonzo ((struct direct *)(dirbuf + prev))->d_reclen = 410192161Sgonzo DIRBLKSIZ - prev; 411192161Sgonzo (void) fwrite(dirbuf, 1, DIRBLKSIZ, df); 412192161Sgonzo dirloc = 0; 413192161Sgonzo } 414192161Sgonzo bcopy((char *)dp, dirbuf + dirloc, (long)dp->d_reclen); 415192161Sgonzo prev = dirloc; 416192161Sgonzo dirloc += dp->d_reclen; 417192161Sgonzo} 418192161Sgonzo 419192161Sgonzo/* 420191872Sgonzo * flush out a directory that is finished. 421191872Sgonzo */ 422191872Sgonzostatic void 423191872Sgonzoflushent() 424191872Sgonzo{ 425191872Sgonzo ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev; 426191872Sgonzo (void) fwrite(dirbuf, (int)dirloc, 1, df); 427191872Sgonzo seekpt = ftell(df); 428191872Sgonzo dirloc = 0; 429191872Sgonzo} 430191872Sgonzo 431191872Sgonzostatic void 432191872Sgonzodcvt(odp, ndp) 433191872Sgonzo register struct odirect *odp; 434191872Sgonzo register struct direct *ndp; 435191872Sgonzo{ 436192822Sgonzo 437210900Sgonzo bzero((char *)ndp, (long)(sizeof *ndp)); 438191872Sgonzo ndp->d_ino = odp->d_ino; 439210900Sgonzo ndp->d_type = DT_UNKNOWN; 440210900Sgonzo (void) strncpy(ndp->d_name, odp->d_name, ODIRSIZ); 441210900Sgonzo ndp->d_namlen = strlen(ndp->d_name); 442210900Sgonzo ndp->d_reclen = DIRSIZ(0, ndp); 443210900Sgonzo} 444210900Sgonzo 445210900Sgonzo/* 446191872Sgonzo * Seek to an entry in a directory. 447191872Sgonzo * Only values returned by rst_telldir should be passed to rst_seekdir. 448191872Sgonzo * This routine handles many directories in a single file. 449191872Sgonzo * It takes the base of the directory in the file, plus 450210900Sgonzo * the desired seek offset into it. 451191872Sgonzo */ 452192822Sgonzostatic void 453191872Sgonzorst_seekdir(dirp, loc, base) 454191872Sgonzo register RST_DIR *dirp; 455191872Sgonzo long loc, base; 456191872Sgonzo{ 457191872Sgonzo 458191872Sgonzo if (loc == rst_telldir(dirp)) 459187706Sgonzo return; 460187706Sgonzo loc -= base; 461191872Sgonzo if (loc < 0) 462191872Sgonzo fprintf(stderr, "bad seek pointer to rst_seekdir %d\n", loc); 463187706Sgonzo (void) lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), SEEK_SET); 464191872Sgonzo dirp->dd_loc = loc & (DIRBLKSIZ - 1); 465191872Sgonzo if (dirp->dd_loc != 0) 466191872Sgonzo dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ); 467191872Sgonzo} 468191872Sgonzo 469191872Sgonzo/* 470191872Sgonzo * get next entry in a directory. 471192822Sgonzo */ 472191872Sgonzostruct direct * 473191872Sgonzorst_readdir(dirp) 474191872Sgonzo register RST_DIR *dirp; 475191872Sgonzo{ 476191872Sgonzo register struct direct *dp; 477191872Sgonzo 478187706Sgonzo for (;;) { 479187706Sgonzo if (dirp->dd_loc == 0) { 480187706Sgonzo dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, 481191872Sgonzo DIRBLKSIZ); 482191872Sgonzo if (dirp->dd_size <= 0) { 483191872Sgonzo dprintf(stderr, "error reading directory\n"); 484191872Sgonzo return (NULL); 485194273Sgonzo } 486191872Sgonzo } 487191872Sgonzo if (dirp->dd_loc >= dirp->dd_size) { 488194273Sgonzo dirp->dd_loc = 0; 489194273Sgonzo continue; 490194273Sgonzo } 491194273Sgonzo dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc); 492194273Sgonzo if (dp->d_reclen == 0 || 493191872Sgonzo dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) { 494191872Sgonzo dprintf(stderr, "corrupted directory: bad reclen %d\n", 495191872Sgonzo dp->d_reclen); 496191872Sgonzo return (NULL); 497191872Sgonzo } 498191872Sgonzo dirp->dd_loc += dp->d_reclen; 499191872Sgonzo if (dp->d_ino == 0 && strcmp(dp->d_name, "/") != 0) 500191872Sgonzo continue; 501191872Sgonzo if (dp->d_ino >= maxino) { 502191872Sgonzo dprintf(stderr, "corrupted directory: bad inum %d\n", 503221256Sadrian dp->d_ino); 504221256Sadrian continue; 505221256Sadrian } 506191872Sgonzo return (dp); 507191872Sgonzo } 508210900Sgonzo} 509191872Sgonzo 510191872Sgonzo/* 511191872Sgonzo * Simulate the opening of a directory 512191872Sgonzo */ 513191872SgonzoRST_DIR * 514191872Sgonzorst_opendir(name) 515191872Sgonzo const char *name; 516187706Sgonzo{ 517187706Sgonzo struct inotab *itp; 518187706Sgonzo RST_DIR *dirp; 519187706Sgonzo ino_t ino; 520187706Sgonzo 521187706Sgonzo if ((ino = dirlookup(name)) > 0 && 522187706Sgonzo (itp = inotablookup(ino)) != NULL) { 523187706Sgonzo dirp = opendirfile(dirfile); 524187706Sgonzo rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 525195474Sgonzo return (dirp); 526195474Sgonzo } 527195474Sgonzo return (NULL); 528187706Sgonzo} 529195474Sgonzo 530187706Sgonzo/* 531187706Sgonzo * In our case, there is nothing to do when closing a directory. 532187706Sgonzo */ 533187706Sgonzovoid 534187706Sgonzorst_closedir(dirp) 535187706Sgonzo RST_DIR *dirp; 536187706Sgonzo{ 537187706Sgonzo 538187706Sgonzo (void)close(dirp->dd_fd); 539187706Sgonzo free(dirp); 540187706Sgonzo return; 541187706Sgonzo} 542187706Sgonzo 543187706Sgonzo/* 544187706Sgonzo * Simulate finding the current offset in the directory. 545187706Sgonzo */ 546192161Sgonzostatic long 547187706Sgonzorst_telldir(dirp) 548191872Sgonzo RST_DIR *dirp; 549187706Sgonzo{ 550187706Sgonzo return ((long)lseek(dirp->dd_fd, 551187706Sgonzo (off_t)0, SEEK_CUR) - dirp->dd_size + dirp->dd_loc); 552187706Sgonzo} 553187706Sgonzo 554187706Sgonzo/* 555187706Sgonzo * Open a directory file. 556187706Sgonzo */ 557187706Sgonzostatic RST_DIR * 558187706Sgonzoopendirfile(name) 559187706Sgonzo const char *name; 560187706Sgonzo{ 561187706Sgonzo register RST_DIR *dirp; 562187706Sgonzo register int fd; 563187706Sgonzo 564187706Sgonzo if ((fd = open(name, O_RDONLY)) == -1) 565187706Sgonzo return (NULL); 566187706Sgonzo if ((dirp = malloc(sizeof(RST_DIR))) == NULL) { 567187706Sgonzo (void)close(fd); 568187706Sgonzo return (NULL); 569 } 570 dirp->dd_fd = fd; 571 dirp->dd_loc = 0; 572 return (dirp); 573} 574 575/* 576 * Set the mode, owner, and times for all new or changed directories 577 */ 578void 579setdirmodes(flags) 580 int flags; 581{ 582 FILE *mf; 583 struct modeinfo node; 584 struct entry *ep; 585 char *cp; 586 587 vprintf(stdout, "Set directory mode, owner, and times.\n"); 588 (void) sprintf(modefile, "%s/rstmode%d", _PATH_TMP, dumpdate); 589 mf = fopen(modefile, "r"); 590 if (mf == NULL) { 591 fprintf(stderr, "fopen: %s\n", strerror(errno)); 592 fprintf(stderr, "cannot open mode file %s\n", modefile); 593 fprintf(stderr, "directory mode, owner, and times not set\n"); 594 return; 595 } 596 clearerr(mf); 597 for (;;) { 598 (void) fread((char *)&node, 1, sizeof(struct modeinfo), mf); 599 if (feof(mf)) 600 break; 601 ep = lookupino(node.ino); 602 if (command == 'i' || command == 'x') { 603 if (ep == NULL) 604 continue; 605 if ((flags & FORCE) == 0 && ep->e_flags & EXISTED) { 606 ep->e_flags &= ~NEW; 607 continue; 608 } 609 if (node.ino == ROOTINO && 610 reply("set owner/mode for '.'") == FAIL) 611 continue; 612 } 613 if (ep == NULL) { 614 panic("cannot find directory inode %d\n", node.ino); 615 } else { 616 cp = myname(ep); 617 (void) chown(cp, node.uid, node.gid); 618 (void) chmod(cp, node.mode); 619 utimes(cp, node.timep); 620 ep->e_flags &= ~NEW; 621 } 622 } 623 if (ferror(mf)) 624 panic("error setting directory modes\n"); 625 (void) fclose(mf); 626} 627 628/* 629 * Generate a literal copy of a directory. 630 */ 631int 632genliteraldir(name, ino) 633 char *name; 634 ino_t ino; 635{ 636 register struct inotab *itp; 637 int ofile, dp, i, size; 638 char buf[BUFSIZ]; 639 640 itp = inotablookup(ino); 641 if (itp == NULL) 642 panic("Cannot find directory inode %d named %s\n", ino, name); 643 if ((ofile = creat(name, 0666)) < 0) { 644 fprintf(stderr, "%s: ", name); 645 (void) fflush(stderr); 646 fprintf(stderr, "cannot create file: %s\n", strerror(errno)); 647 return (FAIL); 648 } 649 rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 650 dp = dup(dirp->dd_fd); 651 for (i = itp->t_size; i > 0; i -= BUFSIZ) { 652 size = i < BUFSIZ ? i : BUFSIZ; 653 if (read(dp, buf, (int) size) == -1) { 654 fprintf(stderr, 655 "write error extracting inode %d, name %s\n", 656 curfile.ino, curfile.name); 657 fprintf(stderr, "read: %s\n", strerror(errno)); 658 done(1); 659 } 660 if (!Nflag && write(ofile, buf, (int) size) == -1) { 661 fprintf(stderr, 662 "write error extracting inode %d, name %s\n", 663 curfile.ino, curfile.name); 664 fprintf(stderr, "write: %s\n", strerror(errno)); 665 done(1); 666 } 667 } 668 (void) close(dp); 669 (void) close(ofile); 670 return (GOOD); 671} 672 673/* 674 * Determine the type of an inode 675 */ 676int 677inodetype(ino) 678 ino_t ino; 679{ 680 struct inotab *itp; 681 682 itp = inotablookup(ino); 683 if (itp == NULL) 684 return (LEAF); 685 return (NODE); 686} 687 688/* 689 * Allocate and initialize a directory inode entry. 690 * If requested, save its pertinent mode, owner, and time info. 691 */ 692static struct inotab * 693allocinotab(ino, dip, seekpt) 694 ino_t ino; 695 struct dinode *dip; 696 long seekpt; 697{ 698 register struct inotab *itp; 699 struct modeinfo node; 700 701 itp = calloc(1, sizeof(struct inotab)); 702 if (itp == NULL) 703 panic("no memory directory table\n"); 704 itp->t_next = inotab[INOHASH(ino)]; 705 inotab[INOHASH(ino)] = itp; 706 itp->t_ino = ino; 707 itp->t_seekpt = seekpt; 708 if (mf == NULL) 709 return (itp); 710 node.ino = ino; 711 node.timep[0].tv_sec = dip->di_atime.ts_sec; 712 node.timep[0].tv_usec = dip->di_atime.ts_nsec / 1000; 713 node.timep[1].tv_sec = dip->di_mtime.ts_sec; 714 node.timep[1].tv_usec = dip->di_mtime.ts_nsec / 1000; 715 node.mode = dip->di_mode; 716 node.uid = dip->di_uid; 717 node.gid = dip->di_gid; 718 (void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf); 719 return (itp); 720} 721 722/* 723 * Look up an inode in the table of directories 724 */ 725static struct inotab * 726inotablookup(ino) 727 ino_t ino; 728{ 729 register struct inotab *itp; 730 731 for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next) 732 if (itp->t_ino == ino) 733 return (itp); 734 return (NULL); 735} 736 737/* 738 * Clean up and exit 739 */ 740__dead void 741done(exitcode) 742 int exitcode; 743{ 744 745 closemt(); 746 if (modefile[0] != '#') 747 (void) unlink(modefile); 748 if (dirfile[0] != '#') 749 (void) unlink(dirfile); 750 exit(exitcode); 751} 752