must flush stderr before reading from the terminal
[unix-history] / usr / src / sbin / restore / symtab.c
index 7976c46..7e19c68 100644 (file)
@@ -1,26 +1,32 @@
 /* Copyright (c) 1983 Regents of the University of California */
 
 #ifndef lint
 /* Copyright (c) 1983 Regents of the University of California */
 
 #ifndef lint
-static char sccsid[] = "@(#)symtab.c   3.6     (Berkeley)      83/03/08";
+static char sccsid[] = "@(#)symtab.c   3.10    (Berkeley)      83/05/03";
 #endif
 
 #endif
 
+/*
+ * These routines maintain the symbol table which tracks the state
+ * of the file system being restored. They provide lookup by either
+ * name or inode number. They also provide for creation, deletion,
+ * and renaming of entries. Because of the dynamic nature of pathnames,
+ * names should not be saved, but always constructed just before they
+ * are needed, by calling "myname".
+ */
+
 #include "restore.h"
 #include <sys/stat.h>
 #include "restore.h"
 #include <sys/stat.h>
+#include <dir.h>
 
 
-struct symtableheader {
-       long    volno;
-       long    stringsize;
-       long    entrytblsize;
-       time_t  dumptime;
-       time_t  dumpdate;
-       ino_t   maxino;
-};
-
-static struct entry *freelist = NIL;
+/*
+ * The following variables define the inode symbol table.
+ * The primary hash table is dynamically allocated based on
+ * the number of inodes in the file system (maxino), scaled by
+ * HASHFACTOR. The variable "entry" points to the hash table;
+ * the variable "entrytblsize" indicates its size (in entries).
+ */
+#define HASHFACTOR 5
 static struct entry **entry;
 static long entrytblsize;
 static struct entry **entry;
 static long entrytblsize;
-/* used to scale maxino to get inode hash table size */
-#define HASHFACTOR 5
 
 /*
  * Look up an entry by inode number
 
 /*
  * Look up an entry by inode number
@@ -92,7 +98,7 @@ lookupname(name)
 {
        register struct entry *ep;
        register char *np, *cp;
 {
        register struct entry *ep;
        register char *np, *cp;
-       char buf[BUFSIZ];
+       char buf[MAXPATHLEN];
 
        cp = name;
        for (ep = lookupino(ROOTINO); ep != NIL; ep = ep->e_entries) {
 
        cp = name;
        for (ep = lookupino(ROOTINO); ep != NIL; ep = ep->e_entries) {
@@ -141,9 +147,9 @@ myname(ep)
        register struct entry *ep;
 {
        register char *cp;
        register struct entry *ep;
 {
        register char *cp;
-       static char namebuf[BUFSIZ];
+       static char namebuf[MAXPATHLEN];
 
 
-       for (cp = &namebuf[BUFSIZ - 2]; cp > &namebuf[ep->e_namlen]; ) {
+       for (cp = &namebuf[MAXPATHLEN - 2]; cp > &namebuf[ep->e_namlen]; ) {
                cp -= ep->e_namlen;
                bcopy(ep->e_name, cp, (long)ep->e_namlen);
                if (ep == lookupino(ROOTINO))
                cp -= ep->e_namlen;
                bcopy(ep->e_name, cp, (long)ep->e_namlen);
                if (ep == lookupino(ROOTINO))
@@ -155,6 +161,12 @@ myname(ep)
        return(cp);
 }
 
        return(cp);
 }
 
+/*
+ * Unused symbol table entries are linked together on a freelist
+ * headed by the following pointer.
+ */
+static struct entry *freelist = NIL;
+
 /*
  * add an entry to the symbol table
  */
 /*
  * add an entry to the symbol table
  */
@@ -193,6 +205,7 @@ addentry(name, inum, type)
                ep = lookupino(inum);
                if (ep == NIL)
                        panic("link to non-existant name\n");
                ep = lookupino(inum);
                if (ep == NIL)
                        panic("link to non-existant name\n");
+               np->e_ino = inum;
                np->e_links = ep->e_links;
                ep->e_links = np;
        } else if (inum != 0) {
                np->e_links = ep->e_links;
                ep->e_links = np;
        } else if (inum != 0) {
@@ -239,6 +252,7 @@ freeentry(ep)
                }
        }
        removeentry(ep);
                }
        }
        removeentry(ep);
+       freename(ep->e_name);
        ep->e_next = freelist;
        freelist = ep;
 }
        ep->e_next = freelist;
        freelist = ep;
 }
