]> git.wh0rd.org - dump.git/blob - restore/symtab.c
LFS compatibility.
[dump.git] / restore / symtab.c
1 /*
2 * Ported to Linux's Second Extended File System as part of the
3 * dump and restore backup suit
4 * Remy Card <card@Linux.EU.Org>, 1994-1997
5 * Stelian Pop <pop@noos.fr>, 1999-2000
6 * Stelian Pop <pop@noos.fr> - AlcĂ´ve <www.alcove.fr>, 2000
7 */
8
9 /*
10 * Copyright (c) 1983, 1993
11 * The Regents of the University of California. All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement:
23 * This product includes software developed by the University of
24 * California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
40 */
41
42 #ifndef lint
43 static const char rcsid[] =
44 "$Id: symtab.c,v 1.12 2000/12/21 11:14:54 stelian Exp $";
45 #endif /* not lint */
46
47 /*
48 * These routines maintain the symbol table which tracks the state
49 * of the file system being restored. They provide lookup by either
50 * name or inode number. They also provide for creation, deletion,
51 * and renaming of entries. Because of the dynamic nature of pathnames,
52 * names should not be saved, but always constructed just before they
53 * are needed, by calling "myname".
54 */
55
56 #include <config.h>
57 #include <sys/param.h>
58 #include <sys/stat.h>
59
60 #ifdef __linux__
61 #include <sys/time.h>
62 #include <linux/ext2_fs.h>
63 #include <bsdcompat.h>
64 #else /* __linux__ */
65 #include <ufs/ufs/dinode.h>
66 #endif /* __linux__ */
67
68 #include <errno.h>
69 #include <compaterr.h>
70 #include <fcntl.h>
71 #include <stdio.h>
72 #include <stdlib.h>
73 #include <string.h>
74 #include <unistd.h>
75
76 #ifdef __linux__
77 #include <ext2fs/ext2fs.h>
78 #endif
79
80 #include "restore.h"
81 #include "extern.h"
82
83 /*
84 * The following variables define the inode symbol table.
85 * The primary hash table is dynamically allocated based on
86 * the number of inodes in the file system (maxino), scaled by
87 * HASHFACTOR. The variable "entry" points to the hash table;
88 * the variable "entrytblsize" indicates its size (in entries).
89 */
90 #define HASHFACTOR 5
91 static struct entry **entry;
92 static long entrytblsize;
93
94 static void addino __P((ino_t, struct entry *));
95 static struct entry *lookupparent __P((char *));
96 static void removeentry __P((struct entry *));
97
98 /*
99 * Look up an entry by inode number
100 */
101 struct entry *
102 lookupino(ino_t inum)
103 {
104 register struct entry *ep;
105
106 if (inum < WINO || inum >= maxino)
107 return (NULL);
108 for (ep = entry[inum % entrytblsize]; ep != NULL; ep = ep->e_next)
109 if (ep->e_ino == inum)
110 return (ep);
111 return (NULL);
112 }
113
114 /*
115 * Add an entry into the entry table
116 */
117 static void
118 addino(ino_t inum, struct entry *np)
119 {
120 struct entry **epp;
121
122 if (inum < WINO || inum >= maxino)
123 panic("addino: out of range %d\n", inum);
124 epp = &entry[inum % entrytblsize];
125 np->e_ino = inum;
126 np->e_next = *epp;
127 *epp = np;
128 if (dflag)
129 for (np = np->e_next; np != NULL; np = np->e_next)
130 if (np->e_ino == inum)
131 badentry(np, "duplicate inum");
132 }
133
134 /*
135 * Delete an entry from the entry table
136 */
137 void
138 deleteino(ino_t inum)
139 {
140 register struct entry *next;
141 struct entry **prev;
142
143 if (inum < WINO || inum >= maxino)
144 panic("deleteino: out of range %d\n", inum);
145 prev = &entry[inum % entrytblsize];
146 for (next = *prev; next != NULL; next = next->e_next) {
147 if (next->e_ino == inum) {
148 next->e_ino = 0;
149 *prev = next->e_next;
150 return;
151 }
152 prev = &next->e_next;
153 }
154 panic("deleteino: %d not found\n", inum);
155 }
156
157 /*
158 * Look up an entry by name
159 */
160 struct entry *
161 lookupname(char *name)
162 {
163 register struct entry *ep;
164 register char *np, *cp;
165 char buf[MAXPATHLEN];
166
167 cp = name;
168 for (ep = lookupino(ROOTINO); ep != NULL; ep = ep->e_entries) {
169 for (np = buf; *cp != '/' && *cp != '\0' &&
170 np < &buf[sizeof(buf)]; )
171 *np++ = *cp++;
172 if (np == &buf[sizeof(buf)])
173 break;
174 *np = '\0';
175 for ( ; ep != NULL; ep = ep->e_sibling)
176 if (strcmp(ep->e_name, buf) == 0)
177 break;
178 if (ep == NULL)
179 break;
180 if (*cp++ == '\0')
181 return (ep);
182 }
183 return (NULL);
184 }
185
186 /*
187 * Look up the parent of a pathname
188 */
189 static struct entry *
190 lookupparent(char *name)
191 {
192 struct entry *ep;
193 char *tailindex;
194
195 tailindex = strrchr(name, '/');
196 if (tailindex == NULL)
197 return (NULL);
198 *tailindex = '\0';
199 ep = lookupname(name);
200 *tailindex = '/';
201 if (ep == NULL)
202 return (NULL);
203 if (ep->e_type != NODE)
204 panic("%s is not a directory\n", name);
205 return (ep);
206 }
207
208 /*
209 * Determine the current pathname of a node or leaf
210 */
211 char *
212 myname(struct entry *ep)
213 {
214 register char *cp;
215 static char namebuf[MAXPATHLEN];
216
217 for (cp = &namebuf[MAXPATHLEN - 2]; cp > &namebuf[ep->e_namlen]; ) {
218 cp -= ep->e_namlen;
219 memmove(cp, ep->e_name, (size_t)ep->e_namlen);
220 if (ep == lookupino(ROOTINO))
221 return (cp);
222 *(--cp) = '/';
223 ep = ep->e_parent;
224 }
225 panic("%s: pathname too long\n", cp);
226 return(cp);
227 }
228
229 /*
230 * Unused symbol table entries are linked together on a free list
231 * headed by the following pointer.
232 */
233 static struct entry *freelist = NULL;
234
235 /*
236 * add an entry to the symbol table
237 */
238 struct entry *
239 addentry(char *name, ino_t inum, int type)
240 {
241 register struct entry *np, *ep;
242
243 if (freelist != NULL) {
244 np = freelist;
245 freelist = np->e_next;
246 memset(np, 0, sizeof(struct entry));
247 } else {
248 np = (struct entry *)calloc(1, sizeof(struct entry));
249 if (np == NULL)
250 errx(1, "no memory to extend symbol table");
251 }
252 np->e_type = type & ~LINK;
253 ep = lookupparent(name);
254 if (ep == NULL) {
255 if (inum != ROOTINO || lookupino(ROOTINO) != NULL)
256 panic("bad name to addentry %s\n", name);
257 np->e_name = savename(name);
258 np->e_namlen = strlen(name);
259 np->e_parent = np;
260 addino(ROOTINO, np);
261 return (np);
262 }
263 np->e_name = savename(strrchr(name, '/') + 1);
264 np->e_namlen = strlen(np->e_name);
265 np->e_parent = ep;
266 np->e_sibling = ep->e_entries;
267 ep->e_entries = np;
268 if (type & LINK) {
269 ep = lookupino(inum);
270 if (ep == NULL)
271 panic("link to non-existent name\n");
272 np->e_ino = inum;
273 np->e_links = ep->e_links;
274 ep->e_links = np;
275 } else if (inum != 0) {
276 if (lookupino(inum) != NULL)
277 panic("duplicate entry\n");
278 addino(inum, np);
279 }
280 return (np);
281 }
282
283 /*
284 * delete an entry from the symbol table
285 */
286 void
287 freeentry(struct entry *ep)
288 {
289 register struct entry *np;
290 ino_t inum;
291
292 if (ep->e_flags != REMOVED)
293 badentry(ep, "not marked REMOVED");
294 if (ep->e_type == NODE) {
295 if (ep->e_links != NULL)
296 badentry(ep, "freeing referenced directory");
297 if (ep->e_entries != NULL)
298 badentry(ep, "freeing non-empty directory");
299 }
300 if (ep->e_ino != 0) {
301 np = lookupino(ep->e_ino);
302 if (np == NULL)
303 badentry(ep, "lookupino failed");
304 if (np == ep) {
305 inum = ep->e_ino;
306 deleteino(inum);
307 if (ep->e_links != NULL)
308 addino(inum, ep->e_links);
309 } else {
310 for (; np != NULL; np = np->e_links) {
311 if (np->e_links == ep) {
312 np->e_links = ep->e_links;
313 break;
314 }
315 }
316 if (np == NULL)
317 badentry(ep, "link not found");
318 }
319 }
320 removeentry(ep);
321 freename(ep->e_name);
322 ep->e_next = freelist;
323 freelist = ep;
324 }
325
326 /*
327 * Relocate an entry in the tree structure
328 */
329 void
330 moveentry(struct entry *ep, char *newname)
331 {
332 struct entry *np;
333 char *cp;
334
335 np = lookupparent(newname);
336 if (np == NULL)
337 badentry(ep, "cannot move ROOT");
338 if (np != ep->e_parent) {
339 removeentry(ep);
340 ep->e_parent = np;
341 ep->e_sibling = np->e_entries;
342 np->e_entries = ep;
343 }
344 cp = strrchr(newname, '/') + 1;
345 freename(ep->e_name);
346 ep->e_name = savename(cp);
347 ep->e_namlen = strlen(cp);
348 if (strcmp(gentempname(ep), ep->e_name) == 0)
349 ep->e_flags |= TMPNAME;
350 else
351 ep->e_flags &= ~TMPNAME;
352 }
353
354 /*
355 * Remove an entry in the tree structure
356 */
357 static void
358 removeentry(struct entry *ep)
359 {
360 register struct entry *np;
361
362 np = ep->e_parent;
363 if (np->e_entries == ep) {
364 np->e_entries = ep->e_sibling;
365 } else {
366 for (np = np->e_entries; np != NULL; np = np->e_sibling) {
367 if (np->e_sibling == ep) {
368 np->e_sibling = ep->e_sibling;
369 break;
370 }
371 }
372 if (np == NULL)
373 badentry(ep, "cannot find entry in parent list");
374 }
375 }
376
377 /*
378 * Table of unused string entries, sorted by length.
379 *
380 * Entries are allocated in STRTBLINCR sized pieces so that names
381 * of similar lengths can use the same entry. The value of STRTBLINCR
382 * is chosen so that every entry has at least enough space to hold
383 * a "struct strtbl" header. Thus every entry can be linked onto an
384 * appropriate free list.
385 *
386 * NB. The macro "allocsize" below assumes that "struct strhdr"
387 * has a size that is a power of two.
388 */
389 struct strhdr {
390 struct strhdr *next;
391 };
392
393 #define STRTBLINCR (sizeof(struct strhdr))
394 #define allocsize(size) (((size) + 1 + STRTBLINCR - 1) & ~(STRTBLINCR - 1))
395
396 static struct strhdr strtblhdr[allocsize(MAXNAMLEN) / STRTBLINCR];
397
398 /*
399 * Allocate space for a name. It first looks to see if it already
400 * has an appropriate sized entry, and if not allocates a new one.
401 */
402 char *
403 savename(char *name)
404 {
405 struct strhdr *np;
406 long len;
407 char *cp;
408
409 if (name == NULL)
410 panic("bad name\n");
411 len = strlen(name);
412 np = strtblhdr[len / STRTBLINCR].next;
413 if (np != NULL) {
414 strtblhdr[len / STRTBLINCR].next = np->next;
415 cp = (char *)np;
416 } else {
417 cp = malloc((unsigned)allocsize(len));
418 if (cp == NULL)
419 errx(1, "no space for string table");
420 }
421 (void) strcpy(cp, name);
422 return (cp);
423 }
424
425 /*
426 * Free space for a name. The resulting entry is linked onto the
427 * appropriate free list.
428 */
429 void
430 freename(char *name)
431 {
432 struct strhdr *tp, *np;
433
434 tp = &strtblhdr[strlen(name) / STRTBLINCR];
435 np = (struct strhdr *)name;
436 np->next = tp->next;
437 tp->next = np;
438 }
439
440 /*
441 * Useful quantities placed at the end of a dumped symbol table.
442 */
443 struct symtableheader {
444 int32_t volno;
445 int32_t stringsize;
446 int32_t entrytblsize;
447 time_t dumptime;
448 time_t dumpdate;
449 ino_t maxino;
450 int32_t ntrec;
451 };
452
453 /*
454 * dump a snapshot of the symbol table
455 */
456 void
457 dumpsymtable(char *filename, long checkpt)
458 {
459 register struct entry *ep, *tep;
460 register ino_t i;
461 struct entry temp, *tentry;
462 long mynum = 1, stroff = 0;
463 FILE *fd;
464 struct symtableheader hdr;
465
466 Vprintf(stdout, "Check pointing the restore\n");
467 if (Nflag)
468 return;
469 if ((fd = fopen(filename, "w")) == NULL) {
470 warn("fopen");
471 panic("cannot create save file %s for symbol table\n",
472 filename);
473 }
474 clearerr(fd);
475 /*
476 * Assign indices to each entry
477 * Write out the string entries
478 */
479 for (i = WINO; i <= maxino; i++) {
480 for (ep = lookupino(i); ep != NULL; ep = ep->e_links) {
481 ep->e_index = mynum++;
482 (void) fwrite(ep->e_name, sizeof(char),
483 (int)allocsize(ep->e_namlen), fd);
484 }
485 }
486 /*
487 * Convert pointers to indexes, and output
488 */
489 tep = &temp;
490 stroff = 0;
491 for (i = WINO; i <= maxino; i++) {
492 for (ep = lookupino(i); ep != NULL; ep = ep->e_links) {
493 memmove(tep, ep, sizeof(struct entry));
494 tep->e_name = (char *)stroff;
495 stroff += allocsize(ep->e_namlen);
496 tep->e_parent = (struct entry *)ep->e_parent->e_index;
497 if (ep->e_links != NULL)
498 tep->e_links =
499 (struct entry *)ep->e_links->e_index;
500 if (ep->e_sibling != NULL)
501 tep->e_sibling =
502 (struct entry *)ep->e_sibling->e_index;
503 if (ep->e_entries != NULL)
504 tep->e_entries =
505 (struct entry *)ep->e_entries->e_index;
506 if (ep->e_next != NULL)
507 tep->e_next =
508 (struct entry *)ep->e_next->e_index;
509 (void) fwrite((char *)tep, sizeof(struct entry), 1, fd);
510 }
511 }
512 /*
513 * Convert entry pointers to indexes, and output
514 */
515 for (i = 0; i < entrytblsize; i++) {
516 if (entry[i] == NULL)
517 tentry = NULL;
518 else
519 tentry = (struct entry *)entry[i]->e_index;
520 (void) fwrite((char *)&tentry, sizeof(struct entry *), 1, fd);
521 }
522 hdr.volno = checkpt;
523 hdr.maxino = maxino;
524 hdr.entrytblsize = entrytblsize;
525 hdr.stringsize = stroff;
526 hdr.dumptime = dumptime;
527 hdr.dumpdate = dumpdate;
528 hdr.ntrec = ntrec;
529 (void) fwrite((char *)&hdr, sizeof(struct symtableheader), 1, fd);
530 if (ferror(fd)) {
531 warn("fwrite");
532 panic("output error to file %s writing symbol table\n",
533 filename);
534 }
535 (void) fclose(fd);
536 }
537
538 /*
539 * Initialize a symbol table from a file
540 */
541 void
542 initsymtable(char *filename)
543 {
544 char *base;
545 long tblsize;
546 register struct entry *ep;
547 struct entry *baseep, *lep;
548 struct symtableheader hdr;
549 struct stat stbuf;
550 register long i;
551 int fd;
552
553 Vprintf(stdout, "Initialize symbol table.\n");
554 if (filename == NULL) {
555 entrytblsize = maxino / HASHFACTOR;
556 entry = (struct entry **)
557 calloc((unsigned)entrytblsize, sizeof(struct entry *));
558 if (entry == (struct entry **)NULL)
559 errx(1, "no memory for entry table");
560 ep = addentry(".", ROOTINO, NODE);
561 ep->e_flags |= NEW;
562 return;
563 }
564 if ((fd = open(filename, O_RDONLY, 0)) < 0) {
565 warn("open");
566 errx(1, "cannot open symbol table file %s", filename);
567 }
568 if (fstat(fd, &stbuf) < 0) {
569 warn("stat");
570 errx(1, "cannot stat symbol table file %s", filename);
571 }
572 tblsize = stbuf.st_size - sizeof(struct symtableheader);
573 base = calloc(sizeof(char), (unsigned)tblsize);
574 if (base == NULL)
575 errx(1, "cannot allocate space for symbol table");
576 if (read(fd, base, (int)tblsize) < 0 ||
577 read(fd, (char *)&hdr, sizeof(struct symtableheader)) < 0) {
578 warn("read");
579 errx(1, "cannot read symbol table file %s", filename);
580 }
581 switch (command) {
582 case 'r':
583 /*
584 * For normal continuation, insure that we are using
585 * the next incremental tape
586 */
587 if (hdr.dumpdate != dumptime)
588 errx(1, "Incremental tape too %s",
589 (hdr.dumpdate < dumptime) ? "low" : "high");
590 break;
591 case 'R':
592 /*
593 * For restart, insure that we are using the same tape
594 */
595 curfile.action = SKIP;
596 dumptime = hdr.dumptime;
597 dumpdate = hdr.dumpdate;
598 if (!bflag)
599 newtapebuf(hdr.ntrec);
600 getvol(hdr.volno);
601 break;
602 default:
603 panic("initsymtable called from command %c\n", command);
604 break;
605 }
606 maxino = hdr.maxino;
607 entrytblsize = hdr.entrytblsize;
608 entry = (struct entry **)
609 (base + tblsize - (entrytblsize * sizeof(struct entry *)));
610 baseep = (struct entry *)(base + hdr.stringsize - sizeof(struct entry));
611 lep = (struct entry *)entry;
612 for (i = 0; i < entrytblsize; i++) {
613 if (entry[i] == NULL)
614 continue;
615 entry[i] = &baseep[(long)entry[i]];
616 }
617 for (ep = &baseep[1]; ep < lep; ep++) {
618 ep->e_name = base + (long)ep->e_name;
619 ep->e_parent = &baseep[(long)ep->e_parent];
620 if (ep->e_sibling != NULL)
621 ep->e_sibling = &baseep[(long)ep->e_sibling];
622 if (ep->e_links != NULL)
623 ep->e_links = &baseep[(long)ep->e_links];
624 if (ep->e_entries != NULL)
625 ep->e_entries = &baseep[(long)ep->e_entries];
626 if (ep->e_next != NULL)
627 ep->e_next = &baseep[(long)ep->e_next];
628 }
629 }