]> git.wh0rd.org - dump.git/blobdiff - restore/restore.c
Fix restoring of files splitted on several volumes and starting on 2nd or later tapes.
[dump.git] / restore / restore.c
index f0118f26b01940dc901fee6a925b137232d05cad..c773d9066f63a2de811133253ef0558537446ba7 100644 (file)
@@ -2,8 +2,8 @@
  *     Ported to Linux's Second Extended File System as part of the
  *     dump and restore backup suit
  *     Remy Card <card@Linux.EU.Org>, 1994-1997
- *     Stelian Pop <pop@noos.fr>, 1999-2000
- *     Stelian Pop <pop@noos.fr> - Alcôve <www.alcove.fr>, 2000
+ *     Stelian Pop <stelian@popies.net>, 1999-2000
+ *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002
  */
 
 /*
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -41,7 +37,7 @@
 
 #ifndef lint
 static const char rcsid[] =
-       "$Id: restore.c,v 1.19 2001/12/24 12:31:12 stelian Exp $";
+       "$Id: restore.c,v 1.40 2010/12/06 14:26:50 stelian Exp $";
 #endif /* not lint */
 
 #include <config.h>
@@ -58,11 +54,20 @@ static const char rcsid[] =
 #endif
 #include <bsdcompat.h>
 #else  /* __linux__ */
+#ifdef sunos
+#include <sys/fcntl.h>
+#include <bsdcompat.h>
+#else
 #include <ufs/ufs/dinode.h>
+#endif
 #endif /* __linux__ */
 
+#include <protocols/dumprestore.h>
+
+#include <compaterr.h>
 #include <stdio.h>
 #include <string.h>
+#include <unistd.h>
 
 #ifdef __linux__
 #include <ext2fs/ext2fs.h>
@@ -83,7 +88,7 @@ listfile(char *name, dump_ino_t ino, int type)
        long descend = hflag ? GOOD : FAIL;
 #ifdef USE_QFA
        long tnum;
-       long tpos;
+       long long tpos;
 #endif
 
        if (TSTINO(ino, dumpmap) == 0)
@@ -92,7 +97,7 @@ listfile(char *name, dump_ino_t ino, int type)
 #ifdef USE_QFA
        if (tapeposflag) {      /* add QFA positions to output */
                (void)Inode2Tapepos(ino, &tnum, &tpos, 1);
-               fprintf(stdout, "%10lu\t%ld\t%ld\t%s\n", (unsigned long)ino, 
+               fprintf(stdout, "%10lu\t%ld\t%lld\t%s\n", (unsigned long)ino, 
                        tnum, tpos, name);
        }
        else
@@ -108,7 +113,7 @@ listfile(char *name, dump_ino_t ino, int type)
 long
 addfile(char *name, dump_ino_t ino, int type)
 {
-       register struct entry *ep, *np;
+       struct entry *ep, *np;
        long descend = hflag ? GOOD : FAIL;
        char buf[100];
 
@@ -140,7 +145,11 @@ addfile(char *name, dump_ino_t ino, int type)
                        }
        }
        ep = addentry(name, ino, type);
+#ifdef USE_QFA
+       if ((type == NODE) && (!createtapeposflag))
+#else
        if (type == NODE)
+#endif
                newnode(ep);
        ep->e_flags |= NEW;
        return (descend);
@@ -152,7 +161,7 @@ addfile(char *name, dump_ino_t ino, int type)
  */
 /* ARGSUSED */
 long
