make machine-independent by generatibg syswrite.s on the fly;
[unix-history] / usr / src / sbin / restore / restore.c
index 7fdc20e..da0652b 100644 (file)
@@ -1,8 +1,12 @@
-/* Copyright (c) 1983 Regents of the University of California */
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
 
 #ifndef lint
 
 #ifndef lint
-static char sccsid[] = "@(#)restore.c  3.10    (Berkeley)      83/04/16";
-#endif
+static char sccsid[] = "@(#)restore.c  5.2 (Berkeley) %G%";
+#endif not lint
 
 #include "restore.h"
 
 
 #include "restore.h"
 
@@ -52,20 +56,41 @@ addfile(name, ino, type)
                        return (descend);
                }
        }
                        return (descend);
                }
        }
-       if (ino == ROOTINO)
-               return (descend);
        ep = lookupino(ino);
        if (ep != NIL) {
        ep = lookupino(ino);
        if (ep != NIL) {
-               if (strcmp(name, myname(ep)) == 0)
+               if (strcmp(name, myname(ep)) == 0) {
+                       ep->e_flags |= NEW;
                        return (descend);
                        return (descend);
+               }
                type |= LINK;
        }
        ep = addentry(name, ino, type);
                type |= LINK;
        }
        ep = addentry(name, ino, type);
-       if (type == NODE) {
+       if (type == NODE)
                newnode(ep);
                newnode(ep);
+       ep->e_flags |= NEW;
+       return (descend);
+}
+
+/*
+ * This is used by the 'i' option to undo previous requests made by addfile.
+ * Delete entries from the request queue.
+ */
+/* ARGSUSED */
+long
+deletefile(name, ino, type)
+       char *name;
+       ino_t ino;
+       int type;
+{
+       long descend = hflag ? GOOD : FAIL;
+       struct entry *ep;
+
+       if (BIT(ino, dumpmap) == 0) {
                return (descend);
        }
                return (descend);
        }
-       ep->e_flags |= NEW;
+       ep = lookupino(ino);
+       if (ep != NIL)
+               ep->e_flags &= ~NEW;
        return (descend);
 }
 
        return (descend);
 }
 
