diff options
4 files changed, 1252 insertions, 0 deletions
diff --git a/.pc/applied-patches b/.pc/applied-patches index ed1a2ff..200f23b 100644 --- a/.pc/applied-patches +++ b/.pc/applied-patches @@ -1 +1,2 @@ bashism_in_examples +auto-0.4b44-5-8544ff70a0b617566795d1e0c611e5e9d98c66a4-1411987963 diff --git a/.pc/auto-0.4b44-5-8544ff70a0b617566795d1e0c611e5e9d98c66a4-1411987963/restore/restore.c b/.pc/auto-0.4b44-5-8544ff70a0b617566795d1e0c611e5e9d98c66a4-1411987963/restore/restore.c new file mode 100644 index 0000000..c773d90 --- /dev/null +++ b/.pc/auto-0.4b44-5-8544ff70a0b617566795d1e0c611e5e9d98c66a4-1411987963/restore/restore.c @@ -0,0 +1,1191 @@ +/* + * 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 <stelian@popies.net>, 1999-2000 + * Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 2000-2002 + */ + +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 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. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char rcsid[] = + "$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> +#endif + +#include "restore.h" +#include "extern.h" + +static char *keyval __P((int)); + +/* + * This implements the 't' option. + * List entries on the tape. + */ +long +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 "); +#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); +} + +/* + * This implements the 'x' option. + * Request that new entries be extracted. + */ +long +addfile(char *name, dump_ino_t ino, int type) +{ + struct entry *ep, *np; + long descend = hflag ? GOOD : FAIL; + char buf[100]; + + if (TSTINO(ino, dumpmap) == 0) { + Dprintf(stdout, "%s: not on the tape\n", name); + return (descend); + } + if (ino == WINO && command == 'i' && !vflag) + return (descend); + if (!mflag) { + (void) snprintf(buf, sizeof(buf), "./%lu", (unsigned long)ino); + name = buf; + if (type == NODE) { + (void) genliteraldir(name, ino); + return (descend); + } + } + ep = lookupino(ino); + if (ep != NULL) { + if (strcmp(name, myname(ep)) == 0) { + ep->e_flags |= NEW; + 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); +} + +/* + * This is used by the 'i' option to undo previous requests made by addfile. + * Delete entries from the request queue. + */ +/* ARGSUSED */ +long +deletefile(char *name, dump_ino_t ino, UNUSED(int type)) +{ + long descend = hflag ? GOOD : FAIL; + struct entry *ep; + + if (TSTINO(ino, dumpmap) == 0) + return (descend); + ep = lookupname(name); + if (ep != NULL) { + ep->e_flags &= ~NEW; + ep->e_flags |= REMOVED; + if (ep->e_type != NODE) + freeentry(ep); + } + return (descend); +} + +/* + * The following four routines implement the incremental + * restore algorithm. The first removes old entries, the second + * does renames and calculates the extraction list, the third + * cleans up link names missed by the first two, and the final + * one deletes old directories. + * + * Directories cannot be immediately deleted, as they may have + * other files in them which need to be moved out first. As + * directories to be deleted are found, they are put on the + * following deletion list. After all deletions and renames + * are done, this list is actually deleted. + */ +static struct entry *removelist; + +/* + * Remove invalid whiteouts from the old tree. + * Remove unneeded leaves from the old tree. + * Remove directories from the lookup chains. + */ +void +removeoldleaves(void) +{ + struct entry *ep, *nextep; + dump_ino_t i, mydirino; + + Vprintf(stdout, "Mark entries to be removed.\n"); + if ((ep = lookupino(WINO))) { + Vprintf(stdout, "Delete whiteouts\n"); + for ( ; ep != NULL; ep = nextep) { + nextep = ep->e_links; + mydirino = ep->e_parent->e_ino; + /* + * We remove all whiteouts that are in directories + * that have been removed or that have been dumped. + */ + if (TSTINO(mydirino, usedinomap) && + !TSTINO(mydirino, dumpmap)) + continue; +#ifdef __linux__ + (void)fprintf(stderr, "BUG! Should call delwhiteout\n"); +#else +#ifdef sunos +#else + delwhiteout(ep); +#endif +#endif + freeentry(ep); + } + } + for (i = ROOTINO + 1; i < maxino; i++) { + ep = lookupino(i); + if (ep == NULL) + continue; + if (TSTINO(i, usedinomap)) + continue; + for ( ; ep != NULL; ep = ep->e_links) { + Dprintf(stdout, "%s: REMOVE\n", myname(ep)); + if (ep->e_type == LEAF) { + removeleaf(ep); + freeentry(ep); + } else { + mktempname(ep); + deleteino(ep->e_ino); + ep->e_next = removelist; + removelist = ep; + } + } + } +} + +/* + * For each directory entry on the incremental tape, determine which + * category it falls into as follows: + * KEEP - entries that are to be left alone. + * NEW - new entries to be added. + * EXTRACT - files that must be updated with new contents. + * LINK - new links to be added. + * Renames are done at the same time. + */ +long +nodeupdates(char *name, dump_ino_t ino, int type) +{ + struct entry *ep, *np, *ip; + long descend = GOOD; + int lookuptype = 0; + int key = 0; + /* key values */ +# define ONTAPE 0x1 /* inode is on the tape */ +# define INOFND 0x2 /* inode already exists */ +# define NAMEFND 0x4 /* name already exists */ +# define MODECHG 0x8 /* mode of inode changed */ + + /* + * This routine is called once for each element in the + * 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 (TSTINO(ino, dumpmap)) + key |= ONTAPE; + /* + * Check to see if the name exists, and if the name is a link. + */ + np = lookupname(name); + if (np != NULL) { + 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 != NULL) { + key |= INOFND; + for (ep = ip->e_links; ep != NULL; ep = ep->e_links) { + 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 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 (lookuptype == LINK) { + removeleaf(np); + freeentry(np); + } else { + Dprintf(stdout, "name/inode conflict, mktempname %s\n", + myname(np)); + mktempname(np); + } + np = NULL; + key &= ~NAMEFND; + } + if ((key & ONTAPE) && + (((key & INOFND) && ip->e_type != type) || + ((key & NAMEFND) && np->e_type != type))) + key |= MODECHG; + + /* + * Decide on the disposition of the file based on its flags. + * Note that we have already handled the case in which + * a name and inode are found that correspond to different files. + * Thus if both NAMEFND and INOFND are set then ip == np. + */ + switch (key) { + + /* + * A previously existing file has been found. + * Mark it as KEEP so that other links to the inode can be + * detected, and so that it will not be reclaimed by the search + * for unreferenced names. + */ + case INOFND|NAMEFND: + ip->e_flags |= KEEP; + Dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, + 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. + * If it is a directory, create it immediately. + * (Since the name is unused there can be no conflict) + */ + case ONTAPE: + ep = addentry(name, ino, type); + if (type == NODE) + newnode(ep); + ep->e_flags |= NEW|KEEP; + Dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, + flagvalues(ep)); + break; + + /* + * A file with the same inode number, but a different + * name has been found. If the other name has not already + * been found (indicated by the KEEP flag, see above) then + * this must be a new name for the file, and it is renamed. + * If the other name has been found then this must be a + * link to the file. Hard links to directories are not + * permitted, and are either deleted or converted to + * symbolic links. Finally, if the file is on the tape, + * a request is made to extract it. + */ + case ONTAPE|INOFND: + if (type == LEAF && (ip->e_flags & KEEP) == 0) + ip->e_flags |= EXTRACT; + /* fall through */ + case INOFND: + if ((ip->e_flags & KEEP) == 0) { + renameit(myname(ip), name); + moveentry(ip, name); + ip->e_flags |= KEEP; + Dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, + flagvalues(ip)); + break; + } + if (ip->e_type == NODE) { + descend = FAIL; + fprintf(stderr, + "deleted hard link %s to directory %s\n", + name, myname(ip)); + break; + } + ep = addentry(name, ino, type|LINK); + ep->e_flags |= NEW; + Dprintf(stdout, "[%s] %s: %s|LINK\n", keyval(key), name, + flagvalues(ep)); + break; + + /* + * A previously known file which is to be updated. If it is a link, + * then all names referring to the previous file must be removed + * so that the subset of them that remain can be recreated. + */ + case ONTAPE|INOFND|NAMEFND: + if (lookuptype == LINK) { + removeleaf(np); + freeentry(np); + ep = addentry(name, ino, type|LINK); + if (type == NODE) + newnode(ep); + ep->e_flags |= NEW|KEEP; + Dprintf(stdout, "[%s] %s: %s|LINK\n", keyval(key), name, + flagvalues(ep)); + break; + } + if (type == LEAF && lookuptype != LINK) + np->e_flags |= EXTRACT; + np->e_flags |= KEEP; + Dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, + flagvalues(np)); + break; + + /* + * An inode is being reused in a completely different way. + * Normally an extract can simply do an "unlink" followed + * by a "creat". Here we must do effectively the same + * thing. The complications arise because we cannot really + * delete a directory since it may still contain files + * that we need to rename, so we delete it from the symbol + * table, and put it on the list to be deleted eventually. + * Conversely if a directory is to be created, it must be + * done immediately, rather than waiting until the + * extraction phase. + */ + case ONTAPE|INOFND|MODECHG: + case ONTAPE|INOFND|NAMEFND|MODECHG: + if (ip->e_flags & KEEP) { + badentry(ip, "cannot KEEP and change modes"); + break; + } + if (ip->e_type == LEAF) { + /* changing from leaf to node */ + for ( ; ip != NULL; ip = ip->e_links) { + if (ip->e_type != LEAF) + badentry(ip, "NODE and LEAF links to same inode"); + removeleaf(ip); + freeentry(ip); + } + ip = addentry(name, ino, type); + newnode(ip); + } else { + /* changing from node to leaf */ + if ((ip->e_flags & TMPNAME) == 0) + mktempname(ip); + deleteino(ip->e_ino); + ip->e_next = removelist; + removelist = ip; + ip = addentry(name, ino, type); + } + ip->e_flags |= NEW|KEEP; + Dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, + flagvalues(ip)); + break; + + /* + * A hard link to a directory that has been removed. + * Ignore it. + */ + case NAMEFND: + Dprintf(stdout, "[%s] %s: Extraneous name\n", keyval(key), + name); + 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 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; + + /* + * If any of these arise, something is grievously wrong with + * the current state of the symbol table. + */ + case INOFND|NAMEFND|MODECHG: + case NAMEFND|MODECHG: + case INOFND|MODECHG: + fprintf(stderr, "[%s] %s: inconsistent state\n", keyval(key), + name); + break; + + /* + * These states "cannot" arise for any state of the symbol table. + */ + case ONTAPE|MODECHG: + case MODECHG: + default: + panic("[%s] %s: impossible state\n", keyval(key), name); + break; + } + return (descend); +} + +/* + * Calculate the active flags in a key. + */ +static char * +keyval(int key) +{ + static char keybuf[32]; + + (void) strcpy(keybuf, "|NIL"); + keybuf[0] = '\0'; + if (key & ONTAPE) + (void) strcat(keybuf, "|ONTAPE"); + if (key & INOFND) + (void) strcat(keybuf, "|INOFND"); + if (key & NAMEFND) + (void) strcat(keybuf, "|NAMEFND"); + if (key & MODECHG) + (void) strcat(keybuf, "|MODECHG"); + return (&keybuf[1]); +} + +/* + * 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; + 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) { + 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; + } + } + } + } + } +} + +/* + * Remove old nodes (directories). + * Note that this routine runs in O(N*D) where: + * N is the number of directory entries to be removed. + * D is the maximum depth of the tree. + * If N == D this can be quite slow. If the list were + * topologically sorted, the deletion could be done in + * time O(N). + */ +void +removeoldnodes(void) +{ + struct entry *ep, **prev; + long change; + + Vprintf(stdout, "Remove old nodes (directories).\n"); + do { + change = 0; + prev = &removelist; + for (ep = removelist; ep != NULL; ep = *prev) { + int docont = 0; + if (ep->e_entries != NULL) { + 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); + change++; + } + } while (change); + for (ep = removelist; ep != NULL; ep = ep->e_next) + badentry(ep, "cannot remove, non-empty"); +} + +/* Compare the file specified in `ep' (which is on tape) to the */ +/* current copy of this file on disk. If do_compare is 0, then just */ +/* make our caller think we did it--this is used to handle hard links */ +/* to files and devices. */ +static void +compare_entry(struct entry *ep, int do_compare) +{ + if ((ep->e_flags & (NEW|EXTRACT)) == 0) { + badentry(ep, "unexpected file on tape"); + do_compare_error; + } + if (do_compare) { + (void) comparefile(myname(ep)); + skipxattr(); + } + ep->e_flags &= ~(NEW|EXTRACT); +} + +/* + * This is the routine used to compare files for the 'C' command. + */ +void +compareleaves(void) +{ + struct entry *ep; + dump_ino_t first; + long curvol; + + first = lowerbnd(ROOTINO); + curvol = volno; + while (curfile.ino < maxino) { + first = lowerbnd(first); + /* + * 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, + * or a file that was removed while the dump was in progress. + */ + while (first < curfile.ino) { + ep = lookupino(first); + if (ep == NULL) + panic("%d: bad first\n", first); + fprintf(stderr, "%s: not found on tape\n", myname(ep)); + do_compare_error; + 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 %ld, got %lu\n", + (long)first, (unsigned long)curfile.ino); + skipfile(); + goto next; + } + ep = lookupino(curfile.ino); + if (ep == NULL) { + panic("unknown file on tape\n"); + do_compare_error; + } + compare_entry(ep, 1); + for (ep = ep->e_links; ep != NULL; ep = ep->e_links) { + compare_entry(ep, 0); + } + + /* + * We checkpoint the restore after every tape reel, so + * as to simplify the amount of work re quired by the + * 'R' command. + */ + next: + if (curvol != 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); + } +} + +/* + * This is the routine used to extract files for the 'r' command. + * Extract new leaves. + */ +void +createleaves(char *symtabfile) +{ + struct entry *ep; + dump_ino_t first; + long curvol; + int doremove; + + if (command == 'R') { + Vprintf(stdout, "Continue extraction of new leaves\n"); + } else { + Vprintf(stdout, "Extract new leaves.\n"); + dumpsymtable(symtabfile, volno); + } + first = lowerbnd(ROOTINO); + curvol = volno; + while (curfile.ino < maxino) { + first = lowerbnd(first); + /* + * 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, + * or a file that was removed while the dump was in progress. + */ + 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); + 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 %ld, got %lu\n", + (long)first, (unsigned long)curfile.ino); + skipfile(); + goto next; + } + ep = lookupino(curfile.ino); + if (ep == NULL) + panic("unknown file on tape\n"); + if ((ep->e_flags & (NEW|EXTRACT)) == 0) + badentry(ep, "unexpected file on tape"); + /* + * If the file is to be extracted, then the old file must + * 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) + 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: + 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); + } +} + +/* + * This is the routine used to extract files for the 'x' and 'i' commands. + * Efficiently extract a subset of the files on a tape. + */ +void +createfiles(void) +{ + 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; +#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); + /* + * Check to see if any files remain to be extracted + */ + if (first > last) + return; + /* + * Reject any volumes with inodes greater + * than the last one needed + */ + while (curfile.ino > last) { + curfile.action = SKIP; + 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(); + } + /* + * Decide on the next inode needed. + * Skip across the inodes until it is found + * 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) { +#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 + */ + if (volno != curvol) + continue; + /* + * 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 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); + if (ep == NULL) + 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); + ep->e_flags &= ~NEW; + next = lowerbnd(next); + } + /* + * The current inode is the one that we are looking for, + * so extract it per its requested name. + */ + if (next == curfile.ino && next <= last) { + ep = lookupino(next); + if (ep == NULL) + panic("corrupted symbol table\n"); +#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(); + } + } +} + +/* + * Add links. + */ +void +createlinks(void) +{ + struct entry *np, *ep; + dump_ino_t i; + char name[BUFSIZ]; + + if ((ep = lookupino(WINO))) { + Vprintf(stdout, "Add whiteouts\n"); + for ( ; ep != NULL; ep = ep->e_links) { + if ((ep->e_flags & NEW) == 0) + 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; + } + } + Vprintf(stdout, "Add links\n"); + for (i = ROOTINO; i < maxino; i++) { + ep = lookupino(i); + if (ep == NULL) + continue; + for (np = ep->e_links; np != NULL; np = np->e_links) { + if ((np->e_flags & NEW) == 0) + continue; + (void) strcpy(name, myname(ep)); + if (ep->e_type == NODE) { + (void) linkit(name, myname(np), SYMLINK); + } else { + (void) linkit(name, myname(np), HARDLINK); + } + np->e_flags &= ~NEW; + } + } +} + +/* + * Check the symbol table. + * We do this to insure that all the requested work was done, and + * that no temporary names remain. + */ +void +checkrestore(void) +{ + struct entry *ep; + dump_ino_t i; + + Vprintf(stdout, "Check the symbol table.\n"); + for (i = WINO; i < maxino; i++) { + for (ep = lookupino(i); ep != NULL; ep = ep->e_links) { + ep->e_flags &= ~KEEP; + if (ep->e_type == NODE) + ep->e_flags &= ~(NEW|EXISTED); + if (ep->e_flags /* != NULL */) + badentry(ep, "incomplete operations"); + } + } +} + +/* + * Compare with the directory structure on the tape + * A paranoid check that things are as they should be. + */ +long +verifyfile(char *name, dump_ino_t ino, int type) +{ + struct entry *np, *ep; + long descend = GOOD; + + ep = lookupname(name); + if (ep == NULL) { + fprintf(stderr, "Warning: missing name %s\n", name); + return (FAIL); + } + np = lookupino(ino); + if (np != ep) + descend = FAIL; + for ( ; np != NULL; np = np->e_links) + if (np == ep) + break; + if (np == NULL) + panic("missing inumber %d\n", ino); + if (ep->e_type == LEAF && type != LEAF) + badentry(ep, "type should be LEAF"); + return (descend); +} diff --git a/debian/patches/auto-0.4b44-5-8544ff70a0b617566795d1e0c611e5e9d98c66a4-1411987963 b/debian/patches/auto-0.4b44-5-8544ff70a0b617566795d1e0c611e5e9d98c66a4-1411987963 new file mode 100644 index 0000000..e3b78d7 --- /dev/null +++ b/debian/patches/auto-0.4b44-5-8544ff70a0b617566795d1e0c611e5e9d98c66a4-1411987963 @@ -0,0 +1,59 @@ +Description: Automatically generated patch (0.4b44-5) + Last (up to) 3 git changes, FYI: + . + commit 8544ff70a0b617566795d1e0c611e5e9d98c66a4 + Author: Matthew Vernon <mcv21@cam.ac.uk> + Date: Mon Sep 29 11:37:04 2014 +0100 + . + Changelog for 0.4b44-5 + . + commit 7da8aa42b8905f2f2c8644dfc148e07570a14a56 + Author: Matthew Vernon <mcv21@cam.ac.uk> + Date: Mon Sep 29 11:33:54 2014 +0100 + . + Patch from Ben Harris to skip directories already scheduled for deletion + . + The patch assumes that if an entry has e_ino == 0, that means it's + already been passed to deletino() and added to removelist. I think + this is true. It's certainly the case that all additions to removelist + have e_ino == 0, so this should stop the hangs and the panics from + removino(). At worst, it will leave spurious directories around after + a restore. + . + commit 870ae1e4acd826d692cf2c547c27ee44f9ca2eab + Author: Mattia Rizzolo <mattia@mapreri.org> + Date: Thu Sep 19 14:51:33 2013 +0100 + . + dump (0.4b44-4) unstable; urgency=low + . + * QA upload. + * debian/postinst: drop --verbose flag from update-alternatives invocation. + * debian/*rm: add set -e to fix lintian warning. + * debian/control: + + add Homepage field. + + Update VCS fields to canonical values. + + Bump Standards-Version to 3.9.4. No changes required. + * Update to debhelper 9: + + debian/rules: update accordingly. + + debian/compat: bump compatibility level to 9. + + debian/control: bump debhelper versioned build-dep to >= 9. + + debian/docs: include docs previously manually installed. + + debian/examples: include previously-included examples. + * debian/copyright: update to DEP-5. + . + # imported from the archive +Author: Matthew Vernon <matthew@debian.org> + +--- + +--- dump-0.4b44.orig/restore/restore.c ++++ dump-0.4b44/restore/restore.c +@@ -593,7 +593,7 @@ findunreflinks(void) + if (np->e_type == LEAF) { + removeleaf(np); + freeentry(np); +- } else { ++ } else if (np->e_ino != 0){ + np->e_flags |= TMPNAME; + deleteino(np->e_ino); + np->e_next = removelist; diff --git a/debian/patches/series b/debian/patches/series index ed1a2ff..200f23b 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1 +1,2 @@ bashism_in_examples +auto-0.4b44-5-8544ff70a0b617566795d1e0c611e5e9d98c66a4-1411987963 |