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