2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
7 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
8 /* All Rights Reserved */
11 * Copyright (c) 1996,1998,2001 by Sun Microsystems, Inc.
12 * All rights reserved.
15 #pragma ident "%Z%%M% %I% %E% SMI"
18 * These routines maintain the symbol table which tracks the state
19 * of the file system being restored. They provide lookup by either
20 * name or inode number. They also provide for creation, deletion,
21 * and renaming of entries. Because of the dynamic nature of pathnames,
22 * names should not be saved, but always constructed just before they
23 * are needed, by calling "myname".
30 * The following variables define the inode symbol table.
31 * The primary hash table is dynamically allocated based on
32 * the number of inodes in the file system (maxino), scaled by
33 * HASHFACTOR. The variable "entry" points to the hash table;
34 * the variable "entrytblsize" indicates its size (in entries).
37 static struct entry
**entry
;
38 static uint_t entrytblsize
;
41 static void addino(ino_t
, struct entry
*);
42 static struct entry
*lookupparent(char *);
43 static void removeentry(struct entry
*);
46 static struct entry
*lookupparent();
47 static void removeentry();
51 * Look up an entry by inode number
59 if (inum
< ROOTINO
|| inum
>= maxino
)
61 for (ep
= entry
[inum
% entrytblsize
]; ep
!= NIL
; ep
= ep
->e_next
)
62 if (ep
->e_ino
== inum
)
68 * We now ignore inodes that are out of range. This
69 * allows us to attempt to proceed in the face of
70 * a corrupted archive, albeit with future complaints
71 * about failed inode lookups. We only complain once
72 * about range problems, to avoid irritating the user
73 * without providing any useful information. Failed
74 * lookups have the bogus name, which is useful, so
77 static int complained_about_range
= 0;
80 * Add an entry into the entry table
89 if (inum
< ROOTINO
|| inum
>= maxino
) {
90 if (!complained_about_range
) {
91 panic(gettext("%s: out of range %d\n"),
93 complained_about_range
= 1;
97 epp
= &entry
[inum
% entrytblsize
];
102 for (np
= np
->e_next
; np
!= NIL
; np
= np
->e_next
)
103 if (np
->e_ino
== inum
)
104 badentry(np
, gettext("duplicate inum"));
108 * Delete an entry from the entry table. We assume our caller
109 * arranges for the necessary memory reclamation, if needed.
118 if (inum
< ROOTINO
|| inum
>= maxino
) {
119 if (!complained_about_range
) {
120 panic(gettext("%s: out of range %d\n"),
122 complained_about_range
= 1;
127 prev
= &entry
[inum
% entrytblsize
];
128 for (next
= *prev
; next
!= NIL
; next
= next
->e_next
) {
129 if (next
->e_ino
== inum
) {
131 *prev
= next
->e_next
;
134 prev
= &next
->e_next
;
139 * Look up an entry by name.
140 * NOTE: this function handles "complex" pathnames (as returned
141 * by myname()) for extended file attributes. The name string
142 * provided to this function should be terminated with *two*
151 char buf
[MAXPATHLEN
];
153 if (strlen(name
) > (sizeof (buf
) - 1)) {
154 (void) fprintf(stderr
, gettext("%s: ignoring too-long name\n"),
160 for (ep
= lookupino(ROOTINO
); ep
!= NIL
; ep
= ep
->e_entries
) {
162 while (*cp
!= '/' && *cp
!= '\0')
165 for (; ep
!= NIL
; ep
= ep
->e_sibling
)
166 if (strcmp(ep
->e_name
, buf
) == 0)
172 * skip over the "./" prefix on all
173 * extended attribute paths
187 * Look up the parent of a pathname. This routine accepts complex
188 * names so the provided name argument must terminate with two NULLs.
190 static struct entry
*
195 char *tailindex
, savechar
, *lastpart
;
198 /* find the last component of the complex name */
201 tailindex
= strrchr(lastpart
, '/');
202 if (tailindex
== 0) {
203 if (lastpart
== name
)
206 * tailindex normaly points to the '/' character
207 * dividing the path, but in the case of an extended
208 * attribute transition it will point to the NULL
209 * separator in front of the attribute path.
211 tailindex
= lastpart
- 1;
216 savechar
= *(tailindex
+1);
217 *(tailindex
+1) = '\0';
218 ep
= lookupname(name
);
219 if (ep
!= NIL
&& !xattrparent
&& ep
->e_type
!= NODE
)
220 panic(gettext("%s is not a directory\n"), name
);
221 if (!xattrparent
) *tailindex
= '/';
222 *(tailindex
+1) = savechar
;
227 * Determine the current pathname of a node or leaf.
228 * The returned pathname will be multiple strings with NULL separators:
230 * ./<path>/entry\0<path>/attrentry\0<path>/...\0\0
232 * return pntr entry attr recursive attr terminator
234 * Guaranteed to return a name that fits within MAXCOMPLEXLEN and is
235 * terminated with two NULLs.
242 struct entry
*root
= lookupino(ROOTINO
);
243 static char namebuf
[MAXCOMPLEXLEN
];
245 cp
= &namebuf
[MAXCOMPLEXLEN
- 3];
248 while (cp
> &namebuf
[ep
->e_namlen
]) {
250 bcopy(ep
->e_name
, cp
, (size_t)ep
->e_namlen
);
253 if (ep
->e_flags
& XATTRROOT
)
259 panic(gettext("%s%s: pathname too long\n"), "...", cp
);
264 * Unused symbol table entries are linked together on a freelist
265 * headed by the following pointer.
267 static struct entry
*freelist
= NIL
;
270 * add an entry to the symbol table
273 addentry(name
, inum
, type
)
278 struct entry
*np
, *ep
;
281 if (freelist
!= NIL
) {
283 freelist
= np
->e_next
;
284 (void) bzero((char *)np
, (size_t)sizeof (*np
));
286 np
= (struct entry
*)calloc(1, sizeof (*np
));
288 (void) fprintf(stderr
,
289 gettext("no memory to extend symbol table\n"));
293 np
->e_type
= type
& ~(LINK
|ROOT
);
295 np
->e_flags
|= XATTR
;
296 ep
= lookupparent(name
);
298 if (inum
!= ROOTINO
|| lookupino(ROOTINO
) != NIL
) {
299 (void) fprintf(stderr
, gettext(
300 "%s: bad name %s\n"), "addentry", name
);
304 np
->e_name
= savename(name
);
305 /* LINTED: savename guarantees that strlen fits in e_namlen */
306 np
->e_namlen
= strlen(name
);
312 if (np
->e_flags
& XATTR
) {
314 * skip to the last part of the complex string: it
315 * containes the extended attribute file name.
319 cp
= strrchr(name
, '/');
325 np
->e_name
= savename(cp
);
326 /* LINTED: savename guarantees that strlen will fit */
327 np
->e_namlen
= strlen(np
->e_name
);
330 * Extended attribute root directories must be linked to their
331 * "parents" via the e_xattrs field. Other entries are simply
332 * added to their parent directories e_entries list.
334 if ((type
& ROOT
) && (np
->e_flags
& XATTR
)) {
335 /* link this extended attribute root dir to its "parent" */
338 /* add this entry to the entry list of the parent dir */
339 np
->e_sibling
= ep
->e_entries
;
343 ep
= lookupino(inum
);
345 /* XXX just bail on this one and continue? */
346 (void) fprintf(stderr
,
347 gettext("link to non-existent name\n"));
351 np
->e_links
= ep
->e_links
;
353 } else if (inum
!= 0) {
354 ep
= lookupino(inum
);
356 panic(gettext("duplicate entry\n"));
364 * delete an entry from the symbol table
373 if ((ep
->e_flags
& REMOVED
) == 0)
374 badentry(ep
, gettext("not marked REMOVED"));
375 if (ep
->e_type
== NODE
) {
376 if (ep
->e_links
!= NIL
)
377 badentry(ep
, gettext("freeing referenced directory"));
378 if (ep
->e_entries
!= NIL
)
379 badentry(ep
, gettext("freeing non-empty directory"));
381 if (ep
->e_ino
!= 0) {
382 np
= lookupino(ep
->e_ino
);
384 badentry(ep
, gettext("lookupino failed"));
388 if (ep
->e_links
!= NIL
)
389 addino(inum
, ep
->e_links
);
391 for (; np
!= NIL
; np
= np
->e_links
) {
392 if (np
->e_links
== ep
) {
393 np
->e_links
= ep
->e_links
;
398 badentry(ep
, gettext("link not found"));
402 freename(ep
->e_name
);
403 ep
->e_next
= freelist
;
408 * Relocate an entry in the tree structure
411 moveentry(ep
, newname
)
418 np
= lookupparent(newname
);
420 badentry(ep
, gettext("cannot move ROOT"));
421 if (np
!= ep
->e_parent
) {
424 ep
->e_sibling
= np
->e_entries
;
427 /* find the last component of the complex name */
429 cp
= strrchr(newname
, '/') + 1;
432 freename(ep
->e_name
);
433 ep
->e_name
= savename(cp
);
434 /* LINTED: savename guarantees that strlen will fit */
435 ep
->e_namlen
= strlen(cp
);
436 if (strcmp(gentempname(ep
), ep
->e_name
) == 0) {
437 /* LINTED: result fits in a short */
438 ep
->e_flags
|= TMPNAME
;
440 /* LINTED: result fits in a short */
441 ep
->e_flags
&= ~TMPNAME
;
446 * Remove an entry in the tree structure
455 if (ep
->e_flags
& XATTRROOT
) {
456 if (np
->e_xattrs
== ep
)
459 badentry(ep
, gettext(
460 "parent does not reference this xattr tree"));
461 } else if (np
->e_entries
== ep
) {
462 np
->e_entries
= ep
->e_sibling
;
464 for (np
= np
->e_entries
; np
!= NIL
; np
= np
->e_sibling
) {
465 if (np
->e_sibling
== ep
) {
466 np
->e_sibling
= ep
->e_sibling
;
471 badentry(ep
, gettext(
472 "cannot find entry in parent list"));
477 * Table of unused string entries, sorted by length.
479 * Entries are allocated in STRTBLINCR sized pieces so that names
480 * of similar lengths can use the same entry. The value of STRTBLINCR
481 * is chosen so that every entry has at least enough space to hold
482 * a "struct strtbl" header. Thus every entry can be linked onto an
483 * apprpriate free list.
485 * NB. The macro "allocsize" below assumes that "struct strhdr"
486 * has a size that is a power of two. Also, an extra byte is
487 * allocated for the string to provide space for the two NULL
488 * string terminator required for extended attribute paths.
494 #define STRTBLINCR ((size_t)sizeof (struct strhdr))
495 #define allocsize(size) (((size) + 2 + STRTBLINCR - 1) & ~(STRTBLINCR - 1))
497 static struct strhdr strtblhdr
[allocsize(MAXCOMPLEXLEN
) / STRTBLINCR
];
500 * Allocate space for a name. It first looks to see if it already
501 * has an appropriate sized entry, and if not allocates a new one.
512 (void) fprintf(stderr
, gettext("bad name\n"));
516 if (len
> MAXPATHLEN
) {
517 (void) fprintf(stderr
, gettext("name too long\n"));
521 np
= strtblhdr
[as
/ STRTBLINCR
].next
;
523 strtblhdr
[as
/ STRTBLINCR
].next
= np
->next
;
526 /* Note that allocsize() adds 2 for the trailing \0s */
529 (void) fprintf(stderr
,
530 gettext("no space for string table\n"));
534 (void) strcpy(cp
, name
);
535 /* add an extra null for complex (attribute) name support */
541 * Free space for a name. The resulting entry is linked onto the
542 * appropriate free list.
548 struct strhdr
*tp
, *np
;
550 /* NULL case should never happen, but might as well be careful */
552 tp
= &strtblhdr
[allocsize(strlen(name
)) / STRTBLINCR
];
553 /*LINTED [name points to at least sizeof (struct strhdr)]*/
554 np
= (struct strhdr
*)name
;
561 * Useful quantities placed at the end of a dumped symbol table.
563 struct symtableheader
{
574 * dump a snapshot of the symbol table
577 dumpsymtable(filename
, checkpt
)
581 struct entry
*ep
, *tep
;
583 struct entry temp
, *tentry
;
587 struct symtableheader hdr
;
589 vprintf(stdout
, gettext("Check pointing the restore\n"));
590 if ((fp
= safe_fopen(filename
, "w", 0600)) == (FILE *)NULL
) {
592 (void) fprintf(stderr
,
593 gettext("cannot create save file %s for symbol table\n"),
599 * Assign an index to each entry
600 * Write out the string entries
602 for (i
= ROOTINO
; i
< maxino
; i
++) {
603 for (ep
= lookupino(i
); ep
!= NIL
; ep
= ep
->e_links
) {
604 ep
->e_index
= mynum
++;
605 (void) fwrite(ep
->e_name
, sizeof (ep
->e_name
[0]),
606 (size_t)allocsize(ep
->e_namlen
), fp
);
610 * Convert e_name pointers to offsets, other pointers
611 * to indices, and output
615 for (i
= ROOTINO
; !ferror(fp
) && i
< maxino
; i
++) {
616 for (ep
= lookupino(i
);
617 !ferror(fp
) && ep
!= NIL
;
619 bcopy((char *)ep
, (char *)tep
, sizeof (*tep
));
620 /* LINTED: type pun ok */
621 tep
->e_name
= (char *)stroff
;
622 stroff
+= allocsize(ep
->e_namlen
);
623 tep
->e_parent
= (struct entry
*)ep
->e_parent
->e_index
;
624 if (ep
->e_links
!= NIL
)
626 (struct entry
*)ep
->e_links
->e_index
;
627 if (ep
->e_sibling
!= NIL
)
629 (struct entry
*)ep
->e_sibling
->e_index
;
630 if (ep
->e_entries
!= NIL
)
632 (struct entry
*)ep
->e_entries
->e_index
;
633 if (ep
->e_xattrs
!= NIL
)
635 (struct entry
*)ep
->e_xattrs
->e_index
;
636 if (ep
->e_next
!= NIL
)
638 (struct entry
*)ep
->e_next
->e_index
;
639 (void) fwrite((char *)tep
, sizeof (*tep
), 1, fp
);
643 * Convert entry pointers to indices, and output
645 for (i
= 0; !ferror(fp
) && i
< (ino_t
)entrytblsize
; i
++) {
649 tentry
= (struct entry
*)entry
[i
]->e_index
;
650 (void) fwrite((char *)&tentry
, sizeof (tentry
), 1, fp
);
654 /* Ought to have a checksum or magic number */
657 hdr
.entrytblsize
= entrytblsize
;
658 hdr
.stringsize
= stroff
;
659 hdr
.dumptime
= dumptime
;
660 hdr
.dumpdate
= dumpdate
;
662 (void) fwrite((char *)&hdr
, sizeof (hdr
), 1, fp
);
667 panic(gettext("output error to file %s writing symbol table\n"),
674 * Initialize a symbol table from a file
677 initsymtable(filename
)
683 struct entry
*baseep
, *lep
;
684 struct symtableheader hdr
;
689 vprintf(stdout
, gettext("Initialize symbol table.\n"));
690 if (filename
== NULL
) {
691 if ((maxino
/ HASHFACTOR
) > UINT_MAX
) {
692 (void) fprintf(stderr
,
693 gettext("file system too large\n"));
696 /* LINTED: result fits in entrytblsize */
697 entrytblsize
= maxino
/ HASHFACTOR
;
698 entry
= (struct entry
**)
699 /* LINTED entrytblsize fits in a size_t */
700 calloc((size_t)entrytblsize
, sizeof (*entry
));
701 if (entry
== (struct entry
**)NULL
) {
702 (void) fprintf(stderr
,
703 gettext("no memory for entry table\n"));
706 ep
= addentry(".", ROOTINO
, NODE
);
707 /* LINTED: result fits in a short */
711 if ((fd
= open(filename
, O_RDONLY
|O_LARGEFILE
)) < 0) {
713 (void) fprintf(stderr
,
714 gettext("cannot open symbol table file %s\n"), filename
);
717 if (fstat64(fd
, &stbuf
) < 0) {
719 (void) fprintf(stderr
,
720 gettext("cannot stat symbol table file %s\n"), filename
);
725 * The symbol table file is too small so say we can't read it.
727 if (stbuf
.st_size
< sizeof (hdr
)) {
728 (void) fprintf(stderr
,
729 gettext("cannot read symbol table file %s\n"), filename
);
733 tblsize
= stbuf
.st_size
- sizeof (hdr
);
734 if (tblsize
> ULONG_MAX
) {
735 (void) fprintf(stderr
,
736 gettext("symbol table file too large\n"));
740 /* LINTED tblsize fits in a size_t */
741 base
= calloc((size_t)sizeof (char), (size_t)tblsize
);
743 (void) fprintf(stderr
,
744 gettext("cannot allocate space for symbol table\n"));
748 /* LINTED tblsize fits in a size_t */
749 if (read(fd
, base
, (size_t)tblsize
) < 0 ||
750 read(fd
, (char *)&hdr
, sizeof (hdr
)) < 0) {
752 (void) fprintf(stderr
,
753 gettext("cannot read symbol table file %s\n"), filename
);
762 * For normal continuation, insure that we are using
763 * the next incremental tape
765 if (hdr
.dumpdate
!= dumptime
) {
766 if (hdr
.dumpdate
< dumptime
)
767 (void) fprintf(stderr
, gettext(
768 "Incremental volume too low\n"));
770 (void) fprintf(stderr
, gettext(
771 "Incremental volume too high\n"));
777 * For restart, insure that we are using the same tape
779 curfile
.action
= SKIP
;
780 dumptime
= hdr
.dumptime
;
781 dumpdate
= hdr
.dumpdate
;
783 newtapebuf(hdr
.ntrec
);
787 (void) fprintf(stderr
,
788 gettext("initsymtable called from command %c\n"),
794 entrytblsize
= hdr
.entrytblsize
;
795 /*LINTED [pointer cast alignment]*/
796 entry
= (struct entry
**)
797 (base
+ tblsize
- (entrytblsize
* sizeof (*entry
)));
798 if (((ulong_t
)entry
% 4) != 0) {
799 (void) fprintf(stderr
,
800 gettext("Symbol table file corrupted\n"));
803 /*LINTED [rvalue % 4 == 0] */
804 baseep
= (struct entry
*)
805 (base
+ hdr
.stringsize
- sizeof (*baseep
));
806 if (((ulong_t
)baseep
% 4) != 0) {
807 (void) fprintf(stderr
,
808 gettext("Symbol table file corrupted\n"));
811 lep
= (struct entry
*)entry
;
812 for (i
= 0; i
< entrytblsize
; i
++) {
815 entry
[i
] = &baseep
[(long)entry
[i
]];
817 for (ep
= &baseep
[1]; ep
< lep
; ep
++) {
818 ep
->e_name
= base
+ (long)ep
->e_name
;
819 ep
->e_parent
= &baseep
[(long)ep
->e_parent
];
820 if (ep
->e_sibling
!= NIL
)
821 ep
->e_sibling
= &baseep
[(long)ep
->e_sibling
];
822 if (ep
->e_links
!= NIL
)
823 ep
->e_links
= &baseep
[(long)ep
->e_links
];
824 if (ep
->e_entries
!= NIL
)
825 ep
->e_entries
= &baseep
[(long)ep
->e_entries
];
826 if (ep
->e_xattrs
!= NIL
)
827 ep
->e_xattrs
= &baseep
[(long)ep
->e_xattrs
];
828 if (ep
->e_next
!= NIL
)
829 ep
->e_next
= &baseep
[(long)ep
->e_next
];