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