dirs.c revision 66907
1251018Sgonzo/* 2251018Sgonzo * Copyright (c) 1983, 1993 3251018Sgonzo * The Regents of the University of California. All rights reserved. 4251018Sgonzo * (c) UNIX System Laboratories, Inc. 5251018Sgonzo * All or some portions of this file are derived from material licensed 6251018Sgonzo * to the University of California by American Telephone and Telegraph 7251018Sgonzo * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8251018Sgonzo * the permission of UNIX System Laboratories, Inc. 9251018Sgonzo * 10251018Sgonzo * Redistribution and use in source and binary forms, with or without 11251018Sgonzo * modification, are permitted provided that the following conditions 12251018Sgonzo * are met: 13251018Sgonzo * 1. Redistributions of source code must retain the above copyright 14251018Sgonzo * notice, this list of conditions and the following disclaimer. 15251018Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 16251018Sgonzo * notice, this list of conditions and the following disclaimer in the 17251018Sgonzo * documentation and/or other materials provided with the distribution. 18251018Sgonzo * 3. All advertising materials mentioning features or use of this software 19251018Sgonzo * must display the following acknowledgement: 20251018Sgonzo * This product includes software developed by the University of 21251018Sgonzo * California, Berkeley and its contributors. 22251018Sgonzo * 4. Neither the name of the University nor the names of its contributors 23251018Sgonzo * may be used to endorse or promote products derived from this software 24251018Sgonzo * without specific prior written permission. 25251018Sgonzo * 26251018Sgonzo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27251018Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28251018Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29251018Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30277716Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31251018Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32251018Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33251018Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34251018Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35251018Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36251018Sgonzo * SUCH DAMAGE. 37251018Sgonzo */ 38251018Sgonzo 39251018Sgonzo#ifndef lint 40251018Sgonzo#if 0 41251018Sgonzostatic char sccsid[] = "@(#)dirs.c 8.7 (Berkeley) 5/1/95"; 42251018Sgonzo#endif 43251018Sgonzostatic const char rcsid[] = 44251018Sgonzo "$FreeBSD: head/sbin/restore/dirs.c 66907 2000-10-10 01:50:26Z wollman $"; 45252282Sgonzo#endif /* not lint */ 46252282Sgonzo 47252282Sgonzo#include <sys/param.h> 48251018Sgonzo#include <sys/file.h> 49251018Sgonzo#include <sys/stat.h> 50251018Sgonzo#include <sys/time.h> 51251018Sgonzo 52251018Sgonzo#include <ufs/ufs/dinode.h> 53251018Sgonzo#include <ufs/ufs/dir.h> 54251018Sgonzo#include <protocols/dumprestore.h> 55252282Sgonzo 56277716Sgonzo#include <err.h> 57252282Sgonzo#include <errno.h> 58277716Sgonzo#include <stdio.h> 59277716Sgonzo#include <stdlib.h> 60277716Sgonzo#include <string.h> 61252282Sgonzo#include <unistd.h> 62251018Sgonzo 63251018Sgonzo#include "pathnames.h" 64251018Sgonzo#include "restore.h" 65251018Sgonzo#include "extern.h" 66251018Sgonzo 67251018Sgonzo/* 68277716Sgonzo * Symbol table of directories read from tape. 69277716Sgonzo */ 70251018Sgonzo#define HASHSIZE 1000 71251018Sgonzo#define INOHASH(val) (val % HASHSIZE) 72251018Sgonzostruct inotab { 73251018Sgonzo struct inotab *t_next; 74251018Sgonzo ino_t t_ino; 75251018Sgonzo int32_t t_seekpt; 76251018Sgonzo int32_t t_size; 77251018Sgonzo}; 78251018Sgonzostatic struct inotab *inotab[HASHSIZE]; 79251018Sgonzo 80251018Sgonzo/* 81251018Sgonzo * Information retained about directories. 82251018Sgonzo */ 83251018Sgonzostruct modeinfo { 84251018Sgonzo ino_t ino; 85251018Sgonzo struct timeval timep[2]; 86251018Sgonzo mode_t mode; 87251018Sgonzo uid_t uid; 88251018Sgonzo gid_t gid; 89251018Sgonzo int flags; 90251018Sgonzo}; 91251018Sgonzo 92251018Sgonzo/* 93251018Sgonzo * Definitions for library routines operating on directories. 94251018Sgonzo */ 95251018Sgonzo#undef DIRBLKSIZ 96251018Sgonzo#define DIRBLKSIZ 1024 97251018Sgonzostruct rstdirdesc { 98251018Sgonzo int dd_fd; 99251018Sgonzo int32_t dd_loc; 100251018Sgonzo int32_t dd_size; 101251018Sgonzo char dd_buf[DIRBLKSIZ]; 102251018Sgonzo}; 103251018Sgonzo 104251018Sgonzo/* 105251018Sgonzo * Global variables for this file. 106251018Sgonzo */ 107251018Sgonzostatic long seekpt; 108251018Sgonzostatic FILE *df, *mf; 109251018Sgonzostatic RST_DIR *dirp; 110251018Sgonzostatic char dirfile[MAXPATHLEN] = "#"; /* No file */ 111251018Sgonzostatic char modefile[MAXPATHLEN] = "#"; /* No file */ 112251018Sgonzostatic char dot[2] = "."; /* So it can be modified */ 113251018Sgonzo 114251018Sgonzo/* 115251018Sgonzo * Format of old style directories. 116251018Sgonzo */ 117251018Sgonzo#define ODIRSIZ 14 118251018Sgonzostruct odirect { 119251018Sgonzo u_short d_ino; 120251018Sgonzo char d_name[ODIRSIZ]; 121251018Sgonzo}; 122251018Sgonzo 123251018Sgonzostatic struct inotab *allocinotab __P((ino_t, struct dinode *, long)); 124251018Sgonzostatic void dcvt __P((struct odirect *, struct direct *)); 125251018Sgonzostatic void flushent __P((void)); 126251018Sgonzostatic struct inotab *inotablookup __P((ino_t)); 127251018Sgonzostatic RST_DIR *opendirfile __P((const char *)); 128251018Sgonzostatic void putdir __P((char *, long)); 129251018Sgonzostatic void putent __P((struct direct *)); 130251018Sgonzostatic void rst_seekdir __P((RST_DIR *, long, long)); 131251018Sgonzostatic long rst_telldir __P((RST_DIR *)); 132251018Sgonzostatic struct direct *searchdir __P((ino_t, char *)); 133251018Sgonzo 134251018Sgonzo/* 135251018Sgonzo * Extract directory contents, building up a directory structure 136251018Sgonzo * on disk for extraction by name. 137251018Sgonzo * If genmode is requested, save mode, owner, and times for all 138251018Sgonzo * directories on the tape. 139251018Sgonzo */ 140251018Sgonzovoid 141251018Sgonzoextractdirs(genmode) 142251018Sgonzo int genmode; 143251018Sgonzo{ 144251018Sgonzo register int i; 145251018Sgonzo register struct dinode *ip; 146251018Sgonzo struct inotab *itp; 147251018Sgonzo struct direct nulldir; 148251018Sgonzo int fd; 149251018Sgonzo 150251018Sgonzo vprintf(stdout, "Extract directories from tape\n"); 151251018Sgonzo (void) sprintf(dirfile, "%srstdir%d", _PATH_TMP, dumpdate); 152251018Sgonzo if (command != 'r' && command != 'R') { 153251018Sgonzo (void *) strcat(dirfile, "-XXXXXX"); 154251018Sgonzo fd = mkstemp(dirfile); 155251018Sgonzo } else 156251018Sgonzo fd = open(dirfile, O_RDWR|O_CREAT|O_EXCL, 0666); 157251018Sgonzo if (fd == -1 || (df = fdopen(fd, "w")) == NULL) { 158277405Sgonzo if (fd != -1) 159251018Sgonzo close(fd); 160251018Sgonzo warn("%s - cannot create directory temporary\nfopen", dirfile); 161251018Sgonzo done(1); 162251018Sgonzo } 163251018Sgonzo if (genmode != 0) { 164251018Sgonzo (void) sprintf(modefile, "%srstmode%d", _PATH_TMP, dumpdate); 165251018Sgonzo if (command != 'r' && command != 'R') { 166251018Sgonzo (void *) strcat(modefile, "-XXXXXX"); 167251018Sgonzo fd = mkstemp(modefile); 168251018Sgonzo } else 169251018Sgonzo fd = open(modefile, O_RDWR|O_CREAT|O_EXCL, 0666); 170251018Sgonzo if (fd == -1 || (mf = fdopen(fd, "w")) == NULL) { 171251018Sgonzo if (fd != -1) 172251018Sgonzo close(fd); 173251018Sgonzo warn("%s - cannot create modefile\nfopen", modefile); 174251018Sgonzo done(1); 175251018Sgonzo } 176251018Sgonzo } 177251018Sgonzo nulldir.d_ino = 0; 178251018Sgonzo nulldir.d_type = DT_DIR; 179251018Sgonzo nulldir.d_namlen = 1; 180251018Sgonzo (void) strcpy(nulldir.d_name, "/"); 181251018Sgonzo nulldir.d_reclen = DIRSIZ(0, &nulldir); 182251018Sgonzo for (;;) { 183251018Sgonzo curfile.name = "<directory file - name unknown>"; 184251018Sgonzo curfile.action = USING; 185251018Sgonzo ip = curfile.dip; 186277716Sgonzo if (ip == NULL || (ip->di_mode & IFMT) != IFDIR) { 187251018Sgonzo (void) fclose(df); 188251018Sgonzo dirp = opendirfile(dirfile); 189251018Sgonzo if (dirp == NULL) 190251018Sgonzo fprintf(stderr, "opendirfile: %s\n", 191251018Sgonzo strerror(errno)); 192251018Sgonzo if (mf != NULL) 193251018Sgonzo (void) fclose(mf); 194251018Sgonzo i = dirlookup(dot); 195251018Sgonzo if (i == 0) 196251018Sgonzo panic("Root directory is not on tape\n"); 197251018Sgonzo return; 198251018Sgonzo } 199251018Sgonzo itp = allocinotab(curfile.ino, ip, seekpt); 200251018Sgonzo getfile(putdir, xtrnull); 201251018Sgonzo putent(&nulldir); 202251018Sgonzo flushent(); 203251018Sgonzo itp->t_size = seekpt - itp->t_seekpt; 204251018Sgonzo } 205251018Sgonzo} 206251018Sgonzo 207251018Sgonzo/* 208251018Sgonzo * skip over all the directories on the tape 209251018Sgonzo */ 210251018Sgonzovoid 211251018Sgonzoskipdirs() 212251018Sgonzo{ 213251018Sgonzo 214251018Sgonzo while (curfile.dip && (curfile.dip->di_mode & IFMT) == IFDIR) { 215251018Sgonzo skipfile(); 216251018Sgonzo } 217251018Sgonzo} 218251018Sgonzo 219251018Sgonzo/* 220251018Sgonzo * Recursively find names and inumbers of all files in subtree 221251018Sgonzo * pname and pass them off to be processed. 222251018Sgonzo */ 223251018Sgonzovoid 224251018Sgonzotreescan(pname, ino, todo) 225251018Sgonzo char *pname; 226251018Sgonzo ino_t ino; 227251018Sgonzo long (*todo) __P((char *, ino_t, int)); 228251018Sgonzo{ 229251018Sgonzo register struct inotab *itp; 230251018Sgonzo register struct direct *dp; 231251018Sgonzo int namelen; 232251018Sgonzo long bpt; 233267171Skevlo char locname[MAXPATHLEN + 1]; 234251018Sgonzo 235251018Sgonzo itp = inotablookup(ino); 236251018Sgonzo if (itp == NULL) { 237251018Sgonzo /* 238251018Sgonzo * Pname is name of a simple file or an unchanged directory. 239251018Sgonzo */ 240251018Sgonzo (void) (*todo)(pname, ino, LEAF); 241251018Sgonzo return; 242251018Sgonzo } 243251018Sgonzo /* 244251018Sgonzo * Pname is a dumped directory name. 245283276Sgonzo */ 246251018Sgonzo if ((*todo)(pname, ino, NODE) == FAIL) 247251018Sgonzo return; 248251018Sgonzo /* 249251018Sgonzo * begin search through the directory 250251018Sgonzo * skipping over "." and ".." 251251018Sgonzo */ 252251018Sgonzo (void) strncpy(locname, pname, sizeof(locname) - 1); 253251018Sgonzo locname[sizeof(locname) - 1] = '\0'; 254251018Sgonzo (void) strncat(locname, "/", sizeof(locname) - strlen(locname)); 255283276Sgonzo namelen = strlen(locname); 256251018Sgonzo rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 257251018Sgonzo dp = rst_readdir(dirp); /* "." */ 258251018Sgonzo if (dp != NULL && strcmp(dp->d_name, ".") == 0) 259251018Sgonzo dp = rst_readdir(dirp); /* ".." */ 260251018Sgonzo else 261251018Sgonzo fprintf(stderr, "Warning: `.' missing from directory %s\n", 262251018Sgonzo pname); 263251018Sgonzo if (dp != NULL && strcmp(dp->d_name, "..") == 0) 264251018Sgonzo dp = rst_readdir(dirp); /* first real entry */ 265251018Sgonzo else 266251018Sgonzo fprintf(stderr, "Warning: `..' missing from directory %s\n", 267251018Sgonzo pname); 268251018Sgonzo bpt = rst_telldir(dirp); 269251018Sgonzo /* 270251018Sgonzo * a zero inode signals end of directory 271283276Sgonzo */ 272251018Sgonzo while (dp != NULL) { 273251018Sgonzo locname[namelen] = '\0'; 274283276Sgonzo if (namelen + dp->d_namlen >= sizeof(locname)) { 275251018Sgonzo fprintf(stderr, "%s%s: name exceeds %d char\n", 276283503Sgonzo locname, dp->d_name, sizeof(locname) - 1); 277283276Sgonzo } else { 278283276Sgonzo (void) strncat(locname, dp->d_name, (int)dp->d_namlen); 279283276Sgonzo treescan(locname, dp->d_ino, todo); 280283276Sgonzo rst_seekdir(dirp, bpt, itp->t_seekpt); 281283276Sgonzo } 282283276Sgonzo dp = rst_readdir(dirp); 283283276Sgonzo bpt = rst_telldir(dirp); 284283276Sgonzo } 285283276Sgonzo} 286283276Sgonzo 287283276Sgonzo/* 288283276Sgonzo * Lookup a pathname which is always assumed to start from the ROOTINO. 289283276Sgonzo */ 290251018Sgonzostruct direct * 291283276Sgonzopathsearch(pathname) 292283276Sgonzo const char *pathname; 293251018Sgonzo{ 294251018Sgonzo ino_t ino; 295283276Sgonzo struct direct *dp; 296283276Sgonzo char *path, *name, buffer[MAXPATHLEN]; 297251018Sgonzo 298251018Sgonzo strcpy(buffer, pathname); 299283276Sgonzo path = buffer; 300283276Sgonzo ino = ROOTINO; 301251018Sgonzo while (*path == '/') 302251018Sgonzo path++; 303283276Sgonzo dp = NULL; 304283276Sgonzo while ((name = strsep(&path, "/")) != NULL && *name != '\0') { 305251018Sgonzo if ((dp = searchdir(ino, name)) == NULL) 306251018Sgonzo return (NULL); 307283276Sgonzo ino = dp->d_ino; 308283276Sgonzo } 309251018Sgonzo return (dp); 310251018Sgonzo} 311283276Sgonzo 312283276Sgonzo/* 313251018Sgonzo * Lookup the requested name in directory inum. 314251018Sgonzo * Return its inode number if found, zero if it does not exist. 315283276Sgonzo */ 316283276Sgonzostatic struct direct * 317251018Sgonzosearchdir(inum, name) 318251018Sgonzo ino_t inum; 319283276Sgonzo char *name; 320283276Sgonzo{ 321251018Sgonzo register struct direct *dp; 322251018Sgonzo register struct inotab *itp; 323283276Sgonzo int len; 324283276Sgonzo 325251018Sgonzo itp = inotablookup(inum); 326251018Sgonzo if (itp == NULL) 327283276Sgonzo return (NULL); 328283276Sgonzo rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 329251018Sgonzo len = strlen(name); 330251018Sgonzo do { 331283276Sgonzo dp = rst_readdir(dirp); 332283276Sgonzo if (dp == NULL) 333251018Sgonzo return (NULL); 334251018Sgonzo } while (dp->d_namlen != len || strncmp(dp->d_name, name, len) != 0); 335283276Sgonzo return (dp); 336283276Sgonzo} 337251018Sgonzo 338251018Sgonzo/* 339283276Sgonzo * Put the directory entries in the directory file 340283276Sgonzo */ 341283276Sgonzostatic void 342283276Sgonzoputdir(buf, size) 343283276Sgonzo char *buf; 344283276Sgonzo long size; 345283276Sgonzo{ 346283276Sgonzo struct direct cvtbuf; 347283276Sgonzo register struct odirect *odp; 348283276Sgonzo struct odirect *eodp; 349283503Sgonzo register struct direct *dp; 350283276Sgonzo long loc, i; 351283276Sgonzo 352283276Sgonzo if (cvtflag) { 353283276Sgonzo eodp = (struct odirect *)&buf[size]; 354283276Sgonzo for (odp = (struct odirect *)buf; odp < eodp; odp++) 355283276Sgonzo if (odp->d_ino != 0) { 356283276Sgonzo dcvt(odp, &cvtbuf); 357251018Sgonzo putent(&cvtbuf); 358251018Sgonzo } 359283276Sgonzo } else { 360283276Sgonzo for (loc = 0; loc < size; ) { 361251018Sgonzo dp = (struct direct *)(buf + loc); 362251018Sgonzo if (Bcvt) 363283276Sgonzo swabst((u_char *)"ls", (u_char *) dp); 364283276Sgonzo if (oldinofmt && dp->d_ino != 0) { 365251018Sgonzo# if BYTE_ORDER == BIG_ENDIAN 366251018Sgonzo if (Bcvt) 367283276Sgonzo dp->d_namlen = dp->d_type; 368283276Sgonzo# else 369251018Sgonzo if (!Bcvt) 370251018Sgonzo dp->d_namlen = dp->d_type; 371283276Sgonzo# endif 372283276Sgonzo dp->d_type = DT_UNKNOWN; 373251018Sgonzo } 374251018Sgonzo i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1)); 375283276Sgonzo if ((dp->d_reclen & 0x3) != 0 || 376283276Sgonzo dp->d_reclen > i || 377251018Sgonzo dp->d_reclen < DIRSIZ(0, dp) || 378251018Sgonzo dp->d_namlen > NAME_MAX) { 379283276Sgonzo vprintf(stdout, "Mangled directory: "); 380283276Sgonzo if ((dp->d_reclen & 0x3) != 0) 381251018Sgonzo vprintf(stdout, 382251018Sgonzo "reclen not multiple of 4 "); 383251018Sgonzo if (dp->d_reclen < DIRSIZ(0, dp)) 384251018Sgonzo vprintf(stdout, 385251018Sgonzo "reclen less than DIRSIZ (%d < %d) ", 386251018Sgonzo dp->d_reclen, DIRSIZ(0, dp)); 387251018Sgonzo if (dp->d_namlen > NAME_MAX) 388251018Sgonzo vprintf(stdout, 389251018Sgonzo "reclen name too big (%d > %d) ", 390251018Sgonzo dp->d_namlen, NAME_MAX); 391251018Sgonzo vprintf(stdout, "\n"); 392251018Sgonzo loc += i; 393251018Sgonzo continue; 394277632Sgonzo } 395277632Sgonzo loc += dp->d_reclen; 396251018Sgonzo if (dp->d_ino != 0) { 397251018Sgonzo putent(dp); 398251018Sgonzo } 399251018Sgonzo } 400251018Sgonzo } 401251018Sgonzo} 402251018Sgonzo 403251018Sgonzo/* 404251018Sgonzo * These variables are "local" to the following two functions. 405277522Sgonzo */ 406251018Sgonzochar dirbuf[DIRBLKSIZ]; 407251018Sgonzolong dirloc = 0; 408251018Sgonzolong prev = 0; 409251018Sgonzo 410251018Sgonzo/* 411251018Sgonzo * add a new directory entry to a file. 412251018Sgonzo */ 413251018Sgonzostatic void 414251018Sgonzoputent(dp) 415251018Sgonzo struct direct *dp; 416277522Sgonzo{ 417251018Sgonzo dp->d_reclen = DIRSIZ(0, dp); 418251018Sgonzo if (dirloc + dp->d_reclen > DIRBLKSIZ) { 419251018Sgonzo ((struct direct *)(dirbuf + prev))->d_reclen = 420251018Sgonzo DIRBLKSIZ - prev; 421251018Sgonzo (void) fwrite(dirbuf, 1, DIRBLKSIZ, df); 422251018Sgonzo dirloc = 0; 423251018Sgonzo } 424251018Sgonzo memmove(dirbuf + dirloc, dp, (long)dp->d_reclen); 425251018Sgonzo prev = dirloc; 426251018Sgonzo dirloc += dp->d_reclen; 427251018Sgonzo} 428251018Sgonzo 429251018Sgonzo/* 430251018Sgonzo * flush out a directory that is finished. 431251018Sgonzo */ 432251018Sgonzostatic void 433251018Sgonzoflushent() 434251018Sgonzo{ 435251018Sgonzo ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev; 436251018Sgonzo (void) fwrite(dirbuf, (int)dirloc, 1, df); 437251018Sgonzo seekpt = ftell(df); 438277405Sgonzo dirloc = 0; 439277522Sgonzo} 440277405Sgonzo 441277632Sgonzostatic void 442277632Sgonzodcvt(odp, ndp) 443251018Sgonzo register struct odirect *odp; 444251018Sgonzo register struct direct *ndp; 445251018Sgonzo{ 446251018Sgonzo 447251018Sgonzo memset(ndp, 0, (long)(sizeof *ndp)); 448277716Sgonzo ndp->d_ino = odp->d_ino; 449252282Sgonzo ndp->d_type = DT_UNKNOWN; 450277716Sgonzo (void) strncpy(ndp->d_name, odp->d_name, ODIRSIZ); 451252282Sgonzo ndp->d_namlen = strlen(ndp->d_name); 452261410Sian ndp->d_reclen = DIRSIZ(0, ndp); 453261410Sian} 454261410Sian 455283276Sgonzo/* 456251018Sgonzo * Seek to an entry in a directory. 457251018Sgonzo * Only values returned by rst_telldir should be passed to rst_seekdir. 458251018Sgonzo * This routine handles many directories in a single file. 459251018Sgonzo * It takes the base of the directory in the file, plus 460277716Sgonzo * the desired seek offset into it. 461252282Sgonzo */ 462252282Sgonzostatic void 463252282Sgonzorst_seekdir(dirp, loc, base) 464252282Sgonzo register RST_DIR *dirp; 465277716Sgonzo long loc, base; 466252282Sgonzo{ 467252282Sgonzo 468251018Sgonzo if (loc == rst_telldir(dirp)) 469251018Sgonzo return; 470251018Sgonzo loc -= base; 471251018Sgonzo if (loc < 0) 472251018Sgonzo fprintf(stderr, "bad seek pointer to rst_seekdir %ld\n", loc); 473251018Sgonzo (void) lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), SEEK_SET); 474251018Sgonzo dirp->dd_loc = loc & (DIRBLKSIZ - 1); 475251018Sgonzo if (dirp->dd_loc != 0) 476251018Sgonzo dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ); 477251018Sgonzo} 478251018Sgonzo 479251018Sgonzo/* 480251018Sgonzo * get next entry in a directory. 481251018Sgonzo */ 482251018Sgonzostruct direct * 483277313Sgonzorst_readdir(dirp) 484277313Sgonzo register RST_DIR *dirp; 485277313Sgonzo{ 486283276Sgonzo register struct direct *dp; 487251018Sgonzo 488251018Sgonzo for (;;) { 489251018Sgonzo if (dirp->dd_loc == 0) { 490251018Sgonzo dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, 491283276Sgonzo DIRBLKSIZ); 492283276Sgonzo if (dirp->dd_size <= 0) { 493283276Sgonzo dprintf(stderr, "error reading directory\n"); 494251018Sgonzo return (NULL); 495283276Sgonzo } 496251018Sgonzo } 497283276Sgonzo if (dirp->dd_loc >= dirp->dd_size) { 498283276Sgonzo dirp->dd_loc = 0; 499283276Sgonzo continue; 500283276Sgonzo } 501283276Sgonzo dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc); 502283276Sgonzo if (dp->d_reclen == 0 || 503283276Sgonzo dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) { 504283276Sgonzo dprintf(stderr, "corrupted directory: bad reclen %d\n", 505283276Sgonzo dp->d_reclen); 506283276Sgonzo return (NULL); 507283276Sgonzo } 508283276Sgonzo dirp->dd_loc += dp->d_reclen; 509283276Sgonzo if (dp->d_ino == 0 && strcmp(dp->d_name, "/") == 0) 510283276Sgonzo return (NULL); 511283276Sgonzo if (dp->d_ino >= maxino) { 512283276Sgonzo dprintf(stderr, "corrupted directory: bad inum %d\n", 513251018Sgonzo dp->d_ino); 514251018Sgonzo continue; 515251018Sgonzo } 516251018Sgonzo return (dp); 517251018Sgonzo } 518251018Sgonzo} 519251018Sgonzo 520251018Sgonzo/* 521251018Sgonzo * Simulate the opening of a directory 522251018Sgonzo */ 523251018SgonzoRST_DIR * 524251018Sgonzorst_opendir(name) 525251018Sgonzo const char *name; 526251018Sgonzo{ 527251018Sgonzo struct inotab *itp; 528251018Sgonzo RST_DIR *dirp; 529251018Sgonzo ino_t ino; 530251018Sgonzo 531251018Sgonzo if ((ino = dirlookup(name)) > 0 && 532251018Sgonzo (itp = inotablookup(ino)) != NULL) { 533251018Sgonzo dirp = opendirfile(dirfile); 534251018Sgonzo rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 535251018Sgonzo return (dirp); 536251018Sgonzo } 537251018Sgonzo return (NULL); 538251018Sgonzo} 539251018Sgonzo 540251018Sgonzo/* 541251018Sgonzo * In our case, there is nothing to do when closing a directory. 542251018Sgonzo */ 543251018Sgonzovoid 544251018Sgonzorst_closedir(dirp) 545251018Sgonzo RST_DIR *dirp; 546251018Sgonzo{ 547251018Sgonzo 548251018Sgonzo (void)close(dirp->dd_fd); 549251018Sgonzo free(dirp); 550251018Sgonzo return; 551251018Sgonzo} 552251018Sgonzo 553251018Sgonzo/* 554251018Sgonzo * Simulate finding the current offset in the directory. 555251018Sgonzo */ 556251018Sgonzostatic long 557251018Sgonzorst_telldir(dirp) 558251018Sgonzo RST_DIR *dirp; 559251018Sgonzo{ 560251018Sgonzo return ((long)lseek(dirp->dd_fd, 561251018Sgonzo (off_t)0, SEEK_CUR) - dirp->dd_size + dirp->dd_loc); 562251018Sgonzo} 563251018Sgonzo 564251018Sgonzo/* 565251018Sgonzo * Open a directory file. 566251018Sgonzo */ 567251018Sgonzostatic RST_DIR * 568251018Sgonzoopendirfile(name) 569251018Sgonzo const char *name; 570252282Sgonzo{ 571251018Sgonzo register RST_DIR *dirp; 572251018Sgonzo register int fd; 573251018Sgonzo 574251018Sgonzo if ((fd = open(name, O_RDONLY)) == -1) 575251018Sgonzo return (NULL); 576251018Sgonzo if ((dirp = malloc(sizeof(RST_DIR))) == NULL) { 577251018Sgonzo (void)close(fd); 578251018Sgonzo return (NULL); 579251018Sgonzo } 580251018Sgonzo dirp->dd_fd = fd; 581251018Sgonzo dirp->dd_loc = 0; 582251018Sgonzo return (dirp); 583251018Sgonzo} 584251018Sgonzo 585251018Sgonzo/* 586251018Sgonzo * Set the mode, owner, and times for all new or changed directories 587251018Sgonzo */ 588251018Sgonzovoid 589251018Sgonzosetdirmodes(flags) 590251018Sgonzo int flags; 591251018Sgonzo{ 592251018Sgonzo FILE *mf; 593251018Sgonzo struct modeinfo node; 594251018Sgonzo struct entry *ep; 595251018Sgonzo char *cp; 596251018Sgonzo 597251018Sgonzo vprintf(stdout, "Set directory mode, owner, and times.\n"); 598251018Sgonzo if (command == 'r' || command == 'R') 599251018Sgonzo (void) sprintf(modefile, "%srstmode%d", _PATH_TMP, dumpdate); 600277313Sgonzo if (modefile[0] == '#') { 601277313Sgonzo panic("modefile not defined\n"); 602277313Sgonzo fprintf(stderr, "directory mode, owner, and times not set\n"); 603277313Sgonzo return; 604277313Sgonzo } 605277313Sgonzo mf = fopen(modefile, "r"); 606277313Sgonzo if (mf == NULL) { 607277313Sgonzo fprintf(stderr, "fopen: %s\n", strerror(errno)); 608277313Sgonzo fprintf(stderr, "cannot open mode file %s\n", modefile); 609277313Sgonzo fprintf(stderr, "directory mode, owner, and times not set\n"); 610277313Sgonzo return; 611251018Sgonzo } 612277313Sgonzo clearerr(mf); 613277313Sgonzo for (;;) { 614251018Sgonzo (void) fread((char *)&node, 1, sizeof(struct modeinfo), mf); 615277313Sgonzo if (feof(mf)) 616277313Sgonzo break; 617251018Sgonzo ep = lookupino(node.ino); 618277313Sgonzo if (command == 'i' || command == 'x') { 619277313Sgonzo if (ep == NULL) 620251018Sgonzo continue; 621251018Sgonzo if ((flags & FORCE) == 0 && ep->e_flags & EXISTED) { 622277313Sgonzo ep->e_flags &= ~NEW; 623277313Sgonzo continue; 624277313Sgonzo } 625251018Sgonzo if (node.ino == ROOTINO && 626251018Sgonzo reply("set owner/mode for '.'") == FAIL) 627277313Sgonzo continue; 628251018Sgonzo } 629277313Sgonzo if (ep == NULL) { 630251018Sgonzo panic("cannot find directory inode %d\n", node.ino); 631251018Sgonzo } else { 632251018Sgonzo cp = myname(ep); 633277313Sgonzo (void) chown(cp, node.uid, node.gid); 634251018Sgonzo (void) chmod(cp, node.mode); 635277313Sgonzo utimes(cp, node.timep); 636251018Sgonzo (void) chflags(cp, node.flags); 637251018Sgonzo ep->e_flags &= ~NEW; 638251018Sgonzo } 639251018Sgonzo } 640251018Sgonzo if (ferror(mf)) 641251018Sgonzo panic("error setting directory modes\n"); 642251018Sgonzo (void) fclose(mf); 643251018Sgonzo} 644251018Sgonzo 645283276Sgonzo/* 646251018Sgonzo * Generate a literal copy of a directory. 647283276Sgonzo */ 648251018Sgonzoint 649283276Sgonzogenliteraldir(name, ino) 650251018Sgonzo char *name; 651251018Sgonzo ino_t ino; 652251018Sgonzo{ 653251018Sgonzo register struct inotab *itp; 654251018Sgonzo int ofile, dp, i, size; 655251018Sgonzo char buf[BUFSIZ]; 656251018Sgonzo 657251018Sgonzo itp = inotablookup(ino); 658251018Sgonzo if (itp == NULL) 659251018Sgonzo panic("Cannot find directory inode %d named %s\n", ino, name); 660251018Sgonzo if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) { 661251018Sgonzo fprintf(stderr, "%s: ", name); 662251018Sgonzo (void) fflush(stderr); 663251018Sgonzo fprintf(stderr, "cannot create file: %s\n", strerror(errno)); 664251018Sgonzo return (FAIL); 665251018Sgonzo } 666251018Sgonzo rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 667251018Sgonzo dp = dup(dirp->dd_fd); 668251018Sgonzo for (i = itp->t_size; i > 0; i -= BUFSIZ) { 669251018Sgonzo size = i < BUFSIZ ? i : BUFSIZ; 670251018Sgonzo if (read(dp, buf, (int) size) == -1) { 671251018Sgonzo fprintf(stderr, 672251018Sgonzo "write error extracting inode %d, name %s\n", 673251018Sgonzo curfile.ino, curfile.name); 674251018Sgonzo fprintf(stderr, "read: %s\n", strerror(errno)); 675251018Sgonzo done(1); 676251018Sgonzo } 677251018Sgonzo if (!Nflag && write(ofile, buf, (int) size) == -1) { 678251018Sgonzo fprintf(stderr, 679251018Sgonzo "write error extracting inode %d, name %s\n", 680251018Sgonzo curfile.ino, curfile.name); 681251018Sgonzo fprintf(stderr, "write: %s\n", strerror(errno)); 682251018Sgonzo done(1); 683251018Sgonzo } 684251018Sgonzo } 685251018Sgonzo (void) close(dp); 686251018Sgonzo (void) close(ofile); 687251018Sgonzo return (GOOD); 688251018Sgonzo} 689251018Sgonzo 690251018Sgonzo/* 691251018Sgonzo * Determine the type of an inode 692251018Sgonzo */ 693251018Sgonzoint 694251018Sgonzoinodetype(ino) 695251018Sgonzo ino_t ino; 696251018Sgonzo{ 697251018Sgonzo struct inotab *itp; 698251018Sgonzo 699251018Sgonzo itp = inotablookup(ino); 700251018Sgonzo if (itp == NULL) 701251018Sgonzo return (LEAF); 702251018Sgonzo return (NODE); 703251018Sgonzo} 704251018Sgonzo 705251018Sgonzo/* 706251018Sgonzo * Allocate and initialize a directory inode entry. 707251018Sgonzo * If requested, save its pertinent mode, owner, and time info. 708251018Sgonzo */ 709251018Sgonzostatic struct inotab * 710251018Sgonzoallocinotab(ino, dip, seekpt) 711251018Sgonzo ino_t ino; 712251018Sgonzo struct dinode *dip; 713251018Sgonzo long seekpt; 714251018Sgonzo{ 715251018Sgonzo register struct inotab *itp; 716251018Sgonzo struct modeinfo node; 717251018Sgonzo 718251018Sgonzo itp = calloc(1, sizeof(struct inotab)); 719251018Sgonzo if (itp == NULL) 720251018Sgonzo panic("no memory directory table\n"); 721251018Sgonzo itp->t_next = inotab[INOHASH(ino)]; 722251018Sgonzo inotab[INOHASH(ino)] = itp; 723251018Sgonzo itp->t_ino = ino; 724251018Sgonzo itp->t_seekpt = seekpt; 725251018Sgonzo if (mf == NULL) 726251018Sgonzo return (itp); 727251018Sgonzo node.ino = ino; 728283276Sgonzo node.timep[0].tv_sec = dip->di_atime; 729251018Sgonzo node.timep[0].tv_usec = dip->di_atimensec / 1000; 730251018Sgonzo node.timep[1].tv_sec = dip->di_mtime; 731251018Sgonzo node.timep[1].tv_usec = dip->di_mtimensec / 1000; 732277716Sgonzo node.mode = dip->di_mode; 733277716Sgonzo node.flags = dip->di_flags; 734277716Sgonzo node.uid = dip->di_uid; 735277716Sgonzo node.gid = dip->di_gid; 736277716Sgonzo (void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf); 737277716Sgonzo return (itp); 738277716Sgonzo} 739277716Sgonzo 740277716Sgonzo/* 741277716Sgonzo * Look up an inode in the table of directories 742252282Sgonzo */ 743252282Sgonzostatic struct inotab * 744252282Sgonzoinotablookup(ino) 745252282Sgonzo ino_t ino; 746252282Sgonzo{ 747252282Sgonzo register struct inotab *itp; 748252282Sgonzo 749252282Sgonzo for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next) 750251018Sgonzo if (itp->t_ino == ino) 751277716Sgonzo return (itp); 752277716Sgonzo return (NULL); 753277716Sgonzo} 754277716Sgonzo 755277716Sgonzo/* 756277716Sgonzo * Clean up and exit 757277716Sgonzo */ 758277716Sgonzovoid 759277716Sgonzodone(exitcode) 760277716Sgonzo int exitcode; 761277716Sgonzo{ 762277716Sgonzo 763251018Sgonzo closemt(); 764251018Sgonzo if (modefile[0] != '#') 765251018Sgonzo (void) unlink(modefile); 766251018Sgonzo if (dirfile[0] != '#') 767251018Sgonzo (void) unlink(dirfile); 768251018Sgonzo exit(exitcode); 769251018Sgonzo} 770251018Sgonzo