1: /*
   2:  * Copyright (c) 1983 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  */
   6: 
   7: #ifndef lint
   8: static char sccsid[] = "@(#)dirs.c	5.4 (Berkeley) 4/23/86";
   9: #endif not lint
  10: 
  11: #include "restore.h"
  12: #include <protocols/dumprestore.h>
  13: #include <sys/file.h>
  14: 
  15: /*
  16:  * Symbol table of directories read from tape.
  17:  */
  18: #define HASHSIZE    1000
  19: #define INOHASH(val) (val % HASHSIZE)
  20: struct inotab {
  21:     struct inotab *t_next;
  22:     ino_t   t_ino;
  23:     daddr_t t_seekpt;
  24:     long t_size;
  25: };
  26: static struct inotab *inotab[HASHSIZE];
  27: extern struct inotab *inotablookup();
  28: extern struct inotab *allocinotab();
  29: 
  30: /*
  31:  * Information retained about directories.
  32:  */
  33: struct modeinfo {
  34:     ino_t ino;
  35:     time_t timep[2];
  36:     short mode;
  37:     short uid;
  38:     short gid;
  39: };
  40: 
  41: /*
  42:  * Global variables for this file.
  43:  */
  44: static daddr_t  seekpt;
  45: static FILE *df, *mf;
  46: static DIR  *dirp;
  47: static char dirfile[32] = "#";  /* No file */
  48: static char modefile[32] = "#"; /* No file */
  49: extern ino_t    search();
  50: struct direct   *rst_readdir();
  51: extern void     rst_seekdir();
  52: 
  53: /*
  54:  * Format of old style directories.
  55:  */
  56: #define ODIRSIZ 14
  57: struct odirect {
  58:     u_short d_ino;
  59:     char    d_name[ODIRSIZ];
  60: };
  61: 
  62: /*
  63:  *	Extract directory contents, building up a directory structure
  64:  *	on disk for extraction by name.
  65:  *	If genmode is requested, save mode, owner, and times for all
  66:  *	directories on the tape.
  67:  */
  68: extractdirs(genmode)
  69:     int genmode;
  70: {
  71:     register int i;
  72:     register struct dinode *ip;
  73:     struct inotab *itp;
  74:     struct direct nulldir;
  75:     int putdir(), null();
  76: 
  77:     vprintf(stdout, "Extract directories from tape\n");
  78:     (void) sprintf(dirfile, "/tmp/rstdir%d", dumpdate);
  79:     df = fopen(dirfile, "w");
  80:     if (df == 0) {
  81:         fprintf(stderr,
  82:             "restore: %s - cannot create directory temporary\n",
  83:             dirfile);
  84:         perror("fopen");
  85:         done(1);
  86:     }
  87:     if (genmode != 0) {
  88:         (void) sprintf(modefile, "/tmp/rstmode%d", dumpdate);
  89:         mf = fopen(modefile, "w");
  90:         if (mf == 0) {
  91:             fprintf(stderr,
  92:                 "restore: %s - cannot create modefile \n",
  93:                 modefile);
  94:             perror("fopen");
  95:             done(1);
  96:         }
  97:     }
  98:     nulldir.d_ino = 0;
  99:     nulldir.d_namlen = 1;
 100:     (void) strcpy(nulldir.d_name, "/");
 101:     nulldir.d_reclen = DIRSIZ(&nulldir);
 102:     for (;;) {
 103:         curfile.name = "<directory file - name unknown>";
 104:         curfile.action = USING;
 105:         ip = curfile.dip;
 106:         if (ip == NULL || (ip->di_mode & IFMT) != IFDIR) {
 107:             (void) fclose(df);
 108:             dirp = opendir(dirfile);
 109:             if (dirp == NULL)
 110:                 perror("opendir");
 111:             if (mf != NULL)
 112:                 (void) fclose(mf);
 113:             i = dirlookup(".");
 114:             if (i == 0)
 115:                 panic("Root directory is not on tape\n");
 116:             return;
 117:         }
 118:         itp = allocinotab(curfile.ino, ip, seekpt);
 119:         getfile(putdir, null);
 120:         putent(&nulldir);
 121:         flushent();
 122:         itp->t_size = seekpt - itp->t_seekpt;
 123:     }
 124: }
 125: 
 126: /*
 127:  * skip over all the directories on the tape
 128:  */
 129: skipdirs()
 130: {
 131: 
 132:     while ((curfile.dip->di_mode & IFMT) == IFDIR) {
 133:         skipfile();
 134:     }
 135: }
 136: 
 137: /*
 138:  *	Recursively find names and inumbers of all files in subtree
 139:  *	pname and pass them off to be processed.
 140:  */
 141: treescan(pname, ino, todo)
 142:     char *pname;
 143:     ino_t ino;
 144:     long (*todo)();
 145: {
 146:     register struct inotab *itp;
 147:     register struct direct *dp;
 148:     register struct entry *np;
 149:     int namelen;
 150:     daddr_t bpt;
 151:     char locname[MAXPATHLEN + 1];
 152: 
 153:     itp = inotablookup(ino);
 154:     if (itp == NULL) {
 155:         /*
 156: 		 * Pname is name of a simple file or an unchanged directory.
 157: 		 */
 158:         (void) (*todo)(pname, ino, LEAF);
 159:         return;
 160:     }
 161:     /*
 162: 	 * Pname is a dumped directory name.
 163: 	 */
 164:     if ((*todo)(pname, ino, NODE) == FAIL)
 165:         return;
 166:     /*
 167: 	 * begin search through the directory
 168: 	 * skipping over "." and ".."
 169: 	 */
 170:     (void) strncpy(locname, pname, MAXPATHLEN);
 171:     (void) strncat(locname, "/", MAXPATHLEN);
 172:     namelen = strlen(locname);
 173:     rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
 174:     dp = rst_readdir(dirp); /* "." */
 175:     if (dp != NULL && strcmp(dp->d_name, ".") == 0)
 176:         dp = rst_readdir(dirp); /* ".." */
 177:     else
 178:         fprintf(stderr, "Warning: `.' missing from directory %s\n",
 179:             pname);
 180:     if (dp != NULL && strcmp(dp->d_name, "..") == 0)
 181:         dp = rst_readdir(dirp); /* first real entry */
 182:     else
 183:         fprintf(stderr, "Warning: `..' missing from directory %s\n",
 184:             pname);
 185:     bpt = telldir(dirp);
 186:     /*
 187: 	 * a zero inode signals end of directory
 188: 	 */
 189:     while (dp != NULL && dp->d_ino != 0) {
 190:         locname[namelen] = '\0';
 191:         if (namelen + dp->d_namlen >= MAXPATHLEN) {
 192:             fprintf(stderr, "%s%s: name exceeds %d char\n",
 193:                 locname, dp->d_name, MAXPATHLEN);
 194:         } else {
 195:             (void) strncat(locname, dp->d_name, (int)dp->d_namlen);
 196:             treescan(locname, dp->d_ino, todo);
 197:             rst_seekdir(dirp, bpt, itp->t_seekpt);
 198:         }
 199:         dp = rst_readdir(dirp);
 200:         bpt = telldir(dirp);
 201:     }
 202:     if (dp == NULL)
 203:         fprintf(stderr, "corrupted directory: %s.\n", locname);
 204: }
 205: 
 206: /*
 207:  * Search the directory tree rooted at inode ROOTINO
 208:  * for the path pointed at by n
 209:  */
 210: ino_t
 211: psearch(n)
 212:     char    *n;
 213: {
 214:     register char *cp, *cp1;
 215:     ino_t ino;
 216:     char c;
 217: 
 218:     ino = ROOTINO;
 219:     if (*(cp = n) == '/')
 220:         cp++;
 221: next:
 222:     cp1 = cp + 1;
 223:     while (*cp1 != '/' && *cp1)
 224:         cp1++;
 225:     c = *cp1;
 226:     *cp1 = 0;
 227:     ino = search(ino, cp);
 228:     if (ino == 0) {
 229:         *cp1 = c;
 230:         return(0);
 231:     }
 232:     *cp1 = c;
 233:     if (c == '/') {
 234:         cp = cp1+1;
 235:         goto next;
 236:     }
 237:     return(ino);
 238: }
 239: 
 240: /*
 241:  * search the directory inode ino
 242:  * looking for entry cp
 243:  */
 244: ino_t
 245: search(inum, cp)
 246:     ino_t   inum;
 247:     char    *cp;
 248: {
 249:     register struct direct *dp;
 250:     register struct inotab *itp;
 251:     int len;
 252: 
 253:     itp = inotablookup(inum);
 254:     if (itp == NULL)
 255:         return(0);
 256:     rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
 257:     len = strlen(cp);
 258:     do {
 259:         dp = rst_readdir(dirp);
 260:         if (dp == NULL || dp->d_ino == 0)
 261:             return (0);
 262:     } while (dp->d_namlen != len || strncmp(dp->d_name, cp, len) != 0);
 263:     return(dp->d_ino);
 264: }
 265: 
 266: /*
 267:  * Put the directory entries in the directory file
 268:  */
 269: putdir(buf, size)
 270:     char *buf;
 271:     int size;
 272: {
 273:     struct direct cvtbuf;
 274:     register struct odirect *odp;
 275:     struct odirect *eodp;
 276:     register struct direct *dp;
 277:     long loc, i;
 278:     extern int Bcvt;
 279: 
 280:     if (cvtflag) {
 281:         eodp = (struct odirect *)&buf[size];
 282:         for (odp = (struct odirect *)buf; odp < eodp; odp++)
 283:             if (odp->d_ino != 0) {
 284:                 dcvt(odp, &cvtbuf);
 285:                 putent(&cvtbuf);
 286:             }
 287:     } else {
 288:         for (loc = 0; loc < size; ) {
 289:             dp = (struct direct *)(buf + loc);
 290:             if (Bcvt) {
 291:                 swabst("l2s", (char *) dp);
 292:             }
 293:             i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1));
 294:             if (dp->d_reclen == 0 || dp->d_reclen > i) {
 295:                 loc += i;
 296:                 continue;
 297:             }
 298:             loc += dp->d_reclen;
 299:             if (dp->d_ino != 0) {
 300:                 putent(dp);
 301:             }
 302:         }
 303:     }
 304: }
 305: 
 306: /*
 307:  * These variables are "local" to the following two functions.
 308:  */
 309: char dirbuf[DIRBLKSIZ];
 310: long dirloc = 0;
 311: long prev = 0;
 312: 
 313: /*
 314:  * add a new directory entry to a file.
 315:  */
 316: putent(dp)
 317:     struct direct *dp;
 318: {
 319:     dp->d_reclen = DIRSIZ(dp);
 320:     if (dirloc + dp->d_reclen > DIRBLKSIZ) {
 321:         ((struct direct *)(dirbuf + prev))->d_reclen =
 322:             DIRBLKSIZ - prev;
 323:         (void) fwrite(dirbuf, 1, DIRBLKSIZ, df);
 324:         dirloc = 0;
 325:     }
 326:     bcopy((char *)dp, dirbuf + dirloc, (long)dp->d_reclen);
 327:     prev = dirloc;
 328:     dirloc += dp->d_reclen;
 329: }
 330: 
 331: /*
 332:  * flush out a directory that is finished.
 333:  */
 334: flushent()
 335: {
 336: 
 337:     ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
 338:     (void) fwrite(dirbuf, (int)dirloc, 1, df);
 339:     seekpt = ftell(df);
 340:     dirloc = 0;
 341: }
 342: 
 343: dcvt(odp, ndp)
 344:     register struct odirect *odp;
 345:     register struct direct *ndp;
 346: {
 347: 
 348:     bzero((char *)ndp, (long)(sizeof *ndp));
 349:     ndp->d_ino =  odp->d_ino;
 350:     (void) strncpy(ndp->d_name, odp->d_name, ODIRSIZ);
 351:     ndp->d_namlen = strlen(ndp->d_name);
 352:     ndp->d_reclen = DIRSIZ(ndp);
 353: }
 354: 
 355: /*
 356:  * Seek to an entry in a directory.
 357:  * Only values returned by ``telldir'' should be passed to rst_seekdir.
 358:  * This routine handles many directories in a single file.
 359:  * It takes the base of the directory in the file, plus
 360:  * the desired seek offset into it.
 361:  */
 362: void
 363: rst_seekdir(dirp, loc, base)
 364:     register DIR *dirp;
 365:     daddr_t loc, base;
 366: {
 367: 
 368:     if (loc == telldir(dirp))
 369:         return;
 370:     loc -= base;
 371:     if (loc < 0)
 372:         fprintf(stderr, "bad seek pointer to rst_seekdir %d\n", loc);
 373:     (void) lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), 0);
 374:     dirp->dd_loc = loc & (DIRBLKSIZ - 1);
 375:     if (dirp->dd_loc != 0)
 376:         dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ);
 377: }
 378: 
 379: /*
 380:  * get next entry in a directory.
 381:  */
 382: struct direct *
 383: rst_readdir(dirp)
 384:     register DIR *dirp;
 385: {
 386:     register struct direct *dp;
 387: 
 388:     for (;;) {
 389:         if (dirp->dd_loc == 0) {
 390:             dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
 391:                 DIRBLKSIZ);
 392:             if (dirp->dd_size <= 0) {
 393:                 dprintf(stderr, "error reading directory\n");
 394:                 return NULL;
 395:             }
 396:         }
 397:         if (dirp->dd_loc >= dirp->dd_size) {
 398:             dirp->dd_loc = 0;
 399:             continue;
 400:         }
 401:         dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc);
 402:         if (dp->d_reclen == 0 ||
 403:             dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) {
 404:             dprintf(stderr, "corrupted directory: bad reclen %d\n",
 405:                 dp->d_reclen);
 406:             return NULL;
 407:         }
 408:         dirp->dd_loc += dp->d_reclen;
 409:         if (dp->d_ino == 0 && strcmp(dp->d_name, "/") != 0)
 410:             continue;
 411:         if (dp->d_ino >= maxino) {
 412:             dprintf(stderr, "corrupted directory: bad inum %d\n",
 413:                 dp->d_ino);
 414:             continue;
 415:         }
 416:         return (dp);
 417:     }
 418: }
 419: 
 420: /*
 421:  * Simulate the opening of a directory
 422:  */
 423: DIR *
 424: rst_opendir(name)
 425:     char *name;
 426: {
 427:     struct inotab *itp;
 428:     ino_t ino;
 429: 
 430:     if ((ino = dirlookup(name)) > 0 &&
 431:         (itp = inotablookup(ino)) != NULL) {
 432:         rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
 433:         return (dirp);
 434:     }
 435:     return (0);
 436: }
 437: 
 438: /*
 439:  * Set the mode, owner, and times for all new or changed directories
 440:  */
 441: setdirmodes()
 442: {
 443:     FILE *mf;
 444:     struct modeinfo node;
 445:     struct entry *ep;
 446:     char *cp;
 447: 
 448:     vprintf(stdout, "Set directory mode, owner, and times.\n");
 449:     (void) sprintf(modefile, "/tmp/rstmode%d", dumpdate);
 450:     mf = fopen(modefile, "r");
 451:     if (mf == NULL) {
 452:         perror("fopen");
 453:         fprintf(stderr, "cannot open mode file %s\n", modefile);
 454:         fprintf(stderr, "directory mode, owner, and times not set\n");
 455:         return;
 456:     }
 457:     clearerr(mf);
 458:     for (;;) {
 459:         (void) fread((char *)&node, 1, sizeof(struct modeinfo), mf);
 460:         if (feof(mf))
 461:             break;
 462:         ep = lookupino(node.ino);
 463:         if (command == 'i' || command == 'x') {
 464:             if (ep == NIL)
 465:                 continue;
 466:             if (ep->e_flags & EXISTED) {
 467:                 ep->e_flags &= ~NEW;
 468:                 continue;
 469:             }
 470:             if (node.ino == ROOTINO &&
 471:                 reply("set owner/mode for '.'") == FAIL)
 472:                 continue;
 473:         }
 474:         if (ep == NIL)
 475:             panic("cannot find directory inode %d\n", node.ino);
 476:         cp = myname(ep);
 477:         (void) chown(cp, node.uid, node.gid);
 478:         (void) chmod(cp, node.mode);
 479:         utime(cp, node.timep);
 480:         ep->e_flags &= ~NEW;
 481:     }
 482:     if (ferror(mf))
 483:         panic("error setting directory modes\n");
 484:     (void) fclose(mf);
 485: }
 486: 
 487: /*
 488:  * Generate a literal copy of a directory.
 489:  */
 490: genliteraldir(name, ino)
 491:     char *name;
 492:     ino_t ino;
 493: {
 494:     register struct inotab *itp;
 495:     int ofile, dp, i, size;
 496:     char buf[BUFSIZ];
 497: 
 498:     itp = inotablookup(ino);
 499:     if (itp == NULL)
 500:         panic("Cannot find directory inode %d named %s\n", ino, name);
 501:     if ((ofile = creat(name, 0666)) < 0) {
 502:         fprintf(stderr, "%s: ", name);
 503:         (void) fflush(stderr);
 504:         perror("cannot create file");
 505:         return (FAIL);
 506:     }
 507:     rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
 508:     dp = dup(dirp->dd_fd);
 509:     for (i = itp->t_size; i > 0; i -= BUFSIZ) {
 510:         size = i < BUFSIZ ? i : BUFSIZ;
 511:         if (read(dp, buf, (int) size) == -1) {
 512:             fprintf(stderr,
 513:                 "write error extracting inode %d, name %s\n",
 514:                 curfile.ino, curfile.name);
 515:             perror("read");
 516:             done(1);
 517:         }
 518:         if (write(ofile, buf, (int) size) == -1) {
 519:             fprintf(stderr,
 520:                 "write error extracting inode %d, name %s\n",
 521:                 curfile.ino, curfile.name);
 522:             perror("write");
 523:             done(1);
 524:         }
 525:     }
 526:     (void) close(dp);
 527:     (void) close(ofile);
 528:     return (GOOD);
 529: }
 530: 
 531: /*
 532:  * Determine the type of an inode
 533:  */
 534: inodetype(ino)
 535:     ino_t ino;
 536: {
 537:     struct inotab *itp;
 538: 
 539:     itp = inotablookup(ino);
 540:     if (itp == NULL)
 541:         return (LEAF);
 542:     return (NODE);
 543: }
 544: 
 545: /*
 546:  * Allocate and initialize a directory inode entry.
 547:  * If requested, save its pertinent mode, owner, and time info.
 548:  */
 549: struct inotab *
 550: allocinotab(ino, dip, seekpt)
 551:     ino_t ino;
 552:     struct dinode *dip;
 553:     daddr_t seekpt;
 554: {
 555:     register struct inotab  *itp;
 556:     struct modeinfo node;
 557: 
 558:     itp = (struct inotab *)calloc(1, sizeof(struct inotab));
 559:     if (itp == 0)
 560:         panic("no memory directory table\n");
 561:     itp->t_next = inotab[INOHASH(ino)];
 562:     inotab[INOHASH(ino)] = itp;
 563:     itp->t_ino = ino;
 564:     itp->t_seekpt = seekpt;
 565:     if (mf == NULL)
 566:         return(itp);
 567:     node.ino = ino;
 568:     node.timep[0] = dip->di_atime;
 569:     node.timep[1] = dip->di_mtime;
 570:     node.mode = dip->di_mode;
 571:     node.uid = dip->di_uid;
 572:     node.gid = dip->di_gid;
 573:     (void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf);
 574:     return(itp);
 575: }
 576: 
 577: /*
 578:  * Look up an inode in the table of directories
 579:  */
 580: struct inotab *
 581: inotablookup(ino)
 582:     ino_t   ino;
 583: {
 584:     register struct inotab *itp;
 585: 
 586:     for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next)
 587:         if (itp->t_ino == ino)
 588:             return(itp);
 589:     return ((struct inotab *)0);
 590: }
 591: 
 592: /*
 593:  * Clean up and exit
 594:  */
 595: done(exitcode)
 596:     int exitcode;
 597: {
 598: 
 599:     closemt();
 600:     if (modefile[0] != '#')
 601:         (void) unlink(modefile);
 602:     if (dirfile[0] != '#')
 603:         (void) unlink(dirfile);
 604:     exit(exitcode);
 605: }