@@ -132,6 +157,7 @@ nodeupdates(name, ino, type)
 {
        register struct entry *ep, *np, *ip;
        long descend = GOOD;
 {
        register struct entry *ep, *np, *ip;
        long descend = GOOD;
+       int lookuptype = 0;
        int key = 0;
                /* key values */
 #              define ONTAPE   0x1     /* inode is on the tape */
        int key = 0;
                /* key values */
 #              define ONTAPE   0x1     /* inode is on the tape */
@@ -145,37 +171,59 @@ nodeupdates(name, ino, type)
         * directory hierarchy, with a full path name.
         * The "type" value is incorrectly specified as LEAF for
         * directories that are not on the dump tape.
         * directory hierarchy, with a full path name.
         * The "type" value is incorrectly specified as LEAF for
         * directories that are not on the dump tape.
+        *
+        * Check to see if the file is on the tape.
         */
        if (BIT(ino, dumpmap))
                key |= ONTAPE;
         */
        if (BIT(ino, dumpmap))
                key |= ONTAPE;
+       /*
+        * Check to see if the name exists, and if the name is a link.
+        */
        np = lookupname(name);
        np = lookupname(name);
-       if (np != NIL)
+       if (np != NIL) {
                key |= NAMEFND;
                key |= NAMEFND;
+               ip = lookupino(np->e_ino);
+               if (ip == NULL)
+                       panic("corrupted symbol table\n");
+               if (ip != np)
+                       lookuptype = LINK;
+       }
+       /*
+        * Check to see if the inode exists, and if one of its links
+        * corresponds to the name (if one was found).
+        */
        ip = lookupino(ino);
        if (ip != NIL) {
                key |= INOFND;
        ip = lookupino(ino);
        if (ip != NIL) {
                key |= INOFND;
-               for (ep = ip; ep != NIL; ep = ep->e_links)
+               for (ep = ip->e_links; ep != NIL; ep = ep->e_links) {
                        if (ep == np) {
                                ip = ep;
                                break;
                        }
                        if (ep == np) {
                                ip = ep;
                                break;
                        }
+               }
        }
        /*
        }
        /*
-        * If both a name and an inode are found, but they do
-        * not correspond to the same file, then both the inode
-        * which has been found and the inode corresponding to
-        * the name which has been found need to be renamed.
-        * The current pathname is the new name for the inode
-        * which has been found. Since all files to be
-        * deleted have already been removed, the file found by
-        * name must live under a new name in this dump level.
-        * For the time being it is given a temporary name in anticipation
-        * that it will be renamed when it is later found by inode number.
+        * If both a name and an inode are found, but they do not
+        * correspond to the same file, then both the inode that has
+        * been found and the inode corresponding to the name that
+        * has been found need to be renamed. The current pathname
+        * is the new name for the inode that has been found. Since
+        * all files to be deleted have already been removed, the
+        * named file is either a now unneeded link, or it must live
+        * under a new name in this dump level. If it is a link, it
+        * can be removed. If it is not a link, it is given a
+        * temporary name in anticipation that it will be renamed
+        * when it is later found by inode number.
         */
        if (((key & (INOFND|NAMEFND)) == (INOFND|NAMEFND)) && ip != np) {
         */
        if (((key & (INOFND|NAMEFND)) == (INOFND|NAMEFND)) && ip != np) {
-               dprintf(stdout, "name/inode conflict, mktempname %s\n",
-                       myname(np));
-               mktempname(np);
+               if (lookuptype == LINK) {
+                       removeleaf(np);
+                       freeentry(np);
+               } else {
+                       dprintf(stdout, "name/inode conflict, mktempname %s\n",
+                               myname(np));
+                       mktempname(np);
+               }
                np = NIL;
                key &= ~NAMEFND;
        }
                np = NIL;
                key &= ~NAMEFND;
        }
@@ -204,6 +252,27 @@ nodeupdates(name, ino, type)
                        flagvalues(ip));
                break;
 
                        flagvalues(ip));
                break;
 
+       /*
+        * A file on the tape has a name which is the same as a name
+        * corresponding to a different file in the previous dump.
+        * Since all files to be deleted have already been removed,
+        * this file is either a now unneeded link, or it must live
+        * under a new name in this dump level. If it is a link, it
+        * can simply be removed. If it is not a link, it is given a
+        * temporary name in anticipation that it will be renamed
+        * when it is later found by inode number (see INOFND case
+        * below). The entry is then treated as a new file.
+        */
+       case ONTAPE|NAMEFND:
+       case ONTAPE|NAMEFND|MODECHG:
+               if (lookuptype == LINK) {
+                       removeleaf(np);
+                       freeentry(np);
+               } else {
+                       mktempname(np);
+               }
+               /* fall through */
+
        /*
         * A previously non-existent file.
         * Add it to the file system, and request its extraction.
        /*
         * A previously non-existent file.
         * Add it to the file system, and request its extraction.
@@ -214,9 +283,7 @@ nodeupdates(name, ino, type)
                ep = addentry(name, ino, type);
                if (type == NODE)
                        newnode(ep);
                ep = addentry(name, ino, type);
                if (type == NODE)
                        newnode(ep);
-               else
-                       ep->e_flags |= NEW;
-               ep->e_flags |= KEEP;
+               ep->e_flags |= NEW|KEEP;
                dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
                        flagvalues(ep));
                break;
                dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
                        flagvalues(ep));
                break;
@@ -241,7 +308,7 @@ nodeupdates(name, ino, type)
                        renameit(myname(ip), name);
                        moveentry(ip, name);
                        ip->e_flags |= KEEP;
                        renameit(myname(ip), name);
                        moveentry(ip, name);
                        ip->e_flags |= KEEP;
-                       dprintf(stdout, "[%s] %s: %s\n", keyval(key),
+                       dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
                                flagvalues(ip));
                        break;
                }
                                flagvalues(ip));
                        break;
                }
@@ -259,25 +326,10 @@ nodeupdates(name, ino, type)
                break;
 
        /*
                break;
 
        /*
-        * A file on the tape has a name which is the same as a name
-        * corresponding to a different file in the previous dump.
-        * Since all files to be deleted have already been removed,
-        * this file must live under a new name in this dump level.
-        * For the time being it is given a temporary name in anticipation
-        * that it will be renamed when it is later found by inode number
-        * (see INOFND case above).
-        * This then falls into the simple case of a previously known
-        * file which is to be updated.
+        * A previously known file which is to be updated.
         */
         */
-       case ONTAPE|NAMEFND:
-       case ONTAPE|NAMEFND|MODECHG:
-               mktempname(np);
-               np = addentry(name, ino, type);
-               if (type == NODE)
-                       newnode(np);
-               /* fall through */
        case ONTAPE|INOFND|NAMEFND:
        case ONTAPE|INOFND|NAMEFND:
-               if (type == LEAF)
+               if (type == LEAF && lookuptype != LINK)
                        np->e_flags |= EXTRACT;
                np->e_flags |= KEEP;
                dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
                        np->e_flags |= EXTRACT;
                np->e_flags |= KEEP;
                dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
@@ -310,14 +362,14 @@ nodeupdates(name, ino, type)
                        newnode(ip);
                } else {
                        /* changing from node to leaf */
                        newnode(ip);
                } else {
                        /* changing from node to leaf */
-                       mktempname(ip);
+                       if ((ip->e_flags & TMPNAME) == 0)
+                               mktempname(ip);
                        deleteino(ip->e_ino);
                        ip->e_next = removelist;
                        removelist = ip;
                        ip = addentry(name, ino, type);
                        deleteino(ip->e_ino);
                        ip->e_next = removelist;
                        removelist = ip;
                        ip = addentry(name, ino, type);
-                       ip->e_flags |= NEW;
                }
                }
