]> 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 5ac6c870d56949ffe319a22414672f92c05869ce..c773d9066f63a2de811133253ef0558537446ba7 100644 (file)
@@ -37,7 +37,7 @@
 
 #ifndef lint
 static const char rcsid[] =
-       "$Id: restore.c,v 1.31 2003/03/30 15:40:39 stelian Exp $";
+       "$Id: restore.c,v 1.40 2010/12/06 14:26:50 stelian Exp $";
 #endif /* not lint */
 
 #include <config.h>
@@ -54,8 +54,14 @@ 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>
@@ -213,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);
                }
@@ -557,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)
 {
        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;
+                                       }
+                               }
                        }
                }
        }
@@ -583,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;
+                                       }
+                               }
                        }
                }
        }
@@ -617,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);
@@ -642,7 +690,10 @@ compare_entry(struct entry *ep, int do_compare)
                badentry(ep, "unexpected file on tape");
                do_compare_error;
        }
-       if (do_compare) (void) comparefile(myname(ep));
+       if (do_compare) {
+               (void) comparefile(myname(ep));
+               skipxattr();
+       }
        ep->e_flags &= ~(NEW|EXTRACT);
 }
 
@@ -686,7 +737,6 @@ compareleaves(void)
                if (first != curfile.ino) {
                        fprintf(stderr, "expected next file %ld, got %lu\n",
                                (long)first, (unsigned long)curfile.ino);
-                       do_compare_error;
                        skipfile();
                        goto next;
                }
@@ -798,13 +848,15 @@ createleaves(char *symtabfile)
                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();
@@ -844,21 +896,23 @@ createfiles(void)
        long curvol;
 #ifdef USE_QFA
        long tnum, tmpcnt;
-       long long tpos, curtpos;
+       long long tpos, curtpos = 0;
        time_t tistart, tiend, titaken;
+       int             volChg;
 #endif
 
        Vprintf(stdout, "Extract requested files\n");
        curfile.action = SKIP;
 #ifdef USE_QFA
-       if (tapeposflag)
-               curfile.ino = 0;
-       else
+       if (!tapeposflag) {
 #endif
                if (volinfo[1] == ROOTINO)
                        curfile.ino = 0;
                else
                        getvol((long)1);
+#ifdef USE_QFA
+       }
+#endif
        skipmaps();
        skipdirs();
        first = lowerbnd(ROOTINO);
@@ -907,38 +961,41 @@ 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 %lld to %lld 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 resync at tape position %lld (%ld, %ld, %s)\n", curtpos, next, curfile.ino, curfile.name);
+                                                       if (GetTapePos(&curtpos) == 0) {
+                                                               msg("before resnyc at tape position %lld (%ld, %ld, %s)\n", curtpos, next, curfile.ino, curfile.name);
+                                                       }
 #endif
                                                        ReReadInodeFromTape(next);
 #ifdef DEBUG_QFA
-                                                       if (GetTapePos(&curtpos) == 0)
-                                                               msg("after resync at tape position %lld (%ld, %ld, %s)\n", curtpos, next, curfile.ino, curfile.name);
+                                                       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
-                                       else
-                                               msg("already at tape %ld position %ld for inode %10lu ...\n", volno, tpos, (unsigned long)next);
+                                               msg("already at tape %ld position %ld for inode %lu ...\n", volno, tpos, (unsigned long)next);
 #endif
+                                       }
                                }
                        }
                }
@@ -999,9 +1056,9 @@ createfiles(void)
                                panic("corrupted symbol table\n");
 #ifdef USE_QFA
                        if (!createtapeposflag)
+#endif
                                fprintf(stderr, "%s: (inode %lu) not found on tape\n", 
                                        myname(ep), (unsigned long)next);
-#endif
                        ep->e_flags &= ~NEW;
                        next = lowerbnd(next);
                }
@@ -1020,13 +1077,13 @@ createfiles(void)
 #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");
+                                       warn("error writing tapepos file.\n");
                                skipfile();
-                       }
-                       else {
-                               msg("restoring %s\n", myname(ep));
+                       } else {
 #endif /* USE_QFA */
                                (void) extractfile(ep, 0);
+                               skipxattr();
+
 #ifdef USE_QFA
                        }
 #endif /* USE_QFA */
@@ -1054,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;
                }