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