-               ip->e_flags |= KEEP;
+               ip->e_flags |= NEW|KEEP;
                dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
                        flagvalues(ip));
                break;
                dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
                        flagvalues(ip));
                break;
@@ -332,6 +384,17 @@ nodeupdates(name, ino, type)
                descend = FAIL;
                break;
 
                descend = FAIL;
                break;
 
+       /*
+        * If we find a directory entry for a file that is not on
+        * the tape, then we must have found a file that was created
+        * while the dump was in progress. Since we have no contents
+        * for it, we discard the name knowing that it will be on the
+        * next incremental tape.
+        */
+       case NIL:
+               fprintf(stderr, "%s: not found on tape\n", name);
+               break;
+
        /*
         * If any of these arise, something is grievously wrong with
         * the current state of the symbol table.
        /*
         * If any of these arise, something is grievously wrong with
         * the current state of the symbol table.
@@ -339,7 +402,6 @@ nodeupdates(name, ino, type)
        case INOFND|NAMEFND|MODECHG:
        case NAMEFND|MODECHG:
        case INOFND|MODECHG:
        case INOFND|NAMEFND|MODECHG:
        case NAMEFND|MODECHG:
        case INOFND|MODECHG:
-       case NIL:
                panic("[%s] %s: inconsistent state\n", keyval(key), name);
                break;
 
                panic("[%s] %s: inconsistent state\n", keyval(key), name);
                break;
 
@@ -364,7 +426,7 @@ keyval(key)
 {
        static char keybuf[32];
 
 {
        static char keybuf[32];
 
-       strcpy(keybuf, "|NIL");
+       (void) strcpy(keybuf, "|NIL");
        keybuf[0] = '\0';
        if (key & ONTAPE)
                (void) strcat(keybuf, "|ONTAPE");
        keybuf[0] = '\0';
        if (key & ONTAPE)
                (void) strcat(keybuf, "|ONTAPE");
@@ -388,7 +450,7 @@ findunreflinks()
        vprintf(stdout, "Find unreferenced names.\n");
        for (i = ROOTINO; i < maxino; i++) {
                ep = lookupino(i);
        vprintf(stdout, "Find unreferenced names.\n");
        for (i = ROOTINO; i < maxino; i++) {
                ep = lookupino(i);
-               if (ep == NIL || ep->e_type == LEAF || !BIT(i, dumpmap))
+               if (ep == NIL || ep->e_type == LEAF || BIT(i, dumpmap) == 0)
                        continue;
                for (np = ep->e_entries; np != NIL; np = np->e_sibling) {
                        if (np->e_flags == 0) {
                        continue;
                for (np = ep->e_entries; np != NIL; np = np->e_sibling) {
                        if (np->e_flags == 0) {
@@ -400,6 +462,22 @@ findunreflinks()
                        }
                }
        }
                        }
                }
        }
+       /*
+        * Any leaves remaining in removed directories is unreferenced.
+        */
+       for (ep = removelist; ep != NIL; ep = ep->e_next) {
+               for (np = ep->e_entries; np != NIL; np = np->e_sibling) {
+                       if (np->e_type == LEAF) {
+                               if (np->e_flags != 0)
+                                       badentry(np, "unreferenced with flags");
+                               dprintf(stdout,
+                                   "%s: remove unreferenced name\n",
+                                   myname(np));
+                               removeleaf(np);
+                               freeentry(np);
+                       }
+               }
+       }
 }
 
 /*
 }
 
 /*
@@ -460,7 +538,8 @@ createleaves(symtabfile)
                 * If the next available file is not the one which we
                 * expect then we have missed one or more files. Since
                 * we do not request files that were not on the tape,
                 * If the next available file is not the one which we
                 * expect then we have missed one or more files. Since
                 * we do not request files that were not on the tape,
-                * the lost files must have been due to a tape read error.
+                * the lost files must have been due to a tape read error,
+                * or a file that was removed while the dump was in progress.
                 */
                while (first < curfile.ino) {
                        ep = lookupino(first);
                 */
                while (first < curfile.ino) {
                        ep = lookupino(first);
@@ -470,6 +549,13 @@ createleaves(symtabfile)
                        ep->e_flags &= ~(NEW|EXTRACT);
                        first = lowerbnd(first);
                }
                        ep->e_flags &= ~(NEW|EXTRACT);
                        first = lowerbnd(first);
                }
