|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)dirs.c 3.16 (Berkeley) 83/08/11";
3: #endif
4:
5: /* Copyright (c) 1983 Regents of the University of California */
6:
7: #include "restore.h"
8: #include <dumprestor.h>
9: #include <sys/file.h>
10: #include <sys/dir.h>
11:
12: /*
13: * Symbol table of directories read from tape.
14: */
15: #define HASHSIZE 1000
16: #define INOHASH(val) (val % HASHSIZE)
17: struct inotab {
18: struct inotab *t_next;
19: ino_t t_ino;
20: daddr_t t_seekpt;
21: long t_size;
22: };
23: static struct inotab *inotab[HASHSIZE];
24: extern struct inotab *inotablookup();
25: extern struct inotab *allocinotab();
26:
27: /*
28: * Information retained about directories.
29: */
30: struct modeinfo {
31: ino_t ino;
32: time_t timep[2];
33: short mode;
34: short uid;
35: short gid;
36: };
37:
38: /*
39: * Global variables for this file.
40: */
41: static daddr_t seekpt;
42: static FILE *df, *mf;
43: static DIR *dirp;
44: static char dirfile[32] = "#"; /* No file */
45: static char modefile[32] = "#"; /* No file */
46: extern ino_t search();
47: struct direct *rst_readdir();
48: extern void rst_seekdir();
49:
50: /*
51: * Format of old style directories.
52: */
53: #define ODIRSIZ 14
54: struct odirect {
55: u_short d_ino;
56: char d_name[ODIRSIZ];
57: };
58:
59: /*
60: * Structure and routines associated with listing directories.
61: */
62: struct afile {
63: ino_t fnum; /* inode number of file */
64: char *fname; /* file name */
65: short fflags; /* extraction flags, if any */
66: char ftype; /* file type, e.g. LEAF or NODE */
67: };
68: extern int fcmp();
69: extern char *fmtentry();
70:
71: /*
72: * Extract directory contents, building up a directory structure
73: * on disk for extraction by name.
74: * If genmode is requested, save mode, owner, and times for all
75: * directories on the tape.
76: */
77: extractdirs(genmode)
78: int genmode;
79: {
80: register int i;
81: register struct dinode *ip;
82: struct inotab *itp;
83: struct direct nulldir;
84: int putdir(), null();
85:
86: vprintf(stdout, "Extract directories from tape\n");
87: (void) sprintf(dirfile, "/tmp/rstdir%d", dumpdate);
88: df = fopen(dirfile, "w");
89: if (df == 0) {
90: fprintf(stderr,
91: "restor: %s - cannot create directory temporary\n",
92: dirfile);
93: perror("fopen");
94: done(1);
95: }
96: if (genmode != 0) {
97: (void) sprintf(modefile, "/tmp/rstmode%d", dumpdate);
98: mf = fopen(modefile, "w");
99: if (mf == 0) {
100: fprintf(stderr,
101: "restor: %s - cannot create modefile \n",
102: modefile);
103: perror("fopen");
104: done(1);
105: }
106: }
107: nulldir.d_ino = 0;
108: nulldir.d_namlen = 1;
109: (void) strcpy(nulldir.d_name, "/");
110: nulldir.d_reclen = DIRSIZ(&nulldir);
111: for (;;) {
112: curfile.name = "<directory file - name unknown>";
113: curfile.action = USING;
114: ip = curfile.dip;
115: i = ip->di_mode & IFMT;
116: if (i != IFDIR) {
117: (void) fclose(df);
118: dirp = opendir(dirfile);
119: if (dirp == NULL)
120: perror("opendir");
121: if (mf != NULL)
122: (void) fclose(mf);
123: i = dirlookup(".");
124: if (i == 0)
125: panic("Root directory is not on tape\n");
126: return;
127: }
128: itp = allocinotab(curfile.ino, ip, seekpt);
129: getfile(putdir, null);
130: putent(&nulldir);
131: flushent();
132: itp->t_size = seekpt - itp->t_seekpt;
133: }
134: }
135:
136: /*
137: * skip over all the directories on the tape
138: */
139: skipdirs()
140: {
141:
142: while ((curfile.dip->di_mode & IFMT) == IFDIR) {
143: skipfile();
144: }
145: }
146:
147: /*
148: * Recursively find names and inumbers of all files in subtree
149: * pname and pass them off to be processed.
150: */
151: treescan(pname, ino, todo)
152: char *pname;
153: ino_t ino;
154: long (*todo)();
155: {
156: register struct inotab *itp;
157: register struct direct *dp;
158: register struct entry *np;
159: int namelen;
160: daddr_t bpt;
161: char locname[MAXPATHLEN + 1];
162:
163: itp = inotablookup(ino);
164: if (itp == NULL) {
165: /*
166: * Pname is name of a simple file or an unchanged directory.
167: */
168: (void) (*todo)(pname, ino, LEAF);
169: return;
170: }
171: /*
172: * Pname is a dumped directory name.
173: */
174: if ((*todo)(pname, ino, NODE) == FAIL)
175: return;
176: /*
177: * begin search through the directory
178: * skipping over "." and ".."
179: */
180: (void) strncpy(locname, pname, MAXPATHLEN);
181: (void) strncat(locname, "/", MAXPATHLEN);
182: namelen = strlen(locname);
183: rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
184: dp = rst_readdir(dirp); /* "." or ".." */
185: if (dp != NULL &&
186: (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)) {
187: dp = rst_readdir(dirp); /* "." or ".." */
188: } else {
189: np = lookupino(ino);
190: if (np == NULL)
191: panic("corrupted symbol table\n");
192: fprintf(stderr, ". and .. are not the first two entries in directory %s\n", myname(np));
193: dp = (struct direct *)NULL;
194: }
195: if (dp != NULL &&
196: (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)) {
197: dp = rst_readdir(dirp); /* first real entry */
198: } else {
199: np = lookupino(ino);
200: if (np == NULL)
201: panic("corrupted symbol table\n");
202: fprintf(stderr, ". and .. are not the first two entries in directory %s\n", myname(np));
203: dp = (struct direct *)NULL;
204: }
205: bpt = telldir(dirp);
206: /*
207: * a zero inode signals end of directory
208: */
209: while (dp != NULL && dp->d_ino != 0) {
210: locname[namelen] = '\0';
211: if (namelen + dp->d_namlen >= MAXPATHLEN) {
212: fprintf(stderr, "%s%s: name exceeds %d char\n",
213: locname, dp->d_name, MAXPATHLEN);
214: } else {
215: (void) strncat(locname, dp->d_name, (int)dp->d_namlen);
216: treescan(locname, dp->d_ino, todo);
217: rst_seekdir(dirp, bpt, itp->t_seekpt);
218: }
219: dp = rst_readdir(dirp);
220: bpt = telldir(dirp);
221: }
222: if (dp == NULL)
223: fprintf(stderr, "corrupted directory: %s.\n", locname);
224: }
225:
226: /*
227: * Search the directory tree rooted at inode ROOTINO
228: * for the path pointed at by n
229: */
230: ino_t
231: psearch(n)
232: char *n;
233: {
234: register char *cp, *cp1;
235: ino_t ino;
236: char c;
237:
238: ino = ROOTINO;
239: if (*(cp = n) == '/')
240: cp++;
241: next:
242: cp1 = cp + 1;
243: while (*cp1 != '/' && *cp1)
244: cp1++;
245: c = *cp1;
246: *cp1 = 0;
247: ino = search(ino, cp);
248: if (ino == 0) {
249: *cp1 = c;
250: return(0);
251: }
252: *cp1 = c;
253: if (c == '/') {
254: cp = cp1+1;
255: goto next;
256: }
257: return(ino);
258: }
259:
260: /*
261: * search the directory inode ino
262: * looking for entry cp
263: */
264: ino_t
265: search(inum, cp)
266: ino_t inum;
267: char *cp;
268: {
269: register struct direct *dp;
270: register struct inotab *itp;
271: int len;
272:
273: itp = inotablookup(inum);
274: if (itp == NULL)
275: return(0);
276: rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
277: len = strlen(cp);
278: do {
279: dp = rst_readdir(dirp);
280: if (dp == NULL || dp->d_ino == 0)
281: return (0);
282: } while (dp->d_namlen != len || strncmp(dp->d_name, cp, len) != 0);
283: return(dp->d_ino);
284: }
285:
286: /*
287: * Put the directory entries in the directory file
288: */
289: putdir(buf, size)
290: char *buf;
291: int size;
292: {
293: struct direct cvtbuf;
294: register struct odirect *odp;
295: struct odirect *eodp;
296: register struct direct *dp;
297: long loc, i;
298:
299: if (cvtflag) {
300: eodp = (struct odirect *)&buf[size];
301: for (odp = (struct odirect *)buf; odp < eodp; odp++)
302: if (odp->d_ino != 0) {
303: dcvt(odp, &cvtbuf);
304: putent(&cvtbuf);
305: }
306: } else {
307: for (loc = 0; loc < size; ) {
308: dp = (struct direct *)(buf + loc);
309: i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1));
310: if (dp->d_reclen == 0 || dp->d_reclen > i) {
311: loc += i;
312: continue;
313: }
314: loc += dp->d_reclen;
315: if (dp->d_ino != 0) {
316: putent(dp);
317: }
318: }
319: }
320: }
321:
322: /*
323: * These variables are "local" to the following two functions.
324: */
325: char dirbuf[DIRBLKSIZ];
326: long dirloc = 0;
327: long prev = 0;
328:
329: /*
330: * add a new directory entry to a file.
331: */
332: putent(dp)
333: struct direct *dp;
334: {
335: dp->d_reclen = DIRSIZ(dp);
336: if (dirloc + dp->d_reclen > DIRBLKSIZ) {
337: ((struct direct *)(dirbuf + prev))->d_reclen =
338: DIRBLKSIZ - prev;
339: (void) fwrite(dirbuf, 1, DIRBLKSIZ, df);
340: dirloc = 0;
341: }
342: bcopy((char *)dp, dirbuf + dirloc, (long)dp->d_reclen);
343: prev = dirloc;
344: dirloc += dp->d_reclen;
345: }
346:
347: /*
348: * flush out a directory that is finished.
349: */
350: flushent()
351: {
352:
353: ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
354: (void) fwrite(dirbuf, (int)dirloc, 1, df);
355: seekpt = ftell(df);
356: dirloc = 0;
357: }
358:
359: dcvt(odp, ndp)
360: register struct odirect *odp;
361: register struct direct *ndp;
362: {
363:
364: bzero((char *)ndp, (long)(sizeof *ndp));
365: ndp->d_ino = odp->d_ino;
366: (void) strncpy(ndp->d_name, odp->d_name, ODIRSIZ);
367: ndp->d_namlen = strlen(ndp->d_name);
368: ndp->d_reclen = DIRSIZ(ndp);
369: }
370:
371: /*
372: * Seek to an entry in a directory.
373: * Only values returned by ``telldir'' should be passed to rst_seekdir.
374: * This routine handles many directories in a single file.
375: * It takes the base of the directory in the file, plus
376: * the desired seek offset into it.
377: */
378: void
379: rst_seekdir(dirp, loc, base)
380: register DIR *dirp;
381: daddr_t loc, base;
382: {
383:
384: if (loc == telldir(dirp))
385: return;
386: loc -= base;
387: if (loc < 0)
388: fprintf(stderr, "bad seek pointer to rst_seekdir %d\n", loc);
389: (void) lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), 0);
390: dirp->dd_loc = loc & (DIRBLKSIZ - 1);
391: if (dirp->dd_loc != 0)
392: dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ);
393: }
394:
395: /*
396: * get next entry in a directory.
397: */
398: struct direct *
399: rst_readdir(dirp)
400: register DIR *dirp;
401: {
402: register struct direct *dp;
403:
404: for (;;) {
405: if (dirp->dd_loc == 0) {
406: dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
407: DIRBLKSIZ);
408: if (dirp->dd_size <= 0) {
409: dprintf(stderr, "error reading directory\n");
410: return NULL;
411: }
412: }
413: if (dirp->dd_loc >= dirp->dd_size) {
414: dirp->dd_loc = 0;
415: continue;
416: }
417: dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc);
418: if (dp->d_reclen == 0 ||
419: dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) {
420: dprintf(stderr, "corrupted directory: bad reclen %d\n",
421: dp->d_reclen);
422: return NULL;
423: }
424: dirp->dd_loc += dp->d_reclen;
425: if (dp->d_ino == 0 && strcmp(dp->d_name, "/") != 0)
426: continue;
427: if (dp->d_ino >= maxino) {
428: dprintf(stderr, "corrupted directory: bad inum %d\n",
429: dp->d_ino);
430: continue;
431: }
432: return (dp);
433: }
434: }
435:
436: /*
437: * Set the mode, owner, and times for all new or changed directories
438: */
439: setdirmodes()
440: {
441: FILE *mf;
442: struct modeinfo node;
443: struct entry *ep;
444: char *cp;
445:
446: vprintf(stdout, "Set directory mode, owner, and times.\n");
447: mf = fopen(modefile, "r");
448: if (mf == NULL) {
449: perror("fopen");
450: panic("cannot open mode file %s\n", modefile);
451: }
452: clearerr(mf);
453: for (;;) {
454: (void) fread((char *)&node, 1, sizeof(struct modeinfo), mf);
455: if (feof(mf))
456: break;
457: ep = lookupino(node.ino);
458: if (command == 'i' || command == 'x' || command == 'X') {
459: if (ep == NIL)
460: continue;
461: if (node.ino == ROOTINO &&
462: reply("set owner/mode for '.'") == FAIL)
463: continue;
464: }
465: if (ep == NIL)
466: panic("cannot find directory inode %d\n", node.ino);
467: cp = myname(ep);
468: (void) chown(cp, node.uid, node.gid);
469: (void) chmod(cp, node.mode);
470: utime(cp, node.timep);
471: ep->e_flags &= ~NEW;
472: }
473: if (ferror(mf))
474: panic("error setting directory modes\n");
475: (void) fclose(mf);
476: }
477:
478: /*
479: * Generate a literal copy of a directory.
480: */
481: genliteraldir(name, ino)
482: char *name;
483: ino_t ino;
484: {
485: register struct inotab *itp;
486: int ofile, dp, i, size;
487: char buf[BUFSIZ];
488:
489: itp = inotablookup(ino);
490: if (itp == NULL)
491: panic("Cannot find directory inode %d named %s\n", ino, name);
492: if ((ofile = creat(name, 0666)) < 0) {
493: fprintf(stderr, "%s: ", name);
494: (void) fflush(stderr);
495: perror("cannot create file");
496: return (FAIL);
497: }
498: rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
499: dp = dup(dirp->dd_fd);
500: for (i = itp->t_size; i > 0; i -= BUFSIZ) {
501: size = i < BUFSIZ ? i : BUFSIZ;
502: if (read(dp, buf, (int) size) == -1) {
503: fprintf(stderr,
504: "write error extracting inode %d, name %s\n",
505: curfile.ino, curfile.name);
506: perror("read");
507: done(1);
508: }
509: if (write(ofile, buf, (int) size) == -1) {
510: fprintf(stderr,
511: "write error extracting inode %d, name %s\n",
512: curfile.ino, curfile.name);
513: perror("write");
514: done(1);
515: }
516: }
517: (void) close(dp);
518: (void) close(ofile);
519: return (GOOD);
520: }
521:
522: /*
523: * Do an "ls" style listing of a directory
524: */
525: printlist(name, ino)
526: char *name;
527: ino_t ino;
528: {
529: register struct afile *fp;
530: register struct inotab *itp;
531: struct afile *dfp0, *dfplast;
532: struct afile single;
533:
534: itp = inotablookup(ino);
535: if (itp == NULL) {
536: single.fnum = ino;
537: single.fname = savename(rindex(name, '/') + 1);
538: dfp0 = &single;
539: dfplast = dfp0 + 1;
540: } else {
541: rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
542: if (getdir(dirp, &dfp0, &dfplast) == FAIL)
543: return;
544: }
545: qsort((char *)dfp0, dfplast - dfp0, sizeof (struct afile), fcmp);
546: formatf(dfp0, dfplast);
547: for (fp = dfp0; fp < dfplast; fp++)
548: freename(fp->fname);
549: }
550:
551: /*
552: * Read the contents of a directory.
553: */
554: getdir(dirp, pfp0, pfplast)
555: DIR *dirp;
556: struct afile **pfp0, **pfplast;
557: {
558: register struct afile *fp;
559: register struct direct *dp;
560: static struct afile *basefp = NULL;
561: static long nent = 20;
562:
563: if (basefp == NULL) {
564: basefp = (struct afile *)calloc((unsigned)nent,
565: sizeof (struct afile));
566: if (basefp == NULL) {
567: fprintf(stderr, "ls: out of memory\n");
568: return (FAIL);
569: }
570: }
571: fp = *pfp0 = basefp;
572: *pfplast = *pfp0 + nent;
573: while (dp = rst_readdir(dirp)) {
574: if (dp == NULL || dp->d_ino == 0)
575: break;
576: if (!dflag && BIT(dp->d_ino, dumpmap) == 0)
577: continue;
578: if (vflag == 0 &&
579: (strcmp(dp->d_name, ".") == 0 ||
580: strcmp(dp->d_name, "..") == 0))
581: continue;
582: fp->fnum = dp->d_ino;
583: fp->fname = savename(dp->d_name);
584: fp++;
585: if (fp == *pfplast) {
586: basefp = (struct afile *)realloc((char *)basefp,
587: (unsigned)(2 * nent * sizeof (struct afile)));
588: if (basefp == 0) {
589: fprintf(stderr, "ls: out of memory\n");
590: return (FAIL);
591: }
592: *pfp0 = basefp;
593: fp = *pfp0 + nent;
594: *pfplast = fp + nent;
595: nent *= 2;
596: }
597: }
598: *pfplast = fp;
599: return (GOOD);
600: }
601:
602: /*
603: * Print out a pretty listing of a directory
604: */
605: formatf(fp0, fplast)
606: struct afile *fp0, *fplast;
607: {
608: register struct afile *fp;
609: struct entry *np;
610: int width = 0, w, nentry = fplast - fp0;
611: int i, j, len, columns, lines;
612: char *cp;
613:
614: if (fp0 == fplast)
615: return;
616: for (fp = fp0; fp < fplast; fp++) {
617: fp->ftype = inodetype(fp->fnum);
618: np = lookupino(fp->fnum);
619: if (np != NIL)
620: fp->fflags = np->e_flags;
621: else
622: fp->fflags = 0;
623: len = strlen(fmtentry(fp));
624: if (len > width)
625: width = len;
626: }
627: width += 2;
628: columns = 80 / width;
629: if (columns == 0)
630: columns = 1;
631: lines = (nentry + columns - 1) / columns;
632: for (i = 0; i < lines; i++) {
633: for (j = 0; j < columns; j++) {
634: fp = fp0 + j * lines + i;
635: cp = fmtentry(fp);
636: fprintf(stderr, "%s", cp);
637: if (fp + lines >= fplast) {
638: fprintf(stderr, "\n");
639: break;
640: }
641: w = strlen(cp);
642: while (w < width) {
643: w++;
644: fprintf(stderr, " ");
645: }
646: }
647: }
648: }
649:
650: /*
651: * Comparison routine for qsort.
652: */
653: fcmp(f1, f2)
654: register struct afile *f1, *f2;
655: {
656:
657: return (strcmp(f1->fname, f2->fname));
658: }
659:
660: /*
661: * Format a directory entry.
662: */
663: char *
664: fmtentry(fp)
665: register struct afile *fp;
666: {
667: static char fmtres[BUFSIZ];
668: register char *cp, *dp;
669:
670: if (vflag)
671: (void) sprintf(fmtres, "%5d ", fp->fnum);
672: else
673: fmtres[0] = '\0';
674: dp = &fmtres[strlen(fmtres)];
675: if (dflag && BIT(fp->fnum, dumpmap) == 0)
676: *dp++ = '^';
677: else if ((fp->fflags & NEW) != 0)
678: *dp++ = '*';
679: else
680: *dp++ = ' ';
681: for (cp = fp->fname; *cp; cp++)
682: if (!vflag && (*cp < ' ' || *cp >= 0177))
683: *dp++ = '?';
684: else
685: *dp++ = *cp;
686: if (fp->ftype == NODE)
687: *dp++ = '/';
688: *dp++ = 0;
689: return (fmtres);
690: }
691:
692: /*
693: * Determine the type of an inode
694: */
695: inodetype(ino)
696: ino_t ino;
697: {
698: struct inotab *itp;
699:
700: itp = inotablookup(ino);
701: if (itp == NULL)
702: return (LEAF);
703: return (NODE);
704: }
705:
706: /*
707: * Allocate and initialize a directory inode entry.
708: * If requested, save its pertinent mode, owner, and time info.
709: */
710: struct inotab *
711: allocinotab(ino, dip, seekpt)
712: ino_t ino;
713: struct dinode *dip;
714: daddr_t seekpt;
715: {
716: register struct inotab *itp;
717: struct modeinfo node;
718:
719: itp = (struct inotab *)calloc(1, sizeof(struct inotab));
720: if (itp == 0)
721: panic("no memory directory table\n");
722: itp->t_next = inotab[INOHASH(ino)];
723: inotab[INOHASH(ino)] = itp;
724: itp->t_ino = ino;
725: itp->t_seekpt = seekpt;
726: if (mf == NULL)
727: return(itp);
728: node.ino = ino;
729: node.timep[0] = dip->di_atime;
730: node.timep[1] = dip->di_mtime;
731: node.mode = dip->di_mode;
732: node.uid = dip->di_uid;
733: node.gid = dip->di_gid;
734: (void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf);
735: return(itp);
736: }
737:
738: /*
739: * Look up an inode in the table of directories
740: */
741: struct inotab *
742: inotablookup(ino)
743: ino_t ino;
744: {
745: register struct inotab *itp;
746:
747: for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next)
748: if (itp->t_ino == ino)
749: return(itp);
750: return ((struct inotab *)0);
751: }
752:
753: /*
754: * Clean up and exit
755: */
756: done(exitcode)
757: int exitcode;
758: {
759:
760: closemt();
761: if (modefile[0] != '#')
762: (void) unlink(modefile);
763: if (dirfile[0] != '#')
764: (void) unlink(dirfile);
765: exit(exitcode);
766: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.