Commit | Line | Data |
---|---|---|
8c5eec2f | 1 | /* |
b42768a6 KB |
2 | * Copyright (c) 1983 The Regents of the University of California. |
3 | * All rights reserved. | |
4 | * | |
70ab3c27 | 5 | * %sccs.include.redist.c% |
8c5eec2f | 6 | */ |
e0519353 | 7 | |
8c5eec2f | 8 | #ifndef lint |
70ab3c27 | 9 | static char sccsid[] = "@(#)restore.c 5.7 (Berkeley) %G%"; |
b42768a6 | 10 | #endif /* not lint */ |
ebd1f727 | 11 | |
e0519353 KM |
12 | #include "restore.h" |
13 | ||
e0519353 | 14 | /* |
ec28ac4a KM |
15 | * This implements the 't' option. |
16 | * List entries on the tape. | |
e0519353 | 17 | */ |
ec28ac4a | 18 | long |
e0519353 KM |
19 | listfile(name, ino, type) |
20 | char *name; | |
21 | ino_t ino; | |
22 | int type; | |
23 | { | |
ec28ac4a | 24 | long descend = hflag ? GOOD : FAIL; |
e0519353 KM |
25 | |
26 | if (BIT(ino, dumpmap) == 0) { | |
ec28ac4a | 27 | return (descend); |
e0519353 | 28 | } |
a08c9679 | 29 | vprintf(stdout, "%s", type == LEAF ? "leaf" : "dir "); |
e0519353 | 30 | fprintf(stdout, "%10d\t%s\n", ino, name); |
ec28ac4a | 31 | return (descend); |
e0519353 KM |
32 | } |
33 | ||
34 | /* | |
ec28ac4a KM |
35 | * This implements the 'x' option. |
36 | * Request that new entries be extracted. | |
e0519353 | 37 | */ |
ec28ac4a | 38 | long |
e0519353 KM |
39 | addfile(name, ino, type) |
40 | char *name; | |
41 | ino_t ino; | |
42 | int type; | |
43 | { | |
44 | register struct entry *ep; | |
ec28ac4a | 45 | long descend = hflag ? GOOD : FAIL; |
e0519353 KM |
46 | char buf[100]; |
47 | ||
48 | if (BIT(ino, dumpmap) == 0) { | |
8e31210a | 49 | dprintf(stdout, "%s: not on the tape\n", name); |
ec28ac4a | 50 | return (descend); |
e0519353 | 51 | } |
0dd9c990 | 52 | if (!mflag) { |
ec28ac4a | 53 | (void) sprintf(buf, "./%u", ino); |
0dd9c990 KM |
54 | name = buf; |
55 | if (type == NODE) { | |
a08c9679 | 56 | (void) genliteraldir(name, ino); |
ec28ac4a | 57 | return (descend); |
0dd9c990 KM |
58 | } |
59 | } | |
0dd9c990 KM |
60 | ep = lookupino(ino); |
61 | if (ep != NIL) { | |
7432ff81 KM |
62 | if (strcmp(name, myname(ep)) == 0) { |
63 | ep->e_flags |= NEW; | |
ec28ac4a | 64 | return (descend); |
7432ff81 | 65 | } |
0dd9c990 KM |
66 | type |= LINK; |
67 | } | |
68 | ep = addentry(name, ino, type); | |
7432ff81 | 69 | if (type == NODE) |
0dd9c990 | 70 | newnode(ep); |
7432ff81 KM |
71 | ep->e_flags |= NEW; |
72 | return (descend); | |
73 | } | |
74 | ||
75 | /* | |
76 | * This is used by the 'i' option to undo previous requests made by addfile. | |
77 | * Delete entries from the request queue. | |
78 | */ | |
79 | /* ARGSUSED */ | |
80 | long | |
81 | deletefile(name, ino, type) | |
82 | char *name; | |
83 | ino_t ino; | |
84 | int type; | |
85 | { | |
86 | long descend = hflag ? GOOD : FAIL; | |
87 | struct entry *ep; | |
88 | ||
89 | if (BIT(ino, dumpmap) == 0) { | |
ec28ac4a | 90 | return (descend); |
e0519353 | 91 | } |
7432ff81 KM |
92 | ep = lookupino(ino); |
93 | if (ep != NIL) | |
94 | ep->e_flags &= ~NEW; | |
ec28ac4a KM |
95 | return (descend); |
96 | } | |
97 | ||
98 | /* | |
99 | * The following four routines implement the incremental | |
100 | * restore algorithm. The first removes old entries, the second | |
101 | * does renames and calculates the extraction list, the third | |
102 | * cleans up link names missed by the first two, and the final | |
103 | * one deletes old directories. | |
104 | * | |
105 | * Directories cannot be immediately deleted, as they may have | |
106 | * other files in them which need to be moved out first. As | |
107 | * directories to be deleted are found, they are put on the | |
108 | * following deletion list. After all deletions and renames | |
109 | * are done, this list is actually deleted. | |
110 | */ | |
111 | static struct entry *removelist; | |
112 | ||
113 | /* | |
114 | * Remove unneeded leaves from the old tree. | |
115 | * Remove directories from the lookup chains. | |
116 | */ | |
117 | removeoldleaves() | |
118 | { | |
119 | register struct entry *ep; | |
120 | register ino_t i; | |
121 | ||
122 | vprintf(stdout, "Mark entries to be removed.\n"); | |
123 | for (i = ROOTINO + 1; i < maxino; i++) { | |
124 | ep = lookupino(i); | |
125 | if (ep == NIL) | |
126 | continue; | |
127 | if (BIT(i, clrimap)) | |
128 | continue; | |
129 | for ( ; ep != NIL; ep = ep->e_links) { | |
130 | dprintf(stdout, "%s: REMOVE\n", myname(ep)); | |
131 | if (ep->e_type == LEAF) { | |
132 | removeleaf(ep); | |
133 | freeentry(ep); | |
134 | } else { | |
135 | mktempname(ep); | |
136 | deleteino(ep->e_ino); | |
137 | ep->e_next = removelist; | |
138 | removelist = ep; | |
139 | } | |
140 | } | |
141 | } | |
e0519353 KM |
142 | } |
143 | ||
144 | /* | |
a08c9679 KM |
145 | * For each directory entry on the incremental tape, determine which |
146 | * category it falls into as follows: | |
e0519353 KM |
147 | * KEEP - entries that are to be left alone. |
148 | * NEW - new entries to be added. | |
149 | * EXTRACT - files that must be updated with new contents. | |
a08c9679 KM |
150 | * LINK - new links to be added. |
151 | * Renames are done at the same time. | |
e0519353 | 152 | */ |
ec28ac4a | 153 | long |
a08c9679 | 154 | nodeupdates(name, ino, type) |
e0519353 KM |
155 | char *name; |
156 | ino_t ino; | |
157 | int type; | |
158 | { | |
159 | register struct entry *ep, *np, *ip; | |
ec28ac4a | 160 | long descend = GOOD; |
c7774b2e | 161 | int lookuptype = 0; |
e0519353 KM |
162 | int key = 0; |
163 | /* key values */ | |
ec28ac4a KM |
164 | # define ONTAPE 0x1 /* inode is on the tape */ |
165 | # define INOFND 0x2 /* inode already exists */ | |
166 | # define NAMEFND 0x4 /* name already exists */ | |
167 | # define MODECHG 0x8 /* mode of inode changed */ | |
55f85ba7 | 168 | extern char *keyval(); |
e0519353 KM |
169 | |
170 | /* | |
171 | * This routine is called once for each element in the | |
5c5f44c7 | 172 | * directory hierarchy, with a full path name. |
e0519353 KM |
173 | * The "type" value is incorrectly specified as LEAF for |
174 | * directories that are not on the dump tape. | |
c7774b2e KM |
175 | * |
176 | * Check to see if the file is on the tape. | |
e0519353 | 177 | */ |
55f85ba7 | 178 | if (BIT(ino, dumpmap)) |
e0519353 | 179 | key |= ONTAPE; |
c7774b2e KM |
180 | /* |
181 | * Check to see if the name exists, and if the name is a link. | |
182 | */ | |
e0519353 | 183 | np = lookupname(name); |
c7774b2e | 184 | if (np != NIL) { |
e0519353 | 185 | key |= NAMEFND; |
c7774b2e KM |
186 | ip = lookupino(np->e_ino); |
187 | if (ip == NULL) | |
188 | panic("corrupted symbol table\n"); | |
189 | if (ip != np) | |
190 | lookuptype = LINK; | |
191 | } | |
192 | /* | |
193 | * Check to see if the inode exists, and if one of its links | |
194 | * corresponds to the name (if one was found). | |
195 | */ | |
e0519353 KM |
196 | ip = lookupino(ino); |
197 | if (ip != NIL) { | |
198 | key |= INOFND; | |
c7774b2e | 199 | for (ep = ip->e_links; ep != NIL; ep = ep->e_links) { |
e0519353 KM |
200 | if (ep == np) { |
201 | ip = ep; | |
202 | break; | |
203 | } | |
c7774b2e | 204 | } |
e0519353 | 205 | } |
ec28ac4a | 206 | /* |
c7774b2e KM |
207 | * If both a name and an inode are found, but they do not |
208 | * correspond to the same file, then both the inode that has | |
209 | * been found and the inode corresponding to the name that | |
210 | * has been found need to be renamed. The current pathname | |
211 | * is the new name for the inode that has been found. Since | |
212 | * all files to be deleted have already been removed, the | |
213 | * named file is either a now unneeded link, or it must live | |
214 | * under a new name in this dump level. If it is a link, it | |
215 | * can be removed. If it is not a link, it is given a | |
216 | * temporary name in anticipation that it will be renamed | |
217 | * when it is later found by inode number. | |
ec28ac4a | 218 | */ |
a08c9679 | 219 | if (((key & (INOFND|NAMEFND)) == (INOFND|NAMEFND)) && ip != np) { |
c7774b2e KM |
220 | if (lookuptype == LINK) { |
221 | removeleaf(np); | |
222 | freeentry(np); | |
223 | } else { | |
224 | dprintf(stdout, "name/inode conflict, mktempname %s\n", | |
225 | myname(np)); | |
226 | mktempname(np); | |
227 | } | |
e0519353 KM |
228 | np = NIL; |
229 | key &= ~NAMEFND; | |
230 | } | |
e0519353 KM |
231 | if ((key & ONTAPE) && |
232 | (((key & INOFND) && ip->e_type != type) || | |
55f85ba7 | 233 | ((key & NAMEFND) && np->e_type != type))) |
e0519353 | 234 | key |= MODECHG; |
ec28ac4a KM |
235 | |
236 | /* | |
237 | * Decide on the disposition of the file based on its flags. | |
238 | * Note that we have already handled the case in which | |
239 | * a name and inode are found that correspond to different files. | |
240 | * Thus if both NAMEFND and INOFND are set then ip == np. | |
241 | */ | |
e0519353 KM |
242 | switch (key) { |
243 | ||
ec28ac4a KM |
244 | /* |
245 | * A previously existing file has been found. | |
246 | * Mark it as KEEP so that other links to the inode can be | |
247 | * detected, and so that it will not be reclaimed by the search | |
248 | * for unreferenced names. | |
249 | */ | |
e0519353 KM |
250 | case INOFND|NAMEFND: |
251 | ip->e_flags |= KEEP; | |
55f85ba7 KM |
252 | dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, |
253 | flagvalues(ip)); | |
e0519353 KM |
254 | break; |
255 | ||
b029b198 KM |
256 | /* |
257 | * A file on the tape has a name which is the same as a name | |
258 | * corresponding to a different file in the previous dump. | |
259 | * Since all files to be deleted have already been removed, | |
c7774b2e KM |
260 | * this file is either a now unneeded link, or it must live |
261 | * under a new name in this dump level. If it is a link, it | |
262 | * can simply be removed. If it is not a link, it is given a | |
263 | * temporary name in anticipation that it will be renamed | |
264 | * when it is later found by inode number (see INOFND case | |
265 | * below). The entry is then treated as a new file. | |
b029b198 KM |
266 | */ |
267 | case ONTAPE|NAMEFND: | |
268 | case ONTAPE|NAMEFND|MODECHG: | |
c7774b2e KM |
269 | if (lookuptype == LINK) { |
270 | removeleaf(np); | |
271 | freeentry(np); | |
272 | } else { | |
273 | mktempname(np); | |
274 | } | |
b029b198 KM |
275 | /* fall through */ |
276 | ||
ec28ac4a KM |
277 | /* |
278 | * A previously non-existent file. | |
279 | * Add it to the file system, and request its extraction. | |
280 | * If it is a directory, create it immediately. | |
281 | * (Since the name is unused there can be no conflict) | |
282 | */ | |
e0519353 KM |
283 | case ONTAPE: |
284 | ep = addentry(name, ino, type); | |
a08c9679 KM |
285 | if (type == NODE) |
286 | newnode(ep); | |
7432ff81 | 287 | ep->e_flags |= NEW|KEEP; |
55f85ba7 KM |
288 | dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, |
289 | flagvalues(ep)); | |
e0519353 KM |
290 | break; |
291 | ||
ec28ac4a KM |
292 | /* |
293 | * A file with the same inode number, but a different | |
294 | * name has been found. If the other name has not already | |
295 | * been found (indicated by the KEEP flag, see above) then | |
296 | * this must be a new name for the file, and it is renamed. | |
297 | * If the other name has been found then this must be a | |
298 | * link to the file. Hard links to directories are not | |
299 | * permitted, and are either deleted or converted to | |
300 | * symbolic links. Finally, if the file is on the tape, | |
301 | * a request is made to extract it. | |
302 | */ | |
e0519353 | 303 | case ONTAPE|INOFND: |
55f85ba7 | 304 | if (type == LEAF && (ip->e_flags & KEEP) == 0) |
a08c9679 | 305 | ip->e_flags |= EXTRACT; |
e0519353 KM |
306 | /* fall through */ |
307 | case INOFND: | |
ec28ac4a KM |
308 | if ((ip->e_flags & KEEP) == 0) { |
309 | renameit(myname(ip), name); | |
310 | moveentry(ip, name); | |
311 | ip->e_flags |= KEEP; | |
429cf058 | 312 | dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, |
55f85ba7 | 313 | flagvalues(ip)); |
e0519353 KM |
314 | break; |
315 | } | |
ec28ac4a KM |
316 | if (ip->e_type == NODE) { |
317 | descend = FAIL; | |
318 | fprintf(stderr, | |
319 | "deleted hard link %s to directory %s\n", | |
320 | name, myname(ip)); | |
321 | break; | |
322 | } | |
323 | ep = addentry(name, ino, type|LINK); | |
324 | ep->e_flags |= NEW; | |
55f85ba7 KM |
325 | dprintf(stdout, "[%s] %s: %s|LINK\n", keyval(key), name, |
326 | flagvalues(ep)); | |
e0519353 KM |
327 | break; |
328 | ||
ec28ac4a | 329 | /* |
b029b198 | 330 | * A previously known file which is to be updated. |
ec28ac4a | 331 | */ |
e0519353 | 332 | case ONTAPE|INOFND|NAMEFND: |
c7774b2e | 333 | if (type == LEAF && lookuptype != LINK) |
a08c9679 KM |
334 | np->e_flags |= EXTRACT; |
335 | np->e_flags |= KEEP; | |
55f85ba7 KM |
336 | dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, |
337 | flagvalues(np)); | |
e0519353 KM |
338 | break; |
339 | ||
ec28ac4a KM |
340 | /* |
341 | * An inode is being reused in a completely different way. | |
342 | * Normally an extract can simply do an "unlink" followed | |
343 | * by a "creat". Here we must do effectively the same | |
344 | * thing. The complications arise because we cannot really | |
345 | * delete a directory since it may still contain files | |
346 | * that we need to rename, so we delete it from the symbol | |
347 | * table, and put it on the list to be deleted eventually. | |
348 | * Conversely if a directory is to be created, it must be | |
349 | * done immediately, rather than waiting until the | |
350 | * extraction phase. | |
351 | */ | |
e0519353 KM |
352 | case ONTAPE|INOFND|MODECHG: |
353 | case ONTAPE|INOFND|NAMEFND|MODECHG: | |
a08c9679 KM |
354 | if (ip->e_flags & KEEP) { |
355 | badentry(ip, "cannot KEEP and change modes"); | |
356 | break; | |
357 | } | |
358 | if (ip->e_type == LEAF) { | |
359 | /* changing from leaf to node */ | |
360 | removeleaf(ip); | |
361 | freeentry(ip); | |
362 | ip = addentry(name, ino, type); | |
363 | newnode(ip); | |
364 | } else { | |
365 | /* changing from node to leaf */ | |
0b50ecdc KM |
366 | if ((ip->e_flags & TMPNAME) == 0) |
367 | mktempname(ip); | |
a08c9679 KM |
368 | deleteino(ip->e_ino); |
369 | ip->e_next = removelist; | |
370 | removelist = ip; | |
371 | ip = addentry(name, ino, type); | |
a08c9679 | 372 | } |
7432ff81 | 373 | ip->e_flags |= NEW|KEEP; |
55f85ba7 KM |
374 | dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, |
375 | flagvalues(ip)); | |
e0519353 KM |
376 | break; |
377 | ||
ec28ac4a KM |
378 | /* |
379 | * A hard link to a diirectory that has been removed. | |
380 | * Ignore it. | |
381 | */ | |
382 | case NAMEFND: | |
55f85ba7 KM |
383 | dprintf(stdout, "[%s] %s: Extraneous name\n", keyval(key), |
384 | name); | |
ec28ac4a KM |
385 | descend = FAIL; |
386 | break; | |
387 | ||
aa306496 KM |
388 | /* |
389 | * If we find a directory entry for a file that is not on | |
390 | * the tape, then we must have found a file that was created | |
391 | * while the dump was in progress. Since we have no contents | |
392 | * for it, we discard the name knowing that it will be on the | |
393 | * next incremental tape. | |
394 | */ | |
395 | case NIL: | |
50746be0 KM |
396 | fprintf(stderr, "%s: (inode %d) not found on tape\n", |
397 | name, ino); | |
aa306496 KM |
398 | break; |
399 | ||
ec28ac4a KM |
400 | /* |
401 | * If any of these arise, something is grievously wrong with | |
402 | * the current state of the symbol table. | |
403 | */ | |
e0519353 KM |
404 | case INOFND|NAMEFND|MODECHG: |
405 | case NAMEFND|MODECHG: | |
406 | case INOFND|MODECHG: | |
a9cf8327 KB |
407 | fprintf(stderr, "[%s] %s: inconsistent state\n", keyval(key), |
408 | name); | |
e0519353 KM |
409 | break; |
410 | ||
ec28ac4a KM |
411 | /* |
412 | * These states "cannot" arise for any state of the symbol table. | |
413 | */ | |
e0519353 KM |
414 | case ONTAPE|MODECHG: |
415 | case MODECHG: | |
416 | default: | |
55f85ba7 | 417 | panic("[%s] %s: impossible state\n", keyval(key), name); |
e0519353 KM |
418 | break; |
419 | } | |
ec28ac4a | 420 | return (descend); |
e0519353 KM |
421 | } |
422 | ||
55f85ba7 KM |
423 | /* |
424 | * Calculate the active flags in a key. | |
425 | */ | |
426 | char * | |
427 | keyval(key) | |
428 | int key; | |
429 | { | |
430 | static char keybuf[32]; | |
431 | ||
7432ff81 | 432 | (void) strcpy(keybuf, "|NIL"); |
55f85ba7 KM |
433 | keybuf[0] = '\0'; |
434 | if (key & ONTAPE) | |
435 | (void) strcat(keybuf, "|ONTAPE"); | |
436 | if (key & INOFND) | |
437 | (void) strcat(keybuf, "|INOFND"); | |
438 | if (key & NAMEFND) | |
439 | (void) strcat(keybuf, "|NAMEFND"); | |
440 | if (key & MODECHG) | |
441 | (void) strcat(keybuf, "|MODECHG"); | |
442 | return (&keybuf[1]); | |
443 | } | |
444 | ||
e0519353 | 445 | /* |
ec28ac4a | 446 | * Find unreferenced link names. |
e0519353 | 447 | */ |
a08c9679 | 448 | findunreflinks() |
e0519353 KM |
449 | { |
450 | register struct entry *ep, *np; | |
a08c9679 | 451 | register ino_t i; |
e0519353 KM |
452 | |
453 | vprintf(stdout, "Find unreferenced names.\n"); | |
454 | for (i = ROOTINO; i < maxino; i++) { | |
455 | ep = lookupino(i); | |
429cf058 | 456 | if (ep == NIL || ep->e_type == LEAF || BIT(i, dumpmap) == 0) |
e0519353 KM |
457 | continue; |
458 | for (np = ep->e_entries; np != NIL; np = np->e_sibling) { | |
459 | if (np->e_flags == 0) { | |
a08c9679 KM |
460 | dprintf(stdout, |
461 | "%s: remove unreferenced name\n", | |
462 | myname(np)); | |
463 | removeleaf(np); | |
464 | freeentry(np); | |
e0519353 KM |
465 | } |
466 | } | |
467 | } | |
0b50ecdc KM |
468 | /* |
469 | * Any leaves remaining in removed directories is unreferenced. | |
470 | */ | |
471 | for (ep = removelist; ep != NIL; ep = ep->e_next) { | |
472 | for (np = ep->e_entries; np != NIL; np = np->e_sibling) { | |
473 | if (np->e_type == LEAF) { | |
474 | if (np->e_flags != 0) | |
475 | badentry(np, "unreferenced with flags"); | |
476 | dprintf(stdout, | |
477 | "%s: remove unreferenced name\n", | |
478 | myname(np)); | |
479 | removeleaf(np); | |
480 | freeentry(np); | |
481 | } | |
482 | } | |
483 | } | |
e0519353 KM |
484 | } |
485 | ||
760da7d2 | 486 | /* |
ec28ac4a KM |
487 | * Remove old nodes (directories). |
488 | * Note that this routine runs in O(N*D) where: | |
489 | * N is the number of directory entries to be removed. | |
490 | * D is the maximum depth of the tree. | |
491 | * If N == D this can be quite slow. If the list were | |
492 | * topologically sorted, the deletion could be done in | |
493 | * time O(N). | |
760da7d2 | 494 | */ |
a08c9679 | 495 | removeoldnodes() |
760da7d2 | 496 | { |
a08c9679 KM |
497 | register struct entry *ep, **prev; |
498 | long change; | |
760da7d2 KM |
499 | |
500 | vprintf(stdout, "Remove old nodes (directories).\n"); | |
a08c9679 KM |
501 | do { |
502 | change = 0; | |
503 | prev = &removelist; | |
504 | for (ep = removelist; ep != NIL; ep = *prev) { | |
505 | if (ep->e_entries != NIL) { | |
506 | prev = &ep->e_next; | |
507 | continue; | |
508 | } | |
509 | *prev = ep->e_next; | |
510 | removenode(ep); | |
760da7d2 | 511 | freeentry(ep); |
a08c9679 KM |
512 | change++; |
513 | } | |
514 | } while (change); | |
515 | for (ep = removelist; ep != NIL; ep = ep->e_next) | |
516 | badentry(ep, "cannot remove, non-empty"); | |
e0519353 KM |
517 | } |
518 | ||
519 | /* | |
ec28ac4a KM |
520 | * This is the routine used to extract files for the 'r' command. |
521 | * Extract new leaves. | |
e0519353 KM |
522 | */ |
523 | createleaves(symtabfile) | |
524 | char *symtabfile; | |
525 | { | |
526 | register struct entry *ep; | |
527 | ino_t first; | |
528 | long curvol; | |
529 | ||
a08c9679 | 530 | if (command == 'R') { |
e0519353 | 531 | vprintf(stdout, "Continue extraction of new leaves\n"); |
a08c9679 | 532 | } else { |
e0519353 | 533 | vprintf(stdout, "Extract new leaves.\n"); |
a08c9679 KM |
534 | dumpsymtable(symtabfile, volno); |
535 | } | |
e0519353 KM |
536 | first = lowerbnd(ROOTINO); |
537 | curvol = volno; | |
538 | while (curfile.ino < maxino) { | |
a08c9679 | 539 | first = lowerbnd(first); |
ec28ac4a KM |
540 | /* |
541 | * If the next available file is not the one which we | |
542 | * expect then we have missed one or more files. Since | |
543 | * we do not request files that were not on the tape, | |
404966c7 KM |
544 | * the lost files must have been due to a tape read error, |
545 | * or a file that was removed while the dump was in progress. | |
ec28ac4a | 546 | */ |
e0519353 KM |
547 | while (first < curfile.ino) { |
548 | ep = lookupino(first); | |
549 | if (ep == NIL) | |
550 | panic("%d: bad first\n", first); | |
551 | fprintf(stderr, "%s: not found on tape\n", myname(ep)); | |
a08c9679 KM |
552 | ep->e_flags &= ~(NEW|EXTRACT); |
553 | first = lowerbnd(first); | |
e0519353 | 554 | } |
404966c7 KM |
555 | /* |
556 | * If we find files on the tape that have no corresponding | |
557 | * directory entries, then we must have found a file that | |
558 | * was created while the dump was in progress. Since we have | |
559 | * no name for it, we discard it knowing that it will be | |
560 | * on the next incremental tape. | |
561 | */ | |
29b92570 KM |
562 | if (first != curfile.ino) { |
563 | fprintf(stderr, "expected next file %d, got %d\n", | |
e0519353 | 564 | first, curfile.ino); |
29b92570 KM |
565 | skipfile(); |
566 | goto next; | |
567 | } | |
e0519353 KM |
568 | ep = lookupino(curfile.ino); |
569 | if (ep == NIL) | |
570 | panic("unknown file on tape\n"); | |
a08c9679 | 571 | if ((ep->e_flags & (NEW|EXTRACT)) == 0) |
e0519353 | 572 | badentry(ep, "unexpected file on tape"); |
ec28ac4a KM |
573 | /* |
574 | * If the file is to be extracted, then the old file must | |
575 | * be removed since its type may change from one leaf type | |
576 | * to another (eg "file" to "character special"). | |
577 | */ | |
a08c9679 KM |
578 | if ((ep->e_flags & EXTRACT) != 0) { |
579 | removeleaf(ep); | |
580 | ep->e_flags &= ~REMOVED; | |
581 | } | |
ec28ac4a | 582 | (void) extractfile(myname(ep)); |
a08c9679 | 583 | ep->e_flags &= ~(NEW|EXTRACT); |
ec28ac4a KM |
584 | /* |
585 | * We checkpoint the restore after every tape reel, so | |
586 | * as to simplify the amount of work re quired by the | |
587 | * 'R' command. | |
588 | */ | |
29b92570 | 589 | next: |
e0519353 KM |
590 | if (curvol != volno) { |
591 | dumpsymtable(symtabfile, volno); | |
a08c9679 | 592 | skipmaps(); |
e0519353 KM |
593 | curvol = volno; |
594 | } | |
595 | } | |
596 | } | |
597 | ||
598 | /* | |
c7774b2e KM |
599 | * This is the routine used to extract files for the 'x' and 'i' commands. |
600 | * Efficiently extract a subset of the files on a tape. | |
e0519353 KM |
601 | */ |
602 | createfiles() | |
603 | { | |
604 | register ino_t first, next, last; | |
605 | register struct entry *ep; | |
606 | long curvol; | |
607 | ||
608 | vprintf(stdout, "Extract requested files\n"); | |
9f13f26d | 609 | curfile.action = SKIP; |
74025ab9 | 610 | getvol((long)1); |
5c5f44c7 KM |
611 | skipmaps(); |
612 | skipdirs(); | |
e0519353 | 613 | first = lowerbnd(ROOTINO); |
9f13f26d | 614 | last = upperbnd(maxino - 1); |
e0519353 KM |
615 | for (;;) { |
616 | first = lowerbnd(first); | |
617 | last = upperbnd(last); | |
5c5f44c7 KM |
618 | /* |
619 | * Check to see if any files remain to be extracted | |
620 | */ | |
e0519353 KM |
621 | if (first > last) |
622 | return; | |
5c5f44c7 KM |
623 | /* |
624 | * Reject any volumes with inodes greater | |
625 | * than the last one needed | |
626 | */ | |
e0519353 KM |
627 | while (curfile.ino > last) { |
628 | curfile.action = SKIP; | |
629 | getvol((long)0); | |
5c5f44c7 KM |
630 | skipmaps(); |
631 | skipdirs(); | |
e0519353 | 632 | } |
5c5f44c7 KM |
633 | /* |
634 | * Decide on the next inode needed. | |
635 | * Skip across the inodes until it is found | |
636 | * or an out of order volume change is encountered | |
637 | */ | |
e0519353 KM |
638 | next = lowerbnd(curfile.ino); |
639 | do { | |
640 | curvol = volno; | |
641 | while (next > curfile.ino && volno == curvol) | |
642 | skipfile(); | |
5c5f44c7 KM |
643 | skipmaps(); |
644 | skipdirs(); | |
e0519353 | 645 | } while (volno == curvol + 1); |
5c5f44c7 KM |
646 | /* |
647 | * If volume change out of order occurred the | |
7432ff81 | 648 | * current state must be recalculated |
5c5f44c7 | 649 | */ |
e0519353 KM |
650 | if (volno != curvol) |
651 | continue; | |
5c5f44c7 KM |
652 | /* |
653 | * If the current inode is greater than the one we were | |
654 | * looking for then we missed the one we were looking for. | |
655 | * Since we only attempt to extract files listed in the | |
7432ff81 KM |
656 | * dump map, the lost files must have been due to a tape |
657 | * read error, or a file that was removed while the dump | |
658 | * was in progress. Thus we report all requested files | |
659 | * between the one we were looking for, and the one we | |
660 | * found as missing, and delete their request flags. | |
5c5f44c7 | 661 | */ |
e0519353 KM |
662 | while (next < curfile.ino) { |
663 | ep = lookupino(next); | |
664 | if (ep == NIL) | |
665 | panic("corrupted symbol table\n"); | |
666 | fprintf(stderr, "%s: not found on tape\n", myname(ep)); | |
667 | ep->e_flags &= ~NEW; | |
5c5f44c7 | 668 | next = lowerbnd(next); |
e0519353 | 669 | } |
5c5f44c7 KM |
670 | /* |
671 | * The current inode is the one that we are looking for, | |
672 | * so extract it per its requested name. | |
673 | */ | |
74025ab9 | 674 | if (next == curfile.ino && next <= last) { |
e0519353 KM |
675 | ep = lookupino(next); |
676 | if (ep == NIL) | |
677 | panic("corrupted symbol table\n"); | |
ec28ac4a | 678 | (void) extractfile(myname(ep)); |
e0519353 | 679 | ep->e_flags &= ~NEW; |
e526193a KM |
680 | if (volno != curvol) |
681 | skipmaps(); | |
e0519353 KM |
682 | } |
683 | } | |
684 | } | |
685 | ||
686 | /* | |
ec28ac4a | 687 | * Add links. |
e0519353 KM |
688 | */ |
689 | createlinks() | |
690 | { | |
691 | register struct entry *np, *ep; | |
a08c9679 | 692 | register ino_t i; |
e0519353 KM |
693 | char name[BUFSIZ]; |
694 | ||
695 | vprintf(stdout, "Add links\n"); | |
696 | for (i = ROOTINO; i < maxino; i++) { | |
697 | ep = lookupino(i); | |
698 | if (ep == NIL) | |
699 | continue; | |
700 | for (np = ep->e_links; np != NIL; np = np->e_links) { | |
404966c7 KM |
701 | if ((np->e_flags & NEW) == 0) |
702 | continue; | |
a08c9679 | 703 | (void) strcpy(name, myname(ep)); |
e0519353 | 704 | if (ep->e_type == NODE) { |
d5e50c65 | 705 | (void) linkit(name, myname(np), SYMLINK); |
e0519353 | 706 | } else { |
d5e50c65 | 707 | (void) linkit(name, myname(np), HARDLINK); |
e0519353 | 708 | } |
9f13f26d | 709 | np->e_flags &= ~NEW; |
e0519353 KM |
710 | } |
711 | } | |
712 | } | |
713 | ||
714 | /* | |
ec28ac4a KM |
715 | * Check the symbol table. |
716 | * We do this to insure that all the requested work was done, and | |
717 | * that no temporary names remain. | |
e0519353 KM |
718 | */ |
719 | checkrestore() | |
720 | { | |
721 | register struct entry *ep; | |
a08c9679 | 722 | register ino_t i; |
e0519353 KM |
723 | |
724 | vprintf(stdout, "Check the symbol table.\n"); | |
725 | for (i = ROOTINO; i < maxino; i++) { | |
a7d37956 | 726 | for (ep = lookupino(i); ep != NIL; ep = ep->e_links) { |
e0519353 | 727 | ep->e_flags &= ~KEEP; |
c7774b2e | 728 | if (ep->e_type == NODE) |
a7d37956 | 729 | ep->e_flags &= ~(NEW|EXISTED); |
e0519353 KM |
730 | if (ep->e_flags != NULL) |
731 | badentry(ep, "incomplete operations"); | |
732 | } | |
733 | } | |
734 | } | |
735 | ||
736 | /* | |
ec28ac4a KM |
737 | * Compare with the directory structure on the tape |
738 | * A paranoid check that things are as they should be. | |
e0519353 | 739 | */ |
ec28ac4a | 740 | long |
e0519353 KM |
741 | verifyfile(name, ino, type) |
742 | char *name; | |
743 | ino_t ino; | |
744 | int type; | |
745 | { | |
746 | struct entry *np, *ep; | |
ec28ac4a | 747 | long descend = GOOD; |
e0519353 KM |
748 | |
749 | ep = lookupname(name); | |
ec28ac4a KM |
750 | if (ep == NIL) { |
751 | fprintf(stderr, "Warning: missing name %s\n", name); | |
752 | return (FAIL); | |
753 | } | |
754 | np = lookupino(ino); | |
755 | if (np != ep) | |
756 | descend = FAIL; | |
757 | for ( ; np != NIL; np = np->e_links) | |
e0519353 KM |
758 | if (np == ep) |
759 | break; | |
760 | if (np == NIL) | |
761 | panic("missing inumber %d\n", ino); | |
762 | if (ep->e_type == LEAF && type != LEAF) | |
763 | badentry(ep, "type should be LEAF"); | |
ec28ac4a | 764 | return (descend); |
e0519353 | 765 | } |