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