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