Commit | Line | Data |
---|---|---|
2ec3b58e | 1 | /* Copyright (c) 1982 Regents of the University of California */ |
7d4dda01 | 2 | |
e9039e39 | 3 | #ifndef lint |
106df965 | 4 | char 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 |
46 | struct 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 | 57 | ino_t ino; |
7d4dda01 | 58 | |
f99961a3 KM |
59 | int eflag = 0, hflag = 0, mflag = 0, vflag = 0, yflag = 0; |
60 | int cvtflag = 0, cvtdir = 0; | |
7d4dda01 | 61 | |
b1001c58 | 62 | long fssize; |
7d4dda01 KM |
63 | char tapename[] = "/dev/rmt8"; |
64 | char *magtape = tapename; | |
b88e54cb KM |
65 | int mt; |
66 | int dumpnum = 1; | |
67 | int volno = 1; | |
68 | int curblk = 0; | |
69 | int bct = NTREC+1; | |
70 | char tbf[NTREC*TP_BSIZE]; | |
7d4dda01 | 71 | |
7d4dda01 | 72 | daddr_t seekpt; |
0841dbb0 | 73 | FILE *df; |
b45e25c0 | 74 | DIR *dirp; |
0841dbb0 | 75 | int ofile; |
028f3676 | 76 | char dirfile[] = "/tmp/rstaXXXXXX"; |
a6b18791 KM |
77 | char lnkbuf[MAXPATHLEN + 1]; |
78 | int pathlen; | |
7d4dda01 | 79 | |
0841dbb0 KM |
80 | #define INOHASH(val) (val % MAXINO) |
81 | struct inotab { | |
82 | struct inotab *t_next; | |
7d4dda01 KM |
83 | ino_t t_ino; |
84 | daddr_t t_seekpt; | |
0841dbb0 | 85 | } *inotab[MAXINO]; |
028f3676 | 86 | int 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 | 92 | struct 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 | 101 | int xtrcnt = 0; |
3b629ff5 KM |
102 | struct xtrlist *entry; |
103 | struct xtrlist *unknown; | |
104 | struct xtrlist *allocxtr(); | |
7d4dda01 | 105 | |
b6407c9d KM |
106 | char *dumpmap; |
107 | char *clrimap; | |
b6407c9d KM |
108 | |
109 | char clearedbuf[MAXBSIZE]; | |
7d4dda01 | 110 | |
0841dbb0 | 111 | extern char *ctime(); |
e9039e39 | 112 | extern int seek(); |
bcfabedf | 113 | ino_t search(); |
b45e25c0 | 114 | int dirwrite(); |
cbd23190 KM |
115 | #ifdef RRESTOR |
116 | char *host; | |
117 | #endif | |
7d4dda01 | 118 | |
e9039e39 | 119 | main(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) { |
134 | usage: | |
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) { | |
154 | nohost: | |
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 | ||
210 | doit(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 |
267 | extractfiles(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 | 321 | newvol: |
cbd23190 KM |
322 | #ifdef RRESTOR |
323 | rmtclose(); | |
324 | #else | |
2ec3b58e | 325 | close(mt); |
cbd23190 | 326 | #endif |
7d4dda01 | 327 | getvol: |
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 | 354 | rbits: |
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) { |
365 | again: | |
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 | } | |
491 | skipfile: | |
492 | getfile(null, null, spcl.c_dinode.di_size); | |
003a2a9e | 493 | finished: |
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 |
525 | pass1(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) { | |
551 | finish: | |
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 |
597 | putdir(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 | */ | |
634 | getleaves(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 | */ | |
696 | psearch(n) | |
697 | char *n; | |
698 | { | |
699 | register char *cp, *cp1; | |
700 | char c; | |
701 | ||
702 | ino = ROOTINO; | |
703 | if (*(cp = n) == '/') | |
704 | cp++; | |
705 | next: | |
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 | */ | |
728 | ino_t | |
729 | search(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); | |
741 | found: | |
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 |
756 | getfile(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 |
802 | out: |
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 |
813 | xtrfile(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 | 824 | xtrskip(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 |
838 | xtrcvtdir(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 | ||
852 | xtrcvtskip(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 | |
862 | xtrlnkfile(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 | ||
876 | xtrlnkskip(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 |
889 | null() {;} |
890 | ||
7d4dda01 | 891 | /* |
19ac1bc8 | 892 | * Do the tape i/o, dealing with volume changes |
7d4dda01 KM |
893 | * etc.. |
894 | */ | |
895 | readtape(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++; | |
939 | loop: | |
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 | ||
972 | flsht() | |
973 | { | |
2ec3b58e | 974 | |
7d4dda01 KM |
975 | bct = NTREC+1; |
976 | } | |
977 | ||
b45e25c0 KM |
978 | blkcpy(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 |
989 | blkclr(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 | ||
1000 | resetmt() | |
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 |
1032 | checkvol(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 |
1042 | readhdr(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 | */ | |
1057 | gethead(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 | */ | |
1125 | ishead(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 | ||
1134 | checktype(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 |
1145 | readbits(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 | |
1164 | checksum(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 | */ | |
1187 | checkdir(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 |
1213 | setdir(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 | */ | |
1239 | char dirbuf[DIRBLKSIZ]; | |
1240 | long dirloc = 0; | |
1241 | long prev = 0; | |
1242 | ||
1243 | /* | |
1244 | * add a new directory entry to a file. | |
1245 | */ | |
1246 | putent(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 | */ | |
1267 | flushent(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 | ||
1276 | dirwrite(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 | ||
1285 | dcvt(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 | */ | |
1312 | DIR * | |
1313 | opendir(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 | */ | |
1333 | void | |
1334 | seekdir(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 |
1353 | struct direct * |
1354 | readdir(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 | 1381 | allocinotab(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 | 1394 | struct xtrlist * |
bcfabedf | 1395 | allocxtr(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 | |
1432 | msg(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 |
1440 | done(exitcode) |
1441 | int exitcode; | |
7d4dda01 | 1442 | { |
2ec3b58e | 1443 | |
b88e54cb | 1444 | unlink(dirfile); |
b88e54cb | 1445 | exit(exitcode); |
7d4dda01 | 1446 | } |