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