cleanup of byte swapping code
[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
8b58f36b 9static char sccsid[] = "@(#)dirs.c 5.13 (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();
56extern long rst_telldir();
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 */
9f13f26d 67extern ino_t search();
e9e7ecc4
KM
68struct direct *rst_readdir();
69extern void rst_seekdir();
f743fc86 70
7432ff81
KM
71/*
72 * Format of old style directories.
73 */
f743fc86
KM
74#define ODIRSIZ 14
75struct odirect {
76 u_short d_ino;
77 char d_name[ODIRSIZ];
78};
79
80/*
81 * Extract directory contents, building up a directory structure
82 * on disk for extraction by name.
7432ff81 83 * If genmode is requested, save mode, owner, and times for all
f743fc86
KM
84 * directories on the tape.
85 */
7432ff81
KM
86extractdirs(genmode)
87 int genmode;
f743fc86
KM
88{
89 register int i;
90 register struct dinode *ip;
9730f69a 91 struct inotab *itp;
f743fc86
KM
92 struct direct nulldir;
93 int putdir(), null();
94
95 vprintf(stdout, "Extract directories from tape\n");
7abf8d65 96 (void) sprintf(dirfile, "%s/rstdir%d", _PATH_TMP, dumpdate);
f743fc86
KM
97 df = fopen(dirfile, "w");
98 if (df == 0) {
99 fprintf(stderr,
97b06931 100 "restore: %s - cannot create directory temporary\n",
f743fc86
KM
101 dirfile);
102 perror("fopen");
103 done(1);
104 }
7432ff81 105 if (genmode != 0) {
7abf8d65 106 (void) sprintf(modefile, "%s/rstmode%d", _PATH_TMP, dumpdate);
f743fc86 107 mf = fopen(modefile, "w");
9f13f26d 108 if (mf == 0) {
f743fc86 109 fprintf(stderr,
97b06931 110 "restore: %s - cannot create modefile \n",
f743fc86
KM
111 modefile);
112 perror("fopen");
113 done(1);
114 }
115 }
9730f69a 116 nulldir.d_ino = 0;
f743fc86 117 nulldir.d_namlen = 1;
93d90477 118 (void) strcpy(nulldir.d_name, "/");
f743fc86
KM
119 nulldir.d_reclen = DIRSIZ(&nulldir);
120 for (;;) {
121 curfile.name = "<directory file - name unknown>";
122 curfile.action = USING;
123 ip = curfile.dip;
58ee757a 124 if (ip == NULL || (ip->di_mode & IFMT) != IFDIR) {
82d46726 125 (void) fclose(df);
97d5016b 126 dirp = opendirfile(dirfile);
f743fc86 127 if (dirp == NULL)
97d5016b 128 perror("opendirfile");
f743fc86 129 if (mf != NULL)
82d46726 130 (void) fclose(mf);
7432ff81
KM
131 i = dirlookup(".");
132 if (i == 0)
7851e15d 133 panic("Root directory is not on tape\n");
f743fc86
KM
134 return;
135 }
9730f69a 136 itp = allocinotab(curfile.ino, ip, seekpt);
f743fc86
KM
137 getfile(putdir, null);
138 putent(&nulldir);
139 flushent();
9730f69a
KM
140 itp->t_size = seekpt - itp->t_seekpt;
141 }
142}
143
144/*
145 * skip over all the directories on the tape
146 */
147skipdirs()
148{
149
150 while ((curfile.dip->di_mode & IFMT) == IFDIR) {
151 skipfile();
f743fc86
KM
152 }
153}
154
155/*
156 * Recursively find names and inumbers of all files in subtree
157 * pname and pass them off to be processed.
158 */
159treescan(pname, ino, todo)
160 char *pname;
161 ino_t ino;
314ac756 162 long (*todo)();
f743fc86
KM
163{
164 register struct inotab *itp;
93d90477
KM
165 register struct direct *dp;
166 register struct entry *np;
f743fc86
KM
167 int namelen;
168 daddr_t bpt;
97d5016b 169 off_t rst_telldir();
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{
97d5016b 390 off_t rst_telldir();
f743fc86 391
97d5016b 392 if (loc == rst_telldir(dirp))
f743fc86
KM
393 return;
394 loc -= base;
395 if (loc < 0)
e9e7ecc4 396 fprintf(stderr, "bad seek pointer to rst_seekdir %d\n", loc);
f743fc86
KM
397 (void) lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), 0);
398 dirp->dd_loc = loc & (DIRBLKSIZ - 1);
399 if (dirp->dd_loc != 0)
400 dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ);
401}
402
403/*
404 * get next entry in a directory.
405 */
406struct direct *
e9e7ecc4 407rst_readdir(dirp)
f743fc86
KM
408 register DIR *dirp;
409{
410 register struct direct *dp;
411
412 for (;;) {
413 if (dirp->dd_loc == 0) {
414 dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
415 DIRBLKSIZ);
93d90477
KM
416 if (dirp->dd_size <= 0) {
417 dprintf(stderr, "error reading directory\n");
f743fc86 418 return NULL;
93d90477 419 }
f743fc86
KM
420 }
421 if (dirp->dd_loc >= dirp->dd_size) {
422 dirp->dd_loc = 0;
423 continue;
424 }
425 dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc);
426 if (dp->d_reclen == 0 ||
93d90477
KM
427 dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) {
428 dprintf(stderr, "corrupted directory: bad reclen %d\n",
429 dp->d_reclen);
f743fc86 430 return NULL;
93d90477 431 }
f743fc86 432 dirp->dd_loc += dp->d_reclen;
93d90477
KM
433 if (dp->d_ino == 0 && strcmp(dp->d_name, "/") != 0)
434 continue;
e9e7ecc4 435 if (dp->d_ino >= maxino) {
93d90477
KM
436 dprintf(stderr, "corrupted directory: bad inum %d\n",
437 dp->d_ino);
438 continue;
439 }
f743fc86
KM
440 return (dp);
441 }
442}
443
f97d7036
KM
444/*
445 * Simulate the opening of a directory
446 */
447DIR *
448rst_opendir(name)
449 char *name;
450{
451 struct inotab *itp;
452 ino_t ino;
453
454 if ((ino = dirlookup(name)) > 0 &&
455 (itp = inotablookup(ino)) != NULL) {
456 rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
457 return (dirp);
458 }
459 return (0);
460}
461
97d5016b
KM
462/*
463 * Simulate finding the current offset in the directory.
464 */
465off_t
466rst_telldir(dirp)
467 DIR *dirp;
468{
469 off_t lseek();
470
471 return (lseek(dirp->dd_fd, 0L, 1) - dirp->dd_size + dirp->dd_loc);
472}
473
474/*
475 * Open a directory file.
476 */
477DIR *
478opendirfile(name)
479 char *name;
480{
481 register DIR *dirp;
482 register int fd;
483
484 if ((fd = open(name, 0)) == -1)
485 return NULL;
486 if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) {
487 close (fd);
488 return NULL;
489 }
490 dirp->dd_fd = fd;
491 dirp->dd_loc = 0;
492 return dirp;
493}
494
f743fc86
KM
495/*
496 * Set the mode, owner, and times for all new or changed directories
497 */
7432ff81 498setdirmodes()
f743fc86
KM
499{
500 FILE *mf;
501 struct modeinfo node;
502 struct entry *ep;
503 char *cp;
504
505 vprintf(stdout, "Set directory mode, owner, and times.\n");
7abf8d65 506 (void) sprintf(modefile, "%s/rstmode%d", _PATH_TMP, dumpdate);
f743fc86
KM
507 mf = fopen(modefile, "r");
508 if (mf == NULL) {
509 perror("fopen");
97b06931
KM
510 fprintf(stderr, "cannot open mode file %s\n", modefile);
511 fprintf(stderr, "directory mode, owner, and times not set\n");
512 return;
f743fc86
KM
513 }
514 clearerr(mf);
9f13f26d 515 for (;;) {
82d46726 516 (void) fread((char *)&node, 1, sizeof(struct modeinfo), mf);
9f13f26d
KM
517 if (feof(mf))
518 break;
f743fc86 519 ep = lookupino(node.ino);
47769c2e
KM
520 if (command == 'i' || command == 'x') {
521 if (ep == NIL)
522 continue;
a7d37956
KM
523 if (ep->e_flags & EXISTED) {
524 ep->e_flags &= ~NEW;
525 continue;
526 }
47769c2e
KM
527 if (node.ino == ROOTINO &&
528 reply("set owner/mode for '.'") == FAIL)
9f13f26d 529 continue;
9f13f26d 530 }
666f15d9 531 if (ep == NIL) {
47769c2e 532 panic("cannot find directory inode %d\n", node.ino);
666f15d9
KM
533 } else {
534 cp = myname(ep);
535 (void) chown(cp, node.uid, node.gid);
536 (void) chmod(cp, node.mode);
537 utimes(cp, node.timep);
538 ep->e_flags &= ~NEW;
539 }
f743fc86
KM
540 }
541 if (ferror(mf))
542 panic("error setting directory modes\n");
82d46726 543 (void) fclose(mf);
f743fc86
KM
544}
545
546/*
547 * Generate a literal copy of a directory.
548 */
549genliteraldir(name, ino)
550 char *name;
551 ino_t ino;
552{
553 register struct inotab *itp;
554 int ofile, dp, i, size;
555 char buf[BUFSIZ];
556
557 itp = inotablookup(ino);
558 if (itp == NULL)
9730f69a 559 panic("Cannot find directory inode %d named %s\n", ino, name);
15aeb519 560 if ((ofile = creat(name, 0666)) < 0) {
e9e7ecc4
KM
561 fprintf(stderr, "%s: ", name);
562 (void) fflush(stderr);
563 perror("cannot create file");
f743fc86
KM
564 return (FAIL);
565 }
e9e7ecc4 566 rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
f743fc86
KM
567 dp = dup(dirp->dd_fd);
568 for (i = itp->t_size; i > 0; i -= BUFSIZ) {
569 size = i < BUFSIZ ? i : BUFSIZ;
570 if (read(dp, buf, (int) size) == -1) {
571 fprintf(stderr,
572 "write error extracting inode %d, name %s\n",
573 curfile.ino, curfile.name);
574 perror("read");
575 done(1);
576 }
414c4f09 577 if (!Nflag && write(ofile, buf, (int) size) == -1) {
f743fc86
KM
578 fprintf(stderr,
579 "write error extracting inode %d, name %s\n",
580 curfile.ino, curfile.name);
581 perror("write");
582 done(1);
583 }
584 }
82d46726
KM
585 (void) close(dp);
586 (void) close(ofile);
f743fc86
KM
587 return (GOOD);
588}
589
7432ff81
KM
590/*
591 * Determine the type of an inode
592 */
593inodetype(ino)
594 ino_t ino;
595{
596 struct inotab *itp;
597
598 itp = inotablookup(ino);
599 if (itp == NULL)
600 return (LEAF);
601 return (NODE);
602}
603
f743fc86
KM
604/*
605 * Allocate and initialize a directory inode entry.
606 * If requested, save its pertinent mode, owner, and time info.
607 */
9730f69a 608struct inotab *
f743fc86
KM
609allocinotab(ino, dip, seekpt)
610 ino_t ino;
611 struct dinode *dip;
612 daddr_t seekpt;
613{
614 register struct inotab *itp;
615 struct modeinfo node;
f743fc86
KM
616
617 itp = (struct inotab *)calloc(1, sizeof(struct inotab));
ad4fabdf
KM
618 if (itp == 0)
619 panic("no memory directory table\n");
f743fc86
KM
620 itp->t_next = inotab[INOHASH(ino)];
621 inotab[INOHASH(ino)] = itp;
622 itp->t_ino = ino;
623 itp->t_seekpt = seekpt;
f743fc86 624 if (mf == NULL)
9730f69a 625 return(itp);
f743fc86 626 node.ino = ino;
2934efa5
KM
627 node.timep[0].tv_sec = dip->di_atime;
628 node.timep[0].tv_usec = 0;
629 node.timep[1].tv_sec = dip->di_mtime;
630 node.timep[1].tv_usec = 0;
f743fc86
KM
631 node.mode = dip->di_mode;
632 node.uid = dip->di_uid;
633 node.gid = dip->di_gid;
82d46726 634 (void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf);
9730f69a 635 return(itp);
f743fc86
KM
636}
637
638/*
639 * Look up an inode in the table of directories
640 */
641struct inotab *
642inotablookup(ino)
643 ino_t ino;
644{
645 register struct inotab *itp;
646
647 for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next)
648 if (itp->t_ino == ino)
649 return(itp);
650 return ((struct inotab *)0);
651}
652
653/*
654 * Clean up and exit
655 */
656done(exitcode)
657 int exitcode;
658{
659
660 closemt();
7432ff81
KM
661 if (modefile[0] != '#')
662 (void) unlink(modefile);
663 if (dirfile[0] != '#')
664 (void) unlink(dirfile);
f743fc86
KM
665 exit(exitcode);
666}