-deletefile(char *name, dump_ino_t ino, int type)
+deletefile(char *name, dump_ino_t ino, UNUSED(int type))
 {
        long descend = hflag ? GOOD : FAIL;
        struct entry *ep;
@@ -192,8 +201,8 @@ static struct entry *removelist;
 void
 removeoldleaves(void)
 {
-       register struct entry *ep, *nextep;
-       register dump_ino_t i, mydirino;
+       struct entry *ep, *nextep;
+       dump_ino_t i, mydirino;
 
        Vprintf(stdout, "Mark entries to be removed.\n");
        if ((ep = lookupino(WINO))) {
@@ -210,8 +219,11 @@ removeoldleaves(void)
                                continue;
 #ifdef __linux__
                        (void)fprintf(stderr, "BUG! Should call delwhiteout\n");
+#else
+#ifdef sunos
 #else
                        delwhiteout(ep);
+#endif
 #endif
                        freeentry(ep);
                }
@@ -249,7 +261,7 @@ removeoldleaves(void)
 long
 nodeupdates(char *name, dump_ino_t ino, int type)
 {
-       register struct entry *ep, *np, *ip;
+       struct entry *ep, *np, *ip;
        long descend = GOOD;
        int lookuptype = 0;
        int key = 0;
@@ -505,7 +517,7 @@ nodeupdates(char *name, dump_ino_t ino, int type)
                if (compare_ignore_not_found) break;
                fprintf(stderr, "%s: (inode %lu) not found on tape\n",
                        name, (unsigned long)ino);
-               compare_errors = 1;
+               do_compare_error;
                break;
 
        /*
@@ -554,25 +566,40 @@ keyval(int key)
 
 /*
  * Find unreferenced link names.
+ *
+ * This also takes care of directories which were missed by removeoldleaves(),
+ * because their inode has been reused, but excluded from the dump.
  */
 void
 findunreflinks(void)
 {
-       register struct entry *ep, *np;
-       register dump_ino_t i;
+       struct entry *ep, *np;
+       dump_ino_t i;
+       int j;
 
        Vprintf(stdout, "Find unreferenced names.\n");
        for (i = ROOTINO; i < maxino; i++) {
                ep = lookupino(i);
                if (ep == NULL || ep->e_type == LEAF || TSTINO(i, dumpmap) == 0)
                        continue;
-               for (np = ep->e_entries; np != NULL; np = np->e_sibling) {
-                       if (np->e_flags == 0) {
-                               Dprintf(stdout,
-                                   "%s: remove unreferenced name\n",
-                                   myname(np));
-                               removeleaf(np);
-                               freeentry(np);
+               if (ep->e_entries == NULL)
+                       continue;
+               for (j = 0; j < dirhash_size; j++) {
+                       for (np = ep->e_entries[j]; np != NULL; np = np->e_sibling) {
+                               if ((np->e_flags & ~TMPNAME) == 0) {
+                                       Dprintf(stdout,
+                                           "%s: remove unreferenced name\n",
+                                           myname(np));
+                                       if (np->e_type == LEAF) {
+                                               removeleaf(np);
+                                               freeentry(np);
+                                       } else {
+                                               np->e_flags |= TMPNAME;
+                                               deleteino(np->e_ino);
+                                               np->e_next = removelist;
+                                               removelist = np;
+                                       }
+                               }
                        }
                }
        }
@@ -580,15 +607,30 @@ findunreflinks(void)
         * Any leaves remaining in removed directories is unreferenced.
         */
        for (ep = removelist; ep != NULL; ep = ep->e_next) {
-               for (np = ep->e_entries; np != NULL; 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);
+               if (ep->e_entries == NULL)
+                       continue;
+               for (j = 0; j < dirhash_size; j++) {
+                       for (np = ep->e_entries[j]; np != NULL; 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);
+                               } else {
+                                       if ((np->e_flags & ~TMPNAME) != 0)
+                                               badentry(np, "unreferenced with flags");
+
+                                       if (np->e_flags == 0) {
+                                               Dprintf(stdout,
+                                                   "%s: remove unreferenced name\n",
+                                                   myname(np));
+                                               np->e_next = ep->e_next;
+                                               ep->e_next = np;
+                                       }
+                               }
                        }
                }
        }
@@ -606,7 +648,7 @@ findunreflinks(void)
 void
 removeoldnodes(void)
 {
-       register struct entry *ep, **prev;
+       struct entry *ep, **prev;
        long change;
 
        Vprintf(stdout, "Remove old nodes (directories).\n");
@@ -614,10 +656,19 @@ removeoldnodes(void)
                change = 0;
                prev = &removelist;
                for (ep = removelist; ep != NULL; ep = *prev) {
+                       int docont = 0;
                        if (ep->e_entries != NULL) {
-                               prev = &ep->e_next;
-                               continue;
+                               int i;
+                               for (i = 0; i < dirhash_size; i++) {
+                                       if (ep->e_entries[i] != NULL) {
+                                               prev = &ep->e_next;
+                                               docont = 1;
+                                               break;
+                                       }
+                               }
                        }
+                       if (docont)
+                               continue;
                        *prev = ep->e_next;
                        removenode(ep);
                        freeentry(ep);
@@ -637,9 +688,12 @@ compare_entry(struct entry *ep, int do_compare)
 {
        if ((ep->e_flags & (NEW|EXTRACT)) == 0) {
                badentry(ep, "unexpected file on tape");
-               compare_errors = 1;
+               do_compare_error;
+       }
+       if (do_compare) {
+               (void) comparefile(myname(ep));
+               skipxattr();
        }
-       if (do_compare) (void) comparefile(myname(ep));
        ep->e_flags &= ~(NEW|EXTRACT);
 }
 
@@ -649,7 +703,7 @@ compare_entry(struct entry *ep, int do_compare)
 void
 compareleaves(void)
 {
-       register struct entry *ep;
+       struct entry *ep;
        dump_ino_t first;
        long curvol;
 
@@ -669,7 +723,7 @@ compareleaves(void)
                        if (ep == NULL)
                                panic("%d: bad first\n", first);
                        fprintf(stderr, "%s: not found on tape\n", myname(ep));
-                       compare_errors = 1;
+                       do_compare_error;
                        ep->e_flags &= ~(NEW|EXTRACT);
                        first = lowerbnd(first);
                }
@@ -683,14 +737,13 @@ compareleaves(void)
                if (first != curfile.ino) {
                        fprintf(stderr, "expected next file %ld, got %lu\n",
                                (long)first, (unsigned long)curfile.ino);
-                       compare_errors = 1;
                        skipfile();
                        goto next;
                }
                ep = lookupino(curfile.ino);
                if (ep == NULL) {
                        panic("unknown file on tape\n");
-                       compare_errors = 1;
+                       do_compare_error;
                }
                compare_entry(ep, 1);
                for (ep = ep->e_links; ep != NULL; ep = ep->e_links) {
@@ -723,7 +776,7 @@ compareleaves(void)
                        panic("%d: bad first\n", first);
                fprintf(stderr, "%s: (inode %lu) not found on tape\n", 
                        myname(ep), (unsigned long)first);
-               compare_errors = 1;
+               do_compare_error;
                ep->e_flags &= ~(NEW|EXTRACT);
                first = lowerbnd(first);
        }
@@ -736,9 +789,10 @@ compareleaves(void)
 void
 createleaves(char *symtabfile)
 {
-       register struct entry *ep;
+       struct entry *ep;
        dump_ino_t first;
        long curvol;
+       int doremove;
 
        if (command == 'R') {
                Vprintf(stdout, "Continue extraction of new leaves\n");
@@ -789,18 +843,20 @@ createleaves(char *symtabfile)
                 * be removed since its type may change from one leaf type
                 * to another (e.g. "file" to "character special").
                 */
-               if ((ep->e_flags & EXTRACT) != 0) {
-                       removeleaf(ep);
-                       ep->e_flags &= ~REMOVED;
-               }
-               (void) extractfile(myname(ep));
+               if ((ep->e_flags & EXTRACT) != 0)
+                       doremove = 1;
+               else
+                       doremove = 0;
+               (void) extractfile(ep, doremove);
+               skipxattr();
                ep->e_flags &= ~(NEW|EXTRACT);
+
                /*
                 * We checkpoint the restore after every tape reel, so
                 * as to simplify the amount of work required by the
                 * 'R' command.
                 */
-       next:
+next:
                if (curvol != volno) {
                        dumpsymtable(symtabfile, volno);
                        skipmaps();
@@ -822,7 +878,7 @@ createleaves(char *symtabfile)
                        panic("%d: bad first\n", first);
                fprintf(stderr, "%s: (inode %lu) not found on tape\n", 
                        myname(ep), (unsigned long)first);
-               compare_errors = 1;
+               do_compare_error;
                ep->e_flags &= ~(NEW|EXTRACT);
                first = lowerbnd(first);
        }
@@ -835,17 +891,28 @@ createleaves(char *symtabfile)
 void
 createfiles(void)
 {
-       register dump_ino_t first, next, last;
-       register struct entry *ep;
+       dump_ino_t first, next, last;
+       struct entry *ep;
        long curvol;
 #ifdef USE_QFA
-       long tnum, tpos, curtpos, tmpcnt;
+       long tnum, tmpcnt;
+       long long tpos, curtpos = 0;
        time_t tistart, tiend, titaken;
+       int             volChg;
 #endif
 
        Vprintf(stdout, "Extract requested files\n");
        curfile.action = SKIP;
-       getvol((long)1);
+#ifdef USE_QFA
+       if (!tapeposflag) {
+#endif
+               if (volinfo[1] == ROOTINO)
+                       curfile.ino = 0;
+               else
+                       getvol((long)1);
+#ifdef USE_QFA
+       }
+#endif
        skipmaps();
        skipdirs();
        first = lowerbnd(ROOTINO);
@@ -867,9 +934,10 @@ createfiles(void)
                 */
                while (curfile.ino > last) {
                        curfile.action = SKIP;
-                       getvol((long)0);
+                       if (!pipein)
+                               getvol((long)0);
                        if (curfile.ino == maxino) {
-                               next = lowerbnd(next);
+                               next = lowerbnd(first);
                                while (next < curfile.ino) {
                                        ep = lookupino(next);
                                        if (ep == NULL)
@@ -893,38 +961,56 @@ createfiles(void)
 #ifdef USE_QFA
                tistart = time(NULL);
                if (tapeposflag) {
-                       /* get tape position for inode (position directly) */
-                       (void)Inode2Tapepos(next, &tnum, &tpos, 1);
-                       if (tpos == 0)
-                               /* get tape position for last available inode
-                                * (position before) */
-                               (void)Inode2Tapepos(next, &tnum, &tpos, 0);
+                       /* get tape position for inode */
+                       (void)Inode2Tapepos(next, &tnum, &tpos, 0);
                        if (tpos != 0) {
-                               if (tnum != volno)
+                               if (tnum != volno) {
                                        (void)RequestVol(tnum);
+                                       volChg = 1;
+                               } else {
+                                       volChg = 0;
+                               }
                                if (GetTapePos(&curtpos) == 0) {
                                        /*  curtpos +1000 ???, some drives 
                                         *  might be too slow */
-                                       if (tpos > curtpos) {
+                                       if (((tpos > (curtpos + 1000)) && (volChg == 0)) || ((tpos != curtpos) && (volChg == 1))) {
+                                               volChg = 0;
 #ifdef DEBUG_QFA
-                                               msg("positioning tape %ld from %ld to %ld for inode %10lu ...\n", volno, curtpos, tpos, (unsigned long)next);
+                                               msg("positioning tape %ld from %lld to %lld for inode %lu ...\n", volno, curtpos, tpos, (unsigned long)next);
 #endif
                                                if (GotoTapePos(tpos) == 0) {
 #ifdef DEBUG_QFA
-                                                       if (GetTapePos(&curtpos) == 0)
-                                                               msg("before resnyc at tape position %ld\n", curtpos);
+                                                       if (GetTapePos(&curtpos) == 0) {
+                                                               msg("before resnyc at tape position %lld (%ld, %ld, %s)\n", curtpos, next, curfile.ino, curfile.name);
+                                                       }
 #endif
-                                                       (void)ReReadFromTape();
+                                                       ReReadInodeFromTape(next);
 #ifdef DEBUG_QFA
-                                                       if (GetTapePos(&curtpos) == 0)
-                                                               msg("after resync at tape position %ld\n", curtpos);
+                                                       if (GetTapePos(&curtpos) == 0) {
+                                                               msg("after resnyc at tape position %lld (%ld, %ld, %s)\n", curtpos, next, curfile.ino, curfile.name);
+                                                       }
 #endif
                                                }
+                                       } else {
+#ifdef DEBUG_QFA
+                                               msg("already at tape %ld position %ld for inode %lu ...\n", volno, tpos, (unsigned long)next);
+#endif
                                        }
                                }
                        }
                }
+               else
 #endif /* USA_QFA */
+                       if (volinfo[1] == ROOTINO) {
+                               int i, goodvol = 1;
+
+                               for (i = 1; i < (int)TP_NINOS && volinfo[i] != 0; ++i)
+                                       if (volinfo[i] < next)
+                                               goodvol = i;
+
+                               if (goodvol != volno)
+                                       RequestVol(goodvol);
+                       }
 
                do      {
                        curvol = volno;
@@ -968,8 +1054,11 @@ createfiles(void)
                        ep = lookupino(next);
                        if (ep == NULL)
                                panic("corrupted symbol table\n");
-                       fprintf(stderr, "%s: (inode %lu) not found on tape\n", 
-                               myname(ep), (unsigned long)next);
+#ifdef USE_QFA
+                       if (!createtapeposflag)
+#endif
+                               fprintf(stderr, "%s: (inode %lu) not found on tape\n", 
+                                       myname(ep), (unsigned long)next);
                        ep->e_flags &= ~NEW;
                        next = lowerbnd(next);
                }
@@ -981,7 +1070,23 @@ createfiles(void)
                        ep = lookupino(next);
                        if (ep == NULL)
                                panic("corrupted symbol table\n");
-                       (void) extractfile(myname(ep));
+#ifdef USE_QFA
+                       if (createtapeposflag) {
+#ifdef DEBUG_QFA
+                               msg("inode %ld at tapepos %ld\n", curfile.ino, curtapepos);
+#endif
+                               sprintf(gTps, "%ld\t%ld\t%lld\n", (unsigned long)curfile.ino, volno, curtapepos);
+                               if (write(gTapeposfd, gTps, strlen(gTps)) != (ssize_t)strlen(gTps))
+                                       warn("error writing tapepos file.\n");
+                               skipfile();
+                       } else {
+#endif /* USE_QFA */
+                               (void) extractfile(ep, 0);
+                               skipxattr();
+
+#ifdef USE_QFA
+                       }
+#endif /* USE_QFA */
                        ep->e_flags &= ~NEW;
                        if (volno != curvol)
                                skipmaps();
@@ -995,8 +1100,8 @@ createfiles(void)
 void
 createlinks(void)
 {
-       register struct entry *np, *ep;
-       register dump_ino_t i;
+       struct entry *np, *ep;
+       dump_ino_t i;
        char name[BUFSIZ];
 
        if ((ep = lookupino(WINO))) {
@@ -1006,8 +1111,11 @@ createlinks(void)
                                continue;
 #ifdef __linux__
                        (void)fprintf(stderr, "BUG! Should call addwhiteout\n");
+#else
+#ifdef sunos
 #else
                        (void) addwhiteout(myname(ep));
+#endif
 #endif
                        ep->e_flags &= ~NEW;
                }
@@ -1039,8 +1147,8 @@ createlinks(void)
 void
 checkrestore(void)
 {
-       register struct entry *ep;
-       register dump_ino_t i;
+       struct entry *ep;
+       dump_ino_t i;
 
        Vprintf(stdout, "Check the symbol table.\n");
        for (i = WINO; i < maxino; i++) {