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