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