* 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@cybercable.fr>, 1999-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.
*
#ifndef lint
static const char rcsid[] =
- "$Id: restore.c,v 1.8 2000/05/28 16:52:21 stelian Exp $";
+ "$Id: restore.c,v 1.40 2010/12/06 14:26:50 stelian Exp $";
#endif /* not lint */
+#include <config.h>
#include <sys/types.h>
#ifdef __linux__
#include <sys/param.h>
#include <sys/time.h>
+#include <time.h>
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include <ext2fs/ext2_fs.h>
+#else
#include <linux/ext2_fs.h>
+#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>
* List entries on the tape.
*/
long
-listfile(char *name, ino_t ino, int type)
+listfile(char *name, dump_ino_t ino, int type)
{
long descend = hflag ? GOOD : FAIL;
+#ifdef USE_QFA
+ long tnum;
+ long long tpos;
+#endif
if (TSTINO(ino, dumpmap) == 0)
return (descend);
Vprintf(stdout, "%s", type == LEAF ? "leaf" : "dir ");
- fprintf(stdout, "%10lu\t%s\n", (unsigned long)ino, name);
+#ifdef USE_QFA
+ if (tapeposflag) { /* add QFA positions to output */
+ (void)Inode2Tapepos(ino, &tnum, &tpos, 1);
+ fprintf(stdout, "%10lu\t%ld\t%lld\t%s\n", (unsigned long)ino,
+ tnum, tpos, name);
+ }
+ else
+#endif
+ fprintf(stdout, "%10lu\t%s\n", (unsigned long)ino, name);
return (descend);
}
* Request that new entries be extracted.
*/
long
-addfile(char *name, ino_t ino, int type)
+addfile(char *name, dump_ino_t ino, int type)
{
- register struct entry *ep;
+ struct entry *ep, *np;
long descend = hflag ? GOOD : FAIL;
char buf[100];
return (descend);
}
type |= LINK;
+ for (np = ep->e_links; np; np = np->e_links)
+ if (strcmp(name, myname(np)) == 0) {
+ np->e_flags |= NEW;
+ return (descend);
+ }
}
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);
*/
/* ARGSUSED */
long
-deletefile(char *name, ino_t ino, int type)
+deletefile(char *name, dump_ino_t ino, UNUSED(int type))
{
long descend = hflag ? GOOD : FAIL;
struct entry *ep;
void
removeoldleaves(void)
{
- register struct entry *ep, *nextep;
- register 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))) {
continue;
#ifdef __linux__
(void)fprintf(stderr, "BUG! Should call delwhiteout\n");
+#else
+#ifdef sunos
#else
delwhiteout(ep);
+#endif
#endif
freeentry(ep);
}
* Renames are done at the same time.
*/
long
-nodeupdates(char *name, ino_t ino, int type)
+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;
* for it, we discard the name knowing that it will be on the
* next incremental tape.
*/
- case NULL:
+ case 0:
if (compare_ignore_not_found) break;
fprintf(stderr, "%s: (inode %lu) not found on tape\n",
name, (unsigned long)ino);
+ do_compare_error;
break;
/*
/*
* 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 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;
+ }
+ }
}
}
}
* 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;
+ }
+ }
}
}
}
void
removeoldnodes(void)
{
- register struct entry *ep, **prev;
+ struct entry *ep, **prev;
long change;
Vprintf(stdout, "Remove old nodes (directories).\n");
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);
{
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);
}
void
compareleaves(void)
{
- register struct entry *ep;
- ino_t first;
+ struct entry *ep;
+ dump_ino_t first;
long curvol;
first = lowerbnd(ROOTINO);
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);
}
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) {
curvol = volno;
}
}
+ /*
+ * If we encounter the end of the tape and 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, or a file that was removed while the dump was
+ * in progress.
+ */
+ first = lowerbnd(first);
+ while (first < curfile.ino) {
+ ep = lookupino(first);
+ if (ep == NULL)
+ panic("%d: bad first\n", first);
+ fprintf(stderr, "%s: (inode %lu) not found on tape\n",
+ myname(ep), (unsigned long)first);
+ do_compare_error;
+ ep->e_flags &= ~(NEW|EXTRACT);
+ first = lowerbnd(first);
+ }
}
/*
void
createleaves(char *symtabfile)
{
- register struct entry *ep;
- ino_t first;
+ struct entry *ep;
+ dump_ino_t first;
long curvol;
+ int doremove;
if (command == 'R') {
Vprintf(stdout, "Continue extraction of new leaves\n");
ep = lookupino(first);
if (ep == NULL)
panic("%d: bad first\n", first);
- fprintf(stderr, "%s: not found on tape\n", myname(ep));
+ fprintf(stderr, "%s: (inode %lu) not found on tape\n",
+ myname(ep), (unsigned long)first);
ep->e_flags &= ~(NEW|EXTRACT);
first = lowerbnd(first);
}
* 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();
curvol = volno;
}
}
+ /*
+ * If we encounter the end of the tape and 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, or a file that was removed while the dump was
+ * in progress.
+ */
+ first = lowerbnd(first);
+ while (first < curfile.ino) {
+ ep = lookupino(first);
+ if (ep == NULL)
+ panic("%d: bad first\n", first);
+ fprintf(stderr, "%s: (inode %lu) not found on tape\n",
+ myname(ep), (unsigned long)first);
+ do_compare_error;
+ ep->e_flags &= ~(NEW|EXTRACT);
+ first = lowerbnd(first);
+ }
}
/*
void
createfiles(void)
{
- register 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, 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);
last = upperbnd(maxino - 1);
for (;;) {
+#ifdef USE_QFA
+ tmpcnt = 1;
+#endif
first = lowerbnd(first);
last = upperbnd(last);
/*
*/
while (curfile.ino > last) {
curfile.action = SKIP;
- getvol((long)0);
+ if (!pipein)
+ getvol((long)0);
+ if (curfile.ino == maxino) {
+ next = lowerbnd(first);
+ while (next < curfile.ino) {
+ 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);
+ ep->e_flags &= ~NEW;
+ next = lowerbnd(next);
+ }
+ return;
+ }
skipmaps();
skipdirs();
}
* or an out of order volume change is encountered
*/
next = lowerbnd(curfile.ino);
+#ifdef USE_QFA
+ tistart = time(NULL);
+ if (tapeposflag) {
+ /* get tape position for inode */
+ (void)Inode2Tapepos(next, &tnum, &tpos, 0);
+ if (tpos != 0) {
+ 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 + 1000)) && (volChg == 0)) || ((tpos != curtpos) && (volChg == 1))) {
+ volChg = 0;
+#ifdef DEBUG_QFA
+ 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 %lld (%ld, %ld, %s)\n", curtpos, next, curfile.ino, curfile.name);
+ }
+#endif
+ ReReadInodeFromTape(next);
+#ifdef DEBUG_QFA
+ 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;
- while (next > curfile.ino && volno == curvol)
+ while (next > curfile.ino && volno == curvol) {
+#ifdef USE_QFA
+ ++tmpcnt;
+#endif
skipfile();
+ }
skipmaps();
skipdirs();
} while (volno == curvol + 1);
+#ifdef USE_QFA
+ tiend = time(NULL);
+ titaken = tiend - tistart;
+#ifdef DEBUG_QFA
+ if (titaken / 60 > 0)
+ msg("%ld reads took %d:%02d:%02d\n",
+ tmpcnt, titaken / 3600,
+ (titaken % 3600) / 60, titaken % 60);
+#endif
+#endif /* USE_QFA */
+
/*
* If volume change out of order occurred the
* current state must be recalculated
ep = lookupino(next);
if (ep == NULL)
panic("corrupted symbol table\n");
- fprintf(stderr, "%s: not found on tape\n", myname(ep));
+#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);
}
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();
void
createlinks(void)
{
- register struct entry *np, *ep;
- register ino_t i;
+ struct entry *np, *ep;
+ dump_ino_t i;
char name[BUFSIZ];
if ((ep = lookupino(WINO))) {
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;
}
void
checkrestore(void)
{
- register struct entry *ep;
- register ino_t i;
+ struct entry *ep;
+ dump_ino_t i;
Vprintf(stdout, "Check the symbol table.\n");
for (i = WINO; i < maxino; i++) {
* A paranoid check that things are as they should be.
*/
long
-verifyfile(char *name, ino_t ino, int type)
+verifyfile(char *name, dump_ino_t ino, int type)
{
struct entry *np, *ep;
long descend = GOOD;