@@ -252,7 +266,6 @@ moveentry(ep, newname)
 {
        struct entry *np;
        char *cp;
 {
        struct entry *np;
        char *cp;
-       long len;
 
        np = lookupparent(newname);
        if (np == NIL)
 
        np = lookupparent(newname);
        if (np == NIL)
@@ -264,16 +277,10 @@ moveentry(ep, newname)
                np->e_entries = ep;
        }
        cp = rindex(newname, '/') + 1;
                np->e_entries = ep;
        }
        cp = rindex(newname, '/') + 1;
-       len = strlen(cp);
-       if (ep->e_flags & TMPNAME)
-               ep->e_namlen--;
-       if (ep->e_namlen >= len) {
-               strcpy(ep->e_name, cp);
-       } else {
-               ep->e_name = savename(cp);
-       }
-       ep->e_namlen = len;
-       if (cp[len - 1] == TMPCHAR)
+       freename(ep->e_name);
+       ep->e_name = savename(cp);
+       ep->e_namlen = strlen(cp);
+       if (strcmp(gentempname(ep), ep->e_name) == 0)
                ep->e_flags |= TMPNAME;
        else
                ep->e_flags &= ~TMPNAME;
                ep->e_flags |= TMPNAME;
        else
                ep->e_flags &= ~TMPNAME;
@@ -303,24 +310,81 @@ removeentry(ep)
 }
 
 /*
 }
 
 /*
- * allocate space for a name
+ * Table of unused string entries, sorted by length.
+ * 
+ * Entries are allocated in STRTBLINCR sized pieces so that names
+ * of similar lengths can use the same entry. The value of STRTBLINCR
+ * is chosen so that every entry has at least enough space to hold
+ * a "struct strtbl" header. Thus every entry can be linked onto an
+ * apprpriate free list.
+ *
+ * NB. The macro "allocsize" below assumes that "struct strhdr"
+ *     has a size that is a power of two.
+ */
+struct strhdr {
+       struct strhdr *next;
+};
+
+#define STRTBLINCR     (sizeof(struct strhdr))
+#define allocsize(size)        (((size) + 1 + STRTBLINCR - 1) & ~(STRTBLINCR - 1))
+
+static struct strhdr strtblhdr[allocsize(MAXNAMLEN) / STRTBLINCR];
+
+/*
+ * Allocate space for a name. It first looks to see if it already
+ * has an appropriate sized entry, and if not allocates a new one.
  */
 char *
 savename(name)
        char *name;
 {
  */
 char *
 savename(name)
        char *name;
 {
+       struct strhdr *np;
        long len;
        char *cp;
 
        if (name == NULL)
                panic("bad name\n");
        long len;
        char *cp;
 
        if (name == NULL)
                panic("bad name\n");
-       len = strlen(name) + 2;
-       len = (len + sizeof(int) - 1) & ~(sizeof(int) - 1);
-       cp = malloc((unsigned)len);
+       len = strlen(name);
+       np = strtblhdr[len / STRTBLINCR].next;
+       if (np != NULL) {
+               strtblhdr[len / STRTBLINCR].next = np->next;
+               cp = (char *)np;
+       } else {
+               cp = malloc((unsigned)allocsize(len));
+               if (cp == NULL)
+                       panic("no space for string table\n");
+       }
        (void) strcpy(cp, name);
        return (cp);
 }
 
        (void) strcpy(cp, name);
        return (cp);
 }
 
+/*
+ * Free space for a name. The resulting entry is linked onto the
+ * appropriate free list.
+ */
+freename(name)
+       char *name;
+{
+       struct strhdr *tp, *np;
+       
+       tp = &strtblhdr[strlen(name) / STRTBLINCR];
+       np = (struct strhdr *)name;
+       np->next = tp->next;
+       tp->next = np;
+}
+
+/*
+ * Useful quantities placed at the end of a dumped symbol table.
+ */
+struct symtableheader {
+       long    volno;
+       long    stringsize;
+       long    entrytblsize;
+       time_t  dumptime;
+       time_t  dumpdate;
+       ino_t   maxino;
+};
+
 /*
  * dump a snapshot of the symbol table
  */
 /*
  * dump a snapshot of the symbol table
  */
