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 |
8e31210a | 8 | static char sccsid[] = "@(#)restore.c 5.4 (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) { | |
8e31210a | 48 | dprintf(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: | |
50746be0 KM |
395 | fprintf(stderr, "%s: (inode %d) not found on tape\n", |
396 | name, ino); | |
aa306496 KM |
397 | break; |
398 | ||
ec28ac4a KM |
399 | /* |
400 | * If any of these arise, something is grievously wrong with | |
401 | * the current state of the symbol table. | |
402 | */ | |
e0519353 KM |
403 | case INOFND|NAMEFND|MODECHG: |
404 | case NAMEFND|MODECHG: | |
405 | case INOFND|MODECHG: | |
55f85ba7 | 406 | panic("[%s] %s: inconsistent state\n", keyval(key), name); |
e0519353 KM |
407 | break; |
408 | ||
ec28ac4a KM |
409 | /* |
410 | * These states "cannot" arise for any state of the symbol table. | |
411 | */ | |
e0519353 KM |
412 | case ONTAPE|MODECHG: |
413 | case MODECHG: | |
414 | default: | |
55f85ba7 | 415 | panic("[%s] %s: impossible state\n", keyval(key), name); |
e0519353 KM |
416 | break; |
417 | } | |
ec28ac4a | 418 | return (descend); |
e0519353 KM |
419 | } |
420 | ||
55f85ba7 KM |
421 | /* |
422 | * Calculate the active flags in a key. | |
423 | */ | |
424 | char * | |
425 | keyval(key) | |
426 | int key; | |
427 | { | |
428 | static char keybuf[32]; | |
429 | ||
7432ff81 | 430 | (void) strcpy(keybuf, "|NIL"); |
55f85ba7 KM |
431 | keybuf[0] = '\0'; |
432 | if (key & ONTAPE) | |
433 | (void) strcat(keybuf, "|ONTAPE"); | |
434 | if (key & INOFND) | |
435 | (void) strcat(keybuf, "|INOFND"); | |
436 | if (key & NAMEFND) | |
437 | (void) strcat(keybuf, "|NAMEFND"); | |
438 | if (key & MODECHG) | |
439 | (void) strcat(keybuf, "|MODECHG"); | |
440 | return (&keybuf[1]); | |
441 | } | |
442 | ||
e0519353 | 443 | /* |
ec28ac4a | 444 | * Find unreferenced link names. |
e0519353 | 445 | */ |
a08c9679 | 446 | findunreflinks() |
e0519353 KM |
447 | { |
448 | register struct entry *ep, *np; | |
a08c9679 | 449 | register ino_t i; |
e0519353 KM |
450 | |
451 | vprintf(stdout, "Find unreferenced names.\n"); | |
452 | for (i = ROOTINO; i < maxino; i++) { | |
453 | ep = lookupino(i); | |
429cf058 | 454 | if (ep == NIL || ep->e_type == LEAF || BIT(i, dumpmap) == 0) |
e0519353 KM |
455 | continue; |
456 | for (np = ep->e_entries; np != NIL; np = np->e_sibling) { | |
457 | if (np->e_flags == 0) { | |
a08c9679 KM |
458 | dprintf(stdout, |
459 | "%s: remove unreferenced name\n", | |
460 | myname(np)); | |
461 | removeleaf(np); | |
462 | freeentry(np); | |
e0519353 KM |
463 | } |
464 | } | |
465 | } | |
0b50ecdc KM |
466 | /* |
467 | * Any leaves remaining in removed directories is unreferenced. | |
468 | */ | |
469 | for (ep = removelist; ep != NIL; ep = ep->e_next) { | |
470 | for (np = ep->e_entries; np != NIL; np = np->e_sibling) { | |
471 | if (np->e_type == LEAF) { | |
472 | if (np->e_flags != 0) | |
473 | badentry(np, "unreferenced with flags"); | |
474 | dprintf(stdout, | |
475 | "%s: remove unreferenced name\n", | |
476 | myname(np)); | |
477 | removeleaf(np); | |
478 | freeentry(np); | |
479 | } | |
480 | } | |
481 | } | |
e0519353 KM |
482 | } |
483 | ||
760da7d2 | 484 | /* |
ec28ac4a KM |
485 | * Remove old nodes (directories). |
486 | * Note that this routine runs in O(N*D) where: | |
487 | * N is the number of directory entries to be removed. | |
488 | * D is the maximum depth of the tree. | |
489 | * If N == D this can be quite slow. If the list were | |
490 | * topologically sorted, the deletion could be done in | |
491 | * time O(N). | |
760da7d2 | 492 | */ |
a08c9679 | 493 | removeoldnodes() |
760da7d2 | 494 | { |
a08c9679 KM |
495 | register struct entry *ep, **prev; |
496 | long change; | |
760da7d2 KM |
497 | |
498 | vprintf(stdout, "Remove old nodes (directories).\n"); | |
a08c9679 KM |
499 | do { |
500 | change = 0; | |
501 | prev = &removelist; | |
502 | for (ep = removelist; ep != NIL; ep = *prev) { | |
503 | if (ep->e_entries != NIL) { | |
504 | prev = &ep->e_next; | |
505 | continue; | |
506 | } | |
507 | *prev = ep->e_next; | |
508 | removenode(ep); | |
760da7d2 | 509 | freeentry(ep); |
a08c9679 KM |
510 | change++; |
511 | } | |
512 | } while (change); | |
513 | for (ep = removelist; ep != NIL; ep = ep->e_next) | |
514 | badentry(ep, "cannot remove, non-empty"); | |
e0519353 KM |
515 | } |
516 | ||
517 | /* | |
ec28ac4a KM |
518 | * This is the routine used to extract files for the 'r' command. |
519 | * Extract new leaves. | |
e0519353 KM |
520 | */ |
521 | createleaves(symtabfile) | |
522 | char *symtabfile; | |
523 | { | |
524 | register struct entry *ep; | |
525 | ino_t first; | |
526 | long curvol; | |
527 | ||
a08c9679 | 528 | if (command == 'R') { |
e0519353 | 529 | vprintf(stdout, "Continue extraction of new leaves\n"); |
a08c9679 | 530 | } else { |
e0519353 | 531 | vprintf(stdout, "Extract new leaves.\n"); |
a08c9679 KM |
532 | dumpsymtable(symtabfile, volno); |
533 | } | |
e0519353 KM |
534 | first = lowerbnd(ROOTINO); |
535 | curvol = volno; | |
536 | while (curfile.ino < maxino) { | |
a08c9679 | 537 | first = lowerbnd(first); |
ec28ac4a KM |
538 | /* |
539 | * If the next available file is not the one which we | |
540 | * expect then we have missed one or more files. Since | |
541 | * we do not request files that were not on the tape, | |
404966c7 KM |
542 | * the lost files must have been due to a tape read error, |
543 | * or a file that was removed while the dump was in progress. | |
ec28ac4a | 544 | */ |
e0519353 KM |
545 | while (first < curfile.ino) { |
546 | ep = lookupino(first); | |
547 | if (ep == NIL) | |
548 | panic("%d: bad first\n", first); | |
549 | fprintf(stderr, "%s: not found on tape\n", myname(ep)); | |
a08c9679 KM |
550 | ep->e_flags &= ~(NEW|EXTRACT); |
551 | first = lowerbnd(first); | |
e0519353 | 552 | } |
404966c7 KM |
553 | /* |
554 | * If we find files on the tape that have no corresponding | |
555 | * directory entries, then we must have found a file that | |
556 | * was created while the dump was in progress. Since we have | |
557 | * no name for it, we discard it knowing that it will be | |
558 | * on the next incremental tape. | |
559 | */ | |
29b92570 KM |
560 | if (first != curfile.ino) { |
561 | fprintf(stderr, "expected next file %d, got %d\n", | |
e0519353 | 562 | first, curfile.ino); |
29b92570 KM |
563 | skipfile(); |
564 | goto next; | |
565 | } | |
e0519353 KM |
566 | ep = lookupino(curfile.ino); |
567 | if (ep == NIL) | |
568 | panic("unknown file on tape\n"); | |
a08c9679 | 569 | if ((ep->e_flags & (NEW|EXTRACT)) == 0) |
e0519353 | 570 | badentry(ep, "unexpected file on tape"); |
ec28ac4a KM |
571 | /* |
572 | * If the file is to be extracted, then the old file must | |
573 | * be removed since its type may change from one leaf type | |
574 | * to another (eg "file" to "character special"). | |
575 | */ | |
a08c9679 KM |
576 | if ((ep->e_flags & EXTRACT) != 0) { |
577 | removeleaf(ep); | |
578 | ep->e_flags &= ~REMOVED; | |
579 | } | |
ec28ac4a | 580 | (void) extractfile(myname(ep)); |
a08c9679 | 581 | ep->e_flags &= ~(NEW|EXTRACT); |
ec28ac4a KM |
582 | /* |
583 | * We checkpoint the restore after every tape reel, so | |
584 | * as to simplify the amount of work re quired by the | |
585 | * 'R' command. | |
586 | */ | |
29b92570 | 587 | next: |
e0519353 KM |
588 | if (curvol != volno) { |
589 | dumpsymtable(symtabfile, volno); | |
a08c9679 | 590 | skipmaps(); |
e0519353 KM |
591 | curvol = volno; |
592 | } | |
593 | } | |
594 | } | |
595 | ||
596 | /* | |
c7774b2e KM |
597 | * This is the routine used to extract files for the 'x' and 'i' commands. |
598 | * Efficiently extract a subset of the files on a tape. | |
e0519353 KM |
599 | */ |
600 | createfiles() | |
601 | { | |
602 | register ino_t first, next, last; | |
603 | register struct entry *ep; | |
604 | long curvol; | |
605 | ||
606 | vprintf(stdout, "Extract requested files\n"); | |
9f13f26d | 607 | curfile.action = SKIP; |
74025ab9 | 608 | getvol((long)1); |
5c5f44c7 KM |
609 | skipmaps(); |
610 | skipdirs(); | |
e0519353 | 611 | first = lowerbnd(ROOTINO); |
9f13f26d | 612 | last = upperbnd(maxino - 1); |
e0519353 KM |
613 | for (;;) { |
614 | first = lowerbnd(first); | |
615 | last = upperbnd(last); | |
5c5f44c7 KM |
616 | /* |
617 | * Check to see if any files remain to be extracted | |
618 | */ | |
e0519353 KM |
619 | if (first > last) |
620 | return; | |
5c5f44c7 KM |
621 | /* |
622 | * Reject any volumes with inodes greater | |
623 | * than the last one needed | |
624 | */ | |
e0519353 KM |
625 | while (curfile.ino > last) { |
626 | curfile.action = SKIP; | |
627 | getvol((long)0); | |
5c5f44c7 KM |
628 | skipmaps(); |
629 | skipdirs(); | |
e0519353 | 630 | } |
5c5f44c7 KM |
631 | /* |
632 | * Decide on the next inode needed. | |
633 | * Skip across the inodes until it is found | |
634 | * or an out of order volume change is encountered | |
635 | */ | |
e0519353 KM |
636 | next = lowerbnd(curfile.ino); |
637 | do { | |
638 | curvol = volno; | |
639 | while (next > curfile.ino && volno == curvol) | |
640 | skipfile(); | |
5c5f44c7 KM |
641 | skipmaps(); |
642 | skipdirs(); | |
e0519353 | 643 | } while (volno == curvol + 1); |
5c5f44c7 KM |
644 | /* |
645 | * If volume change out of order occurred the | |
7432ff81 | 646 | * current state must be recalculated |
5c5f44c7 | 647 | */ |
e0519353 KM |
648 | if (volno != curvol) |
649 | continue; | |
5c5f44c7 KM |
650 | /* |
651 | * If the current inode is greater than the one we were | |
652 | * looking for then we missed the one we were looking for. | |
653 | * Since we only attempt to extract files listed in the | |
7432ff81 KM |
654 | * dump map, the lost files must have been due to a tape |
655 | * read error, or a file that was removed while the dump | |
656 | * was in progress. Thus we report all requested files | |
657 | * between the one we were looking for, and the one we | |
658 | * found as missing, and delete their request flags. | |
5c5f44c7 | 659 | */ |
e0519353 KM |
660 | while (next < curfile.ino) { |
661 | ep = lookupino(next); | |
662 | if (ep == NIL) | |
663 | panic("corrupted symbol table\n"); | |
664 | fprintf(stderr, "%s: not found on tape\n", myname(ep)); | |
665 | ep->e_flags &= ~NEW; | |
5c5f44c7 | 666 | next = lowerbnd(next); |
e0519353 | 667 | } |
5c5f44c7 KM |
668 | /* |
669 | * The current inode is the one that we are looking for, | |
670 | * so extract it per its requested name. | |
671 | */ | |
74025ab9 | 672 | if (next == curfile.ino && next <= last) { |
e0519353 KM |
673 | ep = lookupino(next); |
674 | if (ep == NIL) | |
675 | panic("corrupted symbol table\n"); | |
ec28ac4a | 676 | (void) extractfile(myname(ep)); |
e0519353 | 677 | ep->e_flags &= ~NEW; |
e526193a KM |
678 | if (volno != curvol) |
679 | skipmaps(); | |
e0519353 KM |
680 | } |
681 | } | |
682 | } | |
683 | ||
684 | /* | |
ec28ac4a | 685 | * Add links. |
e0519353 KM |
686 | */ |
687 | createlinks() | |
688 | { | |
689 | register struct entry *np, *ep; | |
a08c9679 | 690 | register ino_t i; |
e0519353 KM |
691 | char name[BUFSIZ]; |
692 | ||
693 | vprintf(stdout, "Add links\n"); | |
694 | for (i = ROOTINO; i < maxino; i++) { | |
695 | ep = lookupino(i); | |
696 | if (ep == NIL) | |
697 | continue; | |
698 | for (np = ep->e_links; np != NIL; np = np->e_links) { | |
404966c7 KM |
699 | if ((np->e_flags & NEW) == 0) |
700 | continue; | |
a08c9679 | 701 | (void) strcpy(name, myname(ep)); |
e0519353 | 702 | if (ep->e_type == NODE) { |
d5e50c65 | 703 | (void) linkit(name, myname(np), SYMLINK); |
e0519353 | 704 | } else { |
d5e50c65 | 705 | (void) linkit(name, myname(np), HARDLINK); |
e0519353 | 706 | } |
9f13f26d | 707 | np->e_flags &= ~NEW; |
e0519353 KM |
708 | } |
709 | } | |
710 | } | |
711 | ||
712 | /* | |
ec28ac4a KM |
713 | * Check the symbol table. |
714 | * We do this to insure that all the requested work was done, and | |
715 | * that no temporary names remain. | |
e0519353 KM |
716 | */ |
717 | checkrestore() | |
718 | { | |
719 | register struct entry *ep; | |
a08c9679 | 720 | register ino_t i; |
e0519353 KM |
721 | |
722 | vprintf(stdout, "Check the symbol table.\n"); | |
723 | for (i = ROOTINO; i < maxino; i++) { | |
a7d37956 | 724 | for (ep = lookupino(i); ep != NIL; ep = ep->e_links) { |
e0519353 | 725 | ep->e_flags &= ~KEEP; |
c7774b2e | 726 | if (ep->e_type == NODE) |
a7d37956 | 727 | ep->e_flags &= ~(NEW|EXISTED); |
e0519353 KM |
728 | if (ep->e_flags != NULL) |
729 | badentry(ep, "incomplete operations"); | |
730 | } | |
731 | } | |
732 | } | |
733 | ||
734 | /* | |
ec28ac4a KM |
735 | * Compare with the directory structure on the tape |
736 | * A paranoid check that things are as they should be. | |
e0519353 | 737 | */ |
ec28ac4a | 738 | long |
e0519353 KM |
739 | verifyfile(name, ino, type) |
740 | char *name; | |
741 | ino_t ino; | |
742 | int type; | |
743 | { | |
744 | struct entry *np, *ep; | |
ec28ac4a | 745 | long descend = GOOD; |
e0519353 KM |
746 | |
747 | ep = lookupname(name); | |
ec28ac4a KM |
748 | if (ep == NIL) { |
749 | fprintf(stderr, "Warning: missing name %s\n", name); | |
750 | return (FAIL); | |
751 | } | |
752 | np = lookupino(ino); | |
753 | if (np != ep) | |
754 | descend = FAIL; | |
755 | for ( ; np != NIL; np = np->e_links) | |
e0519353 KM |
756 | if (np == ep) |
757 | break; | |
758 | if (np == NIL) | |
759 | panic("missing inumber %d\n", ino); | |
760 | if (ep->e_type == LEAF && type != LEAF) | |
761 | badentry(ep, "type should be LEAF"); | |
ec28ac4a | 762 | return (descend); |
e0519353 | 763 | } |