+               /*
+                * If we find files on the tape that have no corresponding
+                * directory entries, then we must have found a file that
+                * was created while the dump was in progress. Since we have 
+                * no name for it, we discard it knowing that it will be
+                * on the next incremental tape.
+                */
                if (first != curfile.ino) {
                        fprintf(stderr, "expected next file %d, got %d\n",
                                first, curfile.ino);
                if (first != curfile.ino) {
                        fprintf(stderr, "expected next file %d, got %d\n",
                                first, curfile.ino);
@@ -507,8 +593,8 @@ createleaves(symtabfile)
 }
 
 /*
 }
 
 /*
- * This is the routine used to extract files for the 'x' command.
- * Efficiently extract a subset of the files on a tape
+ * This is the routine used to extract files for the 'x' and 'i' commands.
+ * Efficiently extract a subset of the files on a tape.
  */
 createfiles()
 {
  */
 createfiles()
 {
@@ -556,7 +642,7 @@ createfiles()
                } while (volno == curvol + 1);
                /*
                 * If volume change out of order occurred the
                } while (volno == curvol + 1);
                /*
                 * If volume change out of order occurred the
-                * current state must be re calculated
+                * current state must be recalculated
                 */
                if (volno != curvol)
                        continue;
                 */
                if (volno != curvol)
                        continue;
@@ -564,10 +650,11 @@ createfiles()
                 * If the current inode is greater than the one we were
                 * looking for then we missed the one we were looking for.
                 * Since we only attempt to extract files listed in the
                 * If the current inode is greater than the one we were
                 * looking for then we missed the one we were looking for.
                 * Since we only attempt to extract files listed in the
-                * dump map, the file must have been lost due to a tape
-                * read error. Thus we report all requested files between
-                * the one we were looking for, and the one we found as
-                * missing, and delete their request flags.
+                * dump map, the lost files must have been due to a tape
+                * read error, or a file that was removed while the dump
+                * was in progress. Thus we report all requested files
+                * between the one we were looking for, and the one we
+                * found as missing, and delete their request flags.
                 */
                while (next < curfile.ino) {
                        ep = lookupino(next);
                 */
                while (next < curfile.ino) {
                        ep = lookupino(next);
@@ -587,6 +674,8 @@ createfiles()
                                panic("corrupted symbol table\n");
                        (void) extractfile(myname(ep));
                        ep->e_flags &= ~NEW;
                                panic("corrupted symbol table\n");
                        (void) extractfile(myname(ep));
                        ep->e_flags &= ~NEW;
+                       if (volno != curvol)
+                               skipmaps();
                }
        }
 }
                }
        }
 }
@@ -606,11 +695,13 @@ createlinks()
                if (ep == NIL)
                        continue;
                for (np = ep->e_links; np != NIL; np = np->e_links) {
                if (ep == NIL)
                        continue;
                for (np = ep->e_links; np != NIL; np = np->e_links) {
+                       if ((np->e_flags & NEW) == 0)
+                               continue;
                        (void) strcpy(name, myname(ep));
                        if (ep->e_type == NODE) {
                        (void) strcpy(name, myname(ep));
                        if (ep->e_type == NODE) {
-                               linkit(name, myname(np), SYMLINK);
+                               (void) linkit(name, myname(np), SYMLINK);
                        } else {
                        } else {
-                               linkit(name, myname(np), HARDLINK);
+                               (void) linkit(name, myname(np), HARDLINK);
                        }
                        np->e_flags &= ~NEW;
                }
                        }
                        np->e_flags &= ~NEW;
                }
@@ -629,8 +720,10 @@ checkrestore()
 
        vprintf(stdout, "Check the symbol table.\n");
        for (i = ROOTINO; i < maxino; i++) {
 
        vprintf(stdout, "Check the symbol table.\n");
        for (i = ROOTINO; i < maxino; i++) {
-               for (ep= lookupino(i); ep != NIL; ep = ep->e_links) {
+               for (ep = lookupino(i); ep != NIL; ep = ep->e_links) {
                        ep->e_flags &= ~KEEP;
                        ep->e_flags &= ~KEEP;
+                       if (ep->e_type == NODE)
+                               ep->e_flags &= ~(NEW|EXISTED);
                        if (ep->e_flags != NULL)
                                badentry(ep, "incomplete operations");
                }
                        if (ep->e_flags != NULL)
                                badentry(ep, "incomplete operations");
                }