Defined functions

allocinotab defined in line 549; used 2 times
dcvt defined in line 343; used 1 times
extractdirs defined in line 68; used 5 times
flushent defined in line 334; used 1 times
genliteraldir defined in line 490; used 2 times
inodetype defined in line 534; used 2 times
inotablookup defined in line 580; used 6 times
psearch defined in line 210; used 3 times
putdir defined in line 269; used 2 times
putent defined in line 316; used 3 times
rst_readdir defined in line 382; used 9 times
rst_seekdir defined in line 362; used 6 times
search defined in line 244; used 2 times
skipdirs defined in line 129; used 4 times
treescan defined in line 141; used 8 times

Defined variables

dirbuf defined in line 309; used 5 times
dirfile defined in line 47; used 6 times
dirloc defined in line 310; used 7 times
inotab defined in line 26; used 3 times
modefile defined in line 48; used 8 times
prev defined in line 311; used 5 times
sccsid defined in line 8; never used

Defined struct's

inotab defined in line 20; used 34 times
modeinfo defined in line 33; used 8 times
odirect defined in line 57; used 10 times

Defined macros

HASHSIZE defined in line 18; used 2 times
INOHASH defined in line 19; used 3 times
ODIRSIZ defined in line 56; used 2 times
Last modified: 1986-04-23
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1974
Valid CSS Valid XHTML 1.0 Strict