diff --git a/sbin/restore/dirs.c b/sbin/restore/dirs.c index a4038eb1f63e..0dfb6452cc18 100644 --- a/sbin/restore/dirs.c +++ b/sbin/restore/dirs.c @@ -37,7 +37,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)dirs.c 8.2 (Berkeley) 1/21/94"; +static char sccsid[] = "@(#)dirs.c 8.7 (Berkeley) 5/1/95"; #endif /* not lint */ #include @@ -45,9 +45,9 @@ static char sccsid[] = "@(#)dirs.c 8.2 (Berkeley) 1/21/94"; #include #include -#include #include #include +#include #include #include @@ -81,9 +81,10 @@ static struct inotab *inotab[HASHSIZE]; struct modeinfo { ino_t ino; struct timeval timep[2]; - short mode; - short uid; - short gid; + mode_t mode; + uid_t uid; + gid_t gid; + int flags; }; /* @@ -272,7 +273,7 @@ treescan(pname, ino, todo) /* * a zero inode signals end of directory */ - while (dp != NULL && dp->d_ino != 0) { + while (dp != NULL) { locname[namelen] = '\0'; if (namelen + dp->d_namlen >= sizeof(locname)) { fprintf(stderr, "%s%s: name exceeds %d char\n", @@ -285,8 +286,6 @@ treescan(pname, ino, todo) dp = rst_readdir(dirp); bpt = rst_telldir(dirp); } - if (dp == NULL) - fprintf(stderr, "corrupted directory: %s.\n", locname); } /* @@ -334,7 +333,7 @@ searchdir(inum, name) len = strlen(name); do { dp = rst_readdir(dirp); - if (dp == NULL || dp->d_ino == 0) + if (dp == NULL) return (NULL); } while (dp->d_namlen != len || strncmp(dp->d_name, name, len) != 0); return (dp); @@ -367,12 +366,13 @@ putdir(buf, size) if (Bcvt) swabst((u_char *)"ls", (u_char *) dp); if (oldinofmt && dp->d_ino != 0) { -#if BYTE_ORDER == BIG_ENDIAN - if (Bcvt) -#else - if (!Bcvt) -#endif - dp->d_namlen = dp->d_type; +# if BYTE_ORDER == BIG_ENDIAN + if (Bcvt) + dp->d_namlen = dp->d_type; +# else + if (!Bcvt) + dp->d_namlen = dp->d_type; +# endif dp->d_type = DT_UNKNOWN; } i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1)); @@ -425,7 +425,7 @@ putent(dp) (void) fwrite(dirbuf, 1, DIRBLKSIZ, df); dirloc = 0; } - bcopy((char *)dp, dirbuf + dirloc, (long)dp->d_reclen); + memmove(dirbuf + dirloc, dp, (long)dp->d_reclen); prev = dirloc; dirloc += dp->d_reclen; } @@ -448,7 +448,7 @@ dcvt(odp, ndp) register struct direct *ndp; { - bzero((char *)ndp, (long)(sizeof *ndp)); + memset(ndp, 0, (long)(sizeof *ndp)); ndp->d_ino = odp->d_ino; ndp->d_type = DT_UNKNOWN; (void) strncpy(ndp->d_name, odp->d_name, ODIRSIZ); @@ -510,8 +510,8 @@ rst_readdir(dirp) return (NULL); } dirp->dd_loc += dp->d_reclen; - if (dp->d_ino == 0 && strcmp(dp->d_name, "/") != 0) - continue; + if (dp->d_ino == 0 && strcmp(dp->d_name, "/") == 0) + return (NULL); if (dp->d_ino >= maxino) { dprintf(stderr, "corrupted directory: bad inum %d\n", dp->d_ino); @@ -636,6 +636,7 @@ setdirmodes(flags) cp = myname(ep); (void) chown(cp, node.uid, node.gid); (void) chmod(cp, node.mode); + (void) chflags(cp, node.flags); utimes(cp, node.timep); ep->e_flags &= ~NEW; } @@ -728,11 +729,12 @@ allocinotab(ino, dip, seekpt) if (mf == NULL) return (itp); node.ino = ino; - node.timep[0].tv_sec = dip->di_atime.tv_sec; - node.timep[0].tv_usec = dip->di_atime.tv_nsec / 1000; - node.timep[1].tv_sec = dip->di_mtime.tv_sec; - node.timep[1].tv_usec = dip->di_mtime.tv_nsec / 1000; + node.timep[0].tv_sec = dip->di_atime; + node.timep[0].tv_usec = dip->di_atimensec / 1000; + node.timep[1].tv_sec = dip->di_mtime; + node.timep[1].tv_usec = dip->di_mtimensec / 1000; node.mode = dip->di_mode; + node.flags = dip->di_flags; node.uid = dip->di_uid; node.gid = dip->di_gid; (void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf); diff --git a/sbin/restore/interactive.c b/sbin/restore/interactive.c index 9e8b9ae9e44c..600cc908df1b 100644 --- a/sbin/restore/interactive.c +++ b/sbin/restore/interactive.c @@ -32,16 +32,16 @@ */ #ifndef lint -static char sccsid[] = "@(#)interactive.c 8.1 (Berkeley) 6/5/93"; +static char sccsid[] = "@(#)interactive.c 8.5 (Berkeley) 5/1/95"; #endif /* not lint */ #include #include #include -#include #include #include +#include #include #include @@ -85,7 +85,7 @@ static void formatf __P((struct afile *, int)); static void getcmd __P((char *, char *, char *, int, struct arglist *)); struct dirent *glob_readdir __P((RST_DIR *dirp)); static int glob_stat __P((const char *, struct stat *)); -static void mkentry __P((struct direct *, struct afile *)); +static void mkentry __P((char *, struct direct *, struct afile *)); static void printlist __P((char *, char *)); /* @@ -503,15 +503,17 @@ printlist(name, basename) register struct direct *dp; struct afile single; RST_DIR *dirp; - int entries, len; + int entries, len, namelen; + char locname[MAXPATHLEN + 1]; dp = pathsearch(name); - if (dp == NULL || (!dflag && TSTINO(dp->d_ino, dumpmap) == 0)) + if (dp == NULL || (!dflag && TSTINO(dp->d_ino, dumpmap) == 0) || + (!vflag && dp->d_ino == WINO)) return; if ((dirp = rst_opendir(name)) == NULL) { entries = 1; list = &single; - mkentry(dp, list); + mkentry(name, dp, list); len = strlen(basename) + 1; if (strlen(name) - len > single.len) { freename(single.fname); @@ -533,17 +535,28 @@ printlist(name, basename) fprintf(stderr, "%s:\n", name); entries = 0; listp = list; + (void) strncpy(locname, name, MAXPATHLEN); + (void) strncat(locname, "/", MAXPATHLEN); + namelen = strlen(locname); while (dp = rst_readdir(dirp)) { - if (dp == NULL || dp->d_ino == 0) + if (dp == NULL) break; if (!dflag && TSTINO(dp->d_ino, dumpmap) == 0) continue; - if (vflag == 0 && - (strcmp(dp->d_name, ".") == 0 || + if (!vflag && (dp->d_ino == WINO || + strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)) continue; - mkentry(dp, listp++); - entries++; + locname[namelen] = '\0'; + if (namelen + dp->d_namlen >= MAXPATHLEN) { + fprintf(stderr, "%s%s: name exceeds %d char\n", + locname, dp->d_name, MAXPATHLEN); + } else { + (void) strncat(locname, dp->d_name, + (int)dp->d_namlen); + mkentry(locname, dp, listp++); + entries++; + } } rst_closedir(dirp); if (entries == 0) { @@ -566,7 +579,8 @@ printlist(name, basename) * Read the contents of a directory. */ static void -mkentry(dp, fp) +mkentry(name, dp, fp) + char *name; struct direct *dp; register struct afile *fp; { @@ -581,7 +595,7 @@ mkentry(dp, fp) fp->len = cp - fp->fname; if (dflag && TSTINO(fp->fnum, dumpmap) == 0) fp->prefix = '^'; - else if ((np = lookupino(fp->fnum)) != NULL && (np->e_flags & NEW)) + else if ((np = lookupname(name)) != NULL && (np->e_flags & NEW)) fp->prefix = '*'; else fp->prefix = ' '; @@ -609,6 +623,10 @@ mkentry(dp, fp) fp->postfix = '#'; break; + case DT_WHT: + fp->postfix = '%'; + break; + case DT_UNKNOWN: case DT_DIR: if (inodetype(dp->d_ino) == NODE) @@ -704,7 +722,7 @@ glob_readdir(dirp) static struct dirent adirent; while ((dp = rst_readdir(dirp)) != NULL) { - if (dp->d_ino == 0) + if (!vflag && dp->d_ino == WINO) continue; if (dflag || TSTINO(dp->d_ino, dumpmap)) break; @@ -713,7 +731,7 @@ glob_readdir(dirp) return (NULL); adirent.d_fileno = dp->d_ino; adirent.d_namlen = dp->d_namlen; - bcopy(dp->d_name, adirent.d_name, dp->d_namlen + 1); + memmove(adirent.d_name, dp->d_name, dp->d_namlen + 1); return (&adirent); } @@ -728,7 +746,8 @@ glob_stat(name, stp) register struct direct *dp; dp = pathsearch(name); - if (dp == NULL || (!dflag && TSTINO(dp->d_ino, dumpmap) == 0)) + if (dp == NULL || (!dflag && TSTINO(dp->d_ino, dumpmap) == 0) || + (!vflag && dp->d_ino == WINO)) return (-1); if (inodetype(dp->d_ino) == NODE) stp->st_mode = IFDIR; diff --git a/sbin/restore/main.c b/sbin/restore/main.c index c2c804f49f7c..b61bbc03cc5e 100644 --- a/sbin/restore/main.c +++ b/sbin/restore/main.c @@ -38,14 +38,14 @@ static char copyright[] = #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)main.c 8.2 (Berkeley) 1/7/94"; +static char sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/4/95"; #endif /* not lint */ #include #include -#include #include +#include #include #include @@ -54,6 +54,7 @@ static char sccsid[] = "@(#)main.c 8.2 (Berkeley) 1/7/94"; #include #include #include +#include #include "pathnames.h" #include "restore.h" @@ -66,7 +67,7 @@ long dumpnum = 1; long volno = 0; long ntrec; char *dumpmap; -char *clrimap; +char *usedinomap; ino_t maxino; time_t dumptime; time_t dumpdate; @@ -276,12 +277,12 @@ main(argc, argv) static void usage() { - (void)fprintf(stderr, "usage:\t%s%s%s%s%s", - "restore tfhsvy [file ...]\n", - "\trestore xfhmsvy [file ...]\n", - "\trestore ifhmsvy\n", - "\trestore rfsvy\n", - "\trestore Rfsvy\n"); + (void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n", + "restore -i [-chmvy] [-b blocksize] [-f file] [-s fileno]", + "restore -r [-cvy] [-b blocksize] [-f file] [-s fileno]", + "restore -R [-cvy] [-b blocksize] [-f file] [-s fileno]", + "restore -x [-chmvy] [-b blocksize] [-f file] [-s fileno] [file ...]", + "restore -t [-chvy] [-b blocksize] [-f file] [-s fileno] [file ...]"); done(1); } @@ -316,19 +317,20 @@ obsolete(argcp, argvp) argv += 2, argc -= 2; for (flags = 0; *ap; ++ap) { - switch(*ap) { + switch (*ap) { case 'b': case 'f': case 's': - if (argc < 1) - usage(); + if (*argv == NULL) { + warnx("option requires an argument -- %c", *ap); + usage(); + } if ((nargv[0] = malloc(strlen(*argv) + 2 + 1)) == NULL) err(1, NULL); nargv[0][0] = '-'; nargv[0][1] = *ap; (void)strcpy(&nargv[0][2], *argv); - if (*argv != NULL) - ++argv; + ++argv; ++nargv; break; default: @@ -349,4 +351,7 @@ obsolete(argcp, argvp) /* Copy remaining arguments. */ while (*nargv++ = *argv++); + + /* Update argument count. */ + *argcp = nargv - *argvp - 1; } diff --git a/sbin/restore/restore.8 b/sbin/restore/restore.8 index 5f7e4a87264b..e660390b2723 100644 --- a/sbin/restore/restore.8 +++ b/sbin/restore/restore.8 @@ -29,10 +29,10 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" @(#)restore.8 8.2 (Berkeley) 12/11/93 -.\" $Id$ -.\" " -.Dd December 11, 1993 +.\" @(#)restore.8 8.4 (Berkeley) 5/1/95 +.\" $Id: restore.8,v 1.9 1997/02/22 14:33:08 peter Exp $ +.\" +.Dd May 1, 1995 .Dt RESTORE 8 .Os BSD 4 .Sh NAME @@ -40,8 +40,43 @@ .Nd "restore files or file systems from backups made with dump" .Sh SYNOPSIS .Nm restore -.Ar key -.Op Ar name Ar ... +.Fl i +.Op Fl chmvy +.Op Fl b Ar blocksize +.Op Fl f Ar file +.Op Fl s Ar fileno +.Nm restore +.Fl R +.Op Fl cvy +.Op Fl b Ar blocksize +.Op Fl f Ar file +.Op Fl s Ar fileno +.Nm restore +.Fl r +.Op Fl cvy +.Op Fl b Ar blocksize +.Op Fl f Ar file +.Op Fl s Ar fileno +.Nm restore +.Fl t +.Op Fl chvy +.Op Fl b Ar blocksize +.Op Fl f Ar file +.Op Fl s Ar fileno +.Op file ... +.Nm restore +.Fl x +.Op Fl chmvy +.Op Fl b Ar blocksize +.Op Fl f Ar file +.Op Fl s Ar fileno +.Op file ... +.Pp +.in -\\n(iSu +(The +.Bx 4.3 +option syntax is implemented for backward compatibility, but +is not documented here.) .Sh DESCRIPTION The .Nm restore @@ -57,42 +92,109 @@ works across a network; to do this see the .Fl f flag described below. -The actions -of -.Nm restore -are controlled by the given -.Cm key , -which -is a string of characters containing -at most one function letter and possibly -one or more function modifiers. Other arguments to the command are file or directory names specifying the files that are to be restored. Unless the -.Cm h -key is specified (see below), +.Fl h +flag is specified (see below), the appearance of a directory name refers to the files and (recursively) subdirectories of that directory. .Pp -The function portion of -the key is specified by one of the following letters: +Exactly one of the following flags is required: .Bl -tag -width Ds -.It Cm r +.It Fl i +This mode allows interactive restoration of files from a dump. +After reading in the directory information from the dump, +.Nm restore +provides a shell like interface that allows the user to move +around the directory tree selecting files to be extracted. +The available commands are given below; +for those commands that require an argument, +the default is the current directory. +.Bl -tag -width Fl +.It Ic add Op Ar arg +The current directory or specified argument is added to the list of +files to be extracted. +If a directory is specified, then it and all its descendents are +added to the extraction list +(unless the +.Fl h +flag is specified on the command line). +Files that are on the extraction list are prepended with a ``*'' +when they are listed by +.Ic ls . +.It Ic \&cd Ar arg +Change the current working directory to the specified argument. +.It Ic delete Op Ar arg +The current directory or specified argument is deleted from the list of +files to be extracted. +If a directory is specified, then it and all its descendents are +deleted from the extraction list +(unless the +.Fl h +flag is specified on the command line). +The most expedient way to extract most of the files from a directory +is to add the directory to the extraction list and then delete +those files that are not needed. +.It Ic extract +All the files that are on the extraction list are extracted +from the dump. +.Nm Restore +will ask which volume the user wishes to mount. +The fastest way to extract a few files is to +start with the last volume, and work towards the first volume. +.It Ic help +List a summary of the available commands. +.It Ic \&ls Op Ar arg +List the current or specified directory. +Entries that are directories are appended with a ``/''. +Entries that have been marked for extraction are prepended with a ``*''. +If the verbose +flag is set the inode number of each entry is also listed. +.It Ic pwd +Print the full pathname of the current working directory. +.It Ic quit +Restore immediately exits, +even if the extraction list is not empty. +.It Ic setmodes +All the directories that have been added to the extraction list +have their owner, modes, and times set; +nothing is extracted from the dump. +This is useful for cleaning up after a restore has been prematurely aborted. +.It Ic verbose +The sense of the +.Fl v +flag is toggled. +When set, the verbose flag causes the +.Ic ls +command to list the inode numbers of all entries. +It also causes +.Nm restore +to print out information about each file as it is extracted. +.El +.It Fl R +.Nm Restore +requests a particular tape of a multi volume set on which to restart +a full restore +(see the +.Fl r +flag below). +This is useful if the restore has been interrupted. +.It Fl r Restore (rebuild a file system). The target file system should be made pristine with .Xr newfs 8 , -mounted and the -user +mounted and the user .Xr cd Ns 'd into the pristine file system before starting the restoration of the initial level 0 backup. If the level 0 restores successfully, the -.Cm r -key may be used to restore +.Fl r +flag may be used to restore any necessary incremental backups on top of the level 0. The -.Cm r -key precludes an interactive file extraction and can be +.Fl r +flag precludes an interactive file extraction and can be detrimental to one's health if not used carefully (not to mention the disk). An example: .Bd -literal -offset indent @@ -119,21 +221,29 @@ and .Xr dump 8 , may be used to modify file system parameters such as size or block size. -.It Cm R -.Nm Restore -requests a particular tape of a multi volume set on which to restart -a full restore -(see the -.Cm r -key above). -This is useful if the restore has been interrupted. -.It Cm x +.It Fl t +The names of the specified files are listed if they occur +on the backup. +If no file argument is given, +then the root directory is listed, +which results in the entire content of the +backup being listed, +unless the +.Fl h +flag has been specified. +Note that the +.Fl t +flag replaces the function of the old +.Xr dumpdir 8 +program. +.ne 1i +.It Fl x The named files are read from the given media. If a named file matches a directory whose contents are on the backup and the -.Cm h -key is not specified, +.Fl h +flag is not specified, the directory is recursively extracted. The owner, modification time, and mode are restored (if possible). @@ -142,170 +252,81 @@ then the root directory is extracted, which results in the entire content of the backup being extracted, unless the -.Cm h -key has been specified. -.It Cm t -The names of the specified files are listed if they occur -on the backup. -If no file argument is given, -then the root directory is listed, -which results in the entire content of the -backup being listed, -unless the -.Cm h -key has been specified. -Note that the -.Cm t -key replaces the function of the old -.Xr dumpdir 8 -program. -.It Cm i -This mode allows interactive restoration of files from a dump. -After reading in the directory information from the dump, -.Nm restore -provides a shell like interface that allows the user to move -around the directory tree selecting files to be extracted. -The available commands are given below; -for those commands that require an argument, -the default is the current directory. -.Bl -tag -width Fl -.It Ic add Op Ar arg -The current directory or specified argument is added to the list of -files to be extracted. -If a directory is specified, then it and all its descendents are -added to the extraction list -(unless the -.Cm h -key is specified on the command line). -Files that are on the extraction list are prepended with a ``*'' -when they are listed by -.Ic ls . -.It Ic \&cd Ar arg -Change the current working directory to the specified argument. -.It Ic delete Op Ar arg -The current directory or specified argument is deleted from the list of -files to be extracted. -If a directory is specified, then it and all its descendents are -deleted from the extraction list -(unless the -.Cm h -key is specified on the command line). -The most expedient way to extract most of the files from a directory -is to add the directory to the extraction list and then delete -those files that are not needed. -.It Ic extract -All the files that are on the extraction list are extracted -from the dump. -.Nm Restore -will ask which volume the user wishes to mount. -The fastest way to extract a few files is to -start with the last volume, and work towards the first volume. -.It Ic help -List a summary of the available commands. -.It Ic \&ls Op Ar arg -List the current or specified directory. -Entries that are directories are appended with a ``/''. -Entries that have been marked for extraction are prepended with a ``*''. -If the verbose key is set the inode number of each entry is also listed. -.It Ic pwd -Print the full pathname of the current working directory. -.It Ic quit -Restore immediately exits, -even if the extraction list is not empty. -.It Ic setmodes -All the directories that have been added to the extraction list -have their owner, modes, and times set; -nothing is extracted from the dump. -This is useful for cleaning up after a restore has been prematurely aborted. -.It Ic verbose -The sense of the -.Cm v -key is toggled. -When set, the verbose key causes the -.Ic ls -command to list the inode numbers of all entries. -It also causes -.Nm restore -to print out information about each file as it is extracted. -.El +.Fl h +flag has been specified. .El .Pp -The following characters may be used in addition to the letter -that selects the function desired. +The following additional options may be specified: .Bl -tag -width Ds -.It Cm b -The next argument to -.Nm restore -is used as the block size of the media (in kilobytes). +.It Fl b Ar blocksize +The number of kilobytes per dump record. If the .Fl b option is not specified, .Nm restore tries to determine the media block size dynamically. -.It Cm f -The next argument to +.It Fl c +Normally, .Nm restore -is used as the name of the archive instead -of -.Pa /dev/rst0 . +will try to determine dynamically whether the dump was made from an +old (pre-4.4) or new format file sytem. The +.Fl c +flag disables this check, and only allows reading a dump in the old +format. +.It Fl f Ar file +Read the backup from +.Ar file ; +.Ar file +may be a special device file +like +.Pa /dev/rmt12 +(a tape drive), +.Pa /dev/rsd1c +(a disk drive), +an ordinary file, +or +.Ql Fl +(the standard input). If the name of the file is of the form .Dq host:file , +or +.Dq user@host:file , .Nm restore reads from the named file on the remote host using .Xr rmt 8 . -If the name of the file is -.Ql Fl , -.Nm restore -reads from standard input. -Thus, -.Xr dump 8 -and -.Nm restore -can be used in a pipeline to dump and restore a file system -with the command -.Bd -literal -offset indent -dump 0f - /usr | (cd /mnt; restore xf -) -.Ed .Pp -.It Cm h -.Nm Restore -extracts the actual directory, +.It Fl h +Extract the actual directory, rather than the files that it references. This prevents hierarchical restoration of complete subtrees from the dump. -.It Cm m -.Nm Restore -will extract by inode numbers rather than by file name. +.It Fl m +Extract by inode numbers rather than by file name. This is useful if only a few files are being extracted, and one wants to avoid regenerating the complete pathname to the file. -.It Cm s -The next argument to -.Nm restore -is a number which -selects the file on a multi-file dump tape. File numbering -starts at 1. -.It Cm v +.It Fl s Ar fileno +Read from the specified +.Ar fileno +on a multi-file tape. +File numbering starts at 1. +.It Fl v Normally .Nm restore does its work silently. The -.Cm v +.Fl v (verbose) -key causes it to type the name of each file it treats +flag causes it to type the name of each file it treats preceded by its file type. -.It Cm y -.Nm Restore -will not ask whether it should abort the restore if it gets an error. -It will always try to skip over the bad block(s) and continue as -best it can. +.It Fl y +Do not ask the user whether to abort the restore in the event of an error. +Always try to skip over the bad block(s) and continue. .El .Sh DIAGNOSTICS -Complaints about bad key characters. -.Pp Complaints if it gets a read error. If -.Cm y +.Fl y has been specified, or the user responds .Ql y , .Nm restore @@ -315,10 +336,10 @@ If a backup was made using more than one tape volume, .Nm restore will notify the user when it is time to mount the next volume. If the -.Cm x +.Fl x or -.Cm i -key has been specified, +.Fl i +flag has been specified, .Nm restore will also ask which volume the user wishes to mount. The fastest way to extract a few files is to @@ -391,7 +412,7 @@ information passed between incremental restores. .Sh BUGS .Nm Restore can get confused when doing incremental restores from -dump that were made on active file systems. +dumps that were made on active file systems. .Pp A level zero dump must be done after a full restore. Because restore runs in user code, diff --git a/sbin/restore/restore.c b/sbin/restore/restore.c index 97bd6ccc3650..936d857d8b52 100644 --- a/sbin/restore/restore.c +++ b/sbin/restore/restore.c @@ -32,7 +32,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)restore.c 8.1 (Berkeley) 6/5/93"; +static char sccsid[] = "@(#)restore.c 8.3 (Berkeley) 9/13/94"; #endif /* not lint */ #include @@ -85,6 +85,8 @@ addfile(name, ino, type) dprintf(stdout, "%s: not on the tape\n", name); return (descend); } + if (ino == WINO && command == 'i' && !vflag) + return (descend); if (!mflag) { (void) sprintf(buf, "./%u", ino); name = buf; @@ -124,9 +126,13 @@ deletefile(name, ino, type) if (TSTINO(ino, dumpmap) == 0) return (descend); - ep = lookupino(ino); - if (ep != NULL) + ep = lookupname(name); + if (ep != NULL) { ep->e_flags &= ~NEW; + ep->e_flags |= REMOVED; + if (ep->e_type != NODE) + freeentry(ep); + } return (descend); } @@ -146,21 +152,38 @@ deletefile(name, ino, type) 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() { - register struct entry *ep; - register ino_t i; + register struct entry *ep, *nextep; + register 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; + delwhiteout(ep); + freeentry(ep); + } + } for (i = ROOTINO + 1; i < maxino; i++) { ep = lookupino(i); if (ep == NULL) continue; - if (TSTINO(i, clrimap)) + if (TSTINO(i, usedinomap)) continue; for ( ; ep != NULL; ep = ep->e_links) { dprintf(stdout, "%s: REMOVE\n", myname(ep)); @@ -745,6 +768,15 @@ createlinks() register 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; + (void) addwhiteout(myname(ep)); + ep->e_flags &= ~NEW; + } + } vprintf(stdout, "Add links\n"); for (i = ROOTINO; i < maxino; i++) { ep = lookupino(i); @@ -776,7 +808,7 @@ checkrestore() register ino_t i; vprintf(stdout, "Check the symbol table.\n"); - for (i = ROOTINO; i < maxino; i++) { + 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) diff --git a/sbin/restore/symtab.c b/sbin/restore/symtab.c index dc779a35e0a4..6895053e802c 100644 --- a/sbin/restore/symtab.c +++ b/sbin/restore/symtab.c @@ -32,7 +32,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)symtab.c 8.1 (Berkeley) 6/5/93"; +static char sccsid[] = "@(#)symtab.c 8.3 (Berkeley) 4/28/95"; #endif /* not lint */ /* @@ -83,7 +83,7 @@ lookupino(inum) { register struct entry *ep; - if (inum < ROOTINO || inum >= maxino) + if (inum < WINO || inum >= maxino) return (NULL); for (ep = entry[inum % entrytblsize]; ep != NULL; ep = ep->e_next) if (ep->e_ino == inum) @@ -101,7 +101,7 @@ addino(inum, np) { struct entry **epp; - if (inum < ROOTINO || inum >= maxino) + if (inum < WINO || inum >= maxino) panic("addino: out of range %d\n", inum); epp = &entry[inum % entrytblsize]; np->e_ino = inum; @@ -123,7 +123,7 @@ deleteino(inum) register struct entry *next; struct entry **prev; - if (inum < ROOTINO || inum >= maxino) + if (inum < WINO || inum >= maxino) panic("deleteino: out of range %d\n", inum); prev = &entry[inum % entrytblsize]; for (next = *prev; next != NULL; next = next->e_next) { @@ -177,7 +177,7 @@ lookupparent(name) struct entry *ep; char *tailindex; - tailindex = rindex(name, '/'); + tailindex = strrchr(name, '/'); if (tailindex == NULL) return (NULL); *tailindex = '\0'; @@ -202,7 +202,7 @@ myname(ep) for (cp = &namebuf[MAXPATHLEN - 2]; cp > &namebuf[ep->e_namlen]; ) { cp -= ep->e_namlen; - bcopy(ep->e_name, cp, (long)ep->e_namlen); + memmove(cp, ep->e_name, (long)ep->e_namlen); if (ep == lookupino(ROOTINO)) return (cp); *(--cp) = '/'; @@ -232,7 +232,7 @@ addentry(name, inum, type) if (freelist != NULL) { np = freelist; freelist = np->e_next; - bzero((char *)np, (long)sizeof(struct entry)); + memset(np, 0, (long)sizeof(struct entry)); } else { np = (struct entry *)calloc(1, sizeof(struct entry)); if (np == NULL) @@ -249,7 +249,7 @@ addentry(name, inum, type) addino(ROOTINO, np); return (np); } - np->e_name = savename(rindex(name, '/') + 1); + np->e_name = savename(strrchr(name, '/') + 1); np->e_namlen = strlen(np->e_name); np->e_parent = ep; np->e_sibling = ep->e_entries; @@ -333,7 +333,7 @@ moveentry(ep, newname) ep->e_sibling = np->e_entries; np->e_entries = ep; } - cp = rindex(newname, '/') + 1; + cp = strrchr(newname, '/') + 1; freename(ep->e_name); ep->e_name = savename(cp); ep->e_namlen = strlen(cp); @@ -473,7 +473,7 @@ dumpsymtable(filename, checkpt) * Assign indicies to each entry * Write out the string entries */ - for (i = ROOTINO; i < maxino; i++) { + for (i = WINO; i <= maxino; i++) { for (ep = lookupino(i); ep != NULL; ep = ep->e_links) { ep->e_index = mynum++; (void) fwrite(ep->e_name, sizeof(char), @@ -485,10 +485,9 @@ dumpsymtable(filename, checkpt) */ tep = &temp; stroff = 0; - for (i = ROOTINO; i < maxino; i++) { + for (i = WINO; i <= maxino; i++) { for (ep = lookupino(i); ep != NULL; ep = ep->e_links) { - bcopy((char *)ep, (char *)tep, - (long)sizeof(struct entry)); + memmove(tep, ep, (long)sizeof(struct entry)); tep->e_name = (char *)stroff; stroff += allocsize(ep->e_namlen); tep->e_parent = (struct entry *)ep->e_parent->e_index; diff --git a/sbin/restore/tape.c b/sbin/restore/tape.c index 79fba3f9b2cf..9ba2683f95b8 100644 --- a/sbin/restore/tape.c +++ b/sbin/restore/tape.c @@ -37,7 +37,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)tape.c 8.3 (Berkeley) 4/1/94"; +static char sccsid[] = "@(#)tape.c 8.9 (Berkeley) 5/1/95"; #endif /* not lint */ #include @@ -119,9 +119,9 @@ setinput(source) terminal = stdin; #ifdef RRESTORE - if (index(source, ':')) { + if (strchr(source, ':')) { host = source; - source = index(host, ':'); + source = strchr(host, ':'); *source++ = '\0'; if (rmthost(host) == 0) done(1); @@ -254,8 +254,8 @@ setup() dprintf(stdout, "maxino = %d\n", maxino); map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY)); if (map == NULL) - panic("no memory for file removal list\n"); - clrimap = map; + panic("no memory for active inode map\n"); + usedinomap = map; curfile.action = USING; getfile(xtrmap, xtrmapskip); if (spcl.c_type != TS_BITS) { @@ -268,6 +268,13 @@ setup() dumpmap = map; curfile.action = USING; getfile(xtrmap, xtrmapskip); + /* + * If there may be whiteout entries on the tape, pretend that the + * whiteout inode exists, so that the whiteout entries can be + * extracted. + */ + if (oldinofmt == 0) + SETINO(WINO, dumpmap); } /* @@ -504,17 +511,19 @@ int extractfile(name) char *name; { - int mode; + int flags; + mode_t mode; struct timeval timep[2]; struct entry *ep; curfile.name = name; curfile.action = USING; - timep[0].tv_sec = curfile.dip->di_atime.tv_sec; - timep[0].tv_usec = curfile.dip->di_atime.tv_nsec / 1000; - timep[1].tv_sec = curfile.dip->di_mtime.tv_sec; - timep[1].tv_usec = curfile.dip->di_mtime.tv_nsec / 1000; + timep[0].tv_sec = curfile.dip->di_atime; + timep[0].tv_usec = curfile.dip->di_atimensec / 1000; + timep[1].tv_sec = curfile.dip->di_mtime; + timep[1].tv_usec = curfile.dip->di_mtimensec / 1000; mode = curfile.dip->di_mode; + flags = curfile.dip->di_flags; switch (mode & IFMT) { default: @@ -550,14 +559,20 @@ extractfile(name) return (linkit(lnkbuf, name, SYMLINK)); case IFIFO: + vprintf(stdout, "extract fifo %s\n", name); + if (Nflag) { + skipfile(); + return (GOOD); + } if (mkfifo(name, mode) < 0) { - fprintf(stderr, "%s: cannot create FIFO: %s\n", - name, strerror(errno)); + fprintf(stderr, "%s: cannot create fifo: %s\n", + name, strerror(errno)); skipfile(); return (FAIL); } (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid); (void) chmod(name, mode); + (void) chflags(name, flags); skipfile(); utimes(name, timep); return (GOOD); @@ -577,6 +592,7 @@ extractfile(name) } (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid); (void) chmod(name, mode); + (void) chflags(name, flags); skipfile(); utimes(name, timep); return (GOOD); @@ -596,6 +612,7 @@ extractfile(name) } (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid); (void) fchmod(ofile, mode); + (void) fchflags(ofile, flags); getfile(xtrfile, xtrskip); (void) close(ofile); utimes(name, timep); @@ -639,7 +656,7 @@ getfile(fill, skip) { register int i; int curblk = 0; - long size = spcl.c_dinode.di_size; + quad_t size = spcl.c_dinode.di_size; static char clearedbuf[MAXBSIZE]; char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE]; char junk[TP_BSIZE]; @@ -656,20 +673,19 @@ getfile(fill, skip) if (spcl.c_addr[i]) { readtape(&buf[curblk++][0]); if (curblk == fssize / TP_BSIZE) { - (*fill)((char *)buf, size > TP_BSIZE ? - (long) (fssize) : - (curblk - 1) * TP_BSIZE + size); + (*fill)((char *)buf, (long)(size > TP_BSIZE ? + fssize : (curblk - 1) * TP_BSIZE + size)); curblk = 0; } } else { if (curblk > 0) { - (*fill)((char *)buf, size > TP_BSIZE ? - (long) (curblk * TP_BSIZE) : - (curblk - 1) * TP_BSIZE + size); + (*fill)((char *)buf, (long)(size > TP_BSIZE ? + curblk * TP_BSIZE : + (curblk - 1) * TP_BSIZE + size)); curblk = 0; } - (*skip)(clearedbuf, size > TP_BSIZE ? - (long) TP_BSIZE : size); + (*skip)(clearedbuf, (long)(size > TP_BSIZE ? + TP_BSIZE : size)); } if ((size -= TP_BSIZE) <= 0) { for (i++; i < spcl.c_count; i++) @@ -686,7 +702,7 @@ getfile(fill, skip) curfile.name, blksread); } if (curblk > 0) - (*fill)((char *)buf, (curblk * TP_BSIZE) + size); + (*fill)((char *)buf, (long)((curblk * TP_BSIZE) + size)); findinode(&spcl); gettingfile = 0; } @@ -770,7 +786,7 @@ xtrmap(buf, size) long size; { - bcopy(buf, map, size); + memmove(map, buf, size); map += size; } @@ -813,7 +829,7 @@ readtape(buf) int cnt, seek_failed; if (blkcnt < numtrec) { - bcopy(&tapebuf[(blkcnt++ * TP_BSIZE)], buf, (long)TP_BSIZE); + memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE); blksread++; tpblksread++; return; @@ -885,7 +901,7 @@ readtape(buf) if (!yflag && !reply("continue")) done(1); i = ntrec * TP_BSIZE; - bzero(tapebuf, i); + memset(tapebuf, 0, i); #ifdef RRESTORE if (host) seek_failed = (rmtseek(i, 1) < 0); @@ -916,10 +932,10 @@ readtape(buf) panic("partial block read: %d should be %d\n", rd, ntrec * TP_BSIZE); terminateinput(); - bcopy((char *)&endoftapemark, &tapebuf[rd], (long)TP_BSIZE); + memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE); } blkcnt = 0; - bcopy(&tapebuf[(blkcnt++ * TP_BSIZE)], buf, (long)TP_BSIZE); + memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE); blksread++; tpblksread++; } @@ -1030,7 +1046,7 @@ gethead(buf) goto good; } readtape((char *)(&u_ospcl.s_ospcl)); - bzero((char *)buf, (long)TP_BSIZE); + memset(buf, 0, (long)TP_BSIZE); buf->c_type = u_ospcl.s_ospcl.c_type; buf->c_date = u_ospcl.s_ospcl.c_date; buf->c_ddate = u_ospcl.s_ospcl.c_ddate; @@ -1045,11 +1061,11 @@ gethead(buf) buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid; buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size; buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev; - buf->c_dinode.di_atime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_atime; - buf->c_dinode.di_mtime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_mtime; - buf->c_dinode.di_ctime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_ctime; + buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime; + buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime; + buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime; buf->c_count = u_ospcl.s_ospcl.c_count; - bcopy(u_ospcl.s_ospcl.c_addr, buf->c_addr, (long)256); + memmove(buf->c_addr, u_ospcl.s_ospcl.c_addr, (long)256); if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC || checksum((int *)(&u_ospcl.s_ospcl)) == FAIL) return(FAIL); @@ -1140,10 +1156,10 @@ accthdr(header) goto newcalc; switch (prevtype) { case TS_BITS: - fprintf(stderr, "Dump mask header"); + fprintf(stderr, "Dumped inodes map header"); break; case TS_CLRI: - fprintf(stderr, "Remove mask header"); + fprintf(stderr, "Used inodes map header"); break; case TS_INODE: fprintf(stderr, "File header, ino %d", previno); diff --git a/sbin/restore/utilities.c b/sbin/restore/utilities.c index b2e442e8104f..6008f7ac2a98 100644 --- a/sbin/restore/utilities.c +++ b/sbin/restore/utilities.c @@ -32,7 +32,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)utilities.c 8.2 (Berkeley) 3/25/94"; +static char sccsid[] = "@(#)utilities.c 8.5 (Berkeley) 4/28/95"; #endif /* not lint */ #include @@ -61,7 +61,7 @@ pathcheck(name) struct entry *ep; char *start; - start = index(name, '/'); + start = strchr(name, '/'); if (start == 0) return; for (cp = start; *cp != '\0'; cp++) { @@ -229,6 +229,45 @@ linkit(existing, new, type) return (GOOD); } +/* + * Create a whiteout. + */ +int +addwhiteout(name) + char *name; +{ + + if (!Nflag && mknod(name, S_IFWHT, 0) < 0) { + fprintf(stderr, "warning: cannot create whiteout %s: %s\n", + name, strerror(errno)); + return (FAIL); + } + vprintf(stdout, "Create whiteout %s\n", name); + return (GOOD); +} + +/* + * Delete a whiteout. + */ +void +delwhiteout(ep) + register struct entry *ep; +{ + char *name; + + if (ep->e_type != LEAF) + badentry(ep, "delwhiteout: not a leaf"); + ep->e_flags |= REMOVED; + ep->e_flags &= ~TMPNAME; + name = myname(ep); + if (!Nflag && undelete(name) < 0) { + fprintf(stderr, "warning: cannot delete whiteout %s: %s\n", + name, strerror(errno)); + return; + } + vprintf(stdout, "Delete whiteout %s\n", name); +} + /* * find lowest number file (above "start") that needs to be extracted */