|
|
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); /* "." */
185: if (dp != NULL && strcmp(dp->d_name, ".") == 0) {
186: dp = rst_readdir(dirp); /* ".." */
187: } else {
188: np = lookupino(ino);
189: if (np == NULL)
190: panic("corrupted symbol table\n");
191: fprintf(stderr, ". missing from directory %s\n", myname(np));
192: }
193: if (dp != NULL && strcmp(dp->d_name, "..") == 0) {
194: dp = rst_readdir(dirp); /* first real entry */
195: } else {
196: np = lookupino(ino);
197: if (np == NULL)
198: panic("corrupted symbol table\n");
199: fprintf(stderr, ".. missing from directory %s\n", myname(np));
200: }
201: bpt = telldir(dirp);
202: /*
203: * a zero inode signals end of directory
204: */
205: while (dp != NULL && dp->d_ino != 0) {
206: locname[namelen] = '\0';
207: if (namelen + dp->d_namlen >= MAXPATHLEN) {
208: fprintf(stderr, "%s%s: name exceeds %d char\n",
209: locname, dp->d_name, MAXPATHLEN);
210: } else {
211: (void) strncat(locname, dp->d_name, (int)dp->d_namlen);
212: treescan(locname, dp->d_ino, todo);
213: rst_seekdir(dirp, bpt, itp->t_seekpt);
214: }
215: dp = rst_readdir(dirp);
216: bpt = telldir(dirp);
217: }
218: if (dp == NULL)
219: fprintf(stderr, "corrupted directory: %s.\n", locname);
220: }
221:
222: /*
223: * Search the directory tree rooted at inode ROOTINO
224: * for the path pointed at by n
225: */
226: ino_t
227: psearch(n)
228: char *n;
229: {
230: register char *cp, *cp1;
231: ino_t ino;
232: char c;
233:
234: ino = ROOTINO;
235: if (*(cp = n) == '/')
236: cp++;
237: next:
238: cp1 = cp + 1;
239: while (*cp1 != '/' && *cp1)
240: cp1++;
241: c = *cp1;
242: *cp1 = 0;
243: ino = search(ino, cp);
244: if (ino == 0) {
245: *cp1 = c;
246: return(0);
247: }
248: *cp1 = c;
249: if (c == '/') {
250: cp = cp1+1;
251: goto next;
252: }
253: return(ino);
254: }
255:
256: /*
257: * search the directory inode ino
258: * looking for entry cp
259: */
260: ino_t
261: search(inum, cp)
262: ino_t inum;
263: char *cp;
264: {
265: register struct direct *dp;
266: register struct inotab *itp;
267: int len;
268:
269: itp = inotablookup(inum);
270: if (itp == NULL)
271: return(0);
272: rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
273: len = strlen(cp);
274: do {
275: dp = rst_readdir(dirp);
276: if (dp == NULL || dp->d_ino == 0)
277: return (0);
278: } while (dp->d_namlen != len || strncmp(dp->d_name, cp, len) != 0);
279: return(dp->d_ino);
280: }
281:
282: /*
283: * Put the directory entries in the directory file
284: */
285: putdir(buf, size)
286: char *buf;
287: int size;
288: {
289: struct direct cvtbuf;
290: register struct odirect *odp;
291: struct odirect *eodp;
292: register struct direct *dp;
293: long loc, i;
294:
295: if (cvtflag) {
296: eodp = (struct odirect *)&buf[size];
297: for (odp = (struct odirect *)buf; odp < eodp; odp++)
298: if (odp->d_ino != 0) {
299: dcvt(odp, &cvtbuf);
300: putent(&cvtbuf);
301: }
302: } else {
303: for (loc = 0; loc < size; ) {
304: dp = (struct direct *)(buf + loc);
305: i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1));
306: if (dp->d_reclen == 0 || dp->d_reclen > i) {
307: loc += i;
308: continue;
309: }
310: loc += dp->d_reclen;
311: if (dp->d_ino != 0) {
312: putent(dp);
313: }
314: }
315: }
316: }
317:
318: /*
319: * These variables are "local" to the following two functions.
320: */
321: char dirbuf[DIRBLKSIZ];
322: long dirloc = 0;
323: long prev = 0;
324:
325: /*
326: * add a new directory entry to a file.
327: */
328: putent(dp)
329: struct direct *dp;
330: {
331: dp->d_reclen = DIRSIZ(dp);
332: if (dirloc + dp->d_reclen > DIRBLKSIZ) {
333: ((struct direct *)(dirbuf + prev))->d_reclen =
334: DIRBLKSIZ - prev;
335: (void) fwrite(dirbuf, 1, DIRBLKSIZ, df);
336: dirloc = 0;
337: }
338: bcopy((char *)dp, dirbuf + dirloc, (long)dp->d_reclen);
339: prev = dirloc;
340: dirloc += dp->d_reclen;
341: }
342:
343: /*
344: * flush out a directory that is finished.
345: */
346: flushent()
347: {
348:
349: ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
350: (void) fwrite(dirbuf, (int)dirloc, 1, df);
351: seekpt = ftell(df);
352: dirloc = 0;
353: }
354:
355: dcvt(odp, ndp)
356: register struct odirect *odp;
357: register struct direct *ndp;
358: {
359:
360: bzero((char *)ndp, (long)(sizeof *ndp));
361: ndp->d_ino = odp->d_ino;
362: (void) strncpy(ndp->d_name, odp->d_name, ODIRSIZ);
363: ndp->d_namlen = strlen(ndp->d_name);
364: ndp->d_reclen = DIRSIZ(ndp);
365: }
366:
367: /*
368: * Seek to an entry in a directory.
369: * Only values returned by ``telldir'' should be passed to rst_seekdir.
370: * This routine handles many directories in a single file.
371: * It takes the base of the directory in the file, plus
372: * the desired seek offset into it.
373: */
374: void
375: rst_seekdir(dirp, loc, base)
376: register DIR *dirp;
377: daddr_t loc, base;
378: {
379:
380: if (loc == telldir(dirp))
381: return;
382: loc -= base;
383: if (loc < 0)
384: fprintf(stderr, "bad seek pointer to rst_seekdir %d\n", loc);
385: (void) lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), 0);
386: dirp->dd_loc = loc & (DIRBLKSIZ - 1);
387: if (dirp->dd_loc != 0)
388: dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ);
389: }
390:
391: /*
392: * get next entry in a directory.
393: */
394: struct direct *
395: rst_readdir(dirp)
396: register DIR *dirp;
397: {
398: register struct direct *dp;
399:
400: for (;;) {
401: if (dirp->dd_loc == 0) {
402: dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
403: DIRBLKSIZ);
404: if (dirp->dd_size <= 0) {
405: dprintf(stderr, "error reading directory\n");
406: return NULL;
407: }
408: }
409: if (dirp->dd_loc >= dirp->dd_size) {
410: dirp->dd_loc = 0;
411: continue;
412: }
413: dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc);
414: if (dp->d_reclen == 0 ||
415: dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) {
416: dprintf(stderr, "corrupted directory: bad reclen %d\n",
417: dp->d_reclen);
418: return NULL;
419: }
420: dirp->dd_loc += dp->d_reclen;
421: if (dp->d_ino == 0 && strcmp(dp->d_name, "/") != 0)
422: continue;
423: if (dp->d_ino >= maxino) {
424: dprintf(stderr, "corrupted directory: bad inum %d\n",
425: dp->d_ino);
426: continue;
427: }
428: return (dp);
429: }
430: }
431:
432: /*
433: * Set the mode, owner, and times for all new or changed directories
434: */
435: setdirmodes()
436: {
437: FILE *mf;
438: struct modeinfo node;
439: struct entry *ep;
440: char *cp;
441:
442: vprintf(stdout, "Set directory mode, owner, and times.\n");
443: mf = fopen(modefile, "r");
444: if (mf == NULL) {
445: perror("fopen");
446: panic("cannot open mode file %s\n", modefile);
447: }
448: clearerr(mf);
449: for (;;) {
450: (void) fread((char *)&node, 1, sizeof(struct modeinfo), mf);
451: if (feof(mf))
452: break;
453: ep = lookupino(node.ino);
454: if (command == 'i' || command == 'x') {
455: if (ep == NIL)
456: continue;
457: if (node.ino == ROOTINO &&
458: reply("set owner/mode for '.'") == FAIL)
459: continue;
460: }
461: if (ep == NIL)
462: panic("cannot find directory inode %d\n", node.ino);
463: cp = myname(ep);
464: (void) chown(cp, node.uid, node.gid);
465: (void) chmod(cp, node.mode);
466: utime(cp, node.timep);
467: ep->e_flags &= ~NEW;
468: }
469: if (ferror(mf))
470: panic("error setting directory modes\n");
471: (void) fclose(mf);
472: }
473:
474: /*
475: * Generate a literal copy of a directory.
476: */
477: genliteraldir(name, ino)
478: char *name;
479: ino_t ino;
480: {
481: register struct inotab *itp;
482: int ofile, dp, i, size;
483: char buf[BUFSIZ];
484:
485: itp = inotablookup(ino);
486: if (itp == NULL)
487: panic("Cannot find directory inode %d named %s\n", ino, name);
488: if ((ofile = creat(name, 0666)) < 0) {
489: fprintf(stderr, "%s: ", name);
490: (void) fflush(stderr);
491: perror("cannot create file");
492: return (FAIL);
493: }
494: rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
495: dp = dup(dirp->dd_fd);
496: for (i = itp->t_size; i > 0; i -= BUFSIZ) {
497: size = i < BUFSIZ ? i : BUFSIZ;
498: if (read(dp, buf, (int) size) == -1) {
499: fprintf(stderr,
500: "write error extracting inode %d, name %s\n",
501: curfile.ino, curfile.name);
502: perror("read");
503: done(1);
504: }
505: if (write(ofile, buf, (int) size) == -1) {
506: fprintf(stderr,
507: "write error extracting inode %d, name %s\n",
508: curfile.ino, curfile.name);
509: perror("write");
510: done(1);
511: }
512: }
513: (void) close(dp);
514: (void) close(ofile);
515: return (GOOD);
516: }
517:
518: /*
519: * Do an "ls" style listing of a directory
520: */
521: printlist(name, ino)
522: char *name;
523: ino_t ino;
524: {
525: register struct afile *fp;
526: register struct inotab *itp;
527: struct afile *dfp0, *dfplast;
528: struct afile single;
529:
530: itp = inotablookup(ino);
531: if (itp == NULL) {
532: single.fnum = ino;
533: single.fname = savename(rindex(name, '/') + 1);
534: dfp0 = &single;
535: dfplast = dfp0 + 1;
536: } else {
537: rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
538: if (getdir(dirp, &dfp0, &dfplast) == FAIL)
539: return;
540: }
541: qsort((char *)dfp0, dfplast - dfp0, sizeof (struct afile), fcmp);
542: formatf(dfp0, dfplast);
543: for (fp = dfp0; fp < dfplast; fp++)
544: freename(fp->fname);
545: }
546:
547: /*
548: * Read the contents of a directory.
549: */
550: getdir(dirp, pfp0, pfplast)
551: DIR *dirp;
552: struct afile **pfp0, **pfplast;
553: {
554: register struct afile *fp;
555: register struct direct *dp;
556: static struct afile *basefp = NULL;
557: static long nent = 20;
558:
559: if (basefp == NULL) {
560: basefp = (struct afile *)calloc((unsigned)nent,
561: sizeof (struct afile));
562: if (basefp == NULL) {
563: fprintf(stderr, "ls: out of memory\n");
564: return (FAIL);
565: }
566: }
567: fp = *pfp0 = basefp;
568: *pfplast = *pfp0 + nent;
569: while (dp = rst_readdir(dirp)) {
570: if (dp == NULL || dp->d_ino == 0)
571: break;
572: if (!dflag && BIT(dp->d_ino, dumpmap) == 0)
573: continue;
574: if (vflag == 0 &&
575: (strcmp(dp->d_name, ".") == 0 ||
576: strcmp(dp->d_name, "..") == 0))
577: continue;
578: fp->fnum = dp->d_ino;
579: fp->fname = savename(dp->d_name);
580: fp++;
581: if (fp == *pfplast) {
582: basefp = (struct afile *)realloc((char *)basefp,
583: (unsigned)(2 * nent * sizeof (struct afile)));
584: if (basefp == 0) {
585: fprintf(stderr, "ls: out of memory\n");
586: return (FAIL);
587: }
588: *pfp0 = basefp;
589: fp = *pfp0 + nent;
590: *pfplast = fp + nent;
591: nent *= 2;
592: }
593: }
594: *pfplast = fp;
595: return (GOOD);
596: }
597:
598: /*
599: * Print out a pretty listing of a directory
600: */
601: formatf(fp0, fplast)
602: struct afile *fp0, *fplast;
603: {
604: register struct afile *fp;
605: struct entry *np;
606: int width = 0, w, nentry = fplast - fp0;
607: int i, j, len, columns, lines;
608: char *cp;
609:
610: if (fp0 == fplast)
611: return;
612: for (fp = fp0; fp < fplast; fp++) {
613: fp->ftype = inodetype(fp->fnum);
614: np = lookupino(fp->fnum);
615: if (np != NIL)
616: fp->fflags = np->e_flags;
617: else
618: fp->fflags = 0;
619: len = strlen(fmtentry(fp));
620: if (len > width)
621: width = len;
622: }
623: width += 2;
624: columns = 80 / width;
625: if (columns == 0)
626: columns = 1;
627: lines = (nentry + columns - 1) / columns;
628: for (i = 0; i < lines; i++) {
629: for (j = 0; j < columns; j++) {
630: fp = fp0 + j * lines + i;
631: cp = fmtentry(fp);
632: fprintf(stderr, "%s", cp);
633: if (fp + lines >= fplast) {
634: fprintf(stderr, "\n");
635: break;
636: }
637: w = strlen(cp);
638: while (w < width) {
639: w++;
640: fprintf(stderr, " ");
641: }
642: }
643: }
644: }
645:
646: /*
647: * Comparison routine for qsort.
648: */
649: fcmp(f1, f2)
650: register struct afile *f1, *f2;
651: {
652:
653: return (strcmp(f1->fname, f2->fname));
654: }
655:
656: /*
657: * Format a directory entry.
658: */
659: char *
660: fmtentry(fp)
661: register struct afile *fp;
662: {
663: static char fmtres[BUFSIZ];
664: register char *cp, *dp;
665:
666: if (vflag)
667: (void) sprintf(fmtres, "%5d ", fp->fnum);
668: else
669: fmtres[0] = '\0';
670: dp = &fmtres[strlen(fmtres)];
671: if (dflag && BIT(fp->fnum, dumpmap) == 0)
672: *dp++ = '^';
673: else if ((fp->fflags & NEW) != 0)
674: *dp++ = '*';
675: else
676: *dp++ = ' ';
677: for (cp = fp->fname; *cp; cp++)
678: if (!vflag && (*cp < ' ' || *cp >= 0177))
679: *dp++ = '?';
680: else
681: *dp++ = *cp;
682: if (fp->ftype == NODE)
683: *dp++ = '/';
684: *dp++ = 0;
685: return (fmtres);
686: }
687:
688: /*
689: * Determine the type of an inode
690: */
691: inodetype(ino)
692: ino_t ino;
693: {
694: struct inotab *itp;
695:
696: itp = inotablookup(ino);
697: if (itp == NULL)
698: return (LEAF);
699: return (NODE);
700: }
701:
702: /*
703: * Allocate and initialize a directory inode entry.
704: * If requested, save its pertinent mode, owner, and time info.
705: */
706: struct inotab *
707: allocinotab(ino, dip, seekpt)
708: ino_t ino;
709: struct dinode *dip;
710: daddr_t seekpt;
711: {
712: register struct inotab *itp;
713: struct modeinfo node;
714:
715: itp = (struct inotab *)calloc(1, sizeof(struct inotab));
716: if (itp == 0)
717: panic("no memory directory table\n");
718: itp->t_next = inotab[INOHASH(ino)];
719: inotab[INOHASH(ino)] = itp;
720: itp->t_ino = ino;
721: itp->t_seekpt = seekpt;
722: if (mf == NULL)
723: return(itp);
724: node.ino = ino;
725: node.timep[0] = dip->di_atime;
726: node.timep[1] = dip->di_mtime;
727: node.mode = dip->di_mode;
728: node.uid = dip->di_uid;
729: node.gid = dip->di_gid;
730: (void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf);
731: return(itp);
732: }
733:
734: /*
735: * Look up an inode in the table of directories
736: */
737: struct inotab *
738: inotablookup(ino)
739: ino_t ino;
740: {
741: register struct inotab *itp;
742:
743: for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next)
744: if (itp->t_ino == ino)
745: return(itp);
746: return ((struct inotab *)0);
747: }
748:
749: /*
750: * Clean up and exit
751: */
752: done(exitcode)
753: int exitcode;
754: {
755:
756: closemt();
757: if (modefile[0] != '#')
758: (void) unlink(modefile);
759: if (dirfile[0] != '#')
760: (void) unlink(dirfile);
761: exit(exitcode);
762: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.