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