umount -> unmount
[unix-history] / usr / src / sbin / restore / main.c
CommitLineData
2ec3b58e 1/* Copyright (c) 1982 Regents of the University of California */
7d4dda01 2
e9039e39 3#ifndef lint
106df965 4char version[] = "@(#)main.c 2.15 %G%";
e9039e39 5#endif
7d4dda01
KM
6
7/* Modified to include h option (recursively extract all files within
8 * a subtree) and m option (recreate the heirarchical structure of
9 * that subtree and move extracted files to their proper homes).
10 * 8/29/80 by Mike Litzkow
11 *
e9039e39
KM
12 * Modified to work on the new file system
13 * 1/19/82 by Kirk McKusick
14 *
7d4dda01
KM
15 * Includes the s (skip files) option for use with multiple dumps on
16 * a single tape.
17 */
18
7d4dda01
KM
19#define MAXINO 3000
20#define BITS 8
21#define NCACHE 3
7d4dda01
KM
22#define SIZEINC 10
23
7d4dda01
KM
24#include <stdio.h>
25#include <signal.h>
b1001c58 26#include <fstab.h>
2ec3b58e
KM
27#ifndef SIMFS
28#include <sys/param.h>
29#include <sys/inode.h>
30#include <sys/fs.h>
31#include <dir.h>
32#include <stat.h>
33#include <dumprestor.h>
34#else
b1001c58
KM
35#include "../h/param.h"
36#include "../h/dir.h"
37#include "../h/stat.h"
38#include "../h/inode.h"
39#include "../h/fs.h"
40#include "../h/dumprestor.h"
2ec3b58e 41#endif
d2a3c486 42#include <sys/ioctl.h>
b88e54cb
KM
43#include <sys/mtio.h>
44
b45e25c0 45#define ODIRSIZ 14
b88e54cb
KM
46struct odirect {
47 u_short d_ino;
b45e25c0 48 char d_name[ODIRSIZ];
b88e54cb 49};
7d4dda01 50
b6407c9d
KM
51#define MWORD(m,i) (m[(unsigned)(i-1)/NBBY])
52#define MBIT(i) (1<<((unsigned)(i-1)%NBBY))
7d4dda01
KM
53#define BIS(i,w) (MWORD(w,i) |= MBIT(i))
54#define BIC(i,w) (MWORD(w,i) &= ~MBIT(i))
55#define BIT(i,w) (MWORD(w,i) & MBIT(i))
56
e9039e39 57ino_t ino;
7d4dda01 58
f99961a3
KM
59int eflag = 0, hflag = 0, mflag = 0, vflag = 0, yflag = 0;
60int cvtflag = 0, cvtdir = 0;
7d4dda01 61
b1001c58 62long fssize;
7d4dda01
KM
63char tapename[] = "/dev/rmt8";
64char *magtape = tapename;
b88e54cb
KM
65int mt;
66int dumpnum = 1;
67int volno = 1;
68int curblk = 0;
69int bct = NTREC+1;
70char tbf[NTREC*TP_BSIZE];
7d4dda01 71
7d4dda01 72daddr_t seekpt;
0841dbb0 73FILE *df;
b45e25c0 74DIR *dirp;
0841dbb0 75int ofile;
028f3676 76char dirfile[] = "/tmp/rstaXXXXXX";
a6b18791
KM
77char lnkbuf[MAXPATHLEN + 1];
78int pathlen;
7d4dda01 79
0841dbb0
KM
80#define INOHASH(val) (val % MAXINO)
81struct inotab {
82 struct inotab *t_next;
7d4dda01
KM
83 ino_t t_ino;
84 daddr_t t_seekpt;
0841dbb0 85} *inotab[MAXINO];
028f3676 86int maxino = 0;
7d4dda01 87
0841dbb0 88#define XISDIR 1
7d4dda01
KM
89#define XTRACTD 2
90#define XINUSE 4
0841dbb0 91#define XLINKED 8
7d4dda01 92struct xtrlist {
0841dbb0
KM
93 struct xtrlist *x_next;
94 struct xtrlist *x_linkedto;
0841dbb0 95 time_t x_timep[2];
bcfabedf 96 ino_t x_ino;
0841dbb0 97 char x_flags;
bcfabedf
KM
98 char x_name[1];
99 /* actually longer */
0841dbb0 100} *xtrlist[MAXINO];
19ac1bc8 101int xtrcnt = 0;
3b629ff5
KM
102struct xtrlist *entry;
103struct xtrlist *unknown;
104struct xtrlist *allocxtr();
7d4dda01 105
b6407c9d
KM
106char *dumpmap;
107char *clrimap;
b6407c9d
KM
108
109char clearedbuf[MAXBSIZE];
7d4dda01 110
0841dbb0 111extern char *ctime();
e9039e39 112extern int seek();
bcfabedf 113ino_t search();
b45e25c0 114int dirwrite();
cbd23190
KM
115#ifdef RRESTOR
116char *host;
117#endif
7d4dda01 118
e9039e39 119main(argc, argv)
003a2a9e
KM
120 int argc;
121 char *argv[];
7d4dda01
KM
122{
123 register char *cp;
124 char command;
003a2a9e 125 int (*signal())();
7d4dda01
KM
126 int done();
127
bcfabedf
KM
128 if (signal(SIGINT, done) == SIG_IGN)
129 signal(SIGINT, SIG_IGN);
130 if (signal(SIGTERM, done) == SIG_IGN)
131 signal(SIGTERM, SIG_IGN);
b1001c58 132 mktemp(dirfile);
7d4dda01
KM
133 if (argc < 2) {
134usage:
0841dbb0 135 fprintf(stderr, "Usage: restor x[s|m|h|v] file file..., restor r|R filesys, or restor t\n");
003a2a9e 136 done(1);
7d4dda01
KM
137 }
138 argv++;
139 argc -= 2;
140 for (cp = *argv++; *cp; cp++) {
141 switch (*cp) {
142 case '-':
143 break;
d8cbdd8d
KM
144 case 'c':
145 cvtflag++;
146 break;
7d4dda01
KM
147 case 'f':
148 magtape = *argv++;
cbd23190
KM
149#ifdef RRESTOR
150 { char *index();
151 host = magtape;
152 magtape = index(host, ':');
153 if (magtape == 0) {
154nohost:
155 msg("need keyletter ``f'' and device ``host:tape''");
156 done(1);
157 }
158 *magtape++ = 0;
159 if (rmthost(host) == 0)
160 done(1);
161 }
162#endif
7d4dda01
KM
163 argc--;
164 break;
165 /* s dumpnum (skip to) for multifile dump tapes */
166 case 's':
167 dumpnum = atoi(*argv++);
2ec3b58e 168 if (dumpnum <= 0) {
003a2a9e
KM
169 fprintf(stderr, "Dump number must be a positive integer\n");
170 done(1);
7d4dda01
KM
171 }
172 argc--;
173 break;
174 case 'h':
175 hflag++;
176 break;
177 case 'm':
178 mflag++;
179 break;
f99961a3
KM
180 case 'x':
181 command = *cp;
182 /* set verbose mode by default */
183 case 'v':
184 vflag++;
185 break;
186 case 'y':
187 yflag++;
188 break;
7d4dda01
KM
189 case 'r':
190 case 'R':
b1001c58
KM
191 hflag++;
192 mflag++;
7d4dda01 193 case 't':
7d4dda01
KM
194 command = *cp;
195 break;
196 default:
003a2a9e 197 fprintf(stderr, "Bad key character %c\n", *cp);
7d4dda01
KM
198 goto usage;
199 }
200 }
cbd23190
KM
201#ifdef RRESTOR
202 if (host == 0)
203 goto nohost;
204#endif
106df965 205 setuid(getuid()); /* no longer need or want root privileges */
7d4dda01 206 doit(command, argc, argv);
003a2a9e 207 done(0);
7d4dda01
KM
208}
209
210doit(command, argc, argv)
003a2a9e
KM
211 char command;
212 int argc;
213 char *argv[];
7d4dda01 214{
b88e54cb
KM
215 struct mtop tcom;
216
cbd23190
KM
217#ifdef RRESTOR
218 if ((mt = rmtopen(magtape, 0)) < 0) {
219#else
7d4dda01 220 if ((mt = open(magtape, 0)) < 0) {
cbd23190 221#endif
003a2a9e
KM
222 fprintf(stderr, "%s: cannot open tape\n", magtape);
223 done(1);
7d4dda01 224 }
bcfabedf 225 if (dumpnum != 1) {
7d4dda01
KM
226 tcom.mt_op = MTFSF;
227 tcom.mt_count = dumpnum -1;
cbd23190
KM
228#ifdef RRESTOR
229 rmtioctl(MTFSF,dumpnum - 1);
230#else
bcfabedf 231 if (ioctl(mt,MTIOCTOP,&tcom) < 0)
7d4dda01 232 perror("ioctl MTFSF");
cbd23190 233#endif
7d4dda01 234 }
e9039e39 235 blkclr(clearedbuf, (long)MAXBSIZE);
27c979b8
KM
236 if (readhdr(&spcl) == 0) {
237 bct--; /* push back this block */
238 cvtflag++;
7d4dda01 239 if (readhdr(&spcl) == 0) {
003a2a9e
KM
240 fprintf(stderr, "Tape is not a dump tape\n");
241 done(1);
7d4dda01 242 }
27c979b8
KM
243 fprintf(stderr, "Converting to new file system format.\n");
244 }
245 switch(command) {
246 case 't':
bcfabedf
KM
247 fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date));
248 fprintf(stdout, "Dumped from: %s", ctime(&spcl.c_ddate));
7d4dda01 249 return;
b1001c58
KM
250 case 'R':
251 case 'r':
252 setdir(*argv);
253 argc = 1;
254 *argv = ".";
255 /* and then extract it all */
7d4dda01 256 case 'x':
b1001c58
KM
257 df = fopen(dirfile, "w");
258 if (df == 0) {
259 fprintf(stderr, "restor: %s - cannot create directory temporary\n", dirfile);
260 done(1);
261 }
0841dbb0
KM
262 extractfiles(argc, argv);
263 return;
0841dbb0 264 }
0841dbb0
KM
265}
266
0841dbb0
KM
267extractfiles(argc, argv)
268 int argc;
269 char **argv;
270{
bcfabedf 271 char *ststore();
0841dbb0
KM
272 register struct xtrlist *xp;
273 struct xtrlist **xpp;
274 ino_t d;
a6b18791
KM
275 int xtrfile(), xtrskip(), xtrcvtdir(), xtrcvtskip(),
276 xtrlnkfile(), xtrlnkskip(), null();
1263e71f 277 int mode, uid, gid, i;
b1001c58 278 struct stat stbuf;
028f3676 279 char name[BUFSIZ + 1];
0841dbb0 280
b1001c58
KM
281 if (stat(".", &stbuf) < 0) {
282 fprintf(stderr, "cannot stat .\n");
283 done(1);
284 }
b1001c58 285 fssize = stbuf.st_blksize;
028f3676
KM
286 if (fssize <= 0 || ((fssize - 1) & fssize) != 0) {
287 fprintf(stderr, "bad block size %d\n", fssize);
288 done(1);
289 }
0841dbb0
KM
290 if (checkvol(&spcl, 1) == 0) {
291 fprintf(stderr, "Tape is not volume 1 of the dump\n");
292 }
b1001c58
KM
293 clrimap = 0;
294 dumpmap = 0;
3b629ff5 295 unknown = allocxtr(0, "name unknown - not extracted", 0);
b88e54cb 296 pass1(1); /* This sets the various maps on the way by */
bcfabedf 297 while (argc--) {
0841dbb0 298 if ((d = psearch(*argv)) == 0 || BIT(d,dumpmap) == 0) {
f99961a3 299 fprintf(stderr, "%s: not on tape\n", *argv++);
0841dbb0 300 continue;
7d4dda01 301 }
bcfabedf
KM
302 if (mflag)
303 checkdir(*argv);
2ec3b58e 304 if (hflag)
0841dbb0 305 getleaves(d, *argv++);
bcfabedf 306 else
3b629ff5 307 (void)allocxtr(d, *argv++, XINUSE);
0841dbb0 308 }
bcfabedf 309 if (dumpnum > 1) {
b88e54cb
KM
310 /*
311 * if this is a multi-dump tape we always start with
312 * volume 1, so as to avoid accidentally restoring
313 * from a different dump!
314 */
315 resetmt();
316 dumpnum = 1;
317 volno = 1;
318 readhdr(&spcl);
319 goto rbits;
0841dbb0 320 }
b88e54cb 321newvol:
cbd23190
KM
322#ifdef RRESTOR
323 rmtclose();
324#else
2ec3b58e 325 close(mt);
cbd23190 326#endif
7d4dda01 327getvol:
b88e54cb 328 fprintf(stderr, "Mount desired tape volume; Specify volume #: ");
0841dbb0
KM
329 if (gets(tbf) == NULL)
330 return;
331 volno = atoi(tbf);
332 if (volno <= 0) {
333 fprintf(stderr, "Volume numbers are positive numerics\n");
334 goto getvol;
335 }
cbd23190
KM
336#ifdef RRESTOR
337 if ((mt = rmtopen(magtape, 0)) == -1) {
338#else
2ec3b58e 339 if ((mt = open(magtape, 0)) == -1) {
cbd23190 340#endif
2ec3b58e
KM
341 fprintf(stderr, "Cannot open tape!\n");
342 goto getvol;
343 }
344 if (dumpnum > 1)
345 resetmt();
0841dbb0
KM
346 if (readhdr(&spcl) == 0) {
347 fprintf(stderr, "tape is not dump tape\n");
348 goto newvol;
349 }
350 if (checkvol(&spcl, volno) == 0) {
351 fprintf(stderr, "Wrong volume (%d)\n", spcl.c_volume);
352 goto newvol;
353 }
7d4dda01 354rbits:
0841dbb0
KM
355 while (gethead(&spcl) == 0)
356 ;
357 if (checktype(&spcl, TS_INODE) == 1) {
358 fprintf(stderr, "Can't find inode mask!\n");
359 goto newvol;
360 }
361 if (checktype(&spcl, TS_BITS) == 0)
362 goto rbits;
b1001c58 363 readbits(&dumpmap);
0841dbb0
KM
364 while (xtrcnt > 0) {
365again:
1263e71f
KM
366 if (ishead(&spcl) == 0) {
367 i = 0;
2ec3b58e 368 while (gethead(&spcl) == 0)
1263e71f 369 i++;
028f3676 370 fprintf(stderr, "resync restor, skipped %d blocks\n",
1263e71f
KM
371 i);
372 }
0841dbb0
KM
373 if (checktype(&spcl, TS_END) == 1) {
374 fprintf(stderr, "end of tape\n");
375 break;
7d4dda01 376 }
0841dbb0
KM
377 if (checktype(&spcl, TS_INODE) == 0) {
378 gethead(&spcl);
379 goto again;
7d4dda01 380 }
0841dbb0 381 d = spcl.c_inumber;
3b629ff5
KM
382 entry = unknown;
383 entry->x_ino = d;
384 for (xp = xtrlist[INOHASH(d)]; xp; xp = xp->x_next) {
385 if (d != xp->x_ino || (xp->x_flags & XLINKED))
386 continue;
387 entry = xp;
0841dbb0
KM
388 xp->x_timep[0] = spcl.c_dinode.di_atime;
389 xp->x_timep[1] = spcl.c_dinode.di_mtime;
390 mode = spcl.c_dinode.di_mode;
391 if (mflag)
bcfabedf 392 strcpy(name, xp->x_name);
0841dbb0
KM
393 else
394 sprintf(name, "%u", xp->x_ino);
395 switch (mode & IFMT) {
396 default:
2ec3b58e
KM
397 fprintf(stderr, "%s: unknown file mode 0%o\n",
398 name, mode);
3b629ff5 399 xp->x_flags |= XTRACTD;
0841dbb0
KM
400 xtrcnt--;
401 goto skipfile;
402 case IFCHR:
403 case IFBLK:
f99961a3
KM
404 if (vflag)
405 fprintf(stdout, "extract special file %s\n", name);
b1001c58 406 if (mknod(name, mode, spcl.c_dinode.di_rdev)) {
0841dbb0 407 fprintf(stderr, "%s: cannot create special file\n", name);
3b629ff5 408 xp->x_flags |= XTRACTD;
0841dbb0
KM
409 xtrcnt--;
410 goto skipfile;
19ac1bc8 411 }
0841dbb0
KM
412 getfile(null, null, spcl.c_dinode.di_size);
413 break;
414 case IFDIR:
415 if (mflag) {
f99961a3
KM
416 if (vflag)
417 fprintf(stdout, "extract directory %s\n", name);
0841dbb0 418 strncat(name, "/.", BUFSIZ);
bcfabedf 419 checkdir(name);
b1001c58 420 chown(xp->x_name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
0841dbb0
KM
421 getfile(null, null, spcl.c_dinode.di_size);
422 break;
423 }
f99961a3
KM
424 if (vflag)
425 fprintf(stdout, "extract file %s\n", name);
b1001c58 426 if ((ofile = creat(name, 0666)) < 0) {
b88e54cb 427 fprintf(stderr, "%s: cannot create file\n", name);
3b629ff5 428 xp->x_flags |= XTRACTD;
b88e54cb
KM
429 xtrcnt--;
430 goto skipfile;
431 }
b1001c58 432 chown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
b45e25c0 433 if (cvtdir) {
b88e54cb
KM
434 getfile(xtrcvtdir, xtrcvtskip,
435 spcl.c_dinode.di_size);
b45e25c0
KM
436 flushent(xtrfile);
437 } else
b88e54cb
KM
438 getfile(xtrfile, xtrskip,
439 spcl.c_dinode.di_size);
b1001c58 440 close(ofile);
b88e54cb 441 break;
a6b18791 442 case IFLNK:
46de1989
SL
443 /*
444 * Some early dump tapes have symbolic links
445 * present without the associated data blocks.
446 * This hack avoids trashing a file system with
447 * inodes with missing data blocks.
448 */
449 if (spcl.c_count == 0) {
450 if (vflag)
451 printf("%s: 0 length symbolic link (ignored)\n", name);
452 xp->x_flags |= XTRACTD;
453 xtrcnt--;
454 goto skipfile;
455 }
f99961a3
KM
456 if (vflag)
457 fprintf(stdout, "extract symbolic link %s\n", name);
a6b18791
KM
458 uid = spcl.c_dinode.di_uid;
459 gid = spcl.c_dinode.di_gid;
460 lnkbuf[0] = '\0';
461 pathlen = 0;
462 getfile(xtrlnkfile, xtrlnkskip, spcl.c_dinode.di_size);
b1001c58 463 if (symlink(lnkbuf, name) < 0) {
a6b18791 464 fprintf(stderr, "%s: cannot create symbolic link\n", name);
3b629ff5 465 xp->x_flags |= XTRACTD;
a6b18791
KM
466 xtrcnt--;
467 goto finished;
468 }
b1001c58 469 chown(name, uid, gid);
a6b18791 470 break;
0841dbb0 471 case IFREG:
f99961a3
KM
472 if (vflag)
473 fprintf(stdout, "extract file %s\n", name);
b1001c58 474 if ((ofile = creat(name, 0666)) < 0) {
0841dbb0 475 fprintf(stderr, "%s: cannot create file\n", name);
3b629ff5 476 xp->x_flags |= XTRACTD;
0841dbb0
KM
477 xtrcnt--;
478 goto skipfile;
7d4dda01 479 }
b1001c58 480 chown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
b88e54cb 481 getfile(xtrfile, xtrskip, spcl.c_dinode.di_size);
b1001c58 482 close(ofile);
0841dbb0 483 break;
7d4dda01 484 }
b1001c58
KM
485 chmod(name, mode);
486 utime(name, xp->x_timep);
3b629ff5 487 xp->x_flags |= XTRACTD;
0841dbb0
KM
488 xtrcnt--;
489 goto finished;
490 }
491skipfile:
492 getfile(null, null, spcl.c_dinode.di_size);
003a2a9e 493finished:
0841dbb0
KM
494 ;
495 }
496 if (xtrcnt == 0 && !mflag)
497 return;
498 for (xpp = xtrlist; xpp < &xtrlist[MAXINO]; xpp++) {
499 for (xp = *xpp; xp; xp = xp->x_next) {
500 if (mflag && (xp->x_flags & XISDIR))
b1001c58 501 utime(xp->x_name, xp->x_timep);
0841dbb0
KM
502 if (xp->x_flags & XTRACTD)
503 continue;
504 if ((xp->x_flags & XLINKED) == 0) {
505 fprintf(stderr, "cannot find file %s\n",
506 xp->x_name);
507 continue;
508 }
bcfabedf
KM
509 if (!mflag)
510 continue;
f99961a3
KM
511 if (vflag)
512 fprintf(stdout, "link %s to %s\n",
513 xp->x_linkedto->x_name, xp->x_name);
b1001c58 514 if (link(xp->x_linkedto->x_name, xp->x_name) < 0)
bcfabedf
KM
515 fprintf(stderr, "link %s to %s failed\n",
516 xp->x_linkedto->x_name, xp->x_name);
7d4dda01 517 }
0841dbb0
KM
518 }
519}
7d4dda01
KM
520
521/*
522 * Read the tape, bulding up a directory structure for extraction
523 * by name
524 */
b88e54cb
KM
525pass1(savedir)
526 int savedir;
7d4dda01 527{
19ac1bc8 528 register int i;
0841dbb0
KM
529 register struct dinode *ip;
530 struct direct nulldir;
b88e54cb 531 char buf[TP_BSIZE];
b45e25c0 532 int putdir(), null(), dirwrite();
7d4dda01 533
b45e25c0
KM
534 nulldir.d_ino = 1;
535 nulldir.d_namlen = 1;
536 strncpy(nulldir.d_name, "/", nulldir.d_namlen);
537 nulldir.d_reclen = DIRSIZ(&nulldir);
7d4dda01 538 while (gethead(&spcl) == 0) {
003a2a9e 539 fprintf(stderr, "Can't find directory header!\n");
7d4dda01
KM
540 }
541 for (;;) {
542 if (checktype(&spcl, TS_BITS) == 1) {
b1001c58 543 readbits(&dumpmap);
7d4dda01
KM
544 continue;
545 }
546 if (checktype(&spcl, TS_CLRI) == 1) {
b1001c58 547 readbits(&clrimap);
7d4dda01
KM
548 continue;
549 }
550 if (checktype(&spcl, TS_INODE) == 0) {
551finish:
b45e25c0
KM
552 if (savedir) {
553 fclose(df);
554 dirp = opendir(dirfile);
555 if (dirp == NULL)
556 perror("opendir");
557 }
b88e54cb 558 resetmt();
7d4dda01
KM
559 return;
560 }
561 ip = &spcl.c_dinode;
562 i = ip->di_mode & IFMT;
563 if (i != IFDIR) {
564 goto finish;
565 }
b88e54cb
KM
566 if (spcl.c_inumber == ROOTINO) {
567 readtape(buf);
568 bct--; /* push back this block */
569 if (((struct direct *)buf)->d_ino != ROOTINO) {
570 if (((struct odirect *)buf)->d_ino != ROOTINO) {
571 fprintf(stderr, "bad root directory\n");
572 done(1);
573 }
574 fprintf(stderr, "converting to new directory format\n");
575 cvtdir = 1;
d8cbdd8d 576 cvtflag = 1;
b88e54cb
KM
577 }
578 if (!savedir && !cvtdir) {
579 /* if no conversion, just return */
580 goto finish;
581 }
582 }
bcfabedf 583 allocinotab(spcl.c_inumber, seekpt);
b88e54cb
KM
584 if (savedir) {
585 getfile(putdir, null, spcl.c_dinode.di_size);
b45e25c0
KM
586 putent(&nulldir, dirwrite);
587 flushent(dirwrite);
b88e54cb
KM
588 } else {
589 getfile(null, null, spcl.c_dinode.di_size);
590 }
7d4dda01
KM
591 }
592}
7d4dda01 593
bcfabedf
KM
594/*
595 * Put the directory entries in the directory file
596 */
bcfabedf
KM
597putdir(buf, size)
598 char *buf;
599 int size;
600{
b88e54cb
KM
601 struct direct cvtbuf;
602 register struct odirect *odp;
603 struct odirect *eodp;
bcfabedf 604 register struct direct *dp;
a6b18791 605 long loc, i;
b88e54cb
KM
606
607 if (cvtdir) {
608 eodp = (struct odirect *)&buf[size];
609 for (odp = (struct odirect *)buf; odp < eodp; odp++)
610 if (odp->d_ino != 0) {
611 dcvt(odp, &cvtbuf);
b45e25c0 612 putent(&cvtbuf, dirwrite);
b88e54cb
KM
613 }
614 } else {
b45e25c0
KM
615 for (loc = 0; loc < size; ) {
616 dp = (struct direct *)(buf + loc);
a6b18791
KM
617 i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1));
618 if (dp->d_reclen <= 0 || dp->d_reclen > i) {
619 loc += i;
620 continue;
621 }
622 loc += dp->d_reclen;
2ec3b58e 623 if (dp->d_ino != 0) {
b45e25c0 624 putent(dp, dirwrite);
2ec3b58e 625 }
b45e25c0 626 }
b88e54cb
KM
627 }
628}
629
bcfabedf
KM
630/*
631 * Recursively find names and inumbers of all files in subtree
632 * pname and put them in xtrlist[]
633 */
634getleaves(ino, pname)
635 ino_t ino;
636 char *pname;
637{
638 register struct inotab *itp;
639 int namelen;
e9039e39 640 daddr_t bpt;
b45e25c0
KM
641 register struct direct *dp;
642 char locname[BUFSIZ + 1];
bcfabedf
KM
643
644 if (BIT(ino, dumpmap) == 0) {
f99961a3
KM
645 if (vflag)
646 fprintf(stdout, "%s: not on the tape\n", pname);
bcfabedf
KM
647 return;
648 }
649 for (itp = inotab[INOHASH(ino)]; itp; itp = itp->t_next) {
650 if (itp->t_ino != ino)
651 continue;
652 /*
653 * pname is a directory name
654 */
3b629ff5 655 (void)allocxtr(ino, pname, XISDIR);
bcfabedf
KM
656 /*
657 * begin search through the directory
658 * skipping over "." and ".."
659 */
660 strncpy(locname, pname, BUFSIZ);
661 strncat(locname, "/", BUFSIZ);
662 namelen = strlen(locname);
b45e25c0
KM
663 seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
664 dp = readdir(dirp);
665 dp = readdir(dirp);
666 dp = readdir(dirp);
667 bpt = telldir(dirp);
bcfabedf
KM
668 /*
669 * "/" signals end of directory
670 */
b45e25c0 671 while (dp->d_namlen != 1 || dp->d_name[0] != '/') {
bcfabedf 672 locname[namelen] = '\0';
b45e25c0
KM
673 if (namelen + dp->d_namlen >= BUFSIZ) {
674 fprintf(stderr, "%s%s: name exceedes %d char\n",
675 locname, dp->d_name, BUFSIZ);
bcfabedf
KM
676 continue;
677 }
b45e25c0
KM
678 strncat(locname, dp->d_name, dp->d_namlen);
679 getleaves(dp->d_ino, locname);
680 seekdir(dirp, bpt, itp->t_seekpt);
681 dp = readdir(dirp);
682 bpt = telldir(dirp);
bcfabedf
KM
683 }
684 return;
685 }
686 /*
687 * locname is name of a simple file
688 */
3b629ff5 689 (void)allocxtr(ino, pname, XINUSE);
bcfabedf
KM
690}
691
692/*
693 * Search the directory tree rooted at inode ROOTINO
694 * for the path pointed at by n
695 */
696psearch(n)
697 char *n;
698{
699 register char *cp, *cp1;
700 char c;
701
702 ino = ROOTINO;
703 if (*(cp = n) == '/')
704 cp++;
705next:
706 cp1 = cp + 1;
707 while (*cp1 != '/' && *cp1)
708 cp1++;
709 c = *cp1;
710 *cp1 = 0;
711 ino = search(ino, cp);
712 if (ino == 0) {
713 *cp1 = c;
714 return(0);
715 }
716 *cp1 = c;
717 if (c == '/') {
718 cp = cp1+1;
719 goto next;
720 }
721 return(ino);
722}
723
724/*
725 * search the directory inode ino
726 * looking for entry cp
727 */
728ino_t
729search(inum, cp)
730 ino_t inum;
731 char *cp;
732{
b45e25c0 733 register struct direct *dp;
bcfabedf 734 register struct inotab *itp;
b45e25c0 735 int len;
bcfabedf
KM
736
737 for (itp = inotab[INOHASH(inum)]; itp; itp = itp->t_next)
738 if (itp->t_ino == inum)
739 goto found;
740 return(0);
741found:
b45e25c0
KM
742 seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
743 len = strlen(cp);
bcfabedf 744 do {
b45e25c0
KM
745 dp = readdir(dirp);
746 if (dp->d_namlen == 1 && dp->d_name[0] == '/')
bcfabedf 747 return(0);
b45e25c0
KM
748 } while (dp->d_namlen != len || strncmp(dp->d_name, cp, len));
749 return(dp->d_ino);
bcfabedf 750}
bcfabedf 751
7d4dda01
KM
752/*
753 * Do the file extraction, calling the supplied functions
754 * with the blocks
755 */
003a2a9e
KM
756getfile(f1, f2, size)
757 int (*f2)(), (*f1)();
e9039e39 758 off_t size;
7d4dda01 759{
19ac1bc8 760 register int i;
b6407c9d 761 char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
0841dbb0
KM
762 union u_spcl addrblk;
763# define addrblock addrblk.s_spcl
7d4dda01 764
0841dbb0 765 addrblock = spcl;
7d4dda01 766 for (;;) {
0841dbb0
KM
767 for (i = 0; i < addrblock.c_count; i++) {
768 if (addrblock.c_addr[i]) {
19ac1bc8 769 readtape(&buf[curblk++][0]);
b1001c58 770 if (curblk == fssize / TP_BSIZE) {
19ac1bc8 771 (*f1)(buf, size > TP_BSIZE ?
b1001c58 772 (long) (fssize) :
19ac1bc8
KM
773 (curblk - 1) * TP_BSIZE + size);
774 curblk = 0;
775 }
b6407c9d 776 } else {
19ac1bc8
KM
777 if (curblk > 0) {
778 (*f1)(buf, size > TP_BSIZE ?
779 (long) (curblk * TP_BSIZE) :
780 (curblk - 1) * TP_BSIZE + size);
781 curblk = 0;
782 }
b6407c9d
KM
783 (*f2)(clearedbuf, size > TP_BSIZE ?
784 (long) TP_BSIZE : size);
7d4dda01 785 }
19ac1bc8 786 if ((size -= TP_BSIZE) <= 0) {
028f3676 787 gethead(&spcl);
19ac1bc8 788 goto out;
7d4dda01
KM
789 }
790 }
0841dbb0 791 if (gethead(&addrblock) == 0) {
028f3676 792 fprintf(stderr, "Missing address (header) block for %s\n",
3b629ff5 793 entry->x_name);
028f3676
KM
794 spcl.c_magic = 0;
795 goto out;
003a2a9e 796 }
0841dbb0
KM
797 if (checktype(&addrblock, TS_ADDR) == 0) {
798 spcl = addrblock;
19ac1bc8 799 goto out;
003a2a9e 800 }
7d4dda01 801 }
19ac1bc8
KM
802out:
803 if (curblk > 0) {
804 (*f1)(buf, (curblk * TP_BSIZE) + size);
805 curblk = 0;
806 }
7d4dda01
KM
807}
808
bcfabedf
KM
809/*
810 * The next routines are called during file extraction to
811 * put the data into the right form and place.
812 */
bcfabedf
KM
813xtrfile(buf, size)
814 char *buf;
815 long size;
816{
2ec3b58e 817
b1001c58 818 if (write(ofile, buf, (int) size) == -1) {
b88e54cb 819 perror("extract write");
bcfabedf
KM
820 done(1);
821 }
822}
823
b88e54cb 824xtrskip(buf, size)
bcfabedf
KM
825 char *buf;
826 long size;
827{
2ec3b58e 828
e9039e39
KM
829#ifdef lint
830 buf = buf;
831#endif
b1001c58 832 if (lseek(ofile, size, 1) == -1) {
b88e54cb 833 perror("extract seek");
bcfabedf
KM
834 done(1);
835 }
836}
bcfabedf 837
b88e54cb
KM
838xtrcvtdir(buf, size)
839 struct odirect *buf;
840 long size;
841{
b88e54cb 842 struct odirect *odp, *edp;
e9039e39 843 struct direct cvtbuf;
b88e54cb
KM
844
845 edp = &buf[size / sizeof(struct odirect)];
b45e25c0
KM
846 for (odp = buf; odp < edp; odp++) {
847 dcvt(odp, &cvtbuf);
848 putent(&cvtbuf, xtrfile);
b88e54cb
KM
849 }
850}
851
852xtrcvtskip(buf, size)
853 char *buf;
854 long size;
855{
2ec3b58e 856
028f3676 857 fprintf(stderr, "unallocated block in directory %s\n",
3b629ff5 858 entry->x_name);
b45e25c0 859 xtrskip(buf, size);
b88e54cb 860}
a6b18791
KM
861
862xtrlnkfile(buf, size)
863 char *buf;
864 long size;
865{
2ec3b58e 866
a6b18791
KM
867 pathlen += size;
868 if (pathlen > MAXPATHLEN) {
869 fprintf(stderr, "symbolic link name: %s; too long %d\n",
870 buf, size);
871 done(1);
872 }
873 strcat(lnkbuf, buf);
874}
875
876xtrlnkskip(buf, size)
877 char *buf;
878 long size;
879{
2ec3b58e 880
e9039e39
KM
881#ifdef lint
882 buf = buf, size = size;
883#endif
028f3676 884 fprintf(stderr, "unallocated block in symbolic link %s\n",
3b629ff5 885 entry->x_name);
a6b18791
KM
886 done(1);
887}
b88e54cb 888
bcfabedf
KM
889null() {;}
890
7d4dda01 891/*
19ac1bc8 892 * Do the tape i/o, dealing with volume changes
7d4dda01
KM
893 * etc..
894 */
895readtape(b)
003a2a9e 896 char *b;
7d4dda01 897{
e9039e39 898 register long i;
2ec3b58e 899 struct u_spcl tmpbuf;
1263e71f 900 char c;
7d4dda01
KM
901
902 if (bct >= NTREC) {
903 for (i = 0; i < NTREC; i++)
19ac1bc8 904 ((struct s_spcl *)&tbf[i*TP_BSIZE])->c_magic = 0;
7d4dda01 905 bct = 0;
cbd23190
KM
906#ifdef RRESTOR
907 if ((i = rmtread(tbf, NTREC*TP_BSIZE)) < 0) {
908#else
19ac1bc8 909 if ((i = read(mt, tbf, NTREC*TP_BSIZE)) < 0) {
cbd23190 910#endif
028f3676 911 fprintf(stderr, "Tape read error while restoring %s\n",
3b629ff5 912 entry->x_name);
f99961a3 913 if (!yflag) {
028f3676 914 fprintf(stderr, "continue? ");
f99961a3 915 do {
028f3676 916 fprintf(stderr, "[yn] ");
f99961a3
KM
917 c = getchar();
918 while (getchar() != '\n')
919 /* void */;
920 } while (c != 'y' && c != 'n');
921 if (c == 'n')
922 done(1);
923 }
7d4dda01 924 eflag++;
1263e71f
KM
925 i = NTREC*TP_BSIZE;
926 blkclr(tbf, i);
cbd23190
KM
927#ifdef RRESTOR
928 if (rmtseek(i, 1) < 0) {
929#else
e9039e39 930 if (lseek(mt, i, 1) < 0) {
cbd23190 931#endif
e9039e39
KM
932 fprintf(stderr, "continuation failed\n");
933 done(1);
934 }
7d4dda01
KM
935 }
936 if (i == 0) {
937 bct = NTREC + 1;
938 volno++;
939loop:
940 flsht();
cbd23190
KM
941#ifdef RRESTOR
942 rmtclose();
943#else
7d4dda01 944 close(mt);
cbd23190 945#endif
003a2a9e 946 fprintf(stderr, "Mount volume %d\n", volno);
7d4dda01
KM
947 while (getchar() != '\n')
948 ;
cbd23190
KM
949#ifdef RRESTOR
950 if ((mt = rmtopen(magtape, 0)) == -1) {
951#else
7d4dda01 952 if ((mt = open(magtape, 0)) == -1) {
cbd23190 953#endif
003a2a9e 954 fprintf(stderr, "Cannot open tape!\n");
7d4dda01
KM
955 goto loop;
956 }
957 if (readhdr(&tmpbuf) == 0) {
003a2a9e 958 fprintf(stderr, "Not a dump tape.Try again\n");
7d4dda01
KM
959 goto loop;
960 }
961 if (checkvol(&tmpbuf, volno) == 0) {
003a2a9e 962 fprintf(stderr, "Wrong tape. Try again\n");
7d4dda01
KM
963 goto loop;
964 }
965 readtape(b);
966 return;
967 }
968 }
e9039e39 969 blkcpy(&tbf[(bct++*TP_BSIZE)], b, (long)TP_BSIZE);
7d4dda01
KM
970}
971
972flsht()
973{
2ec3b58e 974
7d4dda01
KM
975 bct = NTREC+1;
976}
977
b45e25c0
KM
978blkcpy(from, to, size)
979 char *from, *to;
e9039e39 980 long size;
7d4dda01 981{
2ec3b58e 982
e9039e39
KM
983#ifdef lint
984 from = from, to = to, size = size;
985#endif
b45e25c0 986 asm(" movc3 12(ap),*4(ap),*8(ap)");
7d4dda01
KM
987}
988
b88e54cb
KM
989blkclr(buf, size)
990 char *buf;
e9039e39 991 long size;
b88e54cb 992{
2ec3b58e 993
e9039e39
KM
994#ifdef lint
995 buf = buf, size = size;
996#endif
b88e54cb
KM
997 asm("movc5 $0,(r0),$0,8(ap),*4(ap)");
998}
999
1000resetmt()
1001{
1002 struct mtop tcom;
1003
2ec3b58e 1004 if (dumpnum > 1)
b88e54cb
KM
1005 tcom.mt_op = MTBSF;
1006 else
1007 tcom.mt_op = MTREW;
1008 tcom.mt_count = 1;
1009 flsht();
cbd23190
KM
1010#ifdef RRESTOR
1011 if (rmtioctl(tcom.mt_op, 1) == -1) {
1012 /* kludge for disk dumps */
1013 rmtseek((long)0, 0);
1014 }
1015#else
b88e54cb
KM
1016 if (ioctl(mt,MTIOCTOP,&tcom) == -1) {
1017 /* kludge for disk dumps */
1018 lseek(mt, (long)0, 0);
1019 }
cbd23190 1020#endif
b88e54cb 1021 if (dumpnum > 1) {
cbd23190
KM
1022#ifdef RRESTOR
1023 rmtioctl(MTFSF, 1);
1024#else
b88e54cb
KM
1025 tcom.mt_op = MTFSF;
1026 tcom.mt_count = 1;
1027 ioctl(mt,MTIOCTOP,&tcom);
cbd23190 1028#endif
b88e54cb
KM
1029 }
1030}
1031
bcfabedf
KM
1032checkvol(b, t)
1033 struct s_spcl *b;
1034 int t;
7d4dda01 1035{
2ec3b58e 1036
bcfabedf
KM
1037 if (b->c_volume == t)
1038 return(1);
7d4dda01 1039 return(0);
7d4dda01
KM
1040}
1041
bcfabedf
KM
1042readhdr(b)
1043 struct s_spcl *b;
7d4dda01 1044{
2ec3b58e 1045
bcfabedf 1046 if (gethead(b) == 0)
7d4dda01 1047 return(0);
bcfabedf
KM
1048 if (checktype(b, TS_TAPE) == 0)
1049 return(0);
1050 return(1);
7d4dda01 1051}
7d4dda01 1052
7d4dda01
KM
1053/*
1054 * read the tape into buf, then return whether or
1055 * or not it is a header block.
1056 */
1057gethead(buf)
0841dbb0 1058 struct s_spcl *buf;
7d4dda01 1059{
d8cbdd8d
KM
1060 union u_ospcl {
1061 char dummy[TP_BSIZE];
1062 struct s_ospcl {
1063 int c_type;
1064 time_t c_date;
1065 time_t c_ddate;
1066 int c_volume;
1067 daddr_t c_tapea;
1068 ino_t c_inumber;
1069 int c_magic;
1070 int c_checksum;
1071 struct odinode {
1072 unsigned short odi_mode;
1073 short odi_nlink;
1074 short odi_uid;
1075 short odi_gid;
1076 off_t odi_size;
1077 daddr_t odi_rdev;
1078 char odi_addr[36];
1079 time_t odi_atime;
1080 time_t odi_mtime;
1081 time_t odi_ctime;
1082 } c_dinode;
1083 int c_count;
1084 char c_addr[TP_NINDIR];
1085 } s_ospcl;
1086 } u_ospcl;
1087
1088 if (!cvtflag) {
1089 readtape((char *)buf);
27c979b8 1090 if (buf->c_magic != NFS_MAGIC || checksum((int *)buf) == 0)
d8cbdd8d
KM
1091 return(0);
1092 return(1);
1093 }
1094 readtape((char *)(&u_ospcl.s_ospcl));
d8cbdd8d
KM
1095 blkclr((char *)buf, TP_BSIZE);
1096 buf->c_type = u_ospcl.s_ospcl.c_type;
1097 buf->c_date = u_ospcl.s_ospcl.c_date;
1098 buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
1099 buf->c_volume = u_ospcl.s_ospcl.c_volume;
1100 buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
1101 buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
d8cbdd8d 1102 buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
028f3676 1103 buf->c_magic = u_ospcl.s_ospcl.c_magic;
d8cbdd8d
KM
1104 buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
1105 buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
1106 buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
1107 buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
1108 buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
1109 buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
1110 buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
1111 buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
1112 buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
1113 buf->c_count = u_ospcl.s_ospcl.c_count;
1114 blkcpy(u_ospcl.s_ospcl.c_addr, buf->c_addr, TP_NINDIR);
028f3676
KM
1115 if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
1116 checksum((int *)(&u_ospcl.s_ospcl)) == 0)
1117 return(0);
1118 buf->c_magic = NFS_MAGIC;
7d4dda01
KM
1119 return(1);
1120}
1121
1122/*
1123 * return whether or not the buffer contains a header block
1124 */
1125ishead(buf)
0841dbb0 1126 struct s_spcl *buf;
7d4dda01 1127{
2ec3b58e 1128
27c979b8 1129 if (buf->c_magic != NFS_MAGIC)
7d4dda01
KM
1130 return(0);
1131 return(1);
1132}
1133
1134checktype(b, t)
0841dbb0 1135 struct s_spcl *b;
003a2a9e 1136 int t;
7d4dda01 1137{
2ec3b58e 1138
0841dbb0 1139 return(b->c_type == t);
7d4dda01
KM
1140}
1141
b88e54cb
KM
1142/*
1143 * read a bit mask from the tape into m.
1144 */
b1001c58
KM
1145readbits(mapp)
1146 char **mapp;
b88e54cb
KM
1147{
1148 register int i;
b1001c58 1149 char *m;
b88e54cb
KM
1150
1151 i = spcl.c_count;
1152
b1001c58 1153 if (*mapp == 0)
e9039e39 1154 *mapp = (char *)calloc(i, (TP_BSIZE/(NBBY/BITS)));
b1001c58 1155 m = *mapp;
b88e54cb
KM
1156 while (i--) {
1157 readtape((char *) m);
b6407c9d 1158 m += (TP_BSIZE/(NBBY/BITS));
b88e54cb
KM
1159 }
1160 while (gethead(&spcl) == 0)
1161 ;
1162}
7d4dda01
KM
1163
1164checksum(b)
d8cbdd8d 1165 register int *b;
7d4dda01 1166{
19ac1bc8 1167 register int i, j;
7d4dda01 1168
19ac1bc8 1169 j = sizeof(union u_spcl) / sizeof(int);
7d4dda01
KM
1170 i = 0;
1171 do
1172 i += *b++;
1173 while (--j);
1174 if (i != CHECKSUM) {
028f3676 1175 fprintf(stderr, "Checksum error %o, file %s\n", i,
3b629ff5 1176 entry->x_name);
7d4dda01
KM
1177 return(0);
1178 }
1179 return(1);
1180}
1181
b88e54cb
KM
1182/*
1183 * Check for access into each directory in the pathname of an extracted
1184 * file and create such a directory if needed in preparation for moving
1185 * the file to its proper home.
1186 */
1187checkdir(name)
1188 register char *name;
1189{
1190 register char *cp;
1191 int i;
1192
1193 for (cp = name; *cp; cp++) {
1194 if (*cp == '/') {
1195 *cp = '\0';
b1001c58 1196 if (access(name, 01) < 0) {
b88e54cb
KM
1197 register int pid, rp;
1198
f2b2d53e 1199 if ((pid = vfork()) == 0) {
b1001c58
KM
1200 execl("/bin/mkdir", "mkdir", name, 0);
1201 execl("/usr/bin/mkdir", "mkdir", name, 0);
1202 fprintf(stderr, "restor: cannot find mkdir!\n");
b88e54cb
KM
1203 done(0);
1204 }
1205 while ((rp = wait(&i)) >= 0 && rp != pid)
1206 ;
b88e54cb
KM
1207 }
1208 *cp = '/';
1209 }
1210 }
1211}
1212
b1001c58
KM
1213setdir(dev)
1214 char *dev;
1215{
1216 struct fstab *fsp;
1217
1218 if (setfsent() == 0) {
1219 fprintf(stderr, "Can't open checklist file: %s\n", FSTAB);
1220 done(1);
1221 }
1222 while ((fsp = getfsent()) != 0) {
1223 if (strcmp(fsp->fs_spec, dev) == 0) {
f99961a3 1224 fprintf(stderr, "%s mounted on %s\n", dev, fsp->fs_file);
b1001c58
KM
1225 if (chdir(fsp->fs_file) >= 0)
1226 return;
1227 fprintf(stderr, "%s cannot chdir to %s\n",
1228 fsp->fs_file);
1229 done(1);
1230 }
1231 }
1232 fprintf(stderr, "%s not mounted\n", dev);
1233 done(1);
1234}
1235
b45e25c0
KM
1236/*
1237 * These variables are "local" to the following two functions.
1238 */
1239char dirbuf[DIRBLKSIZ];
1240long dirloc = 0;
1241long prev = 0;
1242
1243/*
1244 * add a new directory entry to a file.
1245 */
1246putent(dp, wrtfunc)
1247 struct direct *dp;
1248 int (*wrtfunc)();
1249{
2ec3b58e 1250
b45e25c0
KM
1251 if (dp->d_ino == 0)
1252 return;
2ec3b58e
KM
1253 if (dirloc + dp->d_reclen > DIRBLKSIZ) {
1254 ((struct direct *)(dirbuf + prev))->d_reclen =
1255 DIRBLKSIZ - prev;
b45e25c0
KM
1256 (*wrtfunc)(dirbuf, DIRBLKSIZ);
1257 dirloc = 0;
1258 }
2ec3b58e
KM
1259 blkcpy((char *)dp, dirbuf + dirloc, (long)dp->d_reclen);
1260 prev = dirloc;
1261 dirloc += dp->d_reclen;
b45e25c0
KM
1262}
1263
1264/*
1265 * flush out a directory that is finished.
1266 */
1267flushent(wrtfunc)
1268 int (*wrtfunc)();
1269{
2ec3b58e 1270
b45e25c0
KM
1271 ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
1272 (*wrtfunc)(dirbuf, dirloc);
1273 dirloc = 0;
1274}
1275
1276dirwrite(buf, size)
1277 char *buf;
1278 int size;
1279{
2ec3b58e 1280
b45e25c0
KM
1281 fwrite(buf, 1, size, df);
1282 seekpt = ftell(df);
1283}
1284
1285dcvt(odp, ndp)
1286 register struct odirect *odp;
1287 register struct direct *ndp;
1288{
2ec3b58e 1289
e9039e39 1290 blkclr((char *)ndp, (long)(sizeof *ndp));
b45e25c0
KM
1291 ndp->d_ino = odp->d_ino;
1292 strncpy(ndp->d_name, odp->d_name, ODIRSIZ);
1293 ndp->d_namlen = strlen(ndp->d_name);
1294 ndp->d_reclen = DIRSIZ(ndp);
1295 /*
1296 * this quickly calculates if this inode is a directory.
1297 * Currently not maintained.
1298 *
1299 for (itp = inotab[INOHASH(odp->d_ino)]; itp; itp = itp->t_next) {
1300 if (itp->t_ino != odp->d_ino)
1301 continue;
1302 ndp->d_fmt = IFDIR;
1303 break;
1304 }
1305 */
1306}
1307
1308/*
a6b18791
KM
1309 * Open a directory.
1310 * Modified to allow any random file to be a legal directory.
1311 */
1312DIR *
1313opendir(name)
1314 char *name;
1315{
1316 register DIR *dirp;
1317
1318 dirp = (DIR *)malloc(sizeof(DIR));
1319 dirp->dd_fd = open(name, 0);
1320 if (dirp->dd_fd == -1) {
e9039e39 1321 free((char *)dirp);
a6b18791
KM
1322 return NULL;
1323 }
1324 dirp->dd_loc = 0;
1325 return dirp;
1326}
1327
1328/*
1329 * Seek to an entry in a directory.
b45e25c0
KM
1330 * Only values returned by ``telldir'' should be passed to seekdir.
1331 * Modified to have many directories based in one file.
1332 */
1333void
1334seekdir(dirp, loc, base)
1335 register DIR *dirp;
e9039e39 1336 daddr_t loc, base;
b45e25c0 1337{
2ec3b58e 1338
b45e25c0
KM
1339 if (loc == telldir(dirp))
1340 return;
1341 loc -= base;
1342 if (loc < 0)
1343 fprintf(stderr, "bad seek pointer to seekdir %d\n", loc);
e9039e39 1344 (void)lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), 0);
b45e25c0
KM
1345 dirp->dd_loc = loc & (DIRBLKSIZ - 1);
1346 if (dirp->dd_loc != 0)
1347 dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ);
1348}
1349
003a2a9e 1350/*
b1001c58 1351 * get next entry in a directory.
003a2a9e 1352 */
b1001c58
KM
1353struct direct *
1354readdir(dirp)
1355 register DIR *dirp;
7d4dda01 1356{
b1001c58
KM
1357 register struct direct *dp;
1358
1359 for (;;) {
1360 if (dirp->dd_loc == 0) {
1361 dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
1362 DIRBLKSIZ);
1363 if (dirp->dd_size <= 0)
1364 return NULL;
1365 }
1366 if (dirp->dd_loc >= dirp->dd_size) {
1367 dirp->dd_loc = 0;
1368 continue;
1369 }
1370 dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc);
1371 if (dp->d_reclen <= 0 ||
1372 dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc)
1373 return NULL;
1374 dirp->dd_loc += dp->d_reclen;
1375 if (dp->d_ino == 0)
1376 continue;
1377 return (dp);
003a2a9e 1378 }
7d4dda01
KM
1379}
1380
bcfabedf 1381allocinotab(ino, seekpt)
0841dbb0 1382 ino_t ino;
bcfabedf 1383 daddr_t seekpt;
7d4dda01 1384{
0841dbb0 1385 register struct inotab *itp;
19ac1bc8 1386
0841dbb0
KM
1387 itp = (struct inotab *)calloc(1, sizeof(struct inotab));
1388 itp->t_next = inotab[INOHASH(ino)];
1389 inotab[INOHASH(ino)] = itp;
1390 itp->t_ino = ino;
bcfabedf 1391 itp->t_seekpt = seekpt;
7d4dda01
KM
1392}
1393
3b629ff5 1394struct xtrlist *
bcfabedf 1395allocxtr(ino, name, flags)
0841dbb0 1396 ino_t ino;
bcfabedf
KM
1397 char *name;
1398 char flags;
7d4dda01 1399{
bcfabedf 1400 register struct xtrlist *xp, *pxp;
028f3676 1401 int size;
0841dbb0 1402
028f3676 1403 size = sizeof(struct xtrlist) + strlen(name);
028f3676 1404 xp = (struct xtrlist *)calloc(1, size);
0841dbb0 1405 xp->x_ino = ino;
3b629ff5 1406 xp->x_flags = flags;
bcfabedf 1407 strcpy(xp->x_name, name);
3b629ff5
KM
1408 if (flags == 0)
1409 return (xp);
1410 xp->x_next = xtrlist[INOHASH(ino)];
1411 xtrlist[INOHASH(ino)] = xp;
0841dbb0 1412 xtrcnt++;
bcfabedf
KM
1413 for (pxp = xp->x_next; pxp; pxp = pxp->x_next)
1414 if (pxp->x_ino == ino && (pxp->x_flags & XLINKED) == 0) {
1415 xp->x_flags |= XLINKED;
1416 xp->x_linkedto = pxp;
1417 xtrcnt--;
1418 break;
1419 }
f99961a3 1420 if (!vflag)
3b629ff5 1421 return (xp);
bcfabedf
KM
1422 if (xp->x_flags & XLINKED)
1423 fprintf(stdout, "%s: linked to %s\n", xp->x_name, pxp->x_name);
1424 else if (xp->x_flags & XISDIR)
1425 fprintf(stdout, "%s: directory inode %u\n", xp->x_name, ino);
1426 else
1427 fprintf(stdout, "%s: inode %u\n", xp->x_name, ino);
3b629ff5
KM
1428 return (xp);
1429}
1430
1431#ifdef RRESTOR
1432msg(cp, a1, a2, a3)
1433 char *cp;
1434{
1435
1436 fprintf(stderr, cp, a1, a2, a3);
7d4dda01 1437}
3b629ff5 1438#endif RRESTOR
7d4dda01 1439
b88e54cb
KM
1440done(exitcode)
1441 int exitcode;
7d4dda01 1442{
2ec3b58e 1443
b88e54cb 1444 unlink(dirfile);
b88e54cb 1445 exit(exitcode);
7d4dda01 1446}