@@ -349,14 +413,10 @@ dumpsymtable(filename, checkpt)
        for (i = ROOTINO; i < maxino; i++) {
                for (ep = lookupino(i); ep != NIL; ep = ep->e_links) {
                        ep->e_index = mynum++;
        for (i = ROOTINO; i < maxino; i++) {
                for (ep = lookupino(i); ep != NIL; ep = ep->e_links) {
                        ep->e_index = mynum++;
-                       fwrite(ep->e_name, sizeof(char), ep->e_namlen + 2, fd);
-                       stroff += ep->e_namlen + 2;
+                       (void) fwrite(ep->e_name, sizeof(char),
+                              (int)allocsize(ep->e_namlen), fd);
                }
        }
                }
        }
-       /*
-        * start entries on aligned boundry
-        */
-       fseek(fd, ((stroff + 3) & ~3), 0);
        /*
         * Convert pointers to indexes, and output
         */
        /*
         * Convert pointers to indexes, and output
         */
@@ -364,9 +424,10 @@ dumpsymtable(filename, checkpt)
        stroff = 0;
        for (i = ROOTINO; i < maxino; i++) {
                for (ep = lookupino(i); ep != NIL; ep = ep->e_links) {
        stroff = 0;
        for (i = ROOTINO; i < maxino; i++) {
                for (ep = lookupino(i); ep != NIL; ep = ep->e_links) {
-                       bcopy((char *)ep, (char *)tep, sizeof(struct entry));
+                       bcopy((char *)ep, (char *)tep,
+                               (long)sizeof(struct entry));
                        tep->e_name = (char *)stroff;
                        tep->e_name = (char *)stroff;
-                       stroff += ep->e_namlen + 2;
+                       stroff += allocsize(ep->e_namlen);
                        tep->e_parent = (struct entry *)ep->e_parent->e_index;
                        if (ep->e_links != NIL)
                                tep->e_links =
                        tep->e_parent = (struct entry *)ep->e_parent->e_index;
                        if (ep->e_links != NIL)
                                tep->e_links =
@@ -380,7 +441,7 @@ dumpsymtable(filename, checkpt)
                        if (ep->e_next != NIL)
                                tep->e_next =
                                        (struct entry *)ep->e_next->e_index;
                        if (ep->e_next != NIL)
                                tep->e_next =
                                        (struct entry *)ep->e_next->e_index;
-                       fwrite((char *)tep, sizeof(struct entry), 1, fd);
+                       (void) fwrite((char *)tep, sizeof(struct entry), 1, fd);
                }
        }
        /*
                }
        }
        /*
@@ -391,21 +452,21 @@ dumpsymtable(filename, checkpt)
                        tentry = NIL;
                else
                        tentry = (struct entry *)entry[i]->e_index;
                        tentry = NIL;
                else
                        tentry = (struct entry *)entry[i]->e_index;
-               fwrite((char *)&tentry, sizeof(struct entry *), 1, fd);
+               (void) fwrite((char *)&tentry, sizeof(struct entry *), 1, fd);
        }
        hdr.volno = checkpt;
        hdr.maxino = maxino;
        hdr.entrytblsize = entrytblsize;
        }
        hdr.volno = checkpt;
        hdr.maxino = maxino;
        hdr.entrytblsize = entrytblsize;
-       hdr.stringsize = (stroff + 3) & ~3;
+       hdr.stringsize = stroff;
        hdr.dumptime = dumptime;
        hdr.dumpdate = dumpdate;
        hdr.dumptime = dumptime;
        hdr.dumpdate = dumpdate;
-       fwrite((char *)&hdr, sizeof(struct symtableheader), 1, fd);
+       (void) fwrite((char *)&hdr, sizeof(struct symtableheader), 1, fd);
        if (ferror(fd)) {
                perror("fwrite");
                panic("output error to file %s writing symbol table\n",
                        filename);
        }
        if (ferror(fd)) {
                perror("fwrite");
                panic("output error to file %s writing symbol table\n",
                        filename);
        }
-       fclose(fd);
+       (void) fclose(fd);
 }
 
 /*
 }
 
 /*
@@ -430,7 +491,8 @@ initsymtable(filename)
                        calloc((unsigned)entrytblsize, sizeof(struct entry *));
                if (entry == (struct entry **)NIL)
                        panic("no memory for entry table\n");
                        calloc((unsigned)entrytblsize, sizeof(struct entry *));
                if (entry == (struct entry **)NIL)
                        panic("no memory for entry table\n");
-               (void)addentry(".", ROOTINO, NODE);
+               ep = addentry(".", ROOTINO, NODE);
+               ep->e_flags |= NEW;
                return;
        }
        if ((fd = open(filename, 0)) < 0) {
                return;
        }
        if ((fd = open(filename, 0)) < 0) {