diff -c3 tar-1.11.1/ChangeLog tar-1.11.2/ChangeLog *** tar-1.11.1/ChangeLog Tue Sep 15 20:44:04 1992 --- tar-1.11.2/ChangeLog Thu Mar 25 13:54:56 1993 *************** *** 1,3 **** --- 1,249 ---- + Thu Mar 25 13:32:40 1993 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * version.c: Released version 1.11.2. + + * Makefile.in (dist): Do the link differently; some of the + files have changed filesystems which makes it more complex. + + * Makefile.in (dist, shar): Use gzip instead of compress. + + * create.c (dump_file): Test for curdev==-1, not curdev<0. + Some losing NFS systems give negative device numbers + sometimes. + + Thu Mar 25 11:55:15 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu) + + * level-0, level-1 (TAR_PART1): Use `--block-size', not just + `--block', which is now ambiguous. + + Wed Mar 24 22:12:51 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu) + + * backup-specs (TAR): New variable. + + * level-0, level-1 (TAR_PART1): Get path of GNU tar from `TAR' + variable, don't hardcode it. + + Sat Mar 20 00:20:05 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu) + + * backup-specs (SLEEP_MESSAGE): put backslashes in front of nested + double quotes. + + * level-0, level-1 (BACKUP_DIRS): Don't put in quotes. + (LOGFILE): Use sed to construct name, not awk. + + * dump-remind (recipients): Replaced inefficient pipeline with a + single, simple sed script. + (volno): Deal with the possibility that VOLNO_FILE may not be + created yet. + + Fri Mar 19 15:05:15 1993 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * backup-specs (VOLNO_FILE): Removed abusive comment by Noah. + + * buffer.c (new_volume): Write the global volume number to the + volno file before running the info script, so that the script + can look at it. + + Thu Mar 18 20:11:54 1993 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu) + + * Makefile.in (AUX): Include `dump-remind' in distribution. + + * backup-specs (SLEEP_MESSAGE): New variable. + level-0, level-1: Use it instead of external `dont_touch' file. + + * level-0, level-1: Put most of the script in () and pipe + everything from the subshell through tee -a $LOGFILE. Since you + really want most of the output to go to the logfile anyway, and + since all those pipelines were preventing one from getting the + exit status of most commands, this seems like the right idea. + + * level-0, level-1 (LOGFILE): Use YYYY-MM-DD (all numeric) format + for log file name, since that makes the file names sortable in a + coherent way. Suffix should always be `level-n' where n is the + dump level. level-0 script was just using `-full' instead. + + * level-0, level-1 (DUMP_LEVEL): New variable. Set to `0' or `1' + in each script as appropriate. + + * level-0, level-1 (HOST): Renamed to `localhost' for clarity. + (host): renamed to `remotehost' for clarity. + + * level-0, level-1 (startdate): New variable. Use it in Subject + line of mailed report. + + * level-0, level-1: Fixed all instances where sed is called with a + script on the command line to use `-e' option. + + * level-0, level-1: Don't try to call logfile.sed to filter + LOGFILE. It's not distributed with tar and was never really used + anyway. + + * level-0, level-1: Put quotes around most variable names (barring + those that are known to intentionally contain text that should be + expanded into multiple words, like `TAR_PART1'). + + * level-0, level-1: Got rid of annoying trailing backslashes in awk + scripts. They were gratuitous. Made them a little more readable + by adding some whitespace. + + Wed Mar 17 10:30:58 1993 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * tar.c (describe, long_options): Changed --compress-block to + --block-compress. + (options): Fixed f_compress_block sanity check error message + to give the correct name of the option. + + Tue Mar 16 14:52:40 1993 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * extract.c (extract_archive): case LF_DIR: Do chown when + necessary. Don't bother jumping to set_filestat for + f_modified; repeat the chmod code here. Replace `break', + deleted on 2 September 1992. + + * tar.c (describe, long_options, options): Added gzip options + and use-compress-program option. + * tar.h: Added new compression options. + * buffer.c (child_open, open_archive): Use new compression options. + + * create.c (start_header): Only mask off high bits when + creating old-style archives. + * list.c (decode_header): Mask off potentially misleading + high bits from the mode when reading headers. + + Mon Mar 15 11:34:34 1993 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * extract.c (extract_archive): Put arguments in the right + order for error message. + + * create.c (deal_with_sparse): if the last byte was null, we + didn't write it out. + + * gnu.c, create.c, extract.c, diffarch.c, list.c throughout: + Replace malloc calls with ck_malloc and realloc with ck_realloc. + + * tar.c (describe): Improve doc for -L. + + * tar.c (name_next): Don't apply exclusion to explicitly named + files. + + * tar.c (long_options, describe): Added new-volume-script as + an alias for info-script. + + * extract.c (extract_archive): LF_DUMPDIR case; misplaced paren. + + * extract.c (extract_archive): extract_file case, first if, + include space for null in namelen computation. + + * extract.c (extract_sparse_file): Use value returned by write + to properly create error message. + + * create.c (create_archive): Don't assume we have anything to + dump. + + * buffer.c (open_archive): Set current_file_name for the + volume header so that verbose listings work properly. + + * Makefile.in (realclean): Added getdate.c. + + Thu Jan 14 23:38:44 1993 David J. MacKenzie (djm@kropotkin.gnu.ai.mit.edu) + + * tar.c: Include fnmatch.h after port.h to make sure we get our FNM_* + (e.g. on HPUX 8). + + Tue Nov 24 08:30:54 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu) + + * tar.c (addname), gnu.c (read_dir_file): Use HAVE_GETCWD, not USG. + + * port.h, rmt.h: Use HAVE_STRING_H, not USG. + + * port.h: Add dir header decls. + * create.c, gnu.c: Use SYSNDIR, SYSDIR, and NDIR + instead of BSD42 and USG. Rename DP_NAMELEN to NLENGTH. + Use `struct dirent' instead of `struct direct'. + * create.c, gnu.c, tar.c: Remove dir header decls. + + Wed Nov 18 15:31:30 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu) + + * tar.c: Change FNM_TARPATH to FNM_LEADING_DIR to match change + in fnmatch.[ch]. + + Wed Oct 21 00:52:24 1992 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu) + + * level-0, level-1: put curly braces around variables for clarity. + + * backup-specs (DUMP_REMIND_SCRIPT): define it (but commented out + so that distributed dump scripts won't use it by default). + level-0, level-1 (TAR_PART1): use --info-script if + DUMP_REMIND_SCRIPT is defined. + dump-remind: new file (intended as an example). + + Thu Oct 15 03:33:28 1992 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu) + + * level-0, level-1: remove $LOGFILE.tmp files before exiting. + + Fri Oct 2 00:28:01 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu) + + * tar.c (describe): Fix some tab alignments. + + * Makefile.in (SRC3): Add getdate.c, for systems without bison/yacc + (like MS-DOS). + + * diffarch.c (diff_sparse_files): Add missing arg to fprintf calls. + + * extract.c (extract_archive, restore_saved_dir_info), + buffer.c (child_open), list.c (decode_header, print_header): + Delete unused vars. + + * port.c [__MSDOS__]: Have strstr, rename, and mkdir. Don't + define ck_pipe. + + * buffer.c, tar.c (init_volume_number, closeout_volume_number), + create.c (write_long): Declare as void, not int, since they + don't return a value. + + Thu Sep 24 00:06:02 1992 Michael I Bushnell (mib@churchy.gnu.ai.mit.edu) + + * level-0, level-1 (TAR_PART1): remove --atime-preserve + because of a total screw. + + Tue Sep 22 14:15:48 1992 Michael I Bushnell (mib@wookumz.gnu.ai.mit.edu) + + * buffer.c (close_archive): Removed leftover `break' from when + this was a switch. + + Tue Sep 22 08:33:16 1992 Noah Friedman (friedman@nutrimat.gnu.ai.mit.edu) + + * create.c, port.h: indented #pragma directives with 1 space. + + Fri Sep 18 14:15:17 1992 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * All source files: re indented using GNU indent. + + * rtapelib.c (__rmt_read): Only read the amount left in the + buffer; otherwise a broken rmt server (which puts too much + data out) could overwrite past our buffer. + + Thu Sep 17 14:08:58 1992 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) + + * create.c: Throughout, use struct utimbuf rather than array + of longs. + + * configure.in: Check for getpwuid and getgrgid. + + * Makefile.in (SRC3, AUX): Move alloca.c to SRC3. + (OBJ3): Add @ALLOCA@. + + * Makefile.in (getdate.c): Look in srcdir for getdate.y. + + * buffer.c (close_archive): We can't check WTERMSIG + meaningfully unless we already know tha WIFSIGNALED is true. + (There is no guarantee it WTERMSIG will return zero when + WIFSIGNALED is false.) + * port.c (rmdir, mkdir): Check WIFSIGNALED rather than + WTERMSIG. + + * Makefile.in (getdate.c): Use $(YACC) instead of `yacc'. + Tue Sep 15 14:49:48 1992 Michael I Bushnell (mib@geech.gnu.ai.mit.edu) * version.c: Released version 1.11.1. diff -c3 tar-1.11.1/INSTALL tar-1.11.2/INSTALL *** tar-1.11.1/INSTALL Tue Sep 1 17:41:24 1992 --- tar-1.11.2/INSTALL Fri Jan 22 12:16:53 1993 *************** *** 22,29 **** to `/dev/null'; for example, `./configure >/dev/null'. To compile the package in a different directory from the one ! containing the source code, you must use a version of make that ! supports the VPATH variable, such as GNU make. `cd' to the directory where you want the object files and executables to go and run `configure'. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If for some reason --- 22,29 ---- to `/dev/null'; for example, `./configure >/dev/null'. To compile the package in a different directory from the one ! containing the source code, you must use a version of `make' that ! supports the VPATH variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run `configure'. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If for some reason *************** *** 35,61 **** By default, `make install' will install the package's files in /usr/local/bin, /usr/local/lib, /usr/local/man, etc. You can specify an installation prefix other than /usr/local by giving `configure' the ! option `--prefix=PATH'. Alternately, you can do so by changing the ! `prefix' variable in the Makefile that `configure' creates (the ! Makefile in the top-level directory, if the package contains ! subdirectories). You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If ! you give `configure' the option `--exec_prefix=PATH', the package will ! use PATH as the prefix for installing programs and libraries. Data ! files and documentation will still use the regular prefix. Normally, ! all files are installed using the regular prefix. ! ! You can tell `configure' to figure out the configuration for your ! system, and record it in `config.status', without actually configuring ! the package (creating `Makefile's and perhaps a configuration header ! file). To do this, give `configure' the `--no-create' option. Later, ! you can run `./config.status' to actually configure the package. This ! option is useful mainly in `Makefile' rules for updating `config.status' ! and `Makefile'. You can also give `config.status' the `--recheck' ! option, which makes it re-run `configure' with the same arguments you ! used before. This is useful if you change `configure'. `configure' ignores any other arguments that you give it. --- 35,65 ---- By default, `make install' will install the package's files in /usr/local/bin, /usr/local/lib, /usr/local/man, etc. You can specify an installation prefix other than /usr/local by giving `configure' the ! option `--prefix=PATH'. Alternately, you can do so by giving a value ! for the `prefix' variable when you run `make', e.g., ! make prefix=/usr/gnu You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If ! you give `configure' the option `--exec-prefix=PATH' or set the ! `make' variable `exec_prefix' to PATH, the package will use PATH as ! the prefix for installing programs and libraries. Data files and ! documentation will still use the regular prefix. Normally, all files ! are installed using the regular prefix. ! ! Another `configure' option is useful mainly in `Makefile' rules for ! updating `config.status' and `Makefile'. The `--no-create' option ! figures out the configuration for your system and records it in ! `config.status', without actually configuring the package (creating ! `Makefile's and perhaps a configuration header file). Later, you can ! run `./config.status' to actually configure the package. You can also ! give `config.status' the `--recheck' option, which makes it re-run ! `configure' with the same arguments you used before. This option is ! useful if you change `configure'. ! ! Some packages pay attention to `--with-PACKAGE' options to `configure', ! where PACKAGE is something like `gnu-libc' or `x' (for the X Window System). ! The README should mention any --with- options that the package recognizes. `configure' ignores any other arguments that you give it. *************** *** 79,84 **** --- 83,90 ---- (For these variables, any value given in the environment is added to the value that `configure' chooses:) DEFS Configuration options, in the form `-Dfoo -Dbar ...' + Do not use this variable in packages that create a + configuration header file. LIBS Libraries to link with, in the form `-lfoo -lbar ...' If you need to do unusual things to compile the package, we encourage diff -c3 tar-1.11.1/Makefile.in tar-1.11.2/Makefile.in *** tar-1.11.1/Makefile.in Tue Sep 15 20:43:28 1992 --- tar-1.11.2/Makefile.in Thu Mar 25 13:59:26 1993 *************** *** 1,5 **** # Un*x Makefile for GNU tar program. ! # Copyright (C) 1991, 1992 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by --- 1,5 ---- # Un*x Makefile for GNU tar program. ! # Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by *************** *** 32,45 **** # Things you might add to DEFS: # -DSTDC_HEADERS If you have ANSI C headers and libraries. # -DHAVE_UNISTD_H If you have unistd.h. # -DHAVE_LIMITS_H If you have limits.h. # -DBSD42 If you have sys/dir.h (unless you use -DPOSIX), # sys/file.h, and st_blocks in `struct stat'. ! # -DUSG If you have System V/ANSI C string ! # and memory functions and headers, ! # fcntl.h, getcwd, no valloc, ! # and ndir.h (unless you use -DDIRENT). ! # -DDIRENT If USG and you have dirent.h instead of ndir.h. # -DMAJOR_IN_MKDEV If major, minor, makedev defined in sys/mkdev.h. # -DMAJOR_IN_SYSMACROS If major, minor, makedev defined in sys/sysmacros.h. # -DRETSIGTYPE=int If your signal handlers return int, not void. --- 32,45 ---- # Things you might add to DEFS: # -DSTDC_HEADERS If you have ANSI C headers and libraries. # -DHAVE_UNISTD_H If you have unistd.h. + # -DHAVE_STRING_H If you don't have ANSI C headers but have string.h. # -DHAVE_LIMITS_H If you have limits.h. # -DBSD42 If you have sys/dir.h (unless you use -DPOSIX), # sys/file.h, and st_blocks in `struct stat'. ! # -DDIRENT If you have dirent.h. ! # -DSYSNDIR Old Xenix systems (sys/ndir.h). ! # -DSYSDIR Old BSD systems (sys/dir.h). ! # -DNDIR Old System V systems (ndir.h). # -DMAJOR_IN_MKDEV If major, minor, makedev defined in sys/mkdev.h. # -DMAJOR_IN_SYSMACROS If major, minor, makedev defined in sys/sysmacros.h. # -DRETSIGTYPE=int If your signal handlers return int, not void. *************** *** 56,61 **** --- 56,62 ---- # -DHAVE_MKDIR If you have mkdir and rmdir system calls. # -DHAVE_MKNOD If you have mknod system call. # -DHAVE_RENAME If you have rename system call. + # -DHAVE_GETCWD If not POSIX.1 but have getcwd function. # -DHAVE_FTRUNCATE If you have ftruncate system call. # -DV7 On Version 7 Unix (not tested in a long time). # -DEMUL_OPEN3 If you lack a 3-argument version of open, and want *************** *** 97,114 **** SRC1 = tar.c create.c extract.c buffer.c getoldopt.c update.c gnu.c mangle.c SRC2 = version.c list.c names.c diffarch.c port.c fnmatch.c getopt.c malloc.c ! SRC3 = getopt1.c regex.c getdate.y SRCS = $(SRC1) $(SRC2) $(SRC3) OBJ1 = tar.o create.o extract.o buffer.o getoldopt.o update.o gnu.o mangle.o OBJ2 = version.o list.o names.o diffarch.o port.o fnmatch.o getopt.o @MALLOC@ ! OBJ3 = getopt1.o regex.o getdate.o $(RTAPELIB) OBJS = $(OBJ1) $(OBJ2) $(OBJ3) AUX = README INSTALL NEWS COPYING ChangeLog Makefile.in makefile.pc \ configure configure.in \ tar.h fnmatch.h pathmax.h port.h open3.h getopt.h regex.h \ ! rmt.h rmt.c rtapelib.c alloca.c \ msd_dir.h msd_dir.c tcexparg.c \ ! level-0 level-1 backup-specs testpad.c getpagesize.h # tar.texinfo tar.info* texinfo.tex \ all: @PROGS@ --- 98,115 ---- SRC1 = tar.c create.c extract.c buffer.c getoldopt.c update.c gnu.c mangle.c SRC2 = version.c list.c names.c diffarch.c port.c fnmatch.c getopt.c malloc.c ! SRC3 = getopt1.c regex.c getdate.y getdate.c alloca.c SRCS = $(SRC1) $(SRC2) $(SRC3) OBJ1 = tar.o create.o extract.o buffer.o getoldopt.o update.o gnu.o mangle.o OBJ2 = version.o list.o names.o diffarch.o port.o fnmatch.o getopt.o @MALLOC@ ! OBJ3 = getopt1.o regex.o getdate.o $(RTAPELIB) @ALLOCA@ OBJS = $(OBJ1) $(OBJ2) $(OBJ3) AUX = README INSTALL NEWS COPYING ChangeLog Makefile.in makefile.pc \ configure configure.in \ tar.h fnmatch.h pathmax.h port.h open3.h getopt.h regex.h \ ! rmt.h rmt.c rtapelib.c \ msd_dir.h msd_dir.c tcexparg.c \ ! level-0 level-1 backup-specs dump-remind testpad.c getpagesize.h # tar.texinfo tar.info* texinfo.tex \ all: @PROGS@ *************** *** 142,148 **** tar.o fnmatch.o: fnmatch.h getdate.c: getdate.y ! yacc getdate.y mv y.tab.c getdate.c # getdate.y has 8 shift/reduce conflicts. --- 143,149 ---- tar.o fnmatch.o: fnmatch.h getdate.c: getdate.y ! $(YACC) $(srcdir)/getdate.y mv y.tab.c getdate.c # getdate.y has 8 shift/reduce conflicts. *************** *** 164,180 **** rm -f Makefile config.status realclean: distclean ! rm -f TAGS *.info* shar: $(SRCS) $(AUX) ! shar $(SRCS) $(AUX) | compress > tar-`sed -e '/version_string/!d' -e 's/[^0-9.]*\([0-9.]*\).*/\1/' -e q version.c`.shar.Z dist: $(SRCS) $(AUX) echo tar-`sed -e '/version_string/!d' -e 's/[^0-9.]*\([0-9.]*\).*/\1/' -e q version.c` > .fname -rm -rf `cat .fname` mkdir `cat .fname` ! ln $(SRCS) $(AUX) `cat .fname` ! tar chZf `cat .fname`.tar.Z `cat .fname` -rm -rf `cat .fname` .fname tar.zoo: $(SRCS) $(AUX) --- 165,182 ---- rm -f Makefile config.status realclean: distclean ! rm -f TAGS *.info* getdate.c y.tab.c shar: $(SRCS) $(AUX) ! shar $(SRCS) $(AUX) | gzip > tar-`sed -e '/version_string/!d' -e 's/[^0-9.]*\([0-9.]*\).*/\1/' -e q version.c`.shar.z dist: $(SRCS) $(AUX) echo tar-`sed -e '/version_string/!d' -e 's/[^0-9.]*\([0-9.]*\).*/\1/' -e q version.c` > .fname -rm -rf `cat .fname` mkdir `cat .fname` ! for file in $(SRCS) $(AUX); do \ ! ln $$file `cat .fname` || cp $$file `cat .fname`; done ! tar chzf `cat .fname`.tar.z `cat .fname` -rm -rf `cat .fname` .fname tar.zoo: $(SRCS) $(AUX) diff -c3 tar-1.11.1/NEWS tar-1.11.2/NEWS *** tar-1.11.1/NEWS Mon Sep 14 15:39:21 1992 --- tar-1.11.2/NEWS Thu Mar 25 13:38:41 1993 *************** *** 1,5 **** ! Current Version: 1.11. User-visible changes since 1.10: o Many bug fixes --- 1,36 ---- ! Current Version: 1.11.2 + + User-visible changes since 1.11.1: + + o Changes in backup scripts + - cleaned up considerably; notices error conditions better over rsh + - DUMP_REMIND_SCRIPT is now an option in backup-specs + - new file dump-remind is an example of a DUMP_REMIND_SCRIPT + o Superfluous "Reading dirname" was a bug; fixed. + o Incompatibility problems with a bug on Solaris are fixed. + o New option --gzip (aliases are --ungzip and -z); calls gzip instead + of compress. Also, --use-compress-program lets you specify any + compress program. --compress-block is renamed --block-compress and + now requires one of the three compression options to be specified. + o Several error messages are cleaned up. + o Directory owners are now set properly when running as root. + o Provide DUMP_REMIND_SCRIPT in backup-specs as a possible option + for --info-script. + o Behave better with broken rmt servers. + o Dump scripts no longer use --atime-preserve; this causes a nasty probem. + o Several Makefile cleanups. + + + ============== + Version 1.11.1 + User-visible changes since 1.11: + + o Many bug fixes + + + ============ + Version 1.11 User-visible changes since 1.10: o Many bug fixes *************** *** 53,60 **** long names to work. ! ================== ! User-visible changes since 1.09: Filename to -G is optional. -C works right. --- 84,91 ---- long names to work. ! ============= ! Version 1.10: User-visible changes since 1.09: Filename to -G is optional. -C works right. diff -c3 tar-1.11.1/README tar-1.11.2/README *** tar-1.11.1/README Tue Sep 15 20:35:34 1992 --- tar-1.11.2/README Wed Mar 17 13:33:58 1993 *************** *** 1,16 **** Hey! Emacs! Yo! This is -*- Text -*- !!! ! This GNU tar 1.11.1. Please send bug reports, etc., to bug-gnu-utils@prep.ai.mit.edu. This is a beta-test release. Please ! try it out. After bug reports are processed for this release, version ! 1.12 will be released. This release includes only bugfixes past ! version 1.11, most of which are fairly important. GNU tar is based heavily on John Gilmore's public domain tar, but with ! added features. The manual is currently being written. An old ! manual, surely riddled with errors, is in tar.texinfo. Please don't ! send in bug reports about that manual. In particular, the mechanism ! for doing incremental dumps has been significantly changed. This distribution also includes rmt, the remote tape server (which normally must reside in /etc). The mt tape drive control program is --- 1,12 ---- Hey! Emacs! Yo! This is -*- Text -*- !!! ! This GNU tar 1.11.2. Please send bug reports, etc., to bug-gnu-utils@prep.ai.mit.edu. This is a beta-test release. Please ! try it out. There is no manual; the release of version 1.12 will ! contain a manual. GNU tar is based heavily on John Gilmore's public domain tar, but with ! added features. The manual is currently being written. This distribution also includes rmt, the remote tape server (which normally must reside in /etc). The mt tape drive control program is *************** *** 32,40 **** --newer-mtime to do incremental dumps. The only option that works correctly for this purpose is --listed-incremental. (When extracting incremental dumps, use --incremental (-G).) - - There is no tar manual in this release. The old manual has too many - problems to make it usable. A new manual will appear in version 1.12. If your system needs to link with -lPW to get alloca, but has rename in the C library (so HAVE_RENAME is defined), -lPW might --- 28,33 ---- diff -c3 tar-1.11.1/alloca.c tar-1.11.2/alloca.c *** tar-1.11.1/alloca.c Sat Jul 25 17:40:32 1992 --- tar-1.11.2/alloca.c Tue Dec 1 13:25:53 1992 *************** *** 30,37 **** static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */ #endif ! #ifdef emacs #include "config.h" #ifdef static /* actually, only want this if static is defined as "" -- this is for usg, in which emacs must undefine static --- 30,40 ---- static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */ #endif ! #ifdef HAVE_CONFIG_H #include "config.h" + #endif + + #ifdef emacs #ifdef static /* actually, only want this if static is defined as "" -- this is for usg, in which emacs must undefine static diff -c3 tar-1.11.1/backup-specs tar-1.11.2/backup-specs *** tar-1.11.1/backup-specs Wed Sep 9 17:06:13 1992 --- tar-1.11.2/backup-specs Wed Mar 24 22:10:57 1993 *************** *** 1,12 **** # site-specific parameters for file system backup. # User name of administrator of backups. ! ADMINISTRATOR=friedman # Hour at which backups are normally done. # This should be a number from 0 to 23. BACKUP_HOUR=1 # Device to use for dumping. It should be on the host # on which the dump scripts are run. TAPE_FILE=/dev/nrsmt0 --- 1,15 ---- # site-specific parameters for file system backup. # User name of administrator of backups. ! ADMINISTRATOR=backup-reports # Hour at which backups are normally done. # This should be a number from 0 to 23. BACKUP_HOUR=1 + # Location of GNU tar. This must be the same for all hosts. + TAR=/usr/local/gnubin/tar + # Device to use for dumping. It should be on the host # on which the dump scripts are run. TAPE_FILE=/dev/nrsmt0 *************** *** 14,20 **** # Command to obtain status of tape drive, including error count. # On some tape drives there may not be such a command; # then simply use `TAPE_STATUS=false'. ! TAPE_STATUS="mts -t $TAPE_FILE" # Blocking factor to use for writing the dump. BLOCKING=124 --- 17,27 ---- # Command to obtain status of tape drive, including error count. # On some tape drives there may not be such a command; # then simply use `TAPE_STATUS=false'. ! # ! # Might also consider ! # TAPE_STATUS="mt -f ${TAPE_FILE} status" ! # if `mts' is missing, though this alternative is rather verbose. ! TAPE_STATUS="mts -t ${TAPE_FILE}" # Blocking factor to use for writing the dump. BLOCKING=124 *************** *** 23,63 **** # by all the machines which have filesystems to be dumped. VOLNO_FILE=/home/gd2/dump/volnofile ! # List of file systems to be dumped. ! # Actually, any directory may be used, ! # but if it has subdirectories on other file systems, ! # they are not included. # The host name specifies which host to run tar on. # It should normally be the host that actually has the file system. ! # If GNU tar is not installed on that machine, ! # then you can specify some other host which can access ! # the file system through NFS. # Although these are arranged one per line, that is not mandatory. # It does not work to use # for comments within the string. ! BACKUP_DIRS=" albert:/fs/fsf ! apple-gunkies:/gd albert:/fs/gd2 nutrimat:/fs/gp nutrimat:/fs/gp2 albert:/fs/mailer albert:/ albert:/usr - apple-gunkies:/ - apple-gunkies:/usr nutrimat:/ - placebo:/archive placebo:/ - wombat:/ - wombat:/usr - wombat:/usr1 - gnu:/ - gnu:/usr ernst:/usr1 ! nutrimat:/fs/dist" # List of individual files to be dumped. # These should be accesible from the machine on which the dump is run. ! BACKUP_FILES="" --- 30,81 ---- # by all the machines which have filesystems to be dumped. VOLNO_FILE=/home/gd2/dump/volnofile ! # Script to be run when it's time to insert a new tape in for the next ! # volume. Administrators may want to tailor this script for their site. ! # If this variable isn't set, tar will use some default behavior which is ! # probably defined in the manual. ! #DUMP_REMIND_SCRIPT='rsh apple-gunkies /home/gd2/dump/dump-remind' + # List of file systems to be dumped. + # Actually, any directory may be used, but if it has subdirectories on + # other file systems, they are not included. # The host name specifies which host to run tar on. # It should normally be the host that actually has the file system. ! # If GNU tar is not installed on that machine, then you can specify some ! # other host which can access the file system through NFS. # Although these are arranged one per line, that is not mandatory. # It does not work to use # for comments within the string. ! BACKUP_DIRS=' albert:/fs/fsf ! sugar-bombs:/fs/gd albert:/fs/gd2 nutrimat:/fs/gp nutrimat:/fs/gp2 albert:/fs/mailer + placebo:/archive + nutrimat:/fs/dist albert:/ albert:/usr nutrimat:/ placebo:/ ernst:/usr1 ! ' # List of individual files to be dumped. # These should be accesible from the machine on which the dump is run. ! BACKUP_FILES='' ! ! # Message to display on the terminal while waiting for dump time. Usually ! # this will just be some literal text, preferably something more ! # entertaining than this. The awk script here saves some redundant ! # repetition, but is not really all that desirable. ! SLEEP_MESSAGE="`awk ' ! BEGIN { ! for (i = 0; i < 30; i++) ! print \" \" \ ! \"D O N O T T O U C H T H I S T E R M I N A L !!!!!\" ! }' /dev/null`" ! ! ! # eof diff -c3 tar-1.11.1/buffer.c tar-1.11.2/buffer.c *** tar-1.11.1/buffer.c Mon Sep 14 16:56:39 1992 --- tar-1.11.2/buffer.c Fri Mar 19 15:05:11 1993 *************** *** 1,5 **** /* Buffer management for tar. ! Copyright (C) 1988, 1992 Free Software Foundation This file is part of GNU Tar. --- 1,5 ---- /* Buffer management for tar. ! Copyright (C) 1988, 1992, 1993 Free Software Foundation This file is part of GNU Tar. *************** *** 31,37 **** #include /* For non-Berkeley systems */ #include #include ! time_t time(); #ifdef HAVE_SYS_MTIO_H #include --- 31,37 ---- #include /* For non-Berkeley systems */ #include #include ! time_t time (); #ifdef HAVE_SYS_MTIO_H #include *************** *** 73,93 **** it can't exec. We hope compress/sh never return this status! */ ! void *valloc(); ! void writeerror(); ! void readerror(); ! void ck_pipe(); ! void ck_close(); ! int backspace_output(); ! extern void finish_header(); ! void flush_archive(); ! int isfile(); ! int new_volume(); ! void verify_volume(); ! extern void to_oct(); #ifndef __MSDOS__ /* Obnoxious test to see if dimwit is trying to dump the archive */ --- 73,93 ---- it can't exec. We hope compress/sh never return this status! */ ! void *valloc (); ! void writeerror (); ! void readerror (); ! void ck_pipe (); ! void ck_close (); ! int backspace_output (); ! extern void finish_header (); ! void flush_archive (); ! int isfile (); ! int new_volume (); ! void verify_volume (); ! extern void to_oct (); #ifndef __MSDOS__ /* Obnoxious test to see if dimwit is trying to dump the archive */ *************** *** 104,131 **** * header record. */ static union record **save_rec; ! union record record_save_area; ! static long saved_recno; /* * PID of child program, if f_compress or remote archive access. */ ! static int childpid = 0; /* * Record number of the start of this block of records */ ! long baserec; /* * Error recovery stuff */ ! static int r_error_count; /* * Have we hit EOF yet? */ ! static int hit_eof; /* Checkpointing counter */ static int checkpoint; --- 104,131 ---- * header record. */ static union record **save_rec; ! union record record_save_area; ! static long saved_recno; /* * PID of child program, if f_compress or remote archive access. */ ! static int childpid = 0; /* * Record number of the start of this block of records */ ! long baserec; /* * Error recovery stuff */ ! static int r_error_count; /* * Have we hit EOF yet? */ ! static int hit_eof; /* Checkpointing counter */ static int checkpoint; *************** *** 132,138 **** /* JF we're reading, but we just read the last record and its time to update */ extern time_to_start_writing; ! int file_to_switch_to= -1; /* If remote update, close archive, and use this descriptor to write to */ static int volno = 1; /* JF which volume of a multi-volume tape --- 132,138 ---- /* JF we're reading, but we just read the last record and its time to update */ extern time_to_start_writing; ! int file_to_switch_to = -1; /* If remote update, close archive, and use this descriptor to write to */ static int volno = 1; /* JF which volume of a multi-volume tape *************** *** 155,168 **** /* Reset the EOF flag (if set), and re-set ar_record, etc */ void ! reset_eof() { ! if(hit_eof) { ! hit_eof=0; ! ar_record=ar_block; ! ar_last=ar_block+blocking; ! ar_reading=0; ! } } /* --- 155,169 ---- /* Reset the EOF flag (if set), and re-set ar_record, etc */ void ! reset_eof () { ! if (hit_eof) ! { ! hit_eof = 0; ! ar_record = ar_block; ! ar_last = ar_block + blocking; ! ar_reading = 0; ! } } /* *************** *** 171,188 **** * it, to avoid accidentally going on to the next file on the "tape". */ union record * ! findrec() { ! if (ar_record == ar_last) { ! if (hit_eof) ! return (union record *)NULL; /* EOF */ ! flush_archive(); ! if (ar_record == ar_last) { ! hit_eof++; ! return (union record *)NULL; /* EOF */ ! } } ! return ar_record; } --- 172,191 ---- * it, to avoid accidentally going on to the next file on the "tape". */ union record * ! findrec () { ! if (ar_record == ar_last) ! { ! if (hit_eof) ! return (union record *) NULL; /* EOF */ ! flush_archive (); ! if (ar_record == ar_last) ! { ! hit_eof++; ! return (union record *) NULL; /* EOF */ } ! } ! return ar_record; } *************** *** 191,209 **** * (should the arg have an off-by-1? XXX FIXME) */ void ! userec(rec) ! union record *rec; { ! while(rec >= ar_record) ! ar_record++; ! /* * Do NOT flush the archive here. If we do, the same * argument to userec() could mean the next record (if the * input block is exactly one record long), which is not what * is intended. */ ! if (ar_record > ar_last) ! abort(); } --- 194,212 ---- * (should the arg have an off-by-1? XXX FIXME) */ void ! userec (rec) ! union record *rec; { ! while (rec >= ar_record) ! ar_record++; ! /* * Do NOT flush the archive here. If we do, the same * argument to userec() could mean the next record (if the * input block is exactly one record long), which is not what * is intended. */ ! if (ar_record > ar_last) ! abort (); } *************** *** 213,221 **** * for filling with data, or taking data from. */ union record * ! endofrecs() { ! return ar_last; } --- 216,224 ---- * for filling with data, or taking data from. */ union record * ! endofrecs () { ! return ar_last; } *************** *** 224,478 **** * Equivalent to BSD "dup2" with error reporting. */ void ! dupto(from, to, msg) ! int from, to; ! char *msg; ! { ! int err; ! ! if (from != to) { ! err=close(to); ! if(err<0 && errno!=EBADF) { ! msg_perror("Cannot close descriptor %d",to); ! exit(EX_SYSTEM); ! } ! err = dup(from); ! if (err != to) { ! msg_perror("cannot dup %s",msg); ! exit(EX_SYSTEM); ! } ! ck_close(from); } } #ifdef __MSDOS__ void ! child_open() { ! fprintf(stderr,"MS-DOS %s can't use compressed or remote archives\n",tar); ! exit(EX_ARGSBAD); } #else void ! child_open() { ! int pipe[2]; ! int err = 0; ! int nar; ! int kidpipe[2]; ! int kidchildpid; #define READ 0 #define WRITE 1 ! ck_pipe(pipe); ! childpid=fork(); ! if(childpid<0) { ! msg_perror("cannot fork"); ! exit(EX_SYSTEM); ! } ! if(childpid>0) { ! /* We're the parent. Clean up and be happy */ ! /* This, at least, is easy */ ! ! if(ar_reading) { ! f_reblock++; ! archive=pipe[READ]; ! ck_close(pipe[WRITE]); ! } else { ! archive = pipe[WRITE]; ! ck_close(pipe[READ]); ! } ! return; ! } ! /* We're the kid */ ! if(ar_reading) { ! dupto(pipe[WRITE],STDOUT,"(child) pipe to stdout"); ! ck_close(pipe[READ]); ! } else { ! dupto(pipe[READ],STDIN,"(child) pipe to stdin"); ! ck_close(pipe[WRITE]); } ! /* We need a child tar only if 1: we're reading/writing stdin/out (to force reblocking) 2: the file is to be accessed by rmt (compress doesn't know how) 3: the file is not a plain file */ #ifdef NO_REMOTE ! if(!(ar_files[0][0]=='-' && ar_files[0][1]=='\0') && isfile(ar_files[0])) #else ! if(!(ar_files[0][0]=='-' && ar_files[0][1]=='\0') && !_remdev(ar_files[0]) && isfile(ar_files[0])) #endif { ! /* We don't need a child tar. Open the archive */ ! if(ar_reading) { ! archive=open(ar_files[0], O_RDONLY|O_BINARY, 0666); ! if(archive<0) { ! msg_perror("can't open archive %s",ar_files[0]); ! exit(EX_BADARCH); ! } ! dupto(archive,STDIN,"archive to stdin"); ! /* close(archive); */ ! } else { ! archive=creat(ar_files[0],0666); ! if(archive<0) { ! msg_perror("can't open archive %s",ar_files[0]); ! exit(EX_BADARCH); ! } ! dupto(archive,STDOUT,"archive to stdout"); ! /* close(archive); */ ! } ! } else { ! /* We need a child tar */ ! ck_pipe(kidpipe); ! ! kidchildpid=fork(); ! if(kidchildpid<0) { ! msg_perror("child can't fork"); ! exit(EX_SYSTEM); ! } ! if(kidchildpid>0) { ! /* About to exec compress: set up the files */ ! if(ar_reading) { ! dupto(kidpipe[READ],STDIN,"((child)) pipe to stdin"); ! ck_close(kidpipe[WRITE]); ! /* dup2(pipe[WRITE],STDOUT); */ ! } else { ! /* dup2(pipe[READ],STDIN); */ ! dupto(kidpipe[WRITE],STDOUT,"((child)) pipe to stdout"); ! ck_close(kidpipe[READ]); ! } ! /* ck_close(pipe[READ]); */ ! /* ck_close(pipe[WRITE]); */ ! /* ck_close(kidpipe[READ]); ck_close(kidpipe[WRITE]); */ ! } else { ! /* Grandchild. Do the right thing, namely sit here and read/write the archive, and feed stuff back to compress */ ! tar="tar (child)"; ! if(ar_reading) { ! dupto(kidpipe[WRITE],STDOUT,"[child] pipe to stdout"); ! ck_close(kidpipe[READ]); ! } else { ! dupto(kidpipe[READ],STDIN,"[child] pipe to stdin"); ! ck_close(kidpipe[WRITE]); ! } ! ! if (ar_files[0][0] == '-' && ar_files[0][1] == '\0') { ! if (ar_reading) ! archive = STDIN; ! else ! archive = STDOUT; ! } else /* This can't happen if (ar_reading==2) archive = rmtopen(ar_files[0], O_RDWR|O_CREAT|O_BINARY, 0666); ! else */if(ar_reading) ! archive = rmtopen(ar_files[0], O_RDONLY|O_BINARY, 0666); ! else ! archive = rmtcreat(ar_files[0], 0666); ! ! if (archive < 0) { ! msg_perror("can't open archive %s",ar_files[0]); ! exit(EX_BADARCH); ! } ! ! if(ar_reading) { ! for(;;) { ! char *ptr; ! int max,count; ! ! r_error_count = 0; ! error_loop: ! err=rmtread(archive, ar_block->charptr,(int)(blocksize)); ! if(err<0) { ! readerror(); ! goto error_loop; ! } ! if(err==0) ! break; ! ptr = ar_block->charptr; ! max = err; ! while(max) { ! count = (maxcharptr; ! while(n) { ! err=read(STDIN,ptr,(ncharptr+blocksize-n,n); ! err=rmtwrite(archive,ar_block->charptr,blocksize); ! if(err!=(blocksize)) ! writeerror(err); ! if(f_compress<2) ! blocksize+=n; ! break; ! } ! if(n) { ! msg_perror("can't read from compress"); ! exit(EX_SYSTEM); ! } ! err=rmtwrite(archive, ar_block->charptr, (int)blocksize); ! if(err!=blocksize) ! writeerror(err); ! } } ! ! /* close_archive(); */ ! exit(0); } } ! /* So we should exec compress (-d) */ ! if(ar_reading) ! execlp("compress", "compress", "-d", (char *)0); ! else ! execlp("compress", "compress", (char *)0); ! msg_perror("can't exec compress"); ! _exit(EX_SYSTEM); } /* return non-zero if p is the name of a directory */ int ! isfile(p) ! char *p; { ! struct stat stbuf; ! if(stat(p,&stbuf)<0) ! return 1; ! if(S_ISREG(stbuf.st_mode)) ! return 1; ! return 0; } #endif --- 227,526 ---- * Equivalent to BSD "dup2" with error reporting. */ void ! dupto (from, to, msg) ! int from, to; ! char *msg; ! { ! int err; ! ! if (from != to) ! { ! err = close (to); ! if (err < 0 && errno != EBADF) ! { ! msg_perror ("Cannot close descriptor %d", to); ! exit (EX_SYSTEM); ! } ! err = dup (from); ! if (err != to) ! { ! msg_perror ("cannot dup %s", msg); ! exit (EX_SYSTEM); } + ck_close (from); + } } #ifdef __MSDOS__ void ! child_open () { ! fprintf (stderr, "MS-DOS %s can't use compressed or remote archives\n", tar); ! exit (EX_ARGSBAD); } + #else void ! child_open () { ! int pipe[2]; ! int err = 0; ! int kidpipe[2]; ! int kidchildpid; #define READ 0 #define WRITE 1 ! ck_pipe (pipe); ! childpid = fork (); ! if (childpid < 0) ! { ! msg_perror ("cannot fork"); ! exit (EX_SYSTEM); ! } ! if (childpid > 0) ! { ! /* We're the parent. Clean up and be happy */ ! /* This, at least, is easy */ ! if (ar_reading) ! { ! f_reblock++; ! archive = pipe[READ]; ! ck_close (pipe[WRITE]); } + else + { + archive = pipe[WRITE]; + ck_close (pipe[READ]); + } + return; + } + + /* We're the kid */ + if (ar_reading) + { + dupto (pipe[WRITE], STDOUT, "(child) pipe to stdout"); + ck_close (pipe[READ]); + } + else + { + dupto (pipe[READ], STDIN, "(child) pipe to stdin"); + ck_close (pipe[WRITE]); + } ! /* We need a child tar only if 1: we're reading/writing stdin/out (to force reblocking) 2: the file is to be accessed by rmt (compress doesn't know how) 3: the file is not a plain file */ #ifdef NO_REMOTE ! if (!(ar_files[0][0] == '-' && ar_files[0][1] == '\0') && isfile (ar_files[0])) #else ! if (!(ar_files[0][0] == '-' && ar_files[0][1] == '\0') && !_remdev (ar_files[0]) && isfile (ar_files[0])) #endif + { + /* We don't need a child tar. Open the archive */ + if (ar_reading) { ! archive = open (ar_files[0], O_RDONLY | O_BINARY, 0666); ! if (archive < 0) ! { ! msg_perror ("can't open archive %s", ar_files[0]); ! exit (EX_BADARCH); ! } ! dupto (archive, STDIN, "archive to stdin"); ! /* close(archive); */ ! } ! else ! { ! archive = creat (ar_files[0], 0666); ! if (archive < 0) ! { ! msg_perror ("can't open archive %s", ar_files[0]); ! exit (EX_BADARCH); ! } ! dupto (archive, STDOUT, "archive to stdout"); ! /* close(archive); */ ! } ! } ! else ! { ! /* We need a child tar */ ! ck_pipe (kidpipe); ! kidchildpid = fork (); ! if (kidchildpid < 0) ! { ! msg_perror ("child can't fork"); ! exit (EX_SYSTEM); ! } ! ! if (kidchildpid > 0) ! { ! /* About to exec compress: set up the files */ ! if (ar_reading) ! { ! dupto (kidpipe[READ], STDIN, "((child)) pipe to stdin"); ! ck_close (kidpipe[WRITE]); ! /* dup2(pipe[WRITE],STDOUT); */ ! } ! else ! { ! /* dup2(pipe[READ],STDIN); */ ! dupto (kidpipe[WRITE], STDOUT, "((child)) pipe to stdout"); ! ck_close (kidpipe[READ]); ! } ! /* ck_close(pipe[READ]); */ ! /* ck_close(pipe[WRITE]); */ ! /* ck_close(kidpipe[READ]); ck_close(kidpipe[WRITE]); */ ! } ! else ! { ! /* Grandchild. Do the right thing, namely sit here and read/write the archive, and feed stuff back to compress */ ! tar = "tar (child)"; ! if (ar_reading) ! { ! dupto (kidpipe[WRITE], STDOUT, "[child] pipe to stdout"); ! ck_close (kidpipe[READ]); ! } ! else ! { ! dupto (kidpipe[READ], STDIN, "[child] pipe to stdin"); ! ck_close (kidpipe[WRITE]); ! } ! ! if (ar_files[0][0] == '-' && ar_files[0][1] == '\0') ! { ! if (ar_reading) ! archive = STDIN; ! else ! archive = STDOUT; ! } ! else /* This can't happen if (ar_reading==2) archive = rmtopen(ar_files[0], O_RDWR|O_CREAT|O_BINARY, 0666); ! else */ if (ar_reading) ! archive = rmtopen (ar_files[0], O_RDONLY | O_BINARY, 0666); ! else ! archive = rmtcreat (ar_files[0], 0666); ! ! if (archive < 0) ! { ! msg_perror ("can't open archive %s", ar_files[0]); ! exit (EX_BADARCH); ! } ! ! if (ar_reading) ! { ! for (;;) ! { ! char *ptr; ! int max, count; ! ! r_error_count = 0; ! error_loop: ! err = rmtread (archive, ar_block->charptr, (int) (blocksize)); ! if (err < 0) ! { ! readerror (); ! goto error_loop; ! } ! if (err == 0) ! break; ! ptr = ar_block->charptr; ! max = err; ! while (max) ! { ! count = (max < RECORDSIZE) ? max : RECORDSIZE; ! err = write (STDOUT, ptr, count); ! if (err != count) ! { ! if (err < 0) ! { ! msg_perror ("can't write to compression program"); ! exit (EX_SYSTEM); ! } ! else ! msg ("write to compression program short %d bytes", ! count - err); ! count = (err < 0) ? 0 : err; } ! ptr += count; ! max -= count; ! } ! } ! } ! else ! { ! for (;;) ! { ! int n; ! char *ptr; ! ! n = blocksize; ! ptr = ar_block->charptr; ! while (n) ! { ! err = read (STDIN, ptr, (n < RECORDSIZE) ? n : RECORDSIZE); ! if (err <= 0) ! break; ! n -= err; ! ptr += err; ! } ! /* EOF */ ! if (err == 0) ! { ! if (!f_compress_block) ! blocksize -= n; ! else ! bzero (ar_block->charptr + blocksize - n, n); ! err = rmtwrite (archive, ar_block->charptr, blocksize); ! if (err != (blocksize)) ! writeerror (err); ! if (!f_compress_block) ! blocksize += n; ! break; ! } ! if (n) ! { ! msg_perror ("can't read from compression program"); ! exit (EX_SYSTEM); ! } ! err = rmtwrite (archive, ar_block->charptr, (int) blocksize); ! if (err != blocksize) ! writeerror (err); } + } + + /* close_archive(); */ + exit (0); } ! } ! /* So we should exec compress (-d) */ ! if (ar_reading) ! execlp (f_compressprog, f_compressprog, "-d", (char *) 0); ! else ! execlp (f_compressprog, f_compressprog, (char *) 0); ! msg_perror ("can't exec %s", f_compressprog); ! _exit (EX_SYSTEM); } /* return non-zero if p is the name of a directory */ int ! isfile (p) ! char *p; { ! struct stat stbuf; ! if (stat (p, &stbuf) < 0) ! return 1; ! if (S_ISREG (stbuf.st_mode)) ! return 1; ! return 0; } #endif *************** *** 483,628 **** */ /* JF if the arg is 2, open for reading and writing. */ void ! open_archive(reading) ! int reading; { ! msg_file = f_exstdout ? stderr : stdout; ! if (blocksize == 0) { ! msg("invalid value for blocksize"); ! exit(EX_ARGSBAD); ! } ! if(n_ar_files==0) { ! msg("No archive name given, what should I do?"); ! exit(EX_BADARCH); ! } ! /*NOSTRICT*/ ! if(f_multivol) { ! ar_block = (union record *) valloc((unsigned)(blocksize+(2*RECORDSIZE))); ! if(ar_block) ! ar_block += 2; ! } else ! ar_block = (union record *) valloc((unsigned)blocksize); ! if (!ar_block) { ! msg("could not allocate memory for blocking factor %d", ! blocking); ! exit(EX_ARGSBAD); ! } ! ar_record = ar_block; ! ar_last = ar_block + blocking; ! ar_reading = reading; ! if (f_multivol && f_verify) ! { ! msg ("cannot verify multi-volume archives"); ! exit (EX_ARGSBAD); ! } ! ! if (f_compress) { ! if(reading==2 || f_verify) { ! msg("cannot update or verify compressed archives"); ! exit(EX_ARGSBAD); ! } ! if (f_multivol) { ! msg ("cannot use multi-volume compressed archives"); ! exit (EX_ARGSBAD); ! } ! child_open(); ! if(!reading && ar_files[0][0]=='-' && ar_files[0][1]=='\0') ! msg_file = stderr; ! /* child_open(rem_host, rem_file); */ ! } else if (ar_files[0][0] == '-' && ar_files[0][1] == '\0') { ! f_reblock++; /* Could be a pipe, be safe */ ! if(f_verify) { ! msg("can't verify stdin/stdout archive"); ! exit(EX_ARGSBAD); ! } ! if(reading==2) { ! archive=STDIN; ! msg_file=stderr; ! write_archive_to_stdout++; ! } else if (reading) ! archive = STDIN; ! else { ! archive = STDOUT; ! msg_file = stderr; ! } ! } else if (reading==2 || f_verify) { ! archive = rmtopen(ar_files[0], O_RDWR|O_CREAT|O_BINARY, 0666); ! } else if(reading) { ! archive = rmtopen(ar_files[0], O_RDONLY|O_BINARY, 0666); ! } else { ! archive = rmtcreat(ar_files[0], 0666); ! } ! if (archive < 0) { ! msg_perror("can't open %s",ar_files[0]); ! exit(EX_BADARCH); } #ifndef __MSDOS__ ! if(!_isrmt(archive)) { ! struct stat tmp_stat; ! fstat(archive,&tmp_stat); ! if(S_ISREG(tmp_stat.st_mode)) { ! ar_dev=tmp_stat.st_dev; ! ar_ino=tmp_stat.st_ino; ! } } #endif #ifdef __MSDOS__ ! setmode(archive, O_BINARY); #endif ! if (reading) { ! ar_last = ar_block; /* Set up for 1st block = # 0 */ ! (void) findrec(); /* Read it in, check for EOF */ ! if(f_volhdr) { ! union record *head; #if 0 ! char *ptr; ! if(f_multivol) { ! ptr=malloc(strlen(f_volhdr)+20); ! sprintf(ptr,"%s Volume %d",f_volhdr,1); ! } else ! ptr=f_volhdr; ! #endif ! head=findrec(); ! if(!head) { ! msg("Archive not labelled to match %s",f_volhdr); ! exit(EX_BADVOL); ! } ! if (re_match (label_pattern, head->header.arch_name, ! strlen (head->header.arch_name), 0, 0) < 0) { ! msg ("Volume mismatch! %s!=%s", f_volhdr, ! head->header.arch_name); ! exit (EX_BADVOL); ! } ! #if 0 ! if(strcmp(ptr,head->header.name)) { ! msg("Volume mismatch! %s!=%s",ptr,head->header.name); ! exit(EX_BADVOL); ! } ! if(ptr!=f_volhdr) ! free(ptr); #endif - } - } else if(f_volhdr) { - bzero((void *)ar_block,RECORDSIZE); - if(f_multivol) - sprintf(ar_block->header.arch_name,"%s Volume 1",f_volhdr); - else - strcpy(ar_block->header.arch_name,f_volhdr); - ar_block->header.linkflag = LF_VOLHDR; - to_oct(time(0), 1+12, ar_block->header.mtime); - finish_header(ar_block); - /* ar_record++; */ } } --- 531,709 ---- */ /* JF if the arg is 2, open for reading and writing. */ void ! open_archive (reading) ! int reading; { ! msg_file = f_exstdout ? stderr : stdout; ! if (blocksize == 0) ! { ! msg ("invalid value for blocksize"); ! exit (EX_ARGSBAD); ! } ! if (n_ar_files == 0) ! { ! msg ("No archive name given, what should I do?"); ! exit (EX_BADARCH); ! } ! /*NOSTRICT*/ ! if (f_multivol) ! { ! ar_block = (union record *) valloc ((unsigned) (blocksize + (2 * RECORDSIZE))); ! if (ar_block) ! ar_block += 2; ! } ! else ! ar_block = (union record *) valloc ((unsigned) blocksize); ! if (!ar_block) ! { ! msg ("could not allocate memory for blocking factor %d", ! blocking); ! exit (EX_ARGSBAD); ! } ! ar_record = ar_block; ! ar_last = ar_block + blocking; ! ar_reading = reading; ! if (f_multivol && f_verify) ! { ! msg ("cannot verify multi-volume archives"); ! exit (EX_ARGSBAD); ! } ! ! if (f_compressprog) ! { ! if (reading == 2 || f_verify) ! { ! msg ("cannot update or verify compressed archives"); ! exit (EX_ARGSBAD); ! } ! if (f_multivol) ! { ! msg ("cannot use multi-volume compressed archives"); ! exit (EX_ARGSBAD); ! } ! child_open (); ! if (!reading && ar_files[0][0] == '-' && ar_files[0][1] == '\0') ! msg_file = stderr; ! /* child_open(rem_host, rem_file); */ ! } ! else if (ar_files[0][0] == '-' && ar_files[0][1] == '\0') ! { ! f_reblock++; /* Could be a pipe, be safe */ ! if (f_verify) ! { ! msg ("can't verify stdin/stdout archive"); ! exit (EX_ARGSBAD); ! } ! if (reading == 2) ! { ! archive = STDIN; ! msg_file = stderr; ! write_archive_to_stdout++; ! } ! else if (reading) ! archive = STDIN; ! else ! { ! archive = STDOUT; ! msg_file = stderr; } + } + else if (reading == 2 || f_verify) + { + archive = rmtopen (ar_files[0], O_RDWR | O_CREAT | O_BINARY, 0666); + } + else if (reading) + { + archive = rmtopen (ar_files[0], O_RDONLY | O_BINARY, 0666); + } + else + { + archive = rmtcreat (ar_files[0], 0666); + } + if (archive < 0) + { + msg_perror ("can't open %s", ar_files[0]); + exit (EX_BADARCH); + } #ifndef __MSDOS__ ! if (!_isrmt (archive)) ! { ! struct stat tmp_stat; ! fstat (archive, &tmp_stat); ! if (S_ISREG (tmp_stat.st_mode)) ! { ! ar_dev = tmp_stat.st_dev; ! ar_ino = tmp_stat.st_ino; } + } #endif #ifdef __MSDOS__ ! setmode (archive, O_BINARY); #endif ! if (reading) ! { ! ar_last = ar_block; /* Set up for 1st block = # 0 */ ! (void) findrec (); /* Read it in, check for EOF */ ! if (f_volhdr) ! { ! union record *head; #if 0 ! char *ptr; ! if (f_multivol) ! { ! ptr = malloc (strlen (f_volhdr) + 20); ! sprintf (ptr, "%s Volume %d", f_volhdr, 1); ! } ! else ! ptr = f_volhdr; ! #endif ! head = findrec (); ! if (!head) ! { ! msg ("Archive not labelled to match %s", f_volhdr); ! exit (EX_BADVOL); ! } ! if (re_match (label_pattern, head->header.arch_name, ! strlen (head->header.arch_name), 0, 0) < 0) ! { ! msg ("Volume mismatch! %s!=%s", f_volhdr, ! head->header.arch_name); ! exit (EX_BADVOL); ! } ! #if 0 ! if (strcmp (ptr, head->header.name)) ! { ! msg ("Volume mismatch! %s!=%s", ptr, head->header.name); ! exit (EX_BADVOL); ! } ! if (ptr != f_volhdr) ! free (ptr); #endif } + } + else if (f_volhdr) + { + bzero ((void *) ar_block, RECORDSIZE); + if (f_multivol) + sprintf (ar_block->header.arch_name, "%s Volume 1", f_volhdr); + else + strcpy (ar_block->header.arch_name, f_volhdr); + current_file_name = ar_block->header.arch_name; + ar_block->header.linkflag = LF_VOLHDR; + to_oct (time (0), 1 + 12, ar_block->header.mtime); + finish_header (ar_block); + /* ar_record++; */ + } } *************** *** 637,650 **** * subtracting ar_block from that, shifting it back, losing the top 9 bits. */ void ! saverec(pointer) ! union record **pointer; { ! long offset; ! save_rec = pointer; ! offset = ar_record - ar_block; ! saved_recno = baserec + offset; } /* --- 718,731 ---- * subtracting ar_block from that, shifting it back, losing the top 9 bits. */ void ! saverec (pointer) ! union record **pointer; { ! long offset; ! save_rec = pointer; ! offset = ar_record - ar_block; ! saved_recno = baserec + offset; } /* *************** *** 659,784 **** */ void ! fl_write() { ! int err; ! int copy_back; ! static long bytes_written = 0; ! ! if (f_checkpoint && ! (++checkpoint % 10)) ! msg ("Write checkpoint %d\n", checkpoint); ! if(tape_length && bytes_written >= tape_length * 1024) { ! errno = ENOSPC; ! err = 0; ! } else ! err = rmtwrite(archive, ar_block->charptr,(int) blocksize); ! if(err!=blocksize && !f_multivol) ! writeerror(err); ! else if (f_totals) ! tot_written += blocksize; ! ! if(err>0) ! bytes_written+=err; ! if (err == blocksize) { ! if(f_multivol) { ! if(!save_name) { ! real_s_name[0]='\0'; ! real_s_totsize=0; ! real_s_sizeleft = 0; ! return; ! } #ifdef __MSDOS__ ! if(save_name[1]==':') ! save_name+=2; #endif ! while(*save_name=='/') ! save_name++; ! strcpy(real_s_name,save_name); ! real_s_totsize = save_totsize; ! real_s_sizeleft = save_sizeleft; ! } ! return; } ! /* We're multivol Panic if we didn't get the right kind of response */ ! /* ENXIO is for the UNIX PC */ ! if(err<0 && errno!=ENOSPC && errno!=EIO && errno!=ENXIO) ! writeerror(err); ! ! /* If error indicates a short write, we just move to the next tape. */ ! ! if(new_volume(0)<0) ! return; ! bytes_written=0; ! if(f_volhdr && real_s_name[0]) { ! copy_back=2; ! ar_block-=2; ! } else if(f_volhdr || real_s_name[0]) { ! copy_back = 1; ! ar_block--; ! } else ! copy_back = 0; ! if(f_volhdr) { ! bzero((void *)ar_block,RECORDSIZE); ! sprintf(ar_block->header.arch_name,"%s Volume %d",f_volhdr,volno); ! to_oct(time(0), 1+12, ar_block->header.mtime); ! ar_block->header.linkflag = LF_VOLHDR; ! finish_header(ar_block); ! } ! if(real_s_name[0]) { ! int tmp; ! ! if(f_volhdr) ! ar_block++; ! bzero((void *)ar_block,RECORDSIZE); ! strcpy(ar_block->header.arch_name,real_s_name); ! ar_block->header.linkflag = LF_MULTIVOL; ! to_oct((long)real_s_sizeleft,1+12, ! ar_block->header.size); ! to_oct((long)real_s_totsize-real_s_sizeleft, ! 1+12,ar_block->header.offset); ! tmp=f_verbose; ! f_verbose=0; ! finish_header(ar_block); ! f_verbose=tmp; ! if(f_volhdr) ! ar_block--; ! } ! ! err = rmtwrite(archive, ar_block->charptr,(int) blocksize); ! if(err!=blocksize) ! writeerror(err); ! else if (f_totals) ! tot_written += blocksize; ! ! ! bytes_written = blocksize; ! if(copy_back) { ! ar_block+=copy_back; ! bcopy((void *)(ar_block+blocking-copy_back), ! (void *)ar_record, ! copy_back*RECORDSIZE); ! ar_record+=copy_back; ! ! if(real_s_sizeleft>=copy_back*RECORDSIZE) ! real_s_sizeleft-=copy_back*RECORDSIZE; ! else if((real_s_sizeleft+RECORDSIZE-1)/RECORDSIZE<=copy_back) ! real_s_name[0] = '\0'; ! else { #ifdef __MSDOS__ ! if(save_name[1]==':') ! save_name+=2; #endif ! while(*save_name=='/') ! save_name++; ! strcpy(real_s_name,save_name); ! real_s_sizeleft = save_sizeleft; ! real_s_totsize=save_totsize; ! } ! copy_back = 0; } } /* Handle write errors on the archive. Write errors are always fatal */ --- 740,878 ---- */ void ! fl_write () { ! int err; ! int copy_back; ! static long bytes_written = 0; ! ! if (f_checkpoint && !(++checkpoint % 10)) ! msg ("Write checkpoint %d\n", checkpoint); ! if (tape_length && bytes_written >= tape_length * 1024) ! { ! errno = ENOSPC; ! err = 0; ! } ! else ! err = rmtwrite (archive, ar_block->charptr, (int) blocksize); ! if (err != blocksize && !f_multivol) ! writeerror (err); ! else if (f_totals) ! tot_written += blocksize; ! ! if (err > 0) ! bytes_written += err; ! if (err == blocksize) ! { ! if (f_multivol) ! { ! if (!save_name) ! { ! real_s_name[0] = '\0'; ! real_s_totsize = 0; ! real_s_sizeleft = 0; ! return; ! } #ifdef __MSDOS__ ! if (save_name[1] == ':') ! save_name += 2; #endif ! while (*save_name == '/') ! save_name++; ! strcpy (real_s_name, save_name); ! real_s_totsize = save_totsize; ! real_s_sizeleft = save_sizeleft; } + return; + } + + /* We're multivol Panic if we didn't get the right kind of response */ + /* ENXIO is for the UNIX PC */ + if (err < 0 && errno != ENOSPC && errno != EIO && errno != ENXIO) + writeerror (err); + + /* If error indicates a short write, we just move to the next tape. */ + + if (new_volume (0) < 0) + return; + bytes_written = 0; + if (f_volhdr && real_s_name[0]) + { + copy_back = 2; + ar_block -= 2; + } + else if (f_volhdr || real_s_name[0]) + { + copy_back = 1; + ar_block--; + } + else + copy_back = 0; + if (f_volhdr) + { + bzero ((void *) ar_block, RECORDSIZE); + sprintf (ar_block->header.arch_name, "%s Volume %d", f_volhdr, volno); + to_oct (time (0), 1 + 12, ar_block->header.mtime); + ar_block->header.linkflag = LF_VOLHDR; + finish_header (ar_block); + } + if (real_s_name[0]) + { + int tmp; + + if (f_volhdr) + ar_block++; + bzero ((void *) ar_block, RECORDSIZE); + strcpy (ar_block->header.arch_name, real_s_name); + ar_block->header.linkflag = LF_MULTIVOL; + to_oct ((long) real_s_sizeleft, 1 + 12, + ar_block->header.size); + to_oct ((long) real_s_totsize - real_s_sizeleft, + 1 + 12, ar_block->header.offset); + tmp = f_verbose; + f_verbose = 0; + finish_header (ar_block); + f_verbose = tmp; + if (f_volhdr) + ar_block--; + } + + err = rmtwrite (archive, ar_block->charptr, (int) blocksize); + if (err != blocksize) + writeerror (err); + else if (f_totals) + tot_written += blocksize; + ! bytes_written = blocksize; ! if (copy_back) ! { ! ar_block += copy_back; ! bcopy ((void *) (ar_block + blocking - copy_back), ! (void *) ar_record, ! copy_back * RECORDSIZE); ! ar_record += copy_back; ! ! if (real_s_sizeleft >= copy_back * RECORDSIZE) ! real_s_sizeleft -= copy_back * RECORDSIZE; ! else if ((real_s_sizeleft + RECORDSIZE - 1) / RECORDSIZE <= copy_back) ! real_s_name[0] = '\0'; ! else ! { #ifdef __MSDOS__ ! if (save_name[1] == ':') ! save_name += 2; #endif ! while (*save_name == '/') ! save_name++; ! strcpy (real_s_name, save_name); ! real_s_sizeleft = save_sizeleft; ! real_s_totsize = save_totsize; } + copy_back = 0; + } } /* Handle write errors on the archive. Write errors are always fatal */ *************** *** 786,801 **** * was the first block of the volume */ void ! writeerror(err) ! int err; { ! if (err < 0) { ! msg_perror("can't write to %s",ar_files[cur_ar_file]); ! exit(EX_BADARCH); ! } else { ! msg("only wrote %u of %u bytes to %s",err,blocksize,ar_files[cur_ar_file]); ! exit(EX_BADARCH); ! } } /* --- 880,898 ---- * was the first block of the volume */ void ! writeerror (err) ! int err; { ! if (err < 0) ! { ! msg_perror ("can't write to %s", ar_files[cur_ar_file]); ! exit (EX_BADARCH); ! } ! else ! { ! msg ("only wrote %u of %u bytes to %s", err, blocksize, ar_files[cur_ar_file]); ! exit (EX_BADARCH); ! } } /* *************** *** 804,832 **** * If the read should be retried, readerror() returns to the caller. */ void ! readerror() { # define READ_ERROR_MAX 10 ! read_error_flag++; /* Tell callers */ ! msg_perror("read error on %s",ar_files[cur_ar_file]); ! if (baserec == 0) { ! /* First block of tape. Probably stupidity error */ ! exit(EX_BADARCH); ! } ! /* * Read error in mid archive. We retry up to READ_ERROR_MAX times * and then give up on reading the archive. We set read_error_flag * for our callers, so they can cope if they want. */ ! if (r_error_count++ > READ_ERROR_MAX) { ! msg("Too many errors, quitting."); ! exit(EX_BADARCH); ! } ! return; } --- 901,931 ---- * If the read should be retried, readerror() returns to the caller. */ void ! readerror () { # define READ_ERROR_MAX 10 ! read_error_flag++; /* Tell callers */ ! msg_perror ("read error on %s", ar_files[cur_ar_file]); ! if (baserec == 0) ! { ! /* First block of tape. Probably stupidity error */ ! exit (EX_BADARCH); ! } ! /* * Read error in mid archive. We retry up to READ_ERROR_MAX times * and then give up on reading the archive. We set read_error_flag * for our callers, so they can cope if they want. */ ! if (r_error_count++ > READ_ERROR_MAX) ! { ! msg ("Too many errors, quitting."); ! exit (EX_BADARCH); ! } ! return; } *************** *** 834,1024 **** * Perform a read to flush the buffer. */ void ! fl_read() { ! int err; /* Result from system call */ ! int left; /* Bytes left */ ! char *more; /* Pointer to next byte to read */ ! if (f_checkpoint && ! (++checkpoint % 10)) ! msg ("Read checkpoint %d\n", checkpoint); ! /* * Clear the count of errors. This only applies to a single * call to fl_read. We leave read_error_flag alone; it is * only turned off by higher level software. */ ! r_error_count = 0; /* Clear error count */ ! /* * If we are about to wipe out a record that * somebody needs to keep, copy it out to a holding * area and adjust somebody's pointer to it. */ ! if (save_rec && ! *save_rec >= ar_record && ! *save_rec < ar_last) { ! record_save_area = **save_rec; ! *save_rec = &record_save_area; ! } ! if(write_archive_to_stdout && baserec!=0) { ! err=rmtwrite(1, ar_block->charptr, blocksize); ! if(err!=blocksize) ! writeerror(err); ! } ! if(f_multivol) { ! if(save_name) { ! if(save_name!=real_s_name) { #ifdef __MSDOS__ ! if(save_name[1]==':') ! save_name+=2; #endif ! while(*save_name=='/') ! save_name++; ! strcpy(real_s_name,save_name); ! save_name=real_s_name; ! } ! real_s_totsize = save_totsize; ! real_s_sizeleft = save_sizeleft; ! ! } else { ! real_s_name[0]='\0'; ! real_s_totsize=0; ! real_s_sizeleft = 0; ! } } error_loop: ! err = rmtread(archive, ar_block->charptr, (int)blocksize); ! if (err == blocksize) ! return; ! ! if((err == 0 || (err<0 && errno==ENOSPC) || (err > 0 && !f_reblock)) && f_multivol) { ! union record *head; ! ! try_volume: ! if(new_volume((cmd_mode==CMD_APPEND || cmd_mode==CMD_CAT || cmd_mode==CMD_UPDATE) ? 2 : 1)<0) ! return; ! vol_error: ! err = rmtread(archive, ar_block->charptr,(int) blocksize); ! if(err < 0) { ! readerror(); ! goto vol_error; ! } ! if(err!=blocksize) ! goto short_read; ! head=ar_block; ! if(head->header.linkflag==LF_VOLHDR) { ! if(f_volhdr) { ! #if 0 ! char *ptr; ! ptr=(char *)malloc(strlen(f_volhdr)+20); ! sprintf(ptr,"%s Volume %d",f_volhdr,volno); ! #endif ! if (re_match (label_pattern, head->header.arch_name, ! strlen (head->header.arch_name), ! 0, 0) < 0) { ! msg("Volume mismatch! %s!=%s",f_volhdr, ! head->header.arch_name); ! --volno; ! --global_volno; ! goto try_volume; ! } ! #if 0 ! if(strcmp(ptr,head->header.name)) { ! msg("Volume mismatch! %s!=%s",ptr,head->header.name); ! --volno; ! --global_volno; ! free(ptr); ! goto try_volume; ! } ! free(ptr); #endif ! } ! if(f_verbose) ! fprintf(msg_file,"Reading %s\n",head->header.arch_name); ! head++; ! } else if(f_volhdr) { ! msg("Warning: No volume header!"); } ! if(real_s_name[0]) { ! long from_oct(); ! if(head->header.linkflag!=LF_MULTIVOL || strcmp(head->header.arch_name,real_s_name)) { ! msg("%s is not continued on this volume!",real_s_name); ! --volno; ! --global_volno; ! goto try_volume; ! } ! if(real_s_totsize!=from_oct(1+12,head->header.size)+from_oct(1+12,head->header.offset)) { ! msg("%s is the wrong size (%ld!=%ld+%ld)", ! head->header.arch_name,save_totsize, ! from_oct(1+12,head->header.size), ! from_oct(1+12,head->header.offset)); ! --volno; ! --global_volno; ! goto try_volume; ! } ! if(real_s_totsize-real_s_sizeleft!=from_oct(1+12,head->header.offset)) { ! msg("This volume is out of sequence"); ! --volno; ! --global_volno; ! goto try_volume; ! } ! head++; ! } ! ar_record=head; ! return; ! } else if (err < 0) { ! readerror(); ! goto error_loop; /* Try again */ } ! short_read: ! more = ar_block->charptr + err; ! left = blocksize - err; again: ! if (0 == (((unsigned)left) % RECORDSIZE)) { ! /* FIXME, for size=0, multi vol support */ ! /* On the first block, warn about the problem */ ! if (!f_reblock && baserec == 0 && f_verbose && err > 0) { ! /* msg("Blocksize = %d record%s", err / RECORDSIZE, (err > RECORDSIZE)? "s": "");*/ ! msg("Blocksize = %d records", err / RECORDSIZE); ! } ! ar_last = ar_block + ((unsigned)(blocksize - left))/RECORDSIZE; ! return; } ! if (f_reblock) { ! /* * User warned us about this. Fix up. */ ! if (left > 0) { ! error2loop: ! err = rmtread(archive, more, (int)left); ! if (err < 0) { ! readerror(); ! goto error2loop; /* Try again */ ! } ! if (err == 0) { ! msg("archive %s EOF not on block boundary",ar_files[cur_ar_file]); ! exit(EX_BADARCH); ! } ! left -= err; ! more += err; ! goto again; ! } ! } else { ! msg("only read %d bytes from archive %s",err,ar_files[cur_ar_file]); ! exit(EX_BADARCH); } } --- 933,1152 ---- * Perform a read to flush the buffer. */ void ! fl_read () { ! int err; /* Result from system call */ ! int left; /* Bytes left */ ! char *more; /* Pointer to next byte to read */ ! if (f_checkpoint && !(++checkpoint % 10)) ! msg ("Read checkpoint %d\n", checkpoint); ! /* * Clear the count of errors. This only applies to a single * call to fl_read. We leave read_error_flag alone; it is * only turned off by higher level software. */ ! r_error_count = 0; /* Clear error count */ ! /* * If we are about to wipe out a record that * somebody needs to keep, copy it out to a holding * area and adjust somebody's pointer to it. */ ! if (save_rec && ! *save_rec >= ar_record && ! *save_rec < ar_last) ! { ! record_save_area = **save_rec; ! *save_rec = &record_save_area; ! } ! if (write_archive_to_stdout && baserec != 0) ! { ! err = rmtwrite (1, ar_block->charptr, blocksize); ! if (err != blocksize) ! writeerror (err); ! } ! if (f_multivol) ! { ! if (save_name) ! { ! if (save_name != real_s_name) ! { #ifdef __MSDOS__ ! if (save_name[1] == ':') ! save_name += 2; #endif ! while (*save_name == '/') ! save_name++; ! strcpy (real_s_name, save_name); ! save_name = real_s_name; ! } ! real_s_totsize = save_totsize; ! real_s_sizeleft = save_sizeleft; ! ! } ! else ! { ! real_s_name[0] = '\0'; ! real_s_totsize = 0; ! real_s_sizeleft = 0; } + } error_loop: ! err = rmtread (archive, ar_block->charptr, (int) blocksize); ! if (err == blocksize) ! return; ! if ((err == 0 || (err < 0 && errno == ENOSPC) || (err > 0 && !f_reblock)) && f_multivol) ! { ! union record *head; ! try_volume: ! if (new_volume ((cmd_mode == CMD_APPEND || cmd_mode == CMD_CAT || cmd_mode == CMD_UPDATE) ? 2 : 1) < 0) ! return; ! vol_error: ! err = rmtread (archive, ar_block->charptr, (int) blocksize); ! if (err < 0) ! { ! readerror (); ! goto vol_error; ! } ! if (err != blocksize) ! goto short_read; ! head = ar_block; ! ! if (head->header.linkflag == LF_VOLHDR) ! { ! if (f_volhdr) ! { #if 0 ! char *ptr; ! ! ptr = (char *) malloc (strlen (f_volhdr) + 20); ! sprintf (ptr, "%s Volume %d", f_volhdr, volno); #endif ! if (re_match (label_pattern, head->header.arch_name, ! strlen (head->header.arch_name), ! 0, 0) < 0) ! { ! msg ("Volume mismatch! %s!=%s", f_volhdr, ! head->header.arch_name); ! --volno; ! --global_volno; ! goto try_volume; } ! #if 0 ! if (strcmp (ptr, head->header.name)) ! { ! msg ("Volume mismatch! %s!=%s", ptr, head->header.name); ! --volno; ! --global_volno; ! free (ptr); ! goto try_volume; ! } ! free (ptr); ! #endif ! } ! if (f_verbose) ! fprintf (msg_file, "Reading %s\n", head->header.arch_name); ! head++; ! } ! else if (f_volhdr) ! { ! msg ("Warning: No volume header!"); ! } ! ! if (real_s_name[0]) ! { ! long from_oct (); ! if (head->header.linkflag != LF_MULTIVOL || strcmp (head->header.arch_name, real_s_name)) ! { ! msg ("%s is not continued on this volume!", real_s_name); ! --volno; ! --global_volno; ! goto try_volume; ! } ! if (real_s_totsize != from_oct (1 + 12, head->header.size) + from_oct (1 + 12, head->header.offset)) ! { ! msg ("%s is the wrong size (%ld!=%ld+%ld)", ! head->header.arch_name, save_totsize, ! from_oct (1 + 12, head->header.size), ! from_oct (1 + 12, head->header.offset)); ! --volno; ! --global_volno; ! goto try_volume; ! } ! if (real_s_totsize - real_s_sizeleft != from_oct (1 + 12, head->header.offset)) ! { ! msg ("This volume is out of sequence"); ! --volno; ! --global_volno; ! goto try_volume; ! } ! head++; } + ar_record = head; + return; + } + else if (err < 0) + { + readerror (); + goto error_loop; /* Try again */ + } ! short_read: ! more = ar_block->charptr + err; ! left = blocksize - err; again: ! if (0 == (((unsigned) left) % RECORDSIZE)) ! { ! /* FIXME, for size=0, multi vol support */ ! /* On the first block, warn about the problem */ ! if (!f_reblock && baserec == 0 && f_verbose && err > 0) ! { ! /* msg("Blocksize = %d record%s", err / RECORDSIZE, (err > RECORDSIZE)? "s": "");*/ ! msg ("Blocksize = %d records", err / RECORDSIZE); } ! ar_last = ar_block + ((unsigned) (blocksize - left)) / RECORDSIZE; ! return; ! } ! if (f_reblock) ! { ! /* * User warned us about this. Fix up. */ ! if (left > 0) ! { ! error2loop: ! err = rmtread (archive, more, (int) left); ! if (err < 0) ! { ! readerror (); ! goto error2loop; /* Try again */ ! } ! if (err == 0) ! { ! msg ("archive %s EOF not on block boundary", ar_files[cur_ar_file]); ! exit (EX_BADARCH); ! } ! left -= err; ! more += err; ! goto again; } + } + else + { + msg ("only read %d bytes from archive %s", err, ar_files[cur_ar_file]); + exit (EX_BADARCH); + } } *************** *** 1026,1057 **** * Flush the current buffer to/from the archive. */ void ! flush_archive() { ! int c; ! baserec += ar_last - ar_block; /* Keep track of block #s */ ! ar_record = ar_block; /* Restore pointer to start */ ! ar_last = ar_block + blocking; /* Restore pointer to end */ ! ! if (ar_reading) { ! if(time_to_start_writing) { ! time_to_start_writing=0; ! ar_reading=0; ! ! if(file_to_switch_to>=0) { ! if((c=rmtclose(archive))<0) ! msg_perror("Warning: can't close %s(%d,%d)",ar_files[cur_ar_file],archive,c); ! ! archive=file_to_switch_to; ! } else ! (void)backspace_output(); ! fl_write(); ! } else ! fl_read(); ! } else { ! fl_write(); } } /* Backspace the archive descriptor by one blocks worth. --- 1154,1192 ---- * Flush the current buffer to/from the archive. */ void ! flush_archive () { ! int c; ! ! baserec += ar_last - ar_block;/* Keep track of block #s */ ! ar_record = ar_block; /* Restore pointer to start */ ! ar_last = ar_block + blocking;/* Restore pointer to end */ ! ! if (ar_reading) ! { ! if (time_to_start_writing) ! { ! time_to_start_writing = 0; ! ar_reading = 0; ! if (file_to_switch_to >= 0) ! { ! if ((c = rmtclose (archive)) < 0) ! msg_perror ("Warning: can't close %s(%d,%d)", ar_files[cur_ar_file], archive, c); ! ! archive = file_to_switch_to; ! } ! else ! (void) backspace_output (); ! fl_write (); } + else + fl_read (); + } + else + { + fl_write (); + } } /* Backspace the archive descriptor by one blocks worth. *************** *** 1058,1094 **** If its a tape, MTIOCTOP will work. If its something else, we try to seek on it. If we can't seek, we lose! */ int ! backspace_output() { ! long cur; ! /* int er; */ ! extern char *output_start; #ifdef MTIOCTOP ! struct mtop t; ! t.mt_op = MTBSR; ! t.mt_count = 1; ! if((rmtioctl(archive,MTIOCTOP,&t))>=0) ! return 1; ! if(errno==EIO && (rmtioctl(archive,MTIOCTOP,&t))>=0) ! return 1; #endif ! cur=rmtlseek(archive,0L,1); ! cur-=blocksize; ! /* Seek back to the beginning of this block and start writing there. */ ! if(rmtlseek(archive,cur,0)!=cur) { ! /* Lseek failed. Try a different method */ ! msg("Couldn't backspace archive file. It may be unreadable without -i."); ! /* Replace the first part of the block with nulls */ ! if(ar_block->charptr!=output_start) ! bzero(ar_block->charptr,output_start-ar_block->charptr); ! return 2; ! } ! return 3; } --- 1193,1230 ---- If its a tape, MTIOCTOP will work. If its something else, we try to seek on it. If we can't seek, we lose! */ int ! backspace_output () { ! long cur; ! /* int er; */ ! extern char *output_start; #ifdef MTIOCTOP ! struct mtop t; ! t.mt_op = MTBSR; ! t.mt_count = 1; ! if ((rmtioctl (archive, MTIOCTOP, &t)) >= 0) ! return 1; ! if (errno == EIO && (rmtioctl (archive, MTIOCTOP, &t)) >= 0) ! return 1; #endif ! cur = rmtlseek (archive, 0L, 1); ! cur -= blocksize; ! /* Seek back to the beginning of this block and start writing there. */ ! if (rmtlseek (archive, cur, 0) != cur) ! { ! /* Lseek failed. Try a different method */ ! msg ("Couldn't backspace archive file. It may be unreadable without -i."); ! /* Replace the first part of the block with nulls */ ! if (ar_block->charptr != output_start) ! bzero (ar_block->charptr, output_start - ar_block->charptr); ! return 2; ! } ! return 3; } *************** *** 1096,1161 **** * Close the archive file. */ void ! close_archive() { ! int child; ! int status; ! int c; ! ! if (time_to_start_writing || !ar_reading) ! flush_archive(); ! if(cmd_mode==CMD_DELETE) { ! off_t pos; ! pos = rmtlseek(archive,0L,1); #ifndef __MSDOS__ ! (void) ftruncate(archive,pos); #else ! (void)rmtwrite(archive,"",0); #endif ! } ! if(f_verify) ! verify_volume(); ! if((c=rmtclose(archive))<0) ! msg_perror("Warning: can't close %s(%d,%d)",ar_files[cur_ar_file],archive,c); #ifndef __MSDOS__ ! if (childpid) { ! /* ! * Loop waiting for the right child to die, or for ! * no more kids. ! */ ! while (((child = wait(&status)) != childpid) && child != -1) ! ; ! if (child != -1) { ! switch (WTERMSIG(status)) { ! case 0: ! /* Child voluntarily terminated -- but why? */ ! if (WEXITSTATUS(status) == MAGIC_STAT) { ! exit(EX_SYSTEM);/* Child had trouble */ ! } ! if (WEXITSTATUS(status) == (SIGPIPE + 128)) { ! /* ! * /bin/sh returns this if its child ! * dies with SIGPIPE. 'Sok. ! */ ! break; ! } else if (WEXITSTATUS(status)) ! msg("child returned status %d", ! WEXITSTATUS(status)); ! case SIGPIPE: ! break; /* This is OK. */ ! ! default: ! msg("child died with signal %d%s", ! WTERMSIG(status), ! WIFCOREDUMPED(status)? " (core dumped)": ""); ! } ! } } ! #endif /* __MSDOS__ */ } --- 1232,1303 ---- * Close the archive file. */ void ! close_archive () { ! int child; ! int status; ! int c; ! ! if (time_to_start_writing || !ar_reading) ! flush_archive (); ! if (cmd_mode == CMD_DELETE) ! { ! off_t pos; ! pos = rmtlseek (archive, 0L, 1); #ifndef __MSDOS__ ! (void) ftruncate (archive, pos); #else ! (void) rmtwrite (archive, "", 0); #endif ! } ! if (f_verify) ! verify_volume (); ! if ((c = rmtclose (archive)) < 0) ! msg_perror ("Warning: can't close %s(%d,%d)", ar_files[cur_ar_file], archive, c); #ifndef __MSDOS__ ! if (childpid) ! { ! /* ! * Loop waiting for the right child to die, or for ! * no more kids. ! */ ! while (((child = wait (&status)) != childpid) && child != -1) ! ; ! if (child != -1) ! { ! if (WIFSIGNALED (status)) ! { ! /* SIGPIPE is OK, everything else is a problem. */ ! if (WTERMSIG (status) != SIGPIPE) ! msg ("child died with signal %d%s", WTERMSIG (status), ! WIFCOREDUMPED (status) ? " (core dumped)" : ""); ! } ! else ! { ! /* Child voluntarily terminated -- but why? */ ! if (WEXITSTATUS (status) == MAGIC_STAT) ! { ! exit (EX_SYSTEM); /* Child had trouble */ ! } ! if (WEXITSTATUS (status) == (SIGPIPE + 128)) ! { ! /* ! * /bin/sh returns this if its child ! * dies with SIGPIPE. 'Sok. ! */ ! /* Do nothing. */ ! } ! else if (WEXITSTATUS (status)) ! msg ("child returned status %d", ! WEXITSTATUS (status)); ! } } ! } ! #endif /* __MSDOS__ */ } *************** *** 1176,1229 **** * "current" record # is used. */ void ! anno(stream, prefix, savedp) ! FILE *stream; ! char *prefix; ! int savedp; { # define MAXANNO 50 ! char buffer[MAXANNO]; /* Holds annorecment */ # define ANNOWIDTH 13 ! int space; ! long offset; ! int save_e; ! ! save_e=errno; ! /* Make sure previous output gets out in sequence */ ! if (stream == stderr) ! fflush(stdout); ! if (f_sayblock) { ! if (prefix) { ! fputs(prefix, stream); ! putc(' ', stream); ! } ! offset = ar_record - ar_block; ! (void) sprintf(buffer, "rec %d: ", ! savedp? saved_recno: ! baserec + offset); ! fputs(buffer, stream); ! space = ANNOWIDTH - strlen(buffer); ! if (space > 0) { ! fprintf(stream, "%*s", space, ""); ! } ! } else if (prefix) { ! fputs(prefix, stream); ! fputs(": ", stream); } ! errno=save_e; } #endif /* Called to initialize the global volume number. */ ! int init_volume_number () { FILE *vf; ! vf = fopen (f_volno_file, "r"); if (!vf && errno != ENOENT) msg_perror ("%s", f_volno_file); ! if (vf) { fscanf (vf, "%d", &global_volno); --- 1318,1377 ---- * "current" record # is used. */ void ! anno (stream, prefix, savedp) ! FILE *stream; ! char *prefix; ! int savedp; { # define MAXANNO 50 ! char buffer[MAXANNO]; /* Holds annorecment */ # define ANNOWIDTH 13 ! int space; ! long offset; ! int save_e; ! ! save_e = errno; ! /* Make sure previous output gets out in sequence */ ! if (stream == stderr) ! fflush (stdout); ! if (f_sayblock) ! { ! if (prefix) ! { ! fputs (prefix, stream); ! putc (' ', stream); ! } ! offset = ar_record - ar_block; ! (void) sprintf (buffer, "rec %d: ", ! savedp ? saved_recno : ! baserec + offset); ! fputs (buffer, stream); ! space = ANNOWIDTH - strlen (buffer); ! if (space > 0) ! { ! fprintf (stream, "%*s", space, ""); } ! } ! else if (prefix) ! { ! fputs (prefix, stream); ! fputs (": ", stream); ! } ! errno = save_e; } + #endif /* Called to initialize the global volume number. */ ! void init_volume_number () { FILE *vf; ! vf = fopen (f_volno_file, "r"); if (!vf && errno != ENOENT) msg_perror ("%s", f_volno_file); ! if (vf) { fscanf (vf, "%d", &global_volno); *************** *** 1232,1242 **** } /* Called to write out the closing global volume number. */ ! int closeout_volume_number () { FILE *vf; ! vf = fopen (f_volno_file, "w"); if (!vf) msg_perror ("%s", f_volno_file); --- 1380,1390 ---- } /* Called to write out the closing global volume number. */ ! void closeout_volume_number () { FILE *vf; ! vf = fopen (f_volno_file, "w"); if (!vf) msg_perror ("%s", f_volno_file); *************** *** 1246,1383 **** fclose (vf); } } ! /* We've hit the end of the old volume. Close it and open the next one */ /* Values for type: 0: writing 1: reading 2: updating */ int ! new_volume(type) ! int type; { ! int c; ! char inbuf[80]; ! char *p; ! static FILE *read_file = 0; ! extern int now_verifying; ! extern char TTY_NAME[]; ! static int looped = 0; ! ! if(!read_file && !f_run_script_at_end) ! read_file = (archive==0) ? fopen(TTY_NAME, "r") : stdin; ! ! if(now_verifying) ! return -1; ! if(f_verify) ! verify_volume(); ! if((c=rmtclose(archive))<0) ! msg_perror("Warning: can't close %s(%d,%d)",ar_files[cur_ar_file],archive,c); ! ! global_volno++; ! volno++; ! cur_ar_file++; ! if (cur_ar_file == n_ar_files) ! { ! cur_ar_file = 0; ! looped = 1; ! } ! ! tryagain: ! if (looped) ! { ! /* We have to prompt from now on. */ ! if (f_run_script_at_end) ! system(info_script); ! else for(;;) { ! fprintf(msg_file,"\007Prepare volume #%d for %s and hit return: ",global_volno, ar_files[cur_ar_file]); ! fflush(msg_file); ! if(fgets(inbuf,sizeof(inbuf),read_file)==0) { ! fprintf(msg_file,"EOF? What does that mean?"); ! if(cmd_mode!=CMD_EXTRACT && cmd_mode!=CMD_LIST && cmd_mode!=CMD_DIFF) ! msg("Warning: Archive is INCOMPLETE!"); ! exit(EX_BADARCH); ! } ! if(inbuf[0]=='\n' || inbuf[0]=='y' || inbuf[0]=='Y') ! break; ! switch(inbuf[0]) { ! case '?': ! { ! fprintf(msg_file,"\ n [name] Give a new filename for the next (and subsequent) volume(s)\n\ q Abort tar\n\ ! Spawn a subshell\n\ ? Print this list\n"); ! } ! break; ! ! case 'q': /* Quit */ ! fprintf(msg_file,"No new volume; exiting.\n"); ! if(cmd_mode!=CMD_EXTRACT && cmd_mode!=CMD_LIST && cmd_mode!=CMD_DIFF) ! msg("Warning: Archive is INCOMPLETE!"); ! exit(EX_BADARCH); ! case 'n': /* Get new file name */ { ! char *q,*r; ! static char *old_name; ! ! for(q= &inbuf[1];*q==' ' || *q=='\t';q++) ! ; ! for(r=q;*r;r++) ! if(*r=='\n') ! *r='\0'; ! old_name=p=(char *)malloc((unsigned)(strlen(q)+2)); ! if(p==0) { ! msg("Can't allocate memory for name"); ! exit(EX_SYSTEM); ! } ! (void) strcpy(p,q); ! ar_files[cur_ar_file]=p; } ! break; ! case '!': #ifdef __MSDOS__ ! spawnl(P_WAIT,getenv("COMSPEC"),"-",0); #else ! /* JF this needs work! */ ! switch(fork()) { ! case -1: ! msg_perror("can't fork!"); ! break; ! case 0: ! p=getenv("SHELL"); ! if(p==0) p="/bin/sh"; ! execlp(p,"-sh","-i",0); ! msg_perror("can't exec a shell %s",p); ! _exit(55); ! default: ! wait(0); ! break; ! } ! #endif ! break; } ! } ! } ! ! if(type==2 || f_verify) ! archive=rmtopen(ar_files[cur_ar_file],O_RDWR|O_CREAT,0666); ! else if(type==1) ! archive=rmtopen(ar_files[cur_ar_file],O_RDONLY,0666); ! else if(type==0) ! archive=rmtcreat(ar_files[cur_ar_file],0666); ! else ! archive= -1; ! ! if(archive<0) { ! msg_perror("can't open %s",ar_files[cur_ar_file]); ! goto tryagain; ! } #ifdef __MSDOS__ ! setmode(archive,O_BINARY); #endif ! return 0; } /* this is a useless function that takes a buffer returned by wantbytes --- 1394,1542 ---- fclose (vf); } } ! /* We've hit the end of the old volume. Close it and open the next one */ /* Values for type: 0: writing 1: reading 2: updating */ int ! new_volume (type) ! int type; { ! int c; ! char inbuf[80]; ! char *p; ! static FILE *read_file = 0; ! extern int now_verifying; ! extern char TTY_NAME[]; ! static int looped = 0; ! ! if (!read_file && !f_run_script_at_end) ! read_file = (archive == 0) ? fopen (TTY_NAME, "r") : stdin; ! ! if (now_verifying) ! return -1; ! if (f_verify) ! verify_volume (); ! if ((c = rmtclose (archive)) < 0) ! msg_perror ("Warning: can't close %s(%d,%d)", ar_files[cur_ar_file], archive, c); ! ! global_volno++; ! volno++; ! cur_ar_file++; ! if (cur_ar_file == n_ar_files) ! { ! cur_ar_file = 0; ! looped = 1; ! } ! tryagain: ! if (looped) ! { ! /* We have to prompt from now on. */ ! if (f_run_script_at_end) ! { ! closeout_volume_number (); ! system (info_script); ! } ! else ! for (;;) ! { ! fprintf (msg_file, "\007Prepare volume #%d for %s and hit return: ", global_volno, ar_files[cur_ar_file]); ! fflush (msg_file); ! if (fgets (inbuf, sizeof (inbuf), read_file) == 0) ! { ! fprintf (msg_file, "EOF? What does that mean?"); ! if (cmd_mode != CMD_EXTRACT && cmd_mode != CMD_LIST && cmd_mode != CMD_DIFF) ! msg ("Warning: Archive is INCOMPLETE!"); ! exit (EX_BADARCH); ! } ! if (inbuf[0] == '\n' || inbuf[0] == 'y' || inbuf[0] == 'Y') ! break; ! ! switch (inbuf[0]) ! { ! case '?': ! { ! fprintf (msg_file, "\ n [name] Give a new filename for the next (and subsequent) volume(s)\n\ q Abort tar\n\ ! Spawn a subshell\n\ ? Print this list\n"); ! } ! break; ! case 'q': /* Quit */ ! fprintf (msg_file, "No new volume; exiting.\n"); ! if (cmd_mode != CMD_EXTRACT && cmd_mode != CMD_LIST && cmd_mode != CMD_DIFF) ! msg ("Warning: Archive is INCOMPLETE!"); ! exit (EX_BADARCH); ! ! case 'n': /* Get new file name */ ! { ! char *q, *r; ! static char *old_name; ! ! for (q = &inbuf[1]; *q == ' ' || *q == '\t'; q++) ! ; ! for (r = q; *r; r++) ! if (*r == '\n') ! *r = '\0'; ! old_name = p = (char *) malloc ((unsigned) (strlen (q) + 2)); ! if (p == 0) { ! msg ("Can't allocate memory for name"); ! exit (EX_SYSTEM); } ! (void) strcpy (p, q); ! ar_files[cur_ar_file] = p; ! } ! break; ! case '!': #ifdef __MSDOS__ ! spawnl (P_WAIT, getenv ("COMSPEC"), "-", 0); #else ! /* JF this needs work! */ ! switch (fork ()) ! { ! case -1: ! msg_perror ("can't fork!"); ! break; ! case 0: ! p = getenv ("SHELL"); ! if (p == 0) ! p = "/bin/sh"; ! execlp (p, "-sh", "-i", 0); ! msg_perror ("can't exec a shell %s", p); ! _exit (55); ! default: ! wait (0); ! break; } ! #endif ! break; ! } ! } ! } ! ! if (type == 2 || f_verify) ! archive = rmtopen (ar_files[cur_ar_file], O_RDWR | O_CREAT, 0666); ! else if (type == 1) ! archive = rmtopen (ar_files[cur_ar_file], O_RDONLY, 0666); ! else if (type == 0) ! archive = rmtcreat (ar_files[cur_ar_file], 0666); ! else ! archive = -1; ! ! if (archive < 0) ! { ! msg_perror ("can't open %s", ar_files[cur_ar_file]); ! goto tryagain; ! } #ifdef __MSDOS__ ! setmode (archive, O_BINARY); #endif ! return 0; } /* this is a useless function that takes a buffer returned by wantbytes *************** *** 1386,1396 **** the file. */ int ! no_op(size,data) ! int size; ! char *data; { ! return 0; } /* Some other routine wants SIZE bytes in the archive. For each chunk of --- 1545,1555 ---- the file. */ int ! no_op (size, data) ! int size; ! char *data; { ! return 0; } /* Some other routine wants SIZE bytes in the archive. For each chunk of *************** *** 1398,1423 **** the chunk it can work with. */ int ! wantbytes(size,func) ! long size; ! int (*func)(); ! { ! char *data; ! long data_size; ! ! while(size) { ! data = findrec()->charptr; ! if (data == NULL) { /* Check it... */ ! msg("Unexpected EOF on archive file"); ! return -1; ! } ! data_size = endofrecs()->charptr - data; ! if(data_size>size) ! data_size=size; ! if((*func)(data_size,data)) ! func=no_op; ! userec((union record *)(data + data_size - 1)); ! size-=data_size; ! } ! return 0; } --- 1557,1584 ---- the chunk it can work with. */ int ! wantbytes (size, func) ! long size; ! int (*func) (); ! { ! char *data; ! long data_size; ! ! while (size) ! { ! data = findrec ()->charptr; ! if (data == NULL) ! { /* Check it... */ ! msg ("Unexpected EOF on archive file"); ! return -1; ! } ! data_size = endofrecs ()->charptr - data; ! if (data_size > size) ! data_size = size; ! if ((*func) (data_size, data)) ! func = no_op; ! userec ((union record *) (data + data_size - 1)); ! size -= data_size; ! } ! return 0; } diff -c3 tar-1.11.1/configure tar-1.11.2/configure *** tar-1.11.1/configure Tue Sep 15 20:29:09 1992 --- tar-1.11.2/configure Wed Feb 3 15:43:37 1993 *************** *** 1,7 **** #!/bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated automatically using autoconf. ! # Copyright (C) 1991, 1992 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by --- 1,7 ---- #!/bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated automatically using autoconf. ! # Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by *************** *** 18,31 **** # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # Usage: configure [--srcdir=DIR] [--host=HOST] [--gas] [--nfp] [--no-create] ! # [--prefix=PREFIX] [--exec_prefix=PREFIX] [--with-PROGRAM] [TARGET] ! # Ignores all args except --srcdir, --prefix, --exec_prefix, and --no-create. - trap 'rm -f conftest* core; exit 1' 1 3 15 for arg do ! # Handle --exec_prefix with a space before the argument. if test x$next_exec_prefix = xyes; then exec_prefix=$arg; next_exec_prefix= # Handle --host with a space before the argument. elif test x$next_host = xyes; then next_host= --- 18,31 ---- # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # Usage: configure [--srcdir=DIR] [--host=HOST] [--gas] [--nfp] [--no-create] ! # [--prefix=PREFIX] [--exec-prefix=PREFIX] [--with-PACKAGE] [TARGET] ! # Ignores all args except --srcdir, --prefix, --exec-prefix, --no-create, and ! # --with-PACKAGE unless this script has special code to handle it. for arg do ! # Handle --exec-prefix with a space before the argument. if test x$next_exec_prefix = xyes; then exec_prefix=$arg; next_exec_prefix= # Handle --host with a space before the argument. elif test x$next_host = xyes; then next_host= *************** *** 35,43 **** elif test x$next_srcdir = xyes; then srcdir=$arg; next_srcdir= else case $arg in ! -exec_prefix=* | --exec_prefix=* | --exec_prefi=* | --exec_pref=* | --exec_pre=* | --exec_pr=* | --exec_p=* | --exec_=* | --exec=* | --exe=* | --ex=* | --e=*) exec_prefix=`echo $arg | sed 's/[-a-z_]*=//'` ;; ! -exec_prefix | --exec_prefix | --exec_prefi | --exec_pref | --exec_pre | --exec_pr | --exec_p | --exec_ | --exec | --exe | --ex | --e) next_exec_prefix=yes ;; -gas | --gas | --ga | --g) ;; --- 35,44 ---- elif test x$next_srcdir = xyes; then srcdir=$arg; next_srcdir= else case $arg in ! # For backward compatibility, also recognize exact --exec_prefix. ! -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* | --exec=* | --exe=* | --ex=* | --e=*) exec_prefix=`echo $arg | sed 's/[-a-z_]*=//'` ;; ! -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- | --exec | --exe | --ex | --e) next_exec_prefix=yes ;; -gas | --gas | --ga | --g) ;; *************** *** 61,67 **** -srcdir | --srcdir | --srcdi | --srcd | --src | --sr | --s) next_srcdir=yes ;; ! -with-* | --with-*) ;; *) ;; esac --- 62,74 ---- -srcdir | --srcdir | --srcdi | --srcd | --src | --sr | --s) next_srcdir=yes ;; ! -with-* | --with-*) ! package=`echo $arg|sed 's/-*with-//'` ! # Delete all the valid chars; see if any are left. ! if test -n "`echo $package|sed 's/[-a-zA-Z0-9_]*//g'`"; then ! echo "configure: $package: invalid package name" >&2; exit 1 ! fi ! eval "with_`echo $package|sed s/-/_/g`=1" ;; *) ;; esac *************** *** 68,75 **** fi done rm -f conftest* ! compile='${CC-cc} $DEFS conftest.c -o conftest $LIBS >/dev/null 2>&1' # A filename unique to this package, relative to the directory that # configure is in, which we can look for to find out if srcdir is correct. --- 75,84 ---- fi done + trap 'rm -f conftest* core; exit 1' 1 3 15 + rm -f conftest* ! compile='${CC-cc} $CFLAGS $DEFS conftest.c -o conftest $LIBS >/dev/null 2>&1' # A filename unique to this package, relative to the directory that # configure is in, which we can look for to find out if srcdir is correct. *************** *** 77,88 **** # Find the source files, if location was not specified. if test -z "$srcdir"; then ! srcdirdefaulted=yes; srcdir=. ! if test ! -r $unique_file; then srcdir=..; fi fi if test ! -r $srcdir/$unique_file; then if test x$srcdirdefaulted = xyes; then ! echo "configure: Can not find sources in \`.' or \`..'." 1>&2 else echo "configure: Can not find sources in \`${srcdir}'." 1>&2 fi --- 86,104 ---- # Find the source files, if location was not specified. if test -z "$srcdir"; then ! srcdirdefaulted=yes ! # Try the directory containing this script, then `..'. ! prog=$0 ! confdir=`echo $prog|sed 's%/[^/][^/]*$%%'` ! test "X$confdir" = "X$prog" && confdir=. ! srcdir=$confdir ! if test ! -r $srcdir/$unique_file; then ! srcdir=.. ! fi fi if test ! -r $srcdir/$unique_file; then if test x$srcdirdefaulted = xyes; then ! echo "configure: Can not find sources in \`${confdir}' or \`..'." 1>&2 else echo "configure: Can not find sources in \`${srcdir}'." 1>&2 fi *************** *** 111,117 **** test -z "$CC" && CC="cc" # Find out if we are using GNU C, under whatever name. ! cat < conftest.c #ifdef __GNUC__ yes #endif --- 127,133 ---- test -z "$CC" && CC="cc" # Find out if we are using GNU C, under whatever name. ! cat > conftest.c < conftest.out 2>&1 if egrep yes conftest.out >/dev/null 2>&1; then GCC=1 # For later tests. - CC="$CC -O" fi rm -f conftest* --- 135,140 ---- *************** *** 126,133 **** echo checking how to run the C preprocessor if test -z "$CPP"; then CPP='${CC-cc} -E' ! cat < conftest.c ! #include EOF err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` --- 141,147 ---- echo checking how to run the C preprocessor if test -z "$CPP"; then CPP='${CC-cc} -E' ! cat > conftest.c < EOF err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` *************** *** 144,151 **** pattern="Autoconf.*'x'" prog='#include Autoconf TIOCGETP' ! cat < conftest.c ! $prog EOF eval "$CPP $DEFS conftest.c > conftest.out 2>&1" --- 158,164 ---- pattern="Autoconf.*'x'" prog='#include Autoconf TIOCGETP' ! cat > conftest.c < conftest.out 2>&1" *************** *** 158,165 **** if test -z "$need_trad"; then prog='#include Autoconf TCGETA' ! cat < conftest.c ! $prog EOF eval "$CPP $DEFS conftest.c > conftest.out 2>&1" --- 171,177 ---- if test -z "$need_trad"; then prog='#include Autoconf TCGETA' ! cat > conftest.c < conftest.out 2>&1" *************** *** 174,180 **** # Make sure to not get the incompatible SysV /etc/install and # /usr/sbin/install, which might be in PATH before a BSD-like install, ! # or the SunOS /usr/etc/install directory. if test -z "$INSTALL"; then echo checking for install saveifs="$IFS"; IFS="${IFS}:" --- 186,193 ---- # Make sure to not get the incompatible SysV /etc/install and # /usr/sbin/install, which might be in PATH before a BSD-like install, ! # or the SunOS /usr/etc/install directory, or the AIX /bin/install, ! # or the AFS install, which mishandles nonexistent args. (Sigh.) if test -z "$INSTALL"; then echo checking for install saveifs="$IFS"; IFS="${IFS}:" *************** *** 181,193 **** for dir in $PATH; do test -z "$dir" && dir=. case $dir in ! /etc|/usr/sbin|/usr/etc) ;; *) if test -f $dir/install; then ! INSTALL="$dir/install -c" ! INSTALL_PROGRAM='$(INSTALL)' ! INSTALL_DATA='$(INSTALL) -m 644' ! break fi ;; esac --- 194,210 ---- for dir in $PATH; do test -z "$dir" && dir=. case $dir in ! /etc|/usr/sbin|/usr/etc|/usr/afsws/bin) ;; *) if test -f $dir/install; then ! if grep dspmsg $dir/install >/dev/null 2>&1; then ! : # AIX ! else ! INSTALL="$dir/install -c" ! INSTALL_PROGRAM='$(INSTALL)' ! INSTALL_DATA='$(INSTALL) -m 644' ! break ! fi fi ;; esac *************** *** 228,235 **** echo checking for AIX ! cat < conftest.c ! #ifdef _AIX yes #endif --- 245,251 ---- echo checking for AIX ! cat > conftest.c < conftest.c ! #include EOF err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` --- 259,265 ---- echo checking for minix/config.h ! cat > conftest.c < EOF err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` *************** *** 273,284 **** fi fi ! echo checking return type of signal handlers ! echo '#include ' > conftest.c ! eval "$CPP $DEFS conftest.c > conftest.out 2>&1" ! if egrep "(void|sighandler_t).*signal" conftest.out >/dev/null 2>&1; then ! : ! else DEFS="$DEFS -DRETSIGTYPE=int" fi rm -f conftest* --- 288,307 ---- fi fi ! echo checking for return type of signal handlers ! cat > conftest.c < ! #include ! #ifdef signal ! #undef signal ! #endif ! extern void (*signal ()) (); ! main() { exit(0); } ! t() { int i; } ! EOF ! if eval $compile; then ! DEFS="$DEFS -DRETSIGTYPE=void" ! else DEFS="$DEFS -DRETSIGTYPE=int" fi rm -f conftest* *************** *** 295,302 **** rm -f conftest* echo checking for major, minor and makedev header ! echo "#include ! main() { exit(0); } t() { return makedev(0, 0); }" > conftest.c if eval $compile; then makedev=1 fi --- 318,328 ---- rm -f conftest* echo checking for major, minor and makedev header ! cat > conftest.c < ! main() { exit(0); } ! t() { return makedev(0, 0); } ! EOF if eval $compile; then makedev=1 fi *************** *** 304,311 **** if test -z "$makedev"; then echo checking for sys/mkdev.h ! cat < conftest.c ! #include EOF err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` --- 330,336 ---- if test -z "$makedev"; then echo checking for sys/mkdev.h ! cat > conftest.c < EOF err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` *************** *** 317,324 **** fi if test -z "$makedev"; then echo checking for sys/sysmacros.h ! cat < conftest.c ! #include EOF err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` --- 342,348 ---- fi if test -z "$makedev"; then echo checking for sys/sysmacros.h ! cat > conftest.c < EOF err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` *************** *** 331,338 **** echo checking for directory library header echo checking for dirent.h ! cat < conftest.c ! #include EOF err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` --- 355,361 ---- echo checking for directory library header echo checking for dirent.h ! cat > conftest.c < EOF err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` *************** *** 343,350 **** if test -z "$dirheader"; then echo checking for sys/ndir.h ! cat < conftest.c ! #include EOF err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` --- 366,372 ---- if test -z "$dirheader"; then echo checking for sys/ndir.h ! cat > conftest.c < EOF err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` *************** *** 356,363 **** fi if test -z "$dirheader"; then echo checking for sys/dir.h ! cat < conftest.c ! #include EOF err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` --- 378,384 ---- fi if test -z "$dirheader"; then echo checking for sys/dir.h ! cat > conftest.c < EOF err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` *************** *** 367,375 **** rm -f conftest* fi echo checking for closedir return value ! cat < conftest.c #include #include <$dirheader> int closedir(); main() { exit(0); } --- 388,408 ---- rm -f conftest* fi + if test -z "$dirheader"; then + echo checking for ndir.h + cat > conftest.c < + EOF + err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` + if test -z "$err"; then + DEFS="$DEFS -DNDIR=1" dirheader=ndir.h + fi + rm -f conftest* + + fi echo checking for closedir return value ! cat > conftest.c < #include <$dirheader> int closedir(); main() { exit(0); } *************** *** 385,392 **** # The 3-argument open happens to go along with the O_* defines, # which are easier to check for. echo checking for fcntl.h ! cat < conftest.c ! #include EOF err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` --- 418,424 ---- # The 3-argument open happens to go along with the O_* defines, # which are easier to check for. echo checking for fcntl.h ! cat > conftest.c < EOF err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` *************** *** 398,405 **** rm -f conftest* echo checking for 3-argument open ! echo "#include <$open_header> ! main() { exit(0); } t() { int x = O_RDONLY; }" > conftest.c if eval $compile; then : else --- 430,440 ---- rm -f conftest* echo checking for 3-argument open ! cat > conftest.c < ! main() { exit(0); } ! t() { int x = O_RDONLY; } ! EOF if eval $compile; then : else *************** *** 409,416 **** echo checking for remote tape and socket header files echo checking for sys/mtio.h ! cat < conftest.c ! #include EOF err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` --- 444,450 ---- echo checking for remote tape and socket header files echo checking for sys/mtio.h ! cat > conftest.c < EOF err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` *************** *** 420,427 **** rm -f conftest* if test -n "$have_mtio"; then ! cat < conftest.c ! #include #include EOF --- 454,460 ---- rm -f conftest* if test -n "$have_mtio"; then ! cat > conftest.c < #include EOF *************** *** 438,445 **** RTAPELIB=rtapelib.o else echo checking for netdb.h ! cat < conftest.c ! #include EOF err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` --- 471,477 ---- RTAPELIB=rtapelib.o else echo checking for netdb.h ! cat > conftest.c < EOF err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` *************** *** 453,474 **** fi echo checking for ANSI C header files ! cat < conftest.c ! #include #include #include ! #include EOF err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` if test -z "$err"; then DEFS="$DEFS -DSTDC_HEADERS=1" fi rm -f conftest* ! echo checking for unistd.h ! cat < conftest.c #include EOF err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` --- 485,526 ---- fi echo checking for ANSI C header files ! cat > conftest.c < #include #include ! #include EOF err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` if test -z "$err"; then + # SunOS string.h does not declare mem*, contrary to ANSI. + echo '#include ' > conftest.c + eval "$CPP $DEFS conftest.c > conftest.out 2>&1" + if egrep "memchr" conftest.out >/dev/null 2>&1; then + # SGI's /bin/cc from Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + cat > conftest.c < + #define ISLOWER(c) ('a' <= (c) && (c) <= 'z') + #define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) + #define XOR(e,f) (((e) && !(f)) || (!(e) && (f))) + int main () { int i; for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); + exit (0); } + + EOF + eval $compile + if test -s conftest && (./conftest; exit) 2>/dev/null; then DEFS="$DEFS -DSTDC_HEADERS=1" fi rm -f conftest* + fi + rm -f conftest* ! fi ! rm -f conftest* + echo checking for unistd.h + cat > conftest.c < EOF err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` *************** *** 477,505 **** fi rm -f conftest* ! echo checking for limits.h ! cat < conftest.c ! #include ! EOF ! err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` ! if test -z "$err"; then ! DEFS="$DEFS -DHAVE_LIMITS_H=1" fi rm -f conftest* ! echo checking for BSD string and memory functions ! echo "#include ! main() { exit(0); } t() { rindex(0, 0); bzero(0, 0); }" > conftest.c ! if eval $compile; then ! : ! else ! DEFS="$DEFS -DUSG=1" fi rm -f conftest* echo checking default archive ! # This is likely to guess wrong, but it's not very important. for dev in rmt8 rmt0 rmt0h rct0 rst0 tape rct/c7d0s2 do if test -n "`ls /dev/$dev 2>/dev/null`"; then --- 529,566 ---- fi rm -f conftest* ! echo checking for getgrgid declaration ! echo '#include ' > conftest.c ! eval "$CPP $DEFS conftest.c > conftest.out 2>&1" ! if egrep "getgrgid" conftest.out >/dev/null 2>&1; then ! DEFS="$DEFS -DHAVE_GETGRGID=1" ! fi ! rm -f conftest* ! echo checking for getpwuid declaration ! echo '#include ' > conftest.c ! eval "$CPP $DEFS conftest.c > conftest.out 2>&1" ! if egrep "getpwuid" conftest.out >/dev/null 2>&1; then ! DEFS="$DEFS -DHAVE_GETPWUID=1" fi rm -f conftest* ! for hdr in string.h limits.h ! do ! trhdr=HAVE_`echo $hdr | tr '[a-z]./' '[A-Z]__'` ! echo checking for ${hdr} ! cat > conftest.c < ! EOF ! err=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"` ! if test -z "$err"; then ! DEFS="$DEFS -D${trhdr}=1" fi rm -f conftest* + done echo checking default archive ! # This might guess wrong, but it's not very important. for dev in rmt8 rmt0 rmt0h rct0 rst0 tape rct/c7d0s2 do if test -n "`ls /dev/$dev 2>/dev/null`"; then *************** *** 511,533 **** DEF_AR_FILE=- fi ! for func in strstr valloc mkdir mknod rename ftruncate ftime do ! trfrom='[a-z]' trto='[A-Z]' echo checking for ${func} ! echo " ! main() { exit(0); } t() { /* Override any gcc2 internal prototype to avoid an error. */ ! extern char ${func}(); ${func}(); }" > conftest.c if eval $compile; then ! DEFS="$DEFS -DHAVE_`echo $func|tr "$trfrom" "$trto"`=1" fi rm -f conftest* done echo checking for vprintf ! echo " ! main() { exit(0); } t() { vprintf(); }" > conftest.c if eval $compile; then DEFS="$DEFS -DHAVE_VPRINTF=1" else --- 572,606 ---- DEF_AR_FILE=- fi ! for func in strstr valloc mkdir mknod rename ftruncate ftime getcwd do ! trfunc=HAVE_`echo $func | tr '[a-z]' '[A-Z]'` echo checking for ${func} ! cat > conftest.c < ! main() { exit(0); } ! t() { ! #ifdef __stub_${func} ! choke me ! #else /* Override any gcc2 internal prototype to avoid an error. */ ! extern char ${func}(); ${func}(); ! #endif ! } ! EOF if eval $compile; then ! DEFS="$DEFS -D${trfunc}=1" fi rm -f conftest* + #endif done echo checking for vprintf ! cat > conftest.c < conftest.c if eval $compile; then DEFS="$DEFS -DHAVE_DOPRNT=1" fi --- 610,620 ---- if test -n "$vprintf_missing"; then echo checking for _doprnt ! cat > conftest.c < ! main() { exit(0); } t() { char *p = alloca(2 * sizeof(int)); }" > conftest.c if eval $compile; then DEFS="$DEFS -DHAVE_ALLOCA_H=1" fi --- 625,635 ---- # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works # for constant arguments. Useless! echo checking for working alloca.h ! cat > conftest.c < ! main() { exit(0); } ! t() { char *p = alloca(2 * sizeof(int)); } ! EOF if eval $compile; then DEFS="$DEFS -DHAVE_ALLOCA_H=1" fi *************** *** 571,578 **** #endif " echo checking for alloca ! echo "$decl ! main() { exit(0); } t() { char *p = (char *) alloca(1); }" > conftest.c if eval $compile; then : else --- 650,660 ---- #endif " echo checking for alloca ! cat > conftest.c < conftest.c ! if eval $compile; then ! : ! else ! alloca_missing=1 fi - rm -f conftest* - - fi - if test -n "$alloca_missing"; then - LIBS="$SAVELIBS" ALLOCA=alloca.o - fi - fi echo checking for BSD ( test -f /vmunix || test -f /sdmach || test -f /../../mach ) && DEFS="$DEFS -DBSD42=1" --- 663,674 ---- rm -f conftest* if test -n "$alloca_missing"; then ! # The SVR3 libPW and SVR4 libucb both contain incompatible functions ! # that cause trouble. Some versions do not even contain alloca or ! # contain a buggy version. If you still want to use their alloca, ! # use ar to extract alloca.o from them instead of compiling alloca.c. ! ALLOCA=alloca.o fi echo checking for BSD ( test -f /vmunix || test -f /sdmach || test -f /../../mach ) && DEFS="$DEFS -DBSD42=1" *************** *** 614,621 **** test -f /hp-ux && test ! -f /vmunix && MALLOC=malloc.o echo checking for Xenix ! cat < conftest.c ! #if defined(M_XENIX) && !defined(M_UNIX) yes #endif --- 676,682 ---- test -f /hp-ux && test ! -f /vmunix && MALLOC=malloc.o echo checking for Xenix ! cat > conftest.c < config.status #!/bin/sh # Generated automatically by configure. # Run this file to recreate the current configuration. ! # This directory was configured as follows: # $0 $* ! case "\$1" in ! -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ! exec /bin/sh $0 $* ;; ! esac trap 'rm -f Makefile; exit 1' 1 3 15 PROGS='$PROGS' --- 697,774 ---- esac fi ! libname=`echo "socket" | sed 's/lib\([^\.]*\)\.a/\1/;s/-l//'` ! LIBS_save="${LIBS}" ! LIBS="${LIBS} -l${libname}" ! have_lib="" ! echo checking for -l${libname} ! cat > conftest.c < conftest.c < config.status </dev/null`: ! # # $0 $* ! for arg ! do ! case "\$arg" in ! -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ! exec /bin/sh $0 $* ;; ! *) echo "Usage: config.status --recheck" 2>&1; exit 1 ;; ! esac ! done trap 'rm -f Makefile; exit 1' 1 3 15 PROGS='$PROGS' *************** *** 683,695 **** exec_prefix='$exec_prefix' prsub='$prsub' EOF ! cat <<\EOF >> config.status top_srcdir=$srcdir ! for file in Makefile; do srcdir=$top_srcdir # Remove last slash and all that follows it. Not all systems have dirname. ! dir=`echo $file|sed 's,/[^/][^/]*$,,'` if test "$dir" != "$file"; then test "$top_srcdir" != . && srcdir=$top_srcdir/$dir test ! -d $dir && mkdir $dir --- 789,801 ---- exec_prefix='$exec_prefix' prsub='$prsub' EOF ! cat >> config.status <<\EOF top_srcdir=$srcdir ! for file in .. Makefile; do if [ "x$file" != "x.." ]; then srcdir=$top_srcdir # Remove last slash and all that follows it. Not all systems have dirname. ! dir=`echo $file|sed 's%/[^/][^/]*$%%'` if test "$dir" != "$file"; then test "$top_srcdir" != . && srcdir=$top_srcdir/$dir test ! -d $dir && mkdir $dir *************** *** 696,720 **** fi echo creating $file rm -f $file ! echo "# Generated automatically from `basename $file`.in by configure." > $file sed -e " $prsub ! s,@PROGS@,$PROGS,g ! s,@CC@,$CC,g ! s,@CPP@,$CPP,g ! s,@INSTALL@,$INSTALL,g ! s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,g ! s,@INSTALL_DATA@,$INSTALL_DATA,g ! s,@YACC@,$YACC,g ! s,@RTAPELIB@,$RTAPELIB,g ! s,@DEF_AR_FILE@,$DEF_AR_FILE,g ! s,@ALLOCA@,$ALLOCA,g ! s,@MALLOC@,$MALLOC,g ! s,@LIBS@,$LIBS,g ! s,@srcdir@,$srcdir,g ! s,@DEFS@,$DEFS," $top_srcdir/${file}.in >> $file ! done EOF chmod +x config.status test -n "$no_create" || ./config.status --- 802,828 ---- fi echo creating $file rm -f $file ! echo "# Generated automatically from `echo $file|sed 's|.*/||'`.in by configure." > $file sed -e " $prsub ! s%@PROGS@%$PROGS%g ! s%@CC@%$CC%g ! s%@CPP@%$CPP%g ! s%@INSTALL@%$INSTALL%g ! s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g ! s%@INSTALL_DATA@%$INSTALL_DATA%g ! s%@YACC@%$YACC%g ! s%@RTAPELIB@%$RTAPELIB%g ! s%@DEF_AR_FILE@%$DEF_AR_FILE%g ! s%@ALLOCA@%$ALLOCA%g ! s%@MALLOC@%$MALLOC%g ! s%@LIBS@%$LIBS%g ! s%@srcdir@%$srcdir%g ! s%@DEFS@%$DEFS% ! " $top_srcdir/${file}.in >> $file ! fi; done + exit 0 EOF chmod +x config.status test -n "$no_create" || ./config.status diff -c3 tar-1.11.1/configure.in tar-1.11.2/configure.in *** tar-1.11.1/configure.in Tue Sep 15 20:10:45 1992 --- tar-1.11.2/configure.in Wed Jan 6 18:16:20 1993 *************** *** 23,32 **** AC_RSH AC_STDC_HEADERS AC_UNISTD_H ! AC_HEADER_CHECK(limits.h, AC_DEFINE(HAVE_LIMITS_H)) ! AC_USG echo checking default archive ! # This is likely to guess wrong, but it's not very important. for dev in rmt8 rmt0 rmt0h rct0 rst0 tape rct/c7d0s2 do if test -n "`ls /dev/$dev 2>/dev/null`"; then --- 23,35 ---- AC_RSH AC_STDC_HEADERS AC_UNISTD_H ! echo checking for getgrgid declaration ! AC_HEADER_EGREP(getgrgid, grp.h, AC_DEFINE(HAVE_GETGRGID)) ! echo checking for getpwuid declaration ! AC_HEADER_EGREP(getpwuid, pwd.h, AC_DEFINE(HAVE_GETPWUID)) ! AC_HAVE_HEADERS(string.h limits.h) echo checking default archive ! # This might guess wrong, but it's not very important. for dev in rmt8 rmt0 rmt0h rct0 rst0 tape rct/c7d0s2 do if test -n "`ls /dev/$dev 2>/dev/null`"; then *************** *** 39,45 **** fi AC_SUBST(DEF_AR_FILE)dnl ! AC_HAVE_FUNCS(strstr valloc mkdir mknod rename ftruncate ftime) AC_VPRINTF AC_ALLOCA echo checking for BSD --- 42,48 ---- fi AC_SUBST(DEF_AR_FILE)dnl ! AC_HAVE_FUNCS(strstr valloc mkdir mknod rename ftruncate ftime getcwd) AC_VPRINTF AC_ALLOCA echo checking for BSD *************** *** 48,55 **** test -f /hp-ux && test ! -f /vmunix && MALLOC=malloc.o AC_SUBST(MALLOC) AC_XENIX_DIR ! echo checking for Solaris libraries ! test -f /lib/libsocket.a && LIBS="$LIBS -lsocket" ! test -f /lib/libnsl.a && LIBS="$LIBS -lnsl" ! AC_OUTPUT(Makefile) --- 51,56 ---- test -f /hp-ux && test ! -f /vmunix && MALLOC=malloc.o AC_SUBST(MALLOC) AC_XENIX_DIR ! AC_HAVE_LIBRARY(socket, [LIBS="$LIBS -lsocket"]) ! AC_HAVE_LIBRARY(nsl, [LIBS="$LIBS -lnsl"]) AC_OUTPUT(Makefile) diff -c3 tar-1.11.1/create.c tar-1.11.2/create.c *** tar-1.11.1/create.c Mon Sep 14 17:19:28 1992 --- tar-1.11.2/create.c Thu Mar 25 13:32:31 1993 *************** *** 1,5 **** /* Create a tar archive. ! Copyright (C) 1985, 1992 Free Software Foundation This file is part of GNU Tar. --- 1,5 ---- /* Create a tar archive. ! Copyright (C) 1985, 1992, 1993 Free Software Foundation This file is part of GNU Tar. *************** *** 30,36 **** #include #include #ifndef STDC_HEADERS ! extern int errno; #endif #ifdef BSD42 --- 30,36 ---- #include #include #ifndef STDC_HEADERS ! extern int errno; #endif #ifdef BSD42 *************** *** 49,77 **** #include #endif ! #if defined(_POSIX_VERSION) || defined(DIRENT) ! #include ! #ifdef direct ! #undef direct ! #endif /* direct */ ! #define direct dirent ! #define DP_NAMELEN(x) strlen((x)->d_name) ! #endif /* _POSIX_VERSION or DIRENT */ ! #if !defined(_POSIX_VERSION) && !defined(DIRENT) && defined(BSD42) ! #include ! #define DP_NAMELEN(x) (x)->d_namlen ! #endif /* not _POSIX_VERSION and BSD42 */ ! #ifdef __MSDOS__ ! #include "msd_dir.h" ! #define DP_NAMELEN(x) (x)->d_namlen ! #define direct dirent ! #endif ! #if defined(USG) && !defined(_POSIX_VERSION) && !defined(DIRENT) ! #include ! #define DP_NAMELEN(x) strlen((x)->d_name) ! #endif /* USG and not _POSIX_VERSION and not DIRENT */ ! extern struct stat hstat; /* Stat struct corresponding */ #ifndef __MSDOS__ extern dev_t ar_dev; --- 49,66 ---- #include #endif ! #if defined (_POSIX_VERSION) ! #include ! #else ! struct utimbuf ! { ! long actime; ! long modtime; ! }; ! #endif ! ! extern struct stat hstat; /* Stat struct corresponding */ #ifndef __MSDOS__ extern dev_t ar_dev; *************** *** 88,133 **** #define lstat stat #endif ! extern void print_header(); ! union record *start_header(); ! void blank_name_list(); ! int check_exclude(); ! PTR ck_malloc(); ! PTR ck_realloc(); ! void clear_buffer(); ! void close_archive(); ! void collect_and_sort_names(); ! int confirm(); ! int deal_with_sparse(); ! void find_new_file_size(); ! void finish_header(); ! int finish_sparse_file(); ! void finduname(); ! void findgname(); ! int is_dot_or_dotdot(); ! void open_archive(); ! char *name_next(); ! void name_close(); ! void to_oct(); ! void dump_file(); ! void write_dir_file(); ! void write_eot(); ! int zero_record(); /* This code moved from tar.h since create.c is the only file that cares about 'struct link's. This means that other files might not have to include sys/types.h any more. */ ! struct link { ! struct link *next; ! dev_t dev; ! ino_t ino; ! short linkcount; ! char name[1]; ! }; ! struct link *linklist; /* Points to first link in list */ static nolinks; /* Gets set if we run out of RAM */ --- 77,124 ---- #define lstat stat #endif ! extern void print_header (); ! union record *start_header (); ! void blank_name_list (); ! int check_exclude (); ! PTR ck_malloc (); ! PTR ck_realloc (); ! void clear_buffer (); ! void close_archive (); ! void collect_and_sort_names (); ! int confirm (); ! int deal_with_sparse (); ! void find_new_file_size (); ! void finish_header (); ! int finish_sparse_file (); ! void finduname (); ! void findgname (); ! int is_dot_or_dotdot (); ! void open_archive (); ! char *name_next (); ! void name_close (); ! void to_oct (); ! void dump_file (); ! void write_dir_file (); ! void write_eot (); ! void write_long (); ! int zero_record (); /* This code moved from tar.h since create.c is the only file that cares about 'struct link's. This means that other files might not have to include sys/types.h any more. */ ! struct link ! { ! struct link *next; ! dev_t dev; ! ino_t ino; ! short linkcount; ! char name[1]; ! }; ! struct link *linklist; /* Points to first link in list */ static nolinks; /* Gets set if we run out of RAM */ *************** *** 141,189 **** /*int sparse_array_size = 10;*/ void ! create_archive() { ! register char *p; ! char *name_from_list(); ! open_archive(0); /* Open for writing */ ! if(f_gnudump) { ! char *buf = ck_malloc(PATH_MAX); ! char *q,*bufp; ! ! collect_and_sort_names(); ! ! while(p=name_from_list()) ! dump_file(p,-1, 1); ! /* if(!f_dironly) { */ ! blank_name_list(); ! while(p=name_from_list()) { ! strcpy(buf,p); ! if(p[strlen(p)-1]!='/') ! strcat(buf,"/"); ! bufp=buf+strlen(buf); ! for(q=gnu_list_name->dir_contents;q && *q;q+=strlen(q)+1) { ! if(*q=='Y') { ! strcpy(bufp,q+1); ! dump_file(buf,-1, 1); ! } ! } ! } ! /* } */ ! free(buf); ! } else { ! p = name_next(1); ! do ! dump_file(p, -1, 1); ! while (p = name_next(1)); } ! write_eot(); ! close_archive(); ! if(f_gnudump) ! write_dir_file(); ! name_close(); } /* --- 132,184 ---- /*int sparse_array_size = 10;*/ void ! create_archive () { ! register char *p; ! char *name_from_list (); ! open_archive (0); /* Open for writing */ ! if (f_gnudump) ! { ! char *buf = ck_malloc (PATH_MAX); ! char *q, *bufp; ! ! collect_and_sort_names (); ! ! while (p = name_from_list ()) ! dump_file (p, -1, 1); ! /* if(!f_dironly) { */ ! blank_name_list (); ! while (p = name_from_list ()) ! { ! strcpy (buf, p); ! if (p[strlen (p) - 1] != '/') ! strcat (buf, "/"); ! bufp = buf + strlen (buf); ! for (q = gnu_list_name->dir_contents; q && *q; q += strlen (q) + 1) ! { ! if (*q == 'Y') ! { ! strcpy (bufp, q + 1); ! dump_file (buf, -1, 1); ! } ! } } + /* } */ + free (buf); + } + else + { + while (p = name_next (1)) + dump_file (p, -1, 1); + } ! write_eot (); ! close_archive (); ! if (f_gnudump) ! write_dir_file (); ! name_close (); } /* *************** *** 193,274 **** */ void dump_file (p, curdev, toplevel) ! char *p; /* File name to dump */ ! int curdev; /* Device our parent dir was on */ ! int toplevel; /* Whether we are a toplevel call */ { ! union record *header; ! char type; ! extern char *save_name; /* JF for multi-volume support */ ! extern long save_totsize; ! extern long save_sizeleft; ! union record *exhdr; ! char save_linkflag; ! extern time_t new_time; ! int critical_error = 0; ! time_t restore_times[2]; ! /* int sparse_ind = 0;*/ ! if(f_confirm && !confirm("add",p)) ! return; ! /* * Use stat if following (rather than dumping) 4.2BSD's * symbolic links. Otherwise, use lstat (which, on non-4.2 * systems, is #define'd to stat anyway. */ ! #ifdef STX_HIDDEN /* AIX */ ! if (0 != f_follow_links ? ! statx (p, &hstat, STATSIZE, STX_HIDDEN): ! statx (p, &hstat, STATSIZE, STX_HIDDEN|STX_LINK)) #else ! if (0 != f_follow_links? stat(p, &hstat): lstat(p, &hstat)) #endif ! { ! badperror: ! msg_perror("can't add file %s",p); ! badfile: ! if (!f_ignore_failed_read || critical_error) ! errors++; ! return; ! } ! ! restore_times[0] = hstat.st_atime; ! restore_times[1] = hstat.st_mtime; #ifdef S_ISHIDDEN ! if (S_ISHIDDEN (hstat.st_mode)) { ! char *new = (char *)alloca (strlen (p) + 2); ! if (new) { ! strcpy (new, p); ! strcat (new, "@"); ! p = new; ! } } #endif ! /* See if we only want new files, and check if this one is too old to put in the archive. */ ! if( f_new_files ! && !f_gnudump ! && new_time>hstat.st_mtime ! && !S_ISDIR(hstat.st_mode) ! && (f_new_files>1 || new_time>hstat.st_ctime)) { ! if(curdev<0) { ! msg("%s: is unchanged; not dumped",p); ! } ! return; } #ifndef __MSDOS__ ! /* See if we are trying to dump the archive */ ! if(ar_dev && hstat.st_dev==ar_dev && hstat.st_ino==ar_ino) { ! msg("%s is the archive; not dumped",p); ! return; ! } #endif ! /* * Check for multiple links. * * We maintain a list of all such files that we've written so --- 188,274 ---- */ void dump_file (p, curdev, toplevel) ! char *p; /* File name to dump */ ! int curdev; /* Device our parent dir was on */ ! int toplevel; /* Whether we are a toplevel call */ { ! union record *header; ! char type; ! extern char *save_name; /* JF for multi-volume support */ ! extern long save_totsize; ! extern long save_sizeleft; ! union record *exhdr; ! char save_linkflag; ! extern time_t new_time; ! int critical_error = 0; ! struct utimbuf restore_times; ! /* int sparse_ind = 0;*/ ! if (f_confirm && !confirm ("add", p)) ! return; ! /* * Use stat if following (rather than dumping) 4.2BSD's * symbolic links. Otherwise, use lstat (which, on non-4.2 * systems, is #define'd to stat anyway. */ ! #ifdef STX_HIDDEN /* AIX */ ! if (0 != f_follow_links ? ! statx (p, &hstat, STATSIZE, STX_HIDDEN) : ! statx (p, &hstat, STATSIZE, STX_HIDDEN | STX_LINK)) #else ! if (0 != f_follow_links ? stat (p, &hstat) : lstat (p, &hstat)) #endif ! { ! badperror: ! msg_perror ("can't add file %s", p); ! badfile: ! if (!f_ignore_failed_read || critical_error) ! errors++; ! return; ! } ! ! restore_times.actime = hstat.st_atime; ! restore_times.modtime = hstat.st_mtime; #ifdef S_ISHIDDEN ! if (S_ISHIDDEN (hstat.st_mode)) ! { ! char *new = (char *) alloca (strlen (p) + 2); ! if (new) ! { ! strcpy (new, p); ! strcat (new, "@"); ! p = new; } + } #endif ! /* See if we only want new files, and check if this one is too old to put in the archive. */ ! if (f_new_files ! && !f_gnudump ! && new_time > hstat.st_mtime ! && !S_ISDIR (hstat.st_mode) ! && (f_new_files > 1 || new_time > hstat.st_ctime)) ! { ! if (curdev == -1) ! { ! msg ("%s: is unchanged; not dumped", p); } + return; + } #ifndef __MSDOS__ ! /* See if we are trying to dump the archive */ ! if (ar_dev && hstat.st_dev == ar_dev && hstat.st_ino == ar_ino) ! { ! msg ("%s is the archive; not dumped", p); ! return; ! } #endif ! /* * Check for multiple links. * * We maintain a list of all such files that we've written so *************** *** 275,381 **** * far. Any time we see another, we check the list and * avoid dumping the data again if we've done it once already. */ ! if (hstat.st_nlink > 1 ! && (S_ISREG(hstat.st_mode) #ifdef S_ISCTG ! || S_ISCTG(hstat.st_mode) #endif #ifdef S_ISCHR ! || S_ISCHR(hstat.st_mode) #endif #ifdef S_ISBLK ! || S_ISBLK(hstat.st_mode) #endif #ifdef S_ISFIFO ! || S_ISFIFO(hstat.st_mode) #endif ! )) { ! register struct link *lp; ! /* First quick and dirty. Hashing, etc later FIXME */ ! for (lp = linklist; lp; lp = lp->next) { ! if (lp->ino == hstat.st_ino && ! lp->dev == hstat.st_dev) { ! char *link_name = lp->name; ! ! /* We found a link. */ ! while(!f_absolute_paths && *link_name == '/') { ! static int link_warn = 0; ! ! if (!link_warn) { ! msg("Removing leading / from absolute links"); ! link_warn++; ! } ! link_name++; ! } ! if (link_name - lp->name >= NAMSIZ) ! write_long (link_name, LF_LONGLINK); ! current_link_name = link_name; ! ! hstat.st_size = 0; ! header = start_header(p, &hstat); ! if (header == NULL) ! { ! critical_error = 1; ! goto badfile; ! } ! strncpy(header->header.arch_linkname, ! link_name,NAMSIZ); ! ! /* Force null truncated */ ! header->header.arch_linkname [NAMSIZ-1] = 0; ! ! header->header.linkflag = LF_LINK; ! finish_header(header); ! /* FIXME: Maybe remove from list after all links found? */ ! if (f_remove_files) ! { ! if (unlink (p) == -1) ! msg_perror ("cannot remove %s", p); ! } ! return; /* We dumped it */ ! } } ! /* Not found. Add it to the list of possible links. */ ! lp = (struct link *)malloc((unsigned)(sizeof(struct link)+strlen(p))); ! if (!lp) { ! if (!nolinks) { ! msg( ! "no memory for links, they will be dumped as separate files"); ! nolinks++; ! } ! } ! lp->ino = hstat.st_ino; ! lp->dev = hstat.st_dev; ! strcpy(lp->name, p); ! lp->next = linklist; ! linklist = lp; } ! /* * This is not a link to a previously dumped file, so dump it. */ ! if (S_ISREG(hstat.st_mode) #ifdef S_ISCTG ! || S_ISCTG(hstat.st_mode) #endif ! ) ! { ! int f; /* File descriptor */ ! long bufsize, count; ! long sizeleft; ! register union record *start; ! int header_moved; ! char isextended = 0; ! int upperbound; ! /* int end_nulls = 0; */ ! ! header_moved = 0; #ifdef BSD42 ! if (f_sparse_files) { ! /* * JK - This is the test for sparseness: whether the * "size" of the file matches the number of blocks * allocated for it. If there is a smaller number --- 275,389 ---- * far. Any time we see another, we check the list and * avoid dumping the data again if we've done it once already. */ ! if (hstat.st_nlink > 1 ! && (S_ISREG (hstat.st_mode) #ifdef S_ISCTG ! || S_ISCTG (hstat.st_mode) #endif #ifdef S_ISCHR ! || S_ISCHR (hstat.st_mode) #endif #ifdef S_ISBLK ! || S_ISBLK (hstat.st_mode) #endif #ifdef S_ISFIFO ! || S_ISFIFO (hstat.st_mode) #endif ! )) ! { ! register struct link *lp; ! /* First quick and dirty. Hashing, etc later FIXME */ ! for (lp = linklist; lp; lp = lp->next) ! { ! if (lp->ino == hstat.st_ino && ! lp->dev == hstat.st_dev) ! { ! char *link_name = lp->name; ! ! /* We found a link. */ ! while (!f_absolute_paths && *link_name == '/') ! { ! static int link_warn = 0; ! ! if (!link_warn) ! { ! msg ("Removing leading / from absolute links"); ! link_warn++; ! } ! link_name++; ! } ! if (link_name - lp->name >= NAMSIZ) ! write_long (link_name, LF_LONGLINK); ! current_link_name = link_name; ! ! hstat.st_size = 0; ! header = start_header (p, &hstat); ! if (header == NULL) ! { ! critical_error = 1; ! goto badfile; ! } ! strncpy (header->header.arch_linkname, ! link_name, NAMSIZ); ! ! /* Force null truncated */ ! header->header.arch_linkname[NAMSIZ - 1] = 0; ! ! header->header.linkflag = LF_LINK; ! finish_header (header); ! /* FIXME: Maybe remove from list after all links found? */ ! if (f_remove_files) ! { ! if (unlink (p) == -1) ! msg_perror ("cannot remove %s", p); } + return; /* We dumped it */ + } + } ! /* Not found. Add it to the list of possible links. */ ! lp = (struct link *) ck_malloc ((unsigned) (sizeof (struct link) + strlen (p))); ! if (!lp) ! { ! if (!nolinks) ! { ! msg ( ! "no memory for links, they will be dumped as separate files"); ! nolinks++; ! } } + lp->ino = hstat.st_ino; + lp->dev = hstat.st_dev; + strcpy (lp->name, p); + lp->next = linklist; + linklist = lp; + } ! /* * This is not a link to a previously dumped file, so dump it. */ ! if (S_ISREG (hstat.st_mode) #ifdef S_ISCTG ! || S_ISCTG (hstat.st_mode) #endif ! ) ! { ! int f; /* File descriptor */ ! long bufsize, count; ! long sizeleft; ! register union record *start; ! int header_moved; ! char isextended = 0; ! int upperbound; ! /* int end_nulls = 0; */ + header_moved = 0; + #ifdef BSD42 ! if (f_sparse_files) ! { ! /* * JK - This is the test for sparseness: whether the * "size" of the file matches the number of blocks * allocated for it. If there is a smaller number *************** *** 384,408 **** * at least one of those records in the file is just * a useless hole. */ ! #ifdef hpux /* Nice of HPUX to gratuitiously change it, huh? - mib */ ! if (hstat.st_size - (hstat.st_blocks * 1024) > 1024 ) #else ! if (hstat.st_size - (hstat.st_blocks * RECORDSIZE) > RECORDSIZE) #endif ! { ! int filesize = hstat.st_size; ! register int i; ! ! header = start_header(p, &hstat); ! if (header == NULL) ! { ! critical_error = 1; ! goto badfile; ! } ! header->header.linkflag = LF_SPARSE; ! header_moved++; ! ! /* * Call the routine that figures out the * layout of the sparse file in question. * UPPERBOUND is the index of the last --- 392,416 ---- * at least one of those records in the file is just * a useless hole. */ ! #ifdef hpux /* Nice of HPUX to gratuitiously change it, huh? - mib */ ! if (hstat.st_size - (hstat.st_blocks * 1024) > 1024) #else ! if (hstat.st_size - (hstat.st_blocks * RECORDSIZE) > RECORDSIZE) #endif ! { ! int filesize = hstat.st_size; ! register int i; ! ! header = start_header (p, &hstat); ! if (header == NULL) ! { ! critical_error = 1; ! goto badfile; ! } ! header->header.linkflag = LF_SPARSE; ! header_moved++; ! ! /* * Call the routine that figures out the * layout of the sparse file in question. * UPPERBOUND is the index of the last *************** *** 410,425 **** * the number of elements it needed to * describe the file. */ ! ! upperbound = deal_with_sparse(p, header); ! ! /* * See if we'll need an extended header * later */ ! if (upperbound > SPARSE_IN_HDR-1) ! header->header.isextended++; ! /* * We store the "real" file size so * we can show that in case someone wants * to list the archive, i.e., tar tvf . --- 418,433 ---- * the number of elements it needed to * describe the file. */ ! ! upperbound = deal_with_sparse (p, header); ! ! /* * See if we'll need an extended header * later */ ! if (upperbound > SPARSE_IN_HDR - 1) ! header->header.isextended++; ! /* * We store the "real" file size so * we can show that in case someone wants * to list the archive, i.e., tar tvf . *************** *** 427,665 **** * shrunken file size was the one that showed * up. */ ! to_oct((long) hstat.st_size, 1+12, ! header->header.realsize); ! ! /* * This will be the new "size" of the * file, i.e., the size of the file * minus the records of holes that we're ! * skipping over. */ ! ! find_new_file_size(&filesize, upperbound); ! hstat.st_size = filesize; ! to_oct((long) filesize, 1+12, ! header->header.size); ! /* to_oct((long) end_nulls, 1+12, header->header.ending_blanks);*/ ! ! for (i = 0; i < SPARSE_IN_HDR; i++) { ! if (!sparsearray[i].numbytes) ! break; ! to_oct(sparsearray[i].offset, 1+12, ! header->header.sp[i].offset); ! to_oct(sparsearray[i].numbytes, 1+12, ! header->header.sp[i].numbytes); ! } ! ! } } #else ! upperbound=SPARSE_IN_HDR-1; #endif ! ! sizeleft = hstat.st_size; ! /* Don't bother opening empty, world readable files. */ ! if (sizeleft > 0 || 0444 != (0444 & hstat.st_mode)) { ! f = open(p, O_RDONLY|O_BINARY); ! if (f < 0) goto badperror; ! } else { ! f = -1; ! } ! ! /* If the file is sparse, we've already taken care of this */ ! if (!header_moved) { ! header = start_header(p, &hstat); ! if (header == NULL) { ! if(f>=0) ! (void)close(f); ! critical_error = 1; ! goto badfile; ! } ! } #ifdef S_ISCTG ! /* Mark contiguous files, if we support them */ ! if (f_standard && S_ISCTG(hstat.st_mode)) { ! header->header.linkflag = LF_CONTIG; ! } #endif ! isextended = header->header.isextended; ! save_linkflag = header->header.linkflag; ! finish_header(header); ! if (isextended) { ! /* int sum = 0;*/ ! register int i; ! /* register union record *exhdr;*/ ! /* int arraybound = SPARSE_EXT_HDR;*/ ! /* static */ int index_offset = SPARSE_IN_HDR; ! ! extend: exhdr = findrec(); ! ! if (exhdr == NULL) ! { ! critical_error = 1; ! goto badfile; ! } ! bzero(exhdr->charptr, RECORDSIZE); ! for (i = 0; i < SPARSE_EXT_HDR; i++) { ! if (i+index_offset > upperbound) ! break; ! to_oct((long) sparsearray[i+index_offset].numbytes, ! 1+12, ! exhdr->ext_hdr.sp[i].numbytes); ! to_oct((long) sparsearray[i+index_offset].offset, ! 1+12, ! exhdr->ext_hdr.sp[i].offset); ! } ! userec(exhdr); ! /* sum += i; if (sum < upperbound) goto extend;*/ ! if (index_offset+i < upperbound) { ! index_offset += i; ! exhdr->ext_hdr.isextended++; ! goto extend; ! } ! ! } ! if (save_linkflag == LF_SPARSE) { ! if (finish_sparse_file(f, &sizeleft, hstat.st_size, p)) ! goto padit; ! } ! else ! while (sizeleft > 0) { ! ! if(f_multivol) { ! save_name = p; ! save_sizeleft = sizeleft; ! save_totsize = hstat.st_size; ! } ! start = findrec(); ! bufsize = endofrecs()->charptr - start->charptr; ! ! if (sizeleft < bufsize) { ! /* Last read -- zero out area beyond */ ! bufsize = (int)sizeleft; ! count = bufsize % RECORDSIZE; ! if (count) ! bzero(start->charptr + sizeleft, ! (int)(RECORDSIZE - count)); ! } ! count = read(f, start->charptr, bufsize); ! if (count < 0) { ! msg_perror("read error at byte %ld, reading\ ! %d bytes, in file %s", hstat.st_size - sizeleft, bufsize,p); ! goto padit; ! } ! sizeleft -= count; ! /* This is nonportable (the type of userec's arg). */ ! userec(start+(count-1)/RECORDSIZE); ! if (count == bufsize) continue; ! msg( "file %s shrunk by %d bytes, padding with zeros.", p, sizeleft); ! goto padit; /* Short read */ ! } ! if(f_multivol) ! save_name = 0; ! if (f >= 0) ! (void)close(f); ! if (f_remove_files) ! { ! if (unlink (p) == -1) ! msg_perror ("cannot remove %s", p); ! } ! if (f_atime_preserve) ! utime (p, restore_times); ! return; ! /* * File shrunk or gave error, pad out tape to match * the size we specified in the header. */ ! padit: ! while(sizeleft>0) { ! save_sizeleft=sizeleft; ! start=findrec(); ! bzero(start->charptr,RECORDSIZE); ! userec(start); ! sizeleft-=RECORDSIZE; ! } ! if(f_multivol) ! save_name=0; ! if(f>=0) ! (void)close(f); ! if (f_atime_preserve) ! utime (p, restore_times); ! return; } #ifdef S_ISLNK ! else if(S_ISLNK(hstat.st_mode)) ! { ! int size; ! char *buf = alloca (PATH_MAX + 1); ! size = readlink (p, buf, PATH_MAX + 1); ! if (size < 0) ! goto badperror; ! buf[size] = '\0'; ! if (size >= NAMSIZ) ! write_long (buf, LF_LONGLINK); ! current_link_name = buf; ! ! hstat.st_size = 0; /* Force 0 size on symlink */ ! header = start_header(p, &hstat); ! if (header == NULL) ! { ! critical_error = 1; ! goto badfile; ! } ! strncpy (header->header.arch_linkname, buf, NAMSIZ); ! header->header.arch_linkname[NAMSIZ - 1] = '\0'; ! header->header.linkflag = LF_SYMLINK; ! finish_header(header); /* Nothing more to do to it */ ! if (f_remove_files) ! { ! if (unlink (p) == -1) ! msg_perror ("cannot remove %s", p); ! } ! return; } #endif ! else if (S_ISDIR(hstat.st_mode)) ! { ! register DIR *dirp; ! register struct direct *d; ! char *namebuf; ! int buflen; ! register int len; ! int our_device = hstat.st_dev; ! ! /* Build new prototype name */ ! len = strlen(p); ! buflen=len+NAMSIZ; ! namebuf=ck_malloc(buflen+1); ! strncpy(namebuf, p, buflen); ! while (len >= 1 && '/' == namebuf[len-1]) ! len--; /* Delete trailing slashes */ ! namebuf[len++] = '/'; /* Now add exactly one back */ ! namebuf[len] = '\0'; /* Make sure null-terminated */ ! /* * Output directory header record with permissions * FIXME, do this AFTER files, to avoid R/O dir problems? * If old archive format, don't write record at all. */ ! if (!f_oldarch) { ! hstat.st_size = 0; /* Force 0 size on dir */ ! /* * If people could really read standard archives, * this should be: (FIXME) header = start_header(f_standard? p: namebuf, &hstat); --- 435,692 ---- * shrunken file size was the one that showed * up. */ ! to_oct ((long) hstat.st_size, 1 + 12, ! header->header.realsize); ! ! /* * This will be the new "size" of the * file, i.e., the size of the file * minus the records of holes that we're ! * skipping over. */ ! ! find_new_file_size (&filesize, upperbound); ! hstat.st_size = filesize; ! to_oct ((long) filesize, 1 + 12, ! header->header.size); ! /* to_oct((long) end_nulls, 1+12, header->header.ending_blanks);*/ ! ! for (i = 0; i < SPARSE_IN_HDR; i++) ! { ! if (!sparsearray[i].numbytes) ! break; ! to_oct (sparsearray[i].offset, 1 + 12, ! header->header.sp[i].offset); ! to_oct (sparsearray[i].numbytes, 1 + 12, ! header->header.sp[i].numbytes); } + + } + } #else ! upperbound = SPARSE_IN_HDR - 1; #endif ! ! sizeleft = hstat.st_size; ! /* Don't bother opening empty, world readable files. */ ! if (sizeleft > 0 || 0444 != (0444 & hstat.st_mode)) ! { ! f = open (p, O_RDONLY | O_BINARY); ! if (f < 0) ! goto badperror; ! } ! else ! { ! f = -1; ! } ! ! /* If the file is sparse, we've already taken care of this */ ! if (!header_moved) ! { ! header = start_header (p, &hstat); ! if (header == NULL) ! { ! if (f >= 0) ! (void) close (f); ! critical_error = 1; ! goto badfile; ! } ! } #ifdef S_ISCTG ! /* Mark contiguous files, if we support them */ ! if (f_standard && S_ISCTG (hstat.st_mode)) ! { ! header->header.linkflag = LF_CONTIG; ! } #endif ! isextended = header->header.isextended; ! save_linkflag = header->header.linkflag; ! finish_header (header); ! if (isextended) ! { ! /* int sum = 0;*/ ! register int i; ! /* register union record *exhdr;*/ ! /* int arraybound = SPARSE_EXT_HDR;*/ ! /* static */ int index_offset = SPARSE_IN_HDR; ! ! extend:exhdr = findrec (); ! ! if (exhdr == NULL) ! { ! critical_error = 1; ! goto badfile; ! } ! bzero (exhdr->charptr, RECORDSIZE); ! for (i = 0; i < SPARSE_EXT_HDR; i++) ! { ! if (i + index_offset > upperbound) ! break; ! to_oct ((long) sparsearray[i + index_offset].numbytes, ! 1 + 12, ! exhdr->ext_hdr.sp[i].numbytes); ! to_oct ((long) sparsearray[i + index_offset].offset, ! 1 + 12, ! exhdr->ext_hdr.sp[i].offset); ! } ! userec (exhdr); ! /* sum += i; if (sum < upperbound) goto extend;*/ ! if (index_offset + i <= upperbound) ! { ! index_offset += i; ! exhdr->ext_hdr.isextended++; ! goto extend; ! } ! } ! if (save_linkflag == LF_SPARSE) ! { ! if (finish_sparse_file (f, &sizeleft, hstat.st_size, p)) ! goto padit; ! } ! else ! while (sizeleft > 0) ! { ! if (f_multivol) ! { ! save_name = p; ! save_sizeleft = sizeleft; ! save_totsize = hstat.st_size; ! } ! start = findrec (); ! bufsize = endofrecs ()->charptr - start->charptr; ! ! if (sizeleft < bufsize) ! { ! /* Last read -- zero out area beyond */ ! bufsize = (int) sizeleft; ! count = bufsize % RECORDSIZE; ! if (count) ! bzero (start->charptr + sizeleft, ! (int) (RECORDSIZE - count)); ! } ! count = read (f, start->charptr, bufsize); ! if (count < 0) ! { ! msg_perror ("read error at byte %ld, reading\ ! %d bytes, in file %s", hstat.st_size - sizeleft, bufsize, p); ! goto padit; ! } ! sizeleft -= count; ! ! /* This is nonportable (the type of userec's arg). */ ! userec (start + (count - 1) / RECORDSIZE); ! ! if (count == bufsize) ! continue; ! msg ("file %s shrunk by %d bytes, padding with zeros.", p, sizeleft); ! goto padit; /* Short read */ ! } ! if (f_multivol) ! save_name = 0; ! if (f >= 0) ! (void) close (f); ! if (f_remove_files) ! { ! if (unlink (p) == -1) ! msg_perror ("cannot remove %s", p); ! } ! if (f_atime_preserve) ! utime (p, &restore_times); ! return; ! /* * File shrunk or gave error, pad out tape to match * the size we specified in the header. */ ! padit: ! while (sizeleft > 0) ! { ! save_sizeleft = sizeleft; ! start = findrec (); ! bzero (start->charptr, RECORDSIZE); ! userec (start); ! sizeleft -= RECORDSIZE; } + if (f_multivol) + save_name = 0; + if (f >= 0) + (void) close (f); + if (f_atime_preserve) + utime (p, &restore_times); + return; + } #ifdef S_ISLNK ! else if (S_ISLNK (hstat.st_mode)) ! { ! int size; ! char *buf = alloca (PATH_MAX + 1); ! size = readlink (p, buf, PATH_MAX + 1); ! if (size < 0) ! goto badperror; ! buf[size] = '\0'; ! if (size >= NAMSIZ) ! write_long (buf, LF_LONGLINK); ! current_link_name = buf; ! ! hstat.st_size = 0; /* Force 0 size on symlink */ ! header = start_header (p, &hstat); ! if (header == NULL) ! { ! critical_error = 1; ! goto badfile; ! } ! strncpy (header->header.arch_linkname, buf, NAMSIZ); ! header->header.arch_linkname[NAMSIZ - 1] = '\0'; ! header->header.linkflag = LF_SYMLINK; ! finish_header (header); /* Nothing more to do to it */ ! if (f_remove_files) ! { ! if (unlink (p) == -1) ! msg_perror ("cannot remove %s", p); } + return; + } #endif ! else if (S_ISDIR (hstat.st_mode)) ! { ! register DIR *dirp; ! register struct dirent *d; ! char *namebuf; ! int buflen; ! register int len; ! int our_device = hstat.st_dev; ! ! /* Build new prototype name */ ! len = strlen (p); ! buflen = len + NAMSIZ; ! namebuf = ck_malloc (buflen + 1); ! strncpy (namebuf, p, buflen); ! while (len >= 1 && '/' == namebuf[len - 1]) ! len--; /* Delete trailing slashes */ ! namebuf[len++] = '/'; /* Now add exactly one back */ ! namebuf[len] = '\0'; /* Make sure null-terminated */ ! /* * Output directory header record with permissions * FIXME, do this AFTER files, to avoid R/O dir problems? * If old archive format, don't write record at all. */ ! if (!f_oldarch) ! { ! hstat.st_size = 0; /* Force 0 size on dir */ ! /* * If people could really read standard archives, * this should be: (FIXME) header = start_header(f_standard? p: namebuf, &hstat); *************** *** 666,886 **** * but since they'd interpret LF_DIR records as * regular files, we'd better put the / on the name. */ ! header = start_header(namebuf, &hstat); ! if (header == NULL) ! { ! critical_error = 1; ! goto badfile; /* eg name too long */ ! } ! ! if (f_gnudump) ! header->header.linkflag = LF_DUMPDIR; ! else if (f_standard) ! header->header.linkflag = LF_DIR; ! ! /* If we're gnudumping, we aren't done yet so don't close it. */ ! if(!f_gnudump) ! finish_header(header); /* Done with directory header */ ! } ! if(f_gnudump) { ! int sizeleft; ! int totsize; ! int bufsize; ! union record *start; ! int count; ! char *buf,*p_buf; ! ! buf=gnu_list_name->dir_contents; /* FOO */ ! totsize=0; ! for(p_buf=buf;p_buf && *p_buf;) { ! int tmp; ! ! tmp=strlen(p_buf)+1; ! totsize+=tmp; ! p_buf+=tmp; ! } ! totsize++; ! to_oct((long)totsize,1+12,header->header.size); ! finish_header(header); ! p_buf=buf; ! sizeleft=totsize; ! while(sizeleft>0) { ! if(f_multivol) { ! save_name=p; ! save_sizeleft=sizeleft; ! save_totsize=totsize; ! } ! start=findrec(); ! bufsize=endofrecs()->charptr - start->charptr; ! if(sizeleftcharptr+sizeleft,RECORDSIZE-count); ! } ! bcopy(p_buf,start->charptr,bufsize); ! sizeleft-=bufsize; ! p_buf+=bufsize; ! userec(start+(bufsize-1)/RECORDSIZE); ! } ! if(f_multivol) ! save_name = 0; ! if (f_atime_preserve) ! utime (p, restore_times); ! return; ! } ! /* Now output all the files in the directory */ #if 0 ! if (f_dironly) ! return; /* Unless the cmdline said not to */ #endif ! /* * See if we are crossing from one file system to another, * and avoid doing so if the user only wants to dump one file system. */ ! if (f_local_filesys && !toplevel && curdev != hstat.st_dev) { ! if(f_verbose) ! msg("%s: is on a different filesystem; not dumped",p); ! return; ! } ! errno = 0; ! dirp = opendir(p); ! if (!dirp) { ! if (errno) { ! msg_perror ("can't open directory %s",p); ! } else { ! msg("error opening directory %s", ! p); ! } ! return; ! } ! /* Hack to remove "./" from the front of all the file names */ ! if (len == 2 && namebuf[0] == '.' && namebuf[1]=='/') ! len = 0; ! ! /* Should speed this up by cd-ing into the dir, FIXME */ ! while (NULL != (d=readdir(dirp))) { ! /* Skip . and .. */ ! if(is_dot_or_dotdot(d->d_name)) ! continue; ! ! if (DP_NAMELEN(d) + len >= buflen) { ! buflen=len+DP_NAMELEN(d); ! namebuf=ck_realloc(namebuf,buflen+1); ! /* namebuf[len]='\0'; ! msg("file name %s%s too long", namebuf, d->d_name); continue; */ ! } ! strcpy(namebuf+len, d->d_name); ! if(f_exclude && check_exclude(namebuf)) ! continue; ! dump_file(namebuf, our_device, 0); ! } ! ! closedir(dirp); ! free(namebuf); ! if (f_atime_preserve) ! utime (p, restore_times); ! return; } #ifdef S_ISCHR ! else if (S_ISCHR(hstat.st_mode)) { ! type = LF_CHR; ! } #endif #ifdef S_ISBLK ! else if (S_ISBLK(hstat.st_mode)) { ! type = LF_BLK; ! } #endif ! /* Avoid screwy apollo lossage where S_IFIFO == S_IFSOCK */ #if (_ISP__M68K == 0) && (_ISP__A88K == 0) && defined(S_ISFIFO) ! else if (S_ISFIFO(hstat.st_mode)) { ! type = LF_FIFO; ! } #endif #ifdef S_ISSOCK ! else if (S_ISSOCK(hstat.st_mode)) { ! type = LF_FIFO; ! } #endif ! else ! goto unknown; ! if (!f_standard) goto unknown; ! hstat.st_size = 0; /* Force 0 size */ ! header = start_header(p, &hstat); ! if (header == NULL) ! { ! critical_error = 1; ! goto badfile; /* eg name too long */ ! } ! header->header.linkflag = type; #if defined(S_IFBLK) || defined(S_IFCHR) ! if (type != LF_FIFO) { ! to_oct((long) major(hstat.st_rdev), 8, ! header->header.devmajor); ! to_oct((long) minor(hstat.st_rdev), 8, ! header->header.devminor); ! } #endif ! finish_header(header); ! if (f_remove_files) ! { ! if (unlink (p) == -1) ! msg_perror ("cannot remove %s", p); ! } ! return; ! unknown: ! msg("%s: Unknown file type; file ignored.", p); } int ! finish_sparse_file(fd, sizeleft, fullsize, name) ! int fd; ! long *sizeleft, ! fullsize; ! char *name; { ! union record *start; ! char tempbuf[RECORDSIZE]; ! int bufsize, ! sparse_ind = 0, ! count; ! long pos; ! long nwritten = 0; ! ! ! while (*sizeleft > 0) { ! start = findrec(); ! bzero(start->charptr, RECORDSIZE); ! bufsize = sparsearray[sparse_ind].numbytes; ! if (!bufsize) { /* we blew it, maybe */ ! msg("Wrote %ld of %ld bytes to file %s", ! fullsize - *sizeleft, fullsize, name); ! break; ! } ! pos = lseek(fd, sparsearray[sparse_ind++].offset, 0); ! /* * If the number of bytes to be written here exceeds * the size of the temporary buffer, do it in steps. */ ! while (bufsize > RECORDSIZE) { ! /* if (amt_read) { count = read(fd, start->charptr+amt_read, RECORDSIZE-amt_read); bufsize -= RECORDSIZE - amt_read; amt_read = 0; --- 693,931 ---- * but since they'd interpret LF_DIR records as * regular files, we'd better put the / on the name. */ ! header = start_header (namebuf, &hstat); ! if (header == NULL) ! { ! critical_error = 1; ! goto badfile; /* eg name too long */ ! } ! ! if (f_gnudump) ! header->header.linkflag = LF_DUMPDIR; ! else if (f_standard) ! header->header.linkflag = LF_DIR; ! ! /* If we're gnudumping, we aren't done yet so don't close it. */ ! if (!f_gnudump) ! finish_header (header); /* Done with directory header */ ! } ! if (f_gnudump) ! { ! int sizeleft; ! int totsize; ! int bufsize; ! union record *start; ! int count; ! char *buf, *p_buf; ! ! buf = gnu_list_name->dir_contents; /* FOO */ ! totsize = 0; ! for (p_buf = buf; p_buf && *p_buf;) ! { ! int tmp; ! ! tmp = strlen (p_buf) + 1; ! totsize += tmp; ! p_buf += tmp; ! } ! totsize++; ! to_oct ((long) totsize, 1 + 12, header->header.size); ! finish_header (header); ! p_buf = buf; ! sizeleft = totsize; ! while (sizeleft > 0) ! { ! if (f_multivol) ! { ! save_name = p; ! save_sizeleft = sizeleft; ! save_totsize = totsize; ! } ! start = findrec (); ! bufsize = endofrecs ()->charptr - start->charptr; ! if (sizeleft < bufsize) ! { ! bufsize = sizeleft; ! count = bufsize % RECORDSIZE; ! if (count) ! bzero (start->charptr + sizeleft, RECORDSIZE - count); ! } ! bcopy (p_buf, start->charptr, bufsize); ! sizeleft -= bufsize; ! p_buf += bufsize; ! userec (start + (bufsize - 1) / RECORDSIZE); ! } ! if (f_multivol) ! save_name = 0; ! if (f_atime_preserve) ! utime (p, &restore_times); ! return; ! } ! /* Now output all the files in the directory */ #if 0 ! if (f_dironly) ! return; /* Unless the cmdline said not to */ #endif ! /* * See if we are crossing from one file system to another, * and avoid doing so if the user only wants to dump one file system. */ ! if (f_local_filesys && !toplevel && curdev != hstat.st_dev) ! { ! if (f_verbose) ! msg ("%s: is on a different filesystem; not dumped", p); ! return; ! } ! errno = 0; ! dirp = opendir (p); ! if (!dirp) ! { ! if (errno) ! { ! msg_perror ("can't open directory %s", p); ! } ! else ! { ! msg ("error opening directory %s", ! p); ! } ! return; ! } ! ! /* Hack to remove "./" from the front of all the file names */ ! if (len == 2 && namebuf[0] == '.' && namebuf[1] == '/') ! len = 0; ! /* Should speed this up by cd-ing into the dir, FIXME */ ! while (NULL != (d = readdir (dirp))) ! { ! /* Skip . and .. */ ! if (is_dot_or_dotdot (d->d_name)) ! continue; ! ! if (NLENGTH (d) + len >= buflen) ! { ! buflen = len + NLENGTH (d); ! namebuf = ck_realloc (namebuf, buflen + 1); ! /* namebuf[len]='\0'; ! msg("file name %s%s too long", namebuf, d->d_name); continue; */ ! } ! strcpy (namebuf + len, d->d_name); ! if (f_exclude && check_exclude (namebuf)) ! continue; ! dump_file (namebuf, our_device, 0); } + closedir (dirp); + free (namebuf); + if (f_atime_preserve) + utime (p, &restore_times); + return; + } + #ifdef S_ISCHR ! else if (S_ISCHR (hstat.st_mode)) ! { ! type = LF_CHR; ! } #endif #ifdef S_ISBLK ! else if (S_ISBLK (hstat.st_mode)) ! { ! type = LF_BLK; ! } #endif ! /* Avoid screwy apollo lossage where S_IFIFO == S_IFSOCK */ #if (_ISP__M68K == 0) && (_ISP__A88K == 0) && defined(S_ISFIFO) ! else if (S_ISFIFO (hstat.st_mode)) ! { ! type = LF_FIFO; ! } #endif #ifdef S_ISSOCK ! else if (S_ISSOCK (hstat.st_mode)) ! { ! type = LF_FIFO; ! } #endif ! else ! goto unknown; ! if (!f_standard) ! goto unknown; ! hstat.st_size = 0; /* Force 0 size */ ! header = start_header (p, &hstat); ! if (header == NULL) ! { ! critical_error = 1; ! goto badfile; /* eg name too long */ ! } ! header->header.linkflag = type; #if defined(S_IFBLK) || defined(S_IFCHR) ! if (type != LF_FIFO) ! { ! to_oct ((long) major (hstat.st_rdev), 8, ! header->header.devmajor); ! to_oct ((long) minor (hstat.st_rdev), 8, ! header->header.devminor); ! } #endif ! finish_header (header); ! if (f_remove_files) ! { ! if (unlink (p) == -1) ! msg_perror ("cannot remove %s", p); ! } ! return; ! unknown: ! msg ("%s: Unknown file type; file ignored.", p); } int ! finish_sparse_file (fd, sizeleft, fullsize, name) ! int fd; ! long *sizeleft, fullsize; ! char *name; { ! union record *start; ! char tempbuf[RECORDSIZE]; ! int bufsize, sparse_ind = 0, count; ! long pos; ! long nwritten = 0; ! ! ! while (*sizeleft > 0) ! { ! start = findrec (); ! bzero (start->charptr, RECORDSIZE); ! bufsize = sparsearray[sparse_ind].numbytes; ! if (!bufsize) ! { /* we blew it, maybe */ ! msg ("Wrote %ld of %ld bytes to file %s", ! fullsize - *sizeleft, fullsize, name); ! break; ! } ! pos = lseek (fd, sparsearray[sparse_ind++].offset, 0); ! /* * If the number of bytes to be written here exceeds * the size of the temporary buffer, do it in steps. */ ! while (bufsize > RECORDSIZE) ! { ! /* if (amt_read) { count = read(fd, start->charptr+amt_read, RECORDSIZE-amt_read); bufsize -= RECORDSIZE - amt_read; amt_read = 0; *************** *** 888,918 **** start = findrec(); bzero(start->charptr, RECORDSIZE); }*/ ! /* store the data */ ! count = read(fd, start->charptr, RECORDSIZE); ! if (count < 0) { ! msg_perror("read error at byte %ld, reading %d bytes, in file %s", ! fullsize - *sizeleft, bufsize, name); ! return 1; ! } ! bufsize -= count; ! *sizeleft -= count; ! userec(start); ! nwritten += RECORDSIZE; /* XXX */ ! start = findrec(); ! bzero(start->charptr, RECORDSIZE); ! } ! clear_buffer(tempbuf); ! count = read(fd, tempbuf, bufsize); ! bcopy(tempbuf, start->charptr, RECORDSIZE); ! if (count < 0) { ! msg_perror("read error at byte %ld, reading %d bytes, in file %s", ! fullsize - *sizeleft, bufsize, name); ! return 1; ! } ! /* if (amt_read >= RECORDSIZE) { amt_read = 0; userec(start+(count-1)/RECORDSIZE); if (count != bufsize) { --- 933,965 ---- start = findrec(); bzero(start->charptr, RECORDSIZE); }*/ ! /* store the data */ ! count = read (fd, start->charptr, RECORDSIZE); ! if (count < 0) ! { ! msg_perror ("read error at byte %ld, reading %d bytes, in file %s", ! fullsize - *sizeleft, bufsize, name); ! return 1; ! } ! bufsize -= count; ! *sizeleft -= count; ! userec (start); ! nwritten += RECORDSIZE; /* XXX */ ! start = findrec (); ! bzero (start->charptr, RECORDSIZE); ! } ! clear_buffer (tempbuf); ! count = read (fd, tempbuf, bufsize); ! bcopy (tempbuf, start->charptr, RECORDSIZE); ! if (count < 0) ! { ! msg_perror ("read error at byte %ld, reading %d bytes, in file %s", ! fullsize - *sizeleft, bufsize, name); ! return 1; ! } ! /* if (amt_read >= RECORDSIZE) { amt_read = 0; userec(start+(count-1)/RECORDSIZE); if (count != bufsize) { *************** *** 920,953 **** return 1; } start = findrec(); ! } else amt_read += bufsize;*/ ! nwritten += count; /* XXX */ ! *sizeleft -= count; ! userec(start); ! } ! free(sparsearray); ! /* printf ("Amount actually written is (I hope) %d.\n", nwritten); */ ! /* userec(start+(count-1)/RECORDSIZE);*/ ! return 0; } void ! init_sparsearray() { ! register int i; ! sp_array_size = 10; ! /* * Make room for our scratch space -- initially is 10 elts long */ ! sparsearray = (struct sp_array *) malloc(sp_array_size * sizeof(struct sp_array)); ! for (i = 0; i < sp_array_size; i++) { ! sparsearray[i].offset = 0; ! sparsearray[i].numbytes = 0; ! } } --- 967,1001 ---- return 1; } start = findrec(); ! } else amt_read += bufsize;*/ ! nwritten += count; /* XXX */ ! *sizeleft -= count; ! userec (start); ! } ! free (sparsearray); ! /* printf ("Amount actually written is (I hope) %d.\n", nwritten); */ ! /* userec(start+(count-1)/RECORDSIZE);*/ ! return 0; } void ! init_sparsearray () { ! register int i; ! sp_array_size = 10; ! /* * Make room for our scratch space -- initially is 10 elts long */ ! sparsearray = (struct sp_array *) ck_malloc (sp_array_size * sizeof (struct sp_array)); ! for (i = 0; i < sp_array_size; i++) ! { ! sparsearray[i].offset = 0; ! sparsearray[i].numbytes = 0; ! } } *************** *** 966,1123 **** */ /* There is little point in trimming small amounts of null data at the */ ! /* head and tail of blocks -- it's ok if we only avoid dumping blocks */ ! /* of complete null data */ int ! deal_with_sparse(name, header, nulls_at_end) ! char *name; ! union record *header; ! int nulls_at_end; { ! long numbytes = 0; ! long offset = 0; ! /* long save_offset;*/ ! int fd; ! /* int current_size = hstat.st_size;*/ ! int sparse_ind = 0, ! cc; ! char buf[RECORDSIZE]; #if 0 ! int read_last_data = 0; /* did we just read the last record? */ #endif ! int amidst_data = 0; ! ! header->header.isextended = 0; ! /* * Can't open the file -- this problem will be caught later on, * so just return. */ ! if ((fd = open(name, O_RDONLY)) < 0) ! return 0; ! ! init_sparsearray(); ! clear_buffer(buf); ! ! while ((cc = read(fd, buf, sizeof buf)) != 0) { ! ! if (sparse_ind > sp_array_size-1) { ! ! /* * realloc the scratch area, since we've run out of room -- */ ! sparsearray = (struct sp_array *) ! realloc(sparsearray, ! 2 * sp_array_size * (sizeof(struct sp_array))); ! sp_array_size *= 2; ! } ! if (cc == sizeof buf) { ! if (zero_record(buf)) { ! if (amidst_data) { ! sparsearray[sparse_ind++].numbytes ! = numbytes; ! amidst_data = 0; ! } ! } else { /* !zero_record(buf) */ ! if (amidst_data) ! numbytes += cc; ! else { ! amidst_data = 1; ! numbytes = cc; ! sparsearray[sparse_ind].offset ! = offset; ! } ! } ! } else if (cc < sizeof buf) { ! /* This has to be the last bit of the file, so this */ ! /* is somewhat shorter than the above. */ ! if (!zero_record(buf)) { ! if (!amidst_data) { ! amidst_data = 1; ! numbytes = cc; ! sparsearray[sparse_ind].offset ! = offset; ! } else ! numbytes += cc; ! } } ! offset += cc; ! clear_buffer(buf); } ! if (amidst_data) ! sparsearray[sparse_ind++].numbytes = numbytes; ! close(fd); ! return sparse_ind - 1; } ! /* * Just zeroes out the buffer so we don't confuse ourselves with leftover * data. */ void ! clear_buffer(buf) ! char *buf; { ! register int i; ! for (i = 0; i < RECORDSIZE; i++) ! buf[i] = '\0'; } ! #if 0 /* I'm leaving this as a monument to Joy Kendall, who wrote it -mib */ ! /* ! * JK - * This routine takes a character array, and tells where within that array * the data can be found. It skips over any zeros, and sets the first * non-zero point in the array to be the "start", and continues until it ! * finds non-data again, which is marked as the "end." This routine is * mainly for 1) seeing how far into a file we must lseek to data, given * that we have a sparse file, and 2) determining the "real size" of the * file, i.e., the number of bytes in the sparse file that are data, as * opposed to the zeros we are trying to skip. */ ! where_is_data(from, to, buffer) ! int *from, ! *to; ! char *buffer; { ! register int i = 0; ! register int save_to = *to; ! int amidst_data = 0; ! ! ! while (!buffer[i]) ! i++; ! *from = i; ! ! if (*from < 16) /* don't bother */ ! *from = 0; ! /* keep going to make sure there isn't more real data in this record */ ! while (i < RECORDSIZE) { ! if (!buffer[i]) { ! if (amidst_data) { ! save_to = i; ! amidst_data = 0; ! } ! i++; ! } ! else if (buffer[i]) { ! if (!amidst_data) ! amidst_data = 1; ! i++; ! } } ! if (i == RECORDSIZE) ! *to = i; ! else ! *to = save_to; ! } #endif /* Note that this routine is only called if zero_record returned true */ ! #if 0 /* But we actually don't need it at all. */ where_is_data (from, to, buffer) int *from, *to; char *buffer; --- 1014,1192 ---- */ /* There is little point in trimming small amounts of null data at the */ ! /* head and tail of blocks -- it's ok if we only avoid dumping blocks */ ! /* of complete null data */ int ! deal_with_sparse (name, header, nulls_at_end) ! char *name; ! union record *header; ! int nulls_at_end; { ! long numbytes = 0; ! long offset = 0; ! /* long save_offset;*/ ! int fd; ! /* int current_size = hstat.st_size;*/ ! int sparse_ind = 0, cc; ! char buf[RECORDSIZE]; #if 0 ! int read_last_data = 0; /* did we just read the last record? */ #endif ! int amidst_data = 0; ! ! header->header.isextended = 0; ! /* * Can't open the file -- this problem will be caught later on, * so just return. */ ! if ((fd = open (name, O_RDONLY)) < 0) ! return 0; ! ! init_sparsearray (); ! clear_buffer (buf); ! ! while ((cc = read (fd, buf, sizeof buf)) != 0) ! { ! ! if (sparse_ind > sp_array_size - 1) ! { ! ! /* * realloc the scratch area, since we've run out of room -- */ ! sparsearray = (struct sp_array *) ! ck_realloc (sparsearray, ! 2 * sp_array_size * (sizeof (struct sp_array))); ! sp_array_size *= 2; ! } ! if (cc == sizeof buf) ! { ! if (zero_record (buf)) ! { ! if (amidst_data) ! { ! sparsearray[sparse_ind++].numbytes ! = numbytes; ! amidst_data = 0; ! } ! } ! else ! { /* !zero_record(buf) */ ! if (amidst_data) ! numbytes += cc; ! else ! { ! amidst_data = 1; ! numbytes = cc; ! sparsearray[sparse_ind].offset ! = offset; } ! } } ! else if (cc < sizeof buf) ! { ! /* This has to be the last bit of the file, so this */ ! /* is somewhat shorter than the above. */ ! if (!zero_record (buf)) ! { ! if (!amidst_data) ! { ! amidst_data = 1; ! numbytes = cc; ! sparsearray[sparse_ind].offset ! = offset; ! } ! else ! numbytes += cc; ! } ! } ! offset += cc; ! clear_buffer (buf); ! } ! if (amidst_data) ! sparsearray[sparse_ind++].numbytes = numbytes; ! else ! { ! sparsearray[sparse_ind].offset = offset-1; ! sparsearray[sparse_ind++].numbytes = 1; ! } ! close (fd); ! return sparse_ind - 1; } ! /* * Just zeroes out the buffer so we don't confuse ourselves with leftover * data. */ void ! clear_buffer (buf) ! char *buf; { ! register int i; ! for (i = 0; i < RECORDSIZE; i++) ! buf[i] = '\0'; } ! #if 0 /* I'm leaving this as a monument to Joy Kendall, who wrote it -mib */ ! /* ! * JK - * This routine takes a character array, and tells where within that array * the data can be found. It skips over any zeros, and sets the first * non-zero point in the array to be the "start", and continues until it ! * finds non-data again, which is marked as the "end." This routine is * mainly for 1) seeing how far into a file we must lseek to data, given * that we have a sparse file, and 2) determining the "real size" of the * file, i.e., the number of bytes in the sparse file that are data, as * opposed to the zeros we are trying to skip. */ ! where_is_data (from, to, buffer) ! int *from, *to; ! char *buffer; { ! register int i = 0; ! register int save_to = *to; ! int amidst_data = 0; ! ! ! while (!buffer[i]) ! i++; ! *from = i; ! ! if (*from < 16) /* don't bother */ ! *from = 0; ! /* keep going to make sure there isn't more real data in this record */ ! while (i < RECORDSIZE) ! { ! if (!buffer[i]) ! { ! if (amidst_data) ! { ! save_to = i; ! amidst_data = 0; ! } ! i++; ! } ! else if (buffer[i]) ! { ! if (!amidst_data) ! amidst_data = 1; ! i++; } ! } ! if (i == RECORDSIZE) ! *to = i; ! else ! *to = save_to; ! } + #endif /* Note that this routine is only called if zero_record returned true */ ! #if 0 /* But we actually don't need it at all. */ where_is_data (from, to, buffer) int *from, *to; char *buffer; *************** *** 1124,1136 **** { char *fp, *tp; ! for (fp = buffer; ! *fp; fp++) ; ! for (tp = buffer + RECORDSIZE - 1; ! *tp; tp--) ; *from = fp - buffer; *to = tp - buffer + 1; } #endif --- 1193,1206 ---- { char *fp, *tp; ! for (fp = buffer; !*fp; fp++) ; ! for (tp = buffer + RECORDSIZE - 1; !*tp; tp--) ; *from = fp - buffer; *to = tp - buffer + 1; } + #endif *************** *** 1141,1256 **** * something that is a non-zero, i.e., useful data. */ int ! zero_record(buffer) ! char *buffer; { ! register int i; ! for (i = 0; i < RECORDSIZE; i++) ! if (buffer[i] != '\000') ! return 0; ! return 1; } void ! find_new_file_size(filesize, highest_index) ! int *filesize; ! int highest_index; { ! register int i; ! *filesize = 0; ! for (i = 0; sparsearray[i].numbytes && i <= highest_index; i++) ! *filesize += sparsearray[i].numbytes; } ! /* * Make a header block for the file name whose stat info is st . * Return header pointer for success, NULL if the name is too long. */ union record * ! start_header(name, st) ! char *name; ! register struct stat *st; { ! register union record *header; ! if (strlen (name) >= NAMSIZ) ! write_long (name, LF_LONGNAME); ! header = (union record *) findrec(); ! bzero(header->charptr, sizeof(*header)); /* XXX speed up */ ! /* * Check the file name and put it in the record. */ ! if(!f_absolute_paths) { ! static int warned_once = 0; #ifdef __MSDOS__ ! if(name[1]==':') { ! name+=2; ! if(!warned_once++) ! msg("Removing drive spec from names in the archive"); ! } ! #endif ! while ('/' == *name) { ! name++; /* Force relative path */ ! if (!warned_once++) ! msg("Removing leading / from absolute path names in the archive."); ! } } ! current_file_name = name; ! strncpy(header->header.arch_name, name, NAMSIZ); ! header->header.arch_name[NAMSIZ-1] = '\0'; ! ! to_oct((long) (st->st_mode & 07777), ! 8, header->header.mode); ! to_oct((long) st->st_uid, 8, header->header.uid); ! to_oct((long) st->st_gid, 8, header->header.gid); ! to_oct((long) st->st_size, 1+12, header->header.size); ! to_oct((long) st->st_mtime, 1+12, header->header.mtime); ! /* header->header.linkflag is left as null */ ! if(f_gnudump) { ! to_oct((long) st->st_atime, 1+12, header->header.atime); ! to_oct((long) st->st_ctime, 1+12, header->header.ctime); } #ifndef NONAMES ! /* Fill in new Unix Standard fields if desired. */ ! if (f_standard) { ! header->header.linkflag = LF_NORMAL; /* New default */ ! strcpy(header->header.magic, TMAGIC); /* Mark as Unix Std */ ! finduname(header->header.uname, st->st_uid); ! findgname(header->header.gname, st->st_gid); ! } #endif ! return header; } ! /* * Finish off a filled-in header block and write it out. * We also print the file name and/or full info if verbose is on. */ void ! finish_header(header) ! register union record *header; { ! register int i, sum; ! register char *p; ! bcopy(CHKBLANKS, header->header.chksum, sizeof(header->header.chksum)); ! sum = 0; ! p = header->charptr; ! for (i = sizeof(*header); --i >= 0; ) { ! /* * We can't use unsigned char here because of old compilers, * e.g. V7. */ ! sum += 0xFF & *p++; ! } ! /* * Fill in the checksum field. It's formatted differently * from the other fields: it has [6] digits, a null, then a * space -- rather than digits, a space, then a null. --- 1211,1332 ---- * something that is a non-zero, i.e., useful data. */ int ! zero_record (buffer) ! char *buffer; { ! register int i; ! for (i = 0; i < RECORDSIZE; i++) ! if (buffer[i] != '\000') ! return 0; ! return 1; } void ! find_new_file_size (filesize, highest_index) ! int *filesize; ! int highest_index; { ! register int i; ! *filesize = 0; ! for (i = 0; sparsearray[i].numbytes && i <= highest_index; i++) ! *filesize += sparsearray[i].numbytes; } ! /* * Make a header block for the file name whose stat info is st . * Return header pointer for success, NULL if the name is too long. */ union record * ! start_header (name, st) ! char *name; ! register struct stat *st; { ! register union record *header; ! if (strlen (name) >= NAMSIZ) ! write_long (name, LF_LONGNAME); ! header = (union record *) findrec (); ! bzero (header->charptr, sizeof (*header)); /* XXX speed up */ ! /* * Check the file name and put it in the record. */ ! if (!f_absolute_paths) ! { ! static int warned_once = 0; #ifdef __MSDOS__ ! if (name[1] == ':') ! { ! name += 2; ! if (!warned_once++) ! msg ("Removing drive spec from names in the archive"); } ! #endif ! while ('/' == *name) ! { ! name++; /* Force relative path */ ! if (!warned_once++) ! msg ("Removing leading / from absolute path names in the archive."); } + } + current_file_name = name; + strncpy (header->header.arch_name, name, NAMSIZ); + header->header.arch_name[NAMSIZ - 1] = '\0'; + + to_oct ((long) (f_oldarch ? (st->st_mode & 07777) : st->st_mode), + 8, header->header.mode); + to_oct ((long) st->st_uid, 8, header->header.uid); + to_oct ((long) st->st_gid, 8, header->header.gid); + to_oct ((long) st->st_size, 1 + 12, header->header.size); + to_oct ((long) st->st_mtime, 1 + 12, header->header.mtime); + /* header->header.linkflag is left as null */ + if (f_gnudump) + { + to_oct ((long) st->st_atime, 1 + 12, header->header.atime); + to_oct ((long) st->st_ctime, 1 + 12, header->header.ctime); + } #ifndef NONAMES ! /* Fill in new Unix Standard fields if desired. */ ! if (f_standard) ! { ! header->header.linkflag = LF_NORMAL; /* New default */ ! strcpy (header->header.magic, TMAGIC); /* Mark as Unix Std */ ! finduname (header->header.uname, st->st_uid); ! findgname (header->header.gname, st->st_gid); ! } #endif ! return header; } ! /* * Finish off a filled-in header block and write it out. * We also print the file name and/or full info if verbose is on. */ void ! finish_header (header) ! register union record *header; { ! register int i, sum; ! register char *p; ! bcopy (CHKBLANKS, header->header.chksum, sizeof (header->header.chksum)); ! sum = 0; ! p = header->charptr; ! for (i = sizeof (*header); --i >= 0;) ! { ! /* * We can't use unsigned char here because of old compilers, * e.g. V7. */ ! sum += 0xFF & *p++; ! } ! /* * Fill in the checksum field. It's formatted differently * from the other fields: it has [6] digits, a null, then a * space -- rather than digits, a space, then a null. *************** *** 1261,1283 **** * This is a fast way to do: * (void) sprintf(header->header.chksum, "%6o", sum); */ ! to_oct((long) sum, 8, header->header.chksum); ! header->header.chksum[6] = '\0'; /* Zap the space */ ! userec(header); ! if (f_verbose) { ! extern union record *head; /* Points to current tape header */ ! extern int head_standard; /* Tape header is in ANSI format */ ! /* These globals are parameters to print_header, sigh */ ! head = header; ! /* hstat is already set up */ ! head_standard = f_standard; ! print_header(); ! } ! return; } --- 1337,1360 ---- * This is a fast way to do: * (void) sprintf(header->header.chksum, "%6o", sum); */ ! to_oct ((long) sum, 8, header->header.chksum); ! header->header.chksum[6] = '\0'; /* Zap the space */ ! userec (header); ! if (f_verbose) ! { ! extern union record *head;/* Points to current tape header */ ! extern int head_standard; /* Tape header is in ANSI format */ ! /* These globals are parameters to print_header, sigh */ ! head = header; ! /* hstat is already set up */ ! head_standard = f_standard; ! print_header (); ! } ! return; } *************** *** 1295,1319 **** * except that sprintf fills in the trailing null and we don't. */ void ! to_oct(value, digs, where) ! register long value; ! register int digs; ! register char *where; { - - --digs; /* Trailing null slot is left alone */ - where[--digs] = ' '; /* Put in the space, though */ - - /* Produce the digits -- at least one */ - do { - where[--digs] = '0' + (char)(value & 7); /* one octal digit */ - value >>= 3; - } while (digs > 0 && value != 0); - - /* Leading spaces, if necessary */ - while (digs > 0) - where[--digs] = ' '; } --- 1372,1398 ---- * except that sprintf fills in the trailing null and we don't. */ void ! to_oct (value, digs, where) ! register long value; ! register int digs; ! register char *where; { + --digs; /* Trailing null slot is left alone */ + where[--digs] = ' '; /* Put in the space, though */ + + /* Produce the digits -- at least one */ + do + { + where[--digs] = '0' + (char) (value & 7); /* one octal digit */ + value >>= 3; + } + while (digs > 0 && value != 0); + + /* Leading spaces, if necessary */ + while (digs > 0) + where[--digs] = ' '; + } *************** *** 1323,1343 **** * Old tar writes garbage after two zeroed records -- and PDtar used to. */ void ! write_eot() { ! union record *p; ! int bufsize; ! p = findrec(); ! if (p) ! { ! bufsize = endofrecs()->charptr - p->charptr; ! bzero(p->charptr, bufsize); ! userec(p); ! } } /* Write a LF_LONGLINK or LF_LONGNAME record. */ write_long (p, type) char *p; char type; --- 1402,1423 ---- * Old tar writes garbage after two zeroed records -- and PDtar used to. */ void ! write_eot () { ! union record *p; ! int bufsize; ! p = findrec (); ! if (p) ! { ! bufsize = endofrecs ()->charptr - p->charptr; ! bzero (p->charptr, bufsize); ! userec (p); ! } } /* Write a LF_LONGLINK or LF_LONGNAME record. */ + void write_long (p, type) char *p; char type; *************** *** 1346,1353 **** int bufsize; union record *header; struct stat foo; - bzero (&foo, sizeof foo); foo.st_size = size; --- 1426,1433 ---- int bufsize; union record *header; struct stat foo; + bzero (&foo, sizeof foo); foo.st_size = size; *************** *** 1356,1374 **** finish_header (header); header = findrec (); ! bufsize = endofrecs ()->charptr - header->charptr; ! while (bufsize < size) { bcopy (p, header->charptr, bufsize); p += bufsize; size -= bufsize; ! userec (header + (bufsize - 1)/RECORDSIZE); header = findrec (); bufsize = endofrecs ()->charptr - header->charptr; } bcopy (p, header->charptr, size); bzero (header->charptr + size, bufsize - size); ! userec (header + (size - 1)/RECORDSIZE); } --- 1436,1454 ---- finish_header (header); header = findrec (); ! bufsize = endofrecs ()->charptr - header->charptr; ! while (bufsize < size) { bcopy (p, header->charptr, bufsize); p += bufsize; size -= bufsize; ! userec (header + (bufsize - 1) / RECORDSIZE); header = findrec (); bufsize = endofrecs ()->charptr - header->charptr; } bcopy (p, header->charptr, size); bzero (header->charptr + size, bufsize - size); ! userec (header + (size - 1) / RECORDSIZE); } diff -c3 tar-1.11.1/diffarch.c tar-1.11.2/diffarch.c *** tar-1.11.1/diffarch.c Mon Sep 14 16:56:54 1992 --- tar-1.11.2/diffarch.c Mon Mar 15 13:47:17 1993 *************** *** 1,5 **** /* Diff files from a tar archive. ! Copyright (C) 1988, 1992 Free Software Foundation This file is part of GNU Tar. --- 1,5 ---- /* Diff files from a tar archive. ! Copyright (C) 1988, 1992, 1993 Free Software Foundation This file is part of GNU Tar. *************** *** 51,86 **** #define lstat stat #endif ! extern void *valloc(); ! extern union record *head; /* Points to current tape header */ ! extern struct stat hstat; /* Stat struct corresponding */ ! extern int head_standard; /* Tape header is in ANSI format */ ! ! void decode_header(); ! void diff_sparse_files(); ! void fill_in_sparse_array(); ! void fl_read(); ! long from_oct(); ! int do_stat(); ! extern void print_header(); ! int read_header(); ! void saverec(); ! void sigh(); ! extern void skip_file(); ! extern void skip_extended_headers(); ! int wantbytes(); extern FILE *msg_file; int now_verifying = 0; /* Are we verifying at the moment? */ ! int diff_fd; /* Descriptor of file we're diffing */ ! char *diff_buf = 0; /* Pointer to area for reading file contents into */ ! char *diff_dir; /* Directory contents for LF_DUMPDIR */ int different = 0; --- 51,86 ---- #define lstat stat #endif ! extern void *valloc (); ! extern union record *head; /* Points to current tape header */ ! extern struct stat hstat; /* Stat struct corresponding */ ! extern int head_standard; /* Tape header is in ANSI format */ ! ! void decode_header (); ! void diff_sparse_files (); ! void fill_in_sparse_array (); ! void fl_read (); ! long from_oct (); ! int do_stat (); ! extern void print_header (); ! int read_header (); ! void saverec (); ! void sigh (); ! extern void skip_file (); ! extern void skip_extended_headers (); ! int wantbytes (); extern FILE *msg_file; int now_verifying = 0; /* Are we verifying at the moment? */ ! int diff_fd; /* Descriptor of file we're diffing */ ! char *diff_buf = 0; /* Pointer to area for reading file contents into */ ! char *diff_dir; /* Directory contents for LF_DUMPDIR */ int different = 0; *************** *** 90,104 **** * Initialize for a diff operation */ void ! diff_init() { ! /*NOSTRICT*/ ! diff_buf = (char *) valloc((unsigned)blocksize); ! if (!diff_buf) { ! msg("could not allocate memory for diff buffer of %d bytes", ! blocksize); ! exit(EX_ARGSBAD); ! } } /* --- 90,105 ---- * Initialize for a diff operation */ void ! diff_init () { ! /*NOSTRICT*/ ! diff_buf = (char *) valloc ((unsigned) blocksize); ! if (!diff_buf) ! { ! msg ("could not allocate memory for diff buffer of %d bytes", ! blocksize); ! exit (EX_ARGSBAD); ! } } /* *************** *** 105,441 **** * Diff a file against the archive. */ void ! diff_archive() { ! register char *data; ! int check, namelen; ! int err; ! long offset; ! struct stat filestat; ! int compare_chunk(); ! int compare_dir(); ! int no_op(); #ifndef __MSDOS__ ! dev_t dev; ! ino_t ino; #endif ! char *get_dir_contents(); ! long from_oct(); ! ! errno = EPIPE; /* FIXME, remove perrors */ ! ! saverec(&head); /* Make sure it sticks around */ ! userec(head); /* And go past it in the archive */ ! decode_header(head, &hstat, &head_standard, 1); /* Snarf fields */ ! ! /* Print the record from 'head' and 'hstat' */ ! if (f_verbose) { ! if(now_verifying) ! fprintf(msg_file,"Verify "); ! print_header(); ! } ! ! switch (head->header.linkflag) { ! default: ! msg("Unknown file type '%c' for %s, diffed as normal file", ! head->header.linkflag, current_file_name); ! /* FALL THRU */ ! case LF_OLDNORMAL: ! case LF_NORMAL: ! case LF_SPARSE: ! case LF_CONTIG: ! /* * Appears to be a file. * See if it's really a directory. */ ! namelen = strlen(current_file_name)-1; ! if (current_file_name[namelen] == '/') ! goto really_dir; ! ! ! if(do_stat(&filestat)) { ! if (head->header.isextended) ! skip_extended_headers(); ! skip_file((long)hstat.st_size); ! different++; ! goto quit; ! } - if (!S_ISREG(filestat.st_mode)) { - fprintf(msg_file, "%s: not a regular file\n", - current_file_name); - skip_file((long)hstat.st_size); - different++; - goto quit; - } ! filestat.st_mode &= 07777; ! if (filestat.st_mode != hstat.st_mode) ! sigh("mode"); ! if (filestat.st_uid != hstat.st_uid) ! sigh("uid"); ! if (filestat.st_gid != hstat.st_gid) ! sigh("gid"); ! if (filestat.st_mtime != hstat.st_mtime) ! sigh("mod time"); ! if (head->header.linkflag != LF_SPARSE && ! filestat.st_size != hstat.st_size) { ! sigh("size"); ! skip_file((long)hstat.st_size); ! goto quit; ! } ! diff_fd = open(current_file_name, O_NDELAY|O_RDONLY|O_BINARY); ! if (diff_fd < 0 && !f_absolute_paths) { ! char tmpbuf[NAMSIZ+2]; ! tmpbuf[0]='/'; ! strcpy(&tmpbuf[1],current_file_name); ! diff_fd=open(tmpbuf, O_NDELAY|O_RDONLY); ! } ! if (diff_fd < 0) { ! msg_perror("cannot open %s",current_file_name); ! if (head->header.isextended) ! skip_extended_headers(); ! skip_file((long)hstat.st_size); ! different++; ! goto quit; ! } ! /* * Need to treat sparse files completely differently here. */ ! if (head->header.linkflag == LF_SPARSE) ! diff_sparse_files(hstat.st_size); ! else ! wantbytes((long)(hstat.st_size),compare_chunk); ! ! check = close(diff_fd); ! if (check < 0) ! msg_perror("Error while closing %s",current_file_name); ! quit: ! break; #ifndef __MSDOS__ ! case LF_LINK: ! if(do_stat(&filestat)) ! break; ! dev = filestat.st_dev; ! ino = filestat.st_ino; ! err = stat(current_link_name, &filestat); ! if (err < 0) { ! if (errno==ENOENT) { ! fprintf(msg_file, "%s: does not exist\n",current_file_name); ! } else { ! msg_perror("cannot stat file %s",current_file_name); ! } ! different++; ! break; ! } ! if(filestat.st_dev!=dev || filestat.st_ino!=ino) { ! fprintf(msg_file, "%s not linked to %s\n",current_file_name,current_link_name); ! break; ! } ! break; #endif #ifdef S_ISLNK ! case LF_SYMLINK: ! { ! char linkbuf[NAMSIZ+3]; ! check = readlink(current_file_name, linkbuf, ! (sizeof linkbuf)-1); ! ! if (check < 0) { ! if (errno == ENOENT) { ! fprintf(msg_file, ! "%s: no such file or directory\n", ! current_file_name); ! } else { ! msg_perror("cannot read link %s",current_file_name); ! } ! different++; ! break; ! } ! ! linkbuf[check] = '\0'; /* Null-terminate it */ ! if (strncmp(current_link_name, linkbuf, check) != 0) { ! fprintf(msg_file, "%s: symlink differs\n", ! current_link_name); ! different++; ! } ! } ! break; #endif #ifdef S_IFCHR ! case LF_CHR: ! hstat.st_mode |= S_IFCHR; ! goto check_node; #endif #ifdef S_IFBLK ! /* If local system doesn't support block devices, use default case */ ! case LF_BLK: ! hstat.st_mode |= S_IFBLK; ! goto check_node; #endif #ifdef S_ISFIFO ! /* If local system doesn't support FIFOs, use default case */ ! case LF_FIFO: #ifdef S_IFIFO ! hstat.st_mode |= S_IFIFO; #endif ! hstat.st_rdev = 0; /* FIXME, do we need this? */ ! goto check_node; #endif ! check_node: ! /* FIXME, deal with umask */ ! if(do_stat(&filestat)) ! break; ! if(hstat.st_rdev != filestat.st_rdev) { ! fprintf(msg_file, "%s: device numbers changed\n", current_file_name); ! different++; ! break; ! } #ifdef S_IFMT ! if(hstat.st_mode != filestat.st_mode) #else /* POSIX lossage */ ! if((hstat.st_mode & 07777) != (filestat.st_mode & 07777)) #endif ! { ! fprintf(msg_file, "%s: mode or device-type changed\n", current_file_name); ! different++; ! break; ! } ! break; ! case LF_DUMPDIR: ! data=diff_dir=get_dir_contents(current_file_name,0); ! if (data) { ! wantbytes((long)(hstat.st_size),compare_dir); ! free(data); ! } else ! wantbytes((long)(hstat.st_size),no_op); ! /* FALL THROUGH */ ! ! case LF_DIR: ! /* Check for trailing / */ ! namelen = strlen(current_file_name)-1; ! really_dir: ! while (namelen && current_file_name[namelen] == '/') ! current_file_name[namelen--] = '\0'; /* Zap / */ ! ! if(do_stat(&filestat)) ! break; ! if(!S_ISDIR(filestat.st_mode)) { ! fprintf(msg_file, "%s is no longer a directory\n",current_file_name); ! different++; ! break; ! } ! if((filestat.st_mode&07777) != (hstat.st_mode&07777)) ! sigh("mode"); ! break; ! ! case LF_VOLHDR: ! break; ! ! case LF_MULTIVOL: ! namelen = strlen(current_file_name)-1; ! if (current_file_name[namelen] == '/') ! goto really_dir; ! ! if(do_stat(&filestat)) ! break; ! ! if (!S_ISREG(filestat.st_mode)) { ! fprintf(msg_file, "%s: not a regular file\n", ! current_file_name); ! skip_file((long)hstat.st_size); ! different++; ! break; ! } ! filestat.st_mode &= 07777; ! offset = from_oct(1+12, head->header.offset); ! if (filestat.st_size != hstat.st_size + offset) { ! sigh("size"); ! skip_file((long)hstat.st_size); ! different++; ! break; ! } ! diff_fd = open(current_file_name, O_NDELAY|O_RDONLY|O_BINARY); ! if (diff_fd < 0) { ! msg_perror("cannot open file %s",current_file_name); ! skip_file((long)hstat.st_size); ! different++; ! break; ! } ! err = lseek(diff_fd, offset, 0); ! if(err!=offset) { ! msg_perror("cannot seek to %ld in file %s",offset,current_file_name); ! different++; ! break; ! } ! wantbytes((long)(hstat.st_size),compare_chunk); ! check = close(diff_fd); ! if (check < 0) { ! msg_perror("Error while closing %s",current_file_name); ! } ! break; } ! /* We don't need to save it any longer. */ ! saverec((union record **) 0); /* Unsave it */ } int ! compare_chunk(bytes,buffer) ! long bytes; ! char *buffer; { ! int err; ! err=read(diff_fd,diff_buf,bytes); ! if(err!=bytes) { ! if(err<0) { ! msg_perror("can't read %s",current_file_name); ! } else { ! fprintf(msg_file,"%s: could only read %d of %d bytes\n",current_file_name,err,bytes); ! } ! different++; ! return -1; } ! if(bcmp(buffer,diff_buf,bytes)) { ! fprintf(msg_file, "%s: data differs\n",current_file_name); ! different++; ! return -1; } ! return 0; } int ! compare_dir(bytes,buffer) ! long bytes; ! char *buffer; { ! if(bcmp(buffer,diff_dir,bytes)) { ! fprintf(msg_file, "%s: data differs\n",current_file_name); ! different++; ! return -1; ! } ! diff_dir+=bytes; ! return 0; } /* --- 106,474 ---- * Diff a file against the archive. */ void ! diff_archive () { ! register char *data; ! int check, namelen; ! int err; ! long offset; ! struct stat filestat; ! int compare_chunk (); ! int compare_dir (); ! int no_op (); #ifndef __MSDOS__ ! dev_t dev; ! ino_t ino; #endif ! char *get_dir_contents (); ! long from_oct (); ! errno = EPIPE; /* FIXME, remove perrors */ ! saverec (&head); /* Make sure it sticks around */ ! userec (head); /* And go past it in the archive */ ! decode_header (head, &hstat, &head_standard, 1); /* Snarf fields */ ! ! /* Print the record from 'head' and 'hstat' */ ! if (f_verbose) ! { ! if (now_verifying) ! fprintf (msg_file, "Verify "); ! print_header (); ! } ! ! switch (head->header.linkflag) ! { ! ! default: ! msg ("Unknown file type '%c' for %s, diffed as normal file", ! head->header.linkflag, current_file_name); ! /* FALL THRU */ ! ! case LF_OLDNORMAL: ! case LF_NORMAL: ! case LF_SPARSE: ! case LF_CONTIG: ! /* * Appears to be a file. * See if it's really a directory. */ ! namelen = strlen (current_file_name) - 1; ! if (current_file_name[namelen] == '/') ! goto really_dir; ! if (do_stat (&filestat)) ! { ! if (head->header.isextended) ! skip_extended_headers (); ! skip_file ((long) hstat.st_size); ! different++; ! goto quit; ! } ! ! if (!S_ISREG (filestat.st_mode)) ! { ! fprintf (msg_file, "%s: not a regular file\n", ! current_file_name); ! skip_file ((long) hstat.st_size); ! different++; ! goto quit; ! } ! ! filestat.st_mode &= 07777; ! if (filestat.st_mode != hstat.st_mode) ! sigh ("mode"); ! if (filestat.st_uid != hstat.st_uid) ! sigh ("uid"); ! if (filestat.st_gid != hstat.st_gid) ! sigh ("gid"); ! if (filestat.st_mtime != hstat.st_mtime) ! sigh ("mod time"); ! if (head->header.linkflag != LF_SPARSE && ! filestat.st_size != hstat.st_size) ! { ! sigh ("size"); ! skip_file ((long) hstat.st_size); ! goto quit; ! } ! diff_fd = open (current_file_name, O_NDELAY | O_RDONLY | O_BINARY); ! if (diff_fd < 0 && !f_absolute_paths) ! { ! char tmpbuf[NAMSIZ + 2]; ! tmpbuf[0] = '/'; ! strcpy (&tmpbuf[1], current_file_name); ! diff_fd = open (tmpbuf, O_NDELAY | O_RDONLY); ! } ! if (diff_fd < 0) ! { ! msg_perror ("cannot open %s", current_file_name); ! if (head->header.isextended) ! skip_extended_headers (); ! skip_file ((long) hstat.st_size); ! different++; ! goto quit; ! } ! /* * Need to treat sparse files completely differently here. */ ! if (head->header.linkflag == LF_SPARSE) ! diff_sparse_files (hstat.st_size); ! else ! wantbytes ((long) (hstat.st_size), compare_chunk); ! ! check = close (diff_fd); ! if (check < 0) ! msg_perror ("Error while closing %s", current_file_name); ! quit: ! break; #ifndef __MSDOS__ ! case LF_LINK: ! if (do_stat (&filestat)) ! break; ! dev = filestat.st_dev; ! ino = filestat.st_ino; ! err = stat (current_link_name, &filestat); ! if (err < 0) ! { ! if (errno == ENOENT) ! { ! fprintf (msg_file, "%s: does not exist\n", current_file_name); ! } ! else ! { ! msg_perror ("cannot stat file %s", current_file_name); ! } ! different++; ! break; ! } ! if (filestat.st_dev != dev || filestat.st_ino != ino) ! { ! fprintf (msg_file, "%s not linked to %s\n", current_file_name, current_link_name); ! break; ! } ! break; #endif #ifdef S_ISLNK ! case LF_SYMLINK: ! { ! char linkbuf[NAMSIZ + 3]; ! check = readlink (current_file_name, linkbuf, ! (sizeof linkbuf) - 1); ! ! if (check < 0) ! { ! if (errno == ENOENT) ! { ! fprintf (msg_file, ! "%s: no such file or directory\n", ! current_file_name); ! } ! else ! { ! msg_perror ("cannot read link %s", current_file_name); ! } ! different++; ! break; ! } ! ! linkbuf[check] = '\0'; /* Null-terminate it */ ! if (strncmp (current_link_name, linkbuf, check) != 0) ! { ! fprintf (msg_file, "%s: symlink differs\n", ! current_link_name); ! different++; ! } ! } ! break; #endif #ifdef S_IFCHR ! case LF_CHR: ! hstat.st_mode |= S_IFCHR; ! goto check_node; #endif #ifdef S_IFBLK ! /* If local system doesn't support block devices, use default case */ ! case LF_BLK: ! hstat.st_mode |= S_IFBLK; ! goto check_node; #endif #ifdef S_ISFIFO ! /* If local system doesn't support FIFOs, use default case */ ! case LF_FIFO: #ifdef S_IFIFO ! hstat.st_mode |= S_IFIFO; #endif ! hstat.st_rdev = 0; /* FIXME, do we need this? */ ! goto check_node; #endif ! check_node: ! /* FIXME, deal with umask */ ! if (do_stat (&filestat)) ! break; ! if (hstat.st_rdev != filestat.st_rdev) ! { ! fprintf (msg_file, "%s: device numbers changed\n", current_file_name); ! different++; ! break; ! } #ifdef S_IFMT ! if (hstat.st_mode != filestat.st_mode) #else /* POSIX lossage */ ! if ((hstat.st_mode & 07777) != (filestat.st_mode & 07777)) #endif ! { ! fprintf (msg_file, "%s: mode or device-type changed\n", current_file_name); ! different++; ! break; ! } ! break; ! ! case LF_DUMPDIR: ! data = diff_dir = get_dir_contents (current_file_name, 0); ! if (data) ! { ! wantbytes ((long) (hstat.st_size), compare_dir); ! free (data); ! } ! else ! wantbytes ((long) (hstat.st_size), no_op); ! /* FALL THROUGH */ ! ! case LF_DIR: ! /* Check for trailing / */ ! namelen = strlen (current_file_name) - 1; ! really_dir: ! while (namelen && current_file_name[namelen] == '/') ! current_file_name[namelen--] = '\0'; /* Zap / */ ! ! if (do_stat (&filestat)) ! break; ! if (!S_ISDIR (filestat.st_mode)) ! { ! fprintf (msg_file, "%s is no longer a directory\n", current_file_name); ! different++; ! break; ! } ! if ((filestat.st_mode & 07777) != (hstat.st_mode & 07777)) ! sigh ("mode"); ! break; ! ! case LF_VOLHDR: ! break; ! ! case LF_MULTIVOL: ! namelen = strlen (current_file_name) - 1; ! if (current_file_name[namelen] == '/') ! goto really_dir; ! if (do_stat (&filestat)) ! break; ! if (!S_ISREG (filestat.st_mode)) ! { ! fprintf (msg_file, "%s: not a regular file\n", ! current_file_name); ! skip_file ((long) hstat.st_size); ! different++; ! break; ! } ! filestat.st_mode &= 07777; ! offset = from_oct (1 + 12, head->header.offset); ! if (filestat.st_size != hstat.st_size + offset) ! { ! sigh ("size"); ! skip_file ((long) hstat.st_size); ! different++; ! break; ! } ! diff_fd = open (current_file_name, O_NDELAY | O_RDONLY | O_BINARY); ! if (diff_fd < 0) ! { ! msg_perror ("cannot open file %s", current_file_name); ! skip_file ((long) hstat.st_size); ! different++; ! break; ! } ! err = lseek (diff_fd, offset, 0); ! if (err != offset) ! { ! msg_perror ("cannot seek to %ld in file %s", offset, current_file_name); ! different++; ! break; ! } ! wantbytes ((long) (hstat.st_size), compare_chunk); + check = close (diff_fd); + if (check < 0) + { + msg_perror ("Error while closing %s", current_file_name); } + break; + + } ! /* We don't need to save it any longer. */ ! saverec ((union record **) 0);/* Unsave it */ } int ! compare_chunk (bytes, buffer) ! long bytes; ! char *buffer; { ! int err; ! err = read (diff_fd, diff_buf, bytes); ! if (err != bytes) ! { ! if (err < 0) ! { ! msg_perror ("can't read %s", current_file_name); } ! else ! { ! fprintf (msg_file, "%s: could only read %d of %d bytes\n", current_file_name, err, bytes); } ! different++; ! return -1; ! } ! if (bcmp (buffer, diff_buf, bytes)) ! { ! fprintf (msg_file, "%s: data differs\n", current_file_name); ! different++; ! return -1; ! } ! return 0; } int ! compare_dir (bytes, buffer) ! long bytes; ! char *buffer; { ! if (bcmp (buffer, diff_dir, bytes)) ! { ! fprintf (msg_file, "%s: data differs\n", current_file_name); ! different++; ! return -1; ! } ! diff_dir += bytes; ! return 0; } /* *************** *** 442,623 **** * Sigh about something that differs. */ void ! sigh(what) ! char *what; { ! fprintf(msg_file, "%s: %s differs\n", ! current_file_name, what); } void ! verify_volume() { ! int status; #ifdef MTIOCTOP ! struct mtop t; ! int er; #endif ! if(!diff_buf) ! diff_init(); #ifdef MTIOCTOP ! t.mt_op = MTBSF; ! t.mt_count = 1; ! if((er=rmtioctl(archive,MTIOCTOP,&t))<0) { ! if(errno!=EIO || (er=rmtioctl(archive,MTIOCTOP,&t))<0) { ! #endif ! if(rmtlseek(archive,0L,0)!=0) { ! /* Lseek failed. Try a different method */ ! msg_perror("Couldn't rewind archive file for verify"); ! return; ! } #ifdef MTIOCTOP - } } #endif ! ar_reading=1; ! now_verifying = 1; ! fl_read(); ! for(;;) { ! status = read_header(); ! if(status==0) { ! unsigned n; ! ! n=0; ! do { ! n++; ! status=read_header(); ! } while(status==0); ! msg("VERIFY FAILURE: %d invalid header%s detected!",n,n==1?"":"s"); ! } ! if(status==2 || status==EOF) ! break; ! diff_archive(); } ! ar_reading=0; ! now_verifying = 0; } int ! do_stat(statp) ! struct stat *statp; { ! int err; ! err = f_follow_links ? stat(current_file_name, statp) : lstat(current_file_name, statp); ! if (err < 0) { ! if (errno==ENOENT) { ! fprintf(msg_file, "%s: does not exist\n",current_file_name); ! } else ! msg_perror("can't stat file %s",current_file_name); ! /* skip_file((long)hstat.st_size); different++;*/ ! return 1; ! } else ! return 0; } /* * JK ! * Diff'ing a sparse file with its counterpart on the tar file is a * bit of a different story than a normal file. First, we must know * what areas of the file to skip through, i.e., we need to contruct * a sparsearray, which will hold all the information we need. We must ! * compare small amounts of data at a time as we find it. */ void ! diff_sparse_files(filesize) ! int filesize; { ! int sparse_ind = 0; ! char *buf; ! int buf_size = RECORDSIZE; ! union record *datarec; ! int err; ! long numbytes; ! /* int amt_read = 0;*/ ! int size = filesize; ! ! buf = (char *) malloc(buf_size * sizeof (char)); ! ! fill_in_sparse_array(); ! ! ! while (size > 0) { ! datarec = findrec(); ! if (!sparsearray[sparse_ind].numbytes) ! break; ! /* * 'numbytes' is nicer to write than * 'sparsearray[sparse_ind].numbytes' all the time ... */ ! numbytes = sparsearray[sparse_ind].numbytes; ! ! lseek(diff_fd, sparsearray[sparse_ind].offset, 0); ! /* * take care to not run out of room in our buffer */ ! while (buf_size < numbytes) { ! buf = (char *) realloc(buf, buf_size * 2 * sizeof(char)); ! buf_size *= 2; ! } ! while (numbytes > RECORDSIZE) { ! if ((err = read(diff_fd, buf, RECORDSIZE)) != RECORDSIZE) { ! if (err < 0) ! msg_perror("can't read %s", current_file_name); ! else ! fprintf(msg_file, "%s: could only read %d of %d bytes\n", ! err, numbytes); ! break; ! } ! if (bcmp(buf, datarec->charptr, RECORDSIZE)) { ! different++; ! break; ! } ! numbytes -= err; ! size -= err; ! userec(datarec); ! datarec = findrec(); ! } ! if ((err = read(diff_fd, buf, numbytes)) != numbytes) { ! if (err < 0) ! msg_perror("can't read %s", current_file_name); ! else ! fprintf(msg_file, "%s: could only read %d of %d bytes\n", ! err, numbytes); ! break; ! } ! if (bcmp(buf, datarec->charptr, numbytes)) { ! different++; ! break; ! } ! /* amt_read += numbytes; if (amt_read >= RECORDSIZE) { amt_read = 0; userec(datarec); datarec = findrec(); }*/ ! userec(datarec); ! sparse_ind++; ! size -= numbytes; ! } ! /* * if the number of bytes read isn't the * number of bytes supposedly in the file, * they're different */ ! /* if (amt_read != filesize) different++;*/ ! userec(datarec); ! free(sparsearray); ! if (different) ! fprintf(msg_file, "%s: data differs\n", current_file_name); } --- 475,674 ---- * Sigh about something that differs. */ void ! sigh (what) ! char *what; { ! fprintf (msg_file, "%s: %s differs\n", ! current_file_name, what); } void ! verify_volume () { ! int status; #ifdef MTIOCTOP ! struct mtop t; ! int er; #endif ! if (!diff_buf) ! diff_init (); #ifdef MTIOCTOP ! t.mt_op = MTBSF; ! t.mt_count = 1; ! if ((er = rmtioctl (archive, MTIOCTOP, &t)) < 0) ! { ! if (errno != EIO || (er = rmtioctl (archive, MTIOCTOP, &t)) < 0) ! { ! #endif ! if (rmtlseek (archive, 0L, 0) != 0) ! { ! /* Lseek failed. Try a different method */ ! msg_perror ("Couldn't rewind archive file for verify"); ! return; ! } #ifdef MTIOCTOP } + } #endif ! ar_reading = 1; ! now_verifying = 1; ! fl_read (); ! for (;;) ! { ! status = read_header (); ! if (status == 0) ! { ! unsigned n; ! ! n = 0; ! do ! { ! n++; ! status = read_header (); ! } ! while (status == 0); ! msg ("VERIFY FAILURE: %d invalid header%s detected!", n, n == 1 ? "" : "s"); } ! if (status == 2 || status == EOF) ! break; ! diff_archive (); ! } ! ar_reading = 0; ! now_verifying = 0; } int ! do_stat (statp) ! struct stat *statp; { ! int err; ! err = f_follow_links ? stat (current_file_name, statp) : lstat (current_file_name, statp); ! if (err < 0) ! { ! if (errno == ENOENT) ! { ! fprintf (msg_file, "%s: does not exist\n", current_file_name); ! } ! else ! msg_perror ("can't stat file %s", current_file_name); ! /* skip_file((long)hstat.st_size); different++;*/ ! return 1; ! } ! else ! return 0; } /* * JK ! * Diff'ing a sparse file with its counterpart on the tar file is a * bit of a different story than a normal file. First, we must know * what areas of the file to skip through, i.e., we need to contruct * a sparsearray, which will hold all the information we need. We must ! * compare small amounts of data at a time as we find it. */ void ! diff_sparse_files (filesize) ! int filesize; { ! int sparse_ind = 0; ! char *buf; ! int buf_size = RECORDSIZE; ! union record *datarec; ! int err; ! long numbytes; ! /* int amt_read = 0;*/ ! int size = filesize; ! ! buf = (char *) ck_malloc (buf_size * sizeof (char)); ! ! fill_in_sparse_array (); ! ! ! while (size > 0) ! { ! datarec = findrec (); ! if (!sparsearray[sparse_ind].numbytes) ! break; ! /* * 'numbytes' is nicer to write than * 'sparsearray[sparse_ind].numbytes' all the time ... */ ! numbytes = sparsearray[sparse_ind].numbytes; ! ! lseek (diff_fd, sparsearray[sparse_ind].offset, 0); ! /* * take care to not run out of room in our buffer */ ! while (buf_size < numbytes) ! { ! buf = (char *) ck_realloc (buf, buf_size * 2 * sizeof (char)); ! buf_size *= 2; ! } ! while (numbytes > RECORDSIZE) ! { ! if ((err = read (diff_fd, buf, RECORDSIZE)) != RECORDSIZE) ! { ! if (err < 0) ! msg_perror ("can't read %s", current_file_name); ! else ! fprintf (msg_file, "%s: could only read %d of %d bytes\n", ! current_file_name, err, numbytes); ! break; ! } ! if (bcmp (buf, datarec->charptr, RECORDSIZE)) ! { ! different++; ! break; ! } ! numbytes -= err; ! size -= err; ! userec (datarec); ! datarec = findrec (); ! } ! if ((err = read (diff_fd, buf, numbytes)) != numbytes) ! { ! if (err < 0) ! msg_perror ("can't read %s", current_file_name); ! else ! fprintf (msg_file, "%s: could only read %d of %d bytes\n", ! current_file_name, err, numbytes); ! break; ! } ! if (bcmp (buf, datarec->charptr, numbytes)) ! { ! different++; ! break; ! } ! /* amt_read += numbytes; if (amt_read >= RECORDSIZE) { amt_read = 0; userec(datarec); datarec = findrec(); }*/ ! userec (datarec); ! sparse_ind++; ! size -= numbytes; ! } ! /* * if the number of bytes read isn't the * number of bytes supposedly in the file, * they're different */ ! /* if (amt_read != filesize) different++;*/ ! userec (datarec); ! free (sparsearray); ! if (different) ! fprintf (msg_file, "%s: data differs\n", current_file_name); } *************** *** 631,702 **** * comparisong and such. */ void ! fill_in_sparse_array() { ! int ind; ! /* * allocate space for our scratch space; it's initially * 10 elements long, but can change in this routine if * necessary */ ! sp_array_size = 10; ! sparsearray = (struct sp_array *) malloc(sp_array_size * sizeof(struct sp_array)); ! /* * there are at most five of these structures in the header * itself; read these in first */ ! for (ind = 0; ind < SPARSE_IN_HDR; ind++) { ! if (!head->header.sp[ind].numbytes) ! break; ! sparsearray[ind].offset = ! from_oct(1+12, head->header.sp[ind].offset); ! sparsearray[ind].numbytes = ! from_oct(1+12, head->header.sp[ind].numbytes); ! } ! /* * if the header's extended, we gotta read in exhdr's till * we're done */ ! if (head->header.isextended) { ! /* how far into the sparsearray we are 'so far' */ ! static int so_far_ind = SPARSE_IN_HDR; ! union record *exhdr; ! ! for (;;) { ! exhdr = findrec(); ! for (ind = 0; ind < SPARSE_EXT_HDR; ind++) { ! if (ind+so_far_ind > sp_array_size-1) { ! /* * we just ran out of room in our * scratch area - realloc it */ ! sparsearray = (struct sp_array *) ! realloc(sparsearray, ! sp_array_size*2*sizeof(struct sp_array)); ! sp_array_size *= 2; ! } ! /* * convert the character strings into longs */ ! sparsearray[ind+so_far_ind].offset = ! from_oct(1+12, exhdr->ext_hdr.sp[ind].offset); ! sparsearray[ind+so_far_ind].numbytes = ! from_oct(1+12, exhdr->ext_hdr.sp[ind].numbytes); ! } ! /* * if this is the last extended header for this * file, we can stop */ ! if (!exhdr->ext_hdr.isextended) ! break; ! else { ! so_far_ind += SPARSE_EXT_HDR; ! userec(exhdr); ! } } - /* be sure to skip past the last one */ - userec(exhdr); } } --- 682,759 ---- * comparisong and such. */ void ! fill_in_sparse_array () { ! int ind; ! /* * allocate space for our scratch space; it's initially * 10 elements long, but can change in this routine if * necessary */ ! sp_array_size = 10; ! sparsearray = (struct sp_array *) ck_malloc (sp_array_size * sizeof (struct sp_array)); ! /* * there are at most five of these structures in the header * itself; read these in first */ ! for (ind = 0; ind < SPARSE_IN_HDR; ind++) ! { ! if (!head->header.sp[ind].numbytes) ! break; ! sparsearray[ind].offset = ! from_oct (1 + 12, head->header.sp[ind].offset); ! sparsearray[ind].numbytes = ! from_oct (1 + 12, head->header.sp[ind].numbytes); ! } ! /* * if the header's extended, we gotta read in exhdr's till * we're done */ ! if (head->header.isextended) ! { ! /* how far into the sparsearray we are 'so far' */ ! static int so_far_ind = SPARSE_IN_HDR; ! union record *exhdr; ! ! for (;;) ! { ! exhdr = findrec (); ! for (ind = 0; ind < SPARSE_EXT_HDR; ind++) ! { ! if (ind + so_far_ind > sp_array_size - 1) ! { ! /* * we just ran out of room in our * scratch area - realloc it */ ! sparsearray = (struct sp_array *) ! ck_realloc (sparsearray, ! sp_array_size * 2 * sizeof (struct sp_array)); ! sp_array_size *= 2; ! } ! /* * convert the character strings into longs */ ! sparsearray[ind + so_far_ind].offset = ! from_oct (1 + 12, exhdr->ext_hdr.sp[ind].offset); ! sparsearray[ind + so_far_ind].numbytes = ! from_oct (1 + 12, exhdr->ext_hdr.sp[ind].numbytes); ! } ! /* * if this is the last extended header for this * file, we can stop */ ! if (!exhdr->ext_hdr.isextended) ! break; ! else ! { ! so_far_ind += SPARSE_EXT_HDR; ! userec (exhdr); } } + /* be sure to skip past the last one */ + userec (exhdr); + } } Only in tar-1.11.2: dump-remind diff -c3 tar-1.11.1/extract.c tar-1.11.2/extract.c *** tar-1.11.1/extract.c Tue Sep 15 19:54:58 1992 --- tar-1.11.2/extract.c Tue Mar 16 15:58:01 1993 *************** *** 1,5 **** /* Extract files from a tar archive. ! Copyright (C) 1988, 1992 Free Software Foundation This file is part of GNU Tar. --- 1,5 ---- /* Extract files from a tar archive. ! Copyright (C) 1988, 1992, 1993 Free Software Foundation This file is part of GNU Tar. *************** *** 30,36 **** #endif #include #include ! time_t time(); #ifdef BSD42 #include --- 30,36 ---- #endif #include #include ! time_t time (); #ifdef BSD42 #include *************** *** 61,95 **** long actime; long modtime; }; #endif extern FILE *msg_file; ! extern union record *head; /* Points to current tape header */ ! extern struct stat hstat; /* Stat struct corresponding */ ! extern int head_standard; /* Tape header is in ANSI format */ extern char *save_name; extern long save_totsize; extern long save_sizeleft; ! int confirm(); ! void decode_header(); ! void extract_mangle(); ! void extract_sparse_file(); ! long from_oct(); ! void gnu_restore(); ! extern void print_header(); ! extern void skip_file(); ! extern void skip_extended_headers(); ! extern void pr_mkdir(); ! void saverec(); ! ! int make_dirs(); /* Makes required directories */ ! ! static time_t now = 0; /* Current time */ ! static we_are_root = 0; /* True if our effective uid == 0 */ ! static int notumask = ~0; /* Masks out bits user doesn't want */ /* * "Scratch" space to store the information about a sparse file before --- 61,96 ---- long actime; long modtime; }; + #endif extern FILE *msg_file; ! extern union record *head; /* Points to current tape header */ ! extern struct stat hstat; /* Stat struct corresponding */ ! extern int head_standard; /* Tape header is in ANSI format */ extern char *save_name; extern long save_totsize; extern long save_sizeleft; ! int confirm (); ! void decode_header (); ! void extract_mangle (); ! void extract_sparse_file (); ! long from_oct (); ! void gnu_restore (); ! extern void print_header (); ! extern void skip_file (); ! extern void skip_extended_headers (); ! extern void pr_mkdir (); ! void saverec (); ! ! int make_dirs (); /* Makes required directories */ ! ! static time_t now = 0; /* Current time */ ! static we_are_root = 0; /* True if our effective uid == 0 */ ! static int notumask = ~0; /* Masks out bits user doesn't want */ /* * "Scratch" space to store the information about a sparse file before *************** *** 108,114 **** int mtime; struct saved_dir_info *next; }; ! struct saved_dir_info *saved_dir_info_head; /* --- 109,115 ---- int mtime; struct saved_dir_info *next; }; ! struct saved_dir_info *saved_dir_info_head; /* *************** *** 115,137 **** * Set up to extract files. */ void ! extr_init() { ! int ourmask; ! now = time((time_t *)0); ! if (geteuid() == 0) ! we_are_root = 1; ! /* * We need to know our umask. But if f_use_protection is set, * leave our kernel umask at 0, and our "notumask" at ~0. */ ! ourmask = umask(0); /* Read it */ ! if (!f_use_protection) { ! (void) umask (ourmask); /* Set it back how it was */ ! notumask = ~ourmask; /* Make umask override permissions */ ! } } --- 116,139 ---- * Set up to extract files. */ void ! extr_init () { ! int ourmask; ! now = time ((time_t *) 0); ! if (geteuid () == 0) ! we_are_root = 1; ! /* * We need to know our umask. But if f_use_protection is set, * leave our kernel umask at 0, and our "notumask" at ~0. */ ! ourmask = umask (0); /* Read it */ ! if (!f_use_protection) ! { ! (void) umask (ourmask); /* Set it back how it was */ ! notumask = ~ourmask; /* Make umask override permissions */ ! } } *************** *** 139,176 **** * Extract a file from the archive. */ void ! extract_archive() { ! register char *data; ! int fd, check, namelen, written, openflag; ! long size; ! struct utimbuf acc_upd_times; ! register int skipcrud; ! register int i; ! /* int sparse_ind = 0;*/ ! union record *exhdr; ! struct saved_dir_info *tmp; ! /* int end_nulls; */ ! char **longp; ! char *bp; ! ! saverec(&head); /* Make sure it sticks around */ ! userec(head); /* And go past it in the archive */ ! decode_header(head, &hstat, &head_standard, 1); /* Snarf fields */ ! ! if(f_confirm && !confirm("extract",current_file_name)) { ! if (head->header.isextended) ! skip_extended_headers(); ! skip_file((long)hstat.st_size); ! saverec((union record **)0); ! return; ! } ! ! /* Print the record from 'head' and 'hstat' */ ! if (f_verbose) ! print_header(); ! /* * Check for fully specified pathnames and other atrocities. * * Note, we can't just make a pointer to the new file name, --- 141,177 ---- * Extract a file from the archive. */ void ! extract_archive () { ! register char *data; ! int fd, check, namelen, written, openflag; ! long size; ! struct utimbuf acc_upd_times; ! register int skipcrud; ! register int i; ! /* int sparse_ind = 0;*/ ! union record *exhdr; ! struct saved_dir_info *tmp; ! /* int end_nulls; */ ! ! saverec (&head); /* Make sure it sticks around */ ! userec (head); /* And go past it in the archive */ ! decode_header (head, &hstat, &head_standard, 1); /* Snarf fields */ ! ! if (f_confirm && !confirm ("extract", current_file_name)) ! { ! if (head->header.isextended) ! skip_extended_headers (); ! skip_file ((long) hstat.st_size); ! saverec ((union record **) 0); ! return; ! } ! ! /* Print the record from 'head' and 'hstat' */ ! if (f_verbose) ! print_header (); ! /* * Check for fully specified pathnames and other atrocities. * * Note, we can't just make a pointer to the new file name, *************** *** 178,202 **** * We have to start from "head" every time we want to touch * the header record. */ ! skipcrud = 0; ! while (!f_absolute_paths ! && '/' == current_file_name[skipcrud]) { ! static int warned_once = 0; ! ! skipcrud++; /* Force relative path */ ! if (!warned_once++) { ! msg("Removing leading / from absolute path names in the archive."); ! } ! } ! ! switch (head->header.linkflag) { ! ! default: ! msg("Unknown file type '%c' for %s, extracted as normal file", ! head->header.linkflag, skipcrud+current_file_name); ! /* FALL THRU */ ! /* * JK - What we want to do if the file is sparse is loop through * the array of sparse structures in the header and read in * and translate the character strings representing 1) the offset --- 179,206 ---- * We have to start from "head" every time we want to touch * the header record. */ ! skipcrud = 0; ! while (!f_absolute_paths ! && '/' == current_file_name[skipcrud]) ! { ! static int warned_once = 0; ! ! skipcrud++; /* Force relative path */ ! if (!warned_once++) ! { ! msg ("Removing leading / from absolute path names in the archive."); ! } ! } ! ! switch (head->header.linkflag) ! { ! default: ! msg ("Unknown file type '%c' for %s, extracted as normal file", ! head->header.linkflag, skipcrud + current_file_name); ! /* FALL THRU */ ! ! /* * JK - What we want to do if the file is sparse is loop through * the array of sparse structures in the header and read in * and translate the character strings representing 1) the offset *************** *** 206,288 **** * the tar file that had to deal with a sparse file. * * After we read in the first five (at most) sparse structures, ! * we check to see if the file has an extended header, i.e., * if more sparse structures are needed to describe the contents * of the new file. If so, we read in the extended headers * and continue to store their contents into the sparsearray. */ ! case LF_SPARSE: ! sp_array_size = 10; ! sparsearray = (struct sp_array *) malloc(sp_array_size * sizeof(struct sp_array)); ! for (i = 0; i < SPARSE_IN_HDR; i++) { ! sparsearray[i].offset = ! from_oct(1+12, head->header.sp[i].offset); ! sparsearray[i].numbytes = ! from_oct(1+12, head->header.sp[i].numbytes); ! if (!sparsearray[i].numbytes) ! break; ! } ! ! /* end_nulls = from_oct(1+12, head->header.ending_blanks);*/ ! ! if (head->header.isextended) { ! /* read in the list of extended headers ! and translate them into the sparsearray ! as before */ ! /* static */ int ind = SPARSE_IN_HDR; ! for (;;) { ! exhdr = findrec(); ! for (i = 0; i < SPARSE_EXT_HDR; i++) { ! if (i+ind > sp_array_size-1) { ! /* * realloc the scratch area * since we've run out of room -- */ ! sparsearray = (struct sp_array *) ! realloc(sparsearray, ! 2 * sp_array_size * (sizeof(struct sp_array))); ! sp_array_size *= 2; ! } ! if (!exhdr->ext_hdr.sp[i].numbytes) ! break; ! sparsearray[i+ind].offset = ! from_oct(1+12, exhdr->ext_hdr.sp[i].offset); ! sparsearray[i+ind].numbytes = ! from_oct(1+12, exhdr->ext_hdr.sp[i].numbytes); ! } ! if (!exhdr->ext_hdr.isextended) ! break; ! else { ! ind += SPARSE_EXT_HDR; ! userec(exhdr); ! } ! } ! userec(exhdr); ! } ! /* FALL THRU */ ! case LF_OLDNORMAL: ! case LF_NORMAL: ! case LF_CONTIG: ! /* * Appears to be a file. * See if it's really a directory. */ ! namelen = strlen(skipcrud+current_file_name)-1; ! if (current_file_name[skipcrud+namelen] == '/') ! goto really_dir; ! ! /* FIXME, deal with protection issues */ ! again_file: ! openflag = (f_keep? ! O_BINARY|O_NDELAY|O_WRONLY|O_CREAT|O_EXCL: ! O_BINARY|O_NDELAY|O_WRONLY|O_CREAT|O_TRUNC) ! | ((head->header.linkflag == LF_SPARSE) ? 0 : O_APPEND); ! /* * JK - The last | is a kludge to solve the problem * the O_APPEND flag causes with files we are * trying to make sparse: when a file is opened --- 210,298 ---- * the tar file that had to deal with a sparse file. * * After we read in the first five (at most) sparse structures, ! * we check to see if the file has an extended header, i.e., * if more sparse structures are needed to describe the contents * of the new file. If so, we read in the extended headers * and continue to store their contents into the sparsearray. */ ! case LF_SPARSE: ! sp_array_size = 10; ! sparsearray = (struct sp_array *) ck_malloc (sp_array_size * sizeof (struct sp_array)); ! for (i = 0; i < SPARSE_IN_HDR; i++) ! { ! sparsearray[i].offset = ! from_oct (1 + 12, head->header.sp[i].offset); ! sparsearray[i].numbytes = ! from_oct (1 + 12, head->header.sp[i].numbytes); ! if (!sparsearray[i].numbytes) ! break; ! } ! /* end_nulls = from_oct(1+12, head->header.ending_blanks);*/ ! ! if (head->header.isextended) ! { ! /* read in the list of extended headers ! and translate them into the sparsearray ! as before */ ! /* static */ int ind = SPARSE_IN_HDR; ! for (;;) ! { ! exhdr = findrec (); ! for (i = 0; i < SPARSE_EXT_HDR; i++) ! { ! ! if (i + ind > sp_array_size - 1) ! { ! /* * realloc the scratch area * since we've run out of room -- */ ! sparsearray = (struct sp_array *) ! ck_realloc (sparsearray, ! 2 * sp_array_size * (sizeof (struct sp_array))); ! sp_array_size *= 2; ! } ! if (!exhdr->ext_hdr.sp[i].numbytes) ! break; ! sparsearray[i + ind].offset = ! from_oct (1 + 12, exhdr->ext_hdr.sp[i].offset); ! sparsearray[i + ind].numbytes = ! from_oct (1 + 12, exhdr->ext_hdr.sp[i].numbytes); ! } ! if (!exhdr->ext_hdr.isextended) ! break; ! else ! { ! ind += SPARSE_EXT_HDR; ! userec (exhdr); ! } ! } ! userec (exhdr); ! } ! /* FALL THRU */ ! case LF_OLDNORMAL: ! case LF_NORMAL: ! case LF_CONTIG: ! /* * Appears to be a file. * See if it's really a directory. */ ! namelen = strlen (skipcrud + current_file_name) - 1; ! if (current_file_name[skipcrud + namelen] == '/') ! goto really_dir; ! ! /* FIXME, deal with protection issues */ ! again_file: ! openflag = (f_keep ? ! O_BINARY | O_NDELAY | O_WRONLY | O_CREAT | O_EXCL : ! O_BINARY | O_NDELAY | O_WRONLY | O_CREAT | O_TRUNC) ! | ((head->header.linkflag == LF_SPARSE) ? 0 : O_APPEND); ! /* * JK - The last | is a kludge to solve the problem * the O_APPEND flag causes with files we are * trying to make sparse: when a file is opened *************** *** 295,352 **** * me to waste a good deal of time, I might add) */ ! if(f_exstdout) { ! fd = 1; ! goto extract_file; ! } #ifdef O_CTG ! /* * Contiguous files (on the Masscomp) have to specify * the size in the open call that creates them. */ ! if (head->header.linkflag == LF_CONTIG) ! fd = open((longname ? longname : head->header.name) ! + skipcrud, ! openflag | O_CTG, ! hstat.st_mode, hstat.st_size); ! else #endif ! { #ifdef NO_OPEN3 ! /* * On raw V7 we won't let them specify -k (f_keep), but * we just bull ahead and create the files. */ ! fd = creat((longname ! ? longname ! : head->header.name) + skipcrud, ! hstat.st_mode); #else ! /* * With 3-arg open(), we can do this up right. */ ! fd = open(skipcrud + current_file_name, ! openflag, hstat.st_mode); #endif ! } ! if (fd < 0) { ! if (make_dirs(skipcrud + current_file_name)) ! goto again_file; ! msg_perror("Could not create file %s", ! skipcrud + current_file_name); ! if (head->header.isextended) ! skip_extended_headers(); ! skip_file((long)hstat.st_size); ! goto quit; ! } ! ! extract_file: ! if (head->header.linkflag == LF_SPARSE) { ! char *name; ! int namelen; ! /* * Kludge alert. NAME is assigned to header.name * because during the extraction, the space that * contains the header will get scribbled on, and --- 305,365 ---- * me to waste a good deal of time, I might add) */ ! if (f_exstdout) ! { ! fd = 1; ! goto extract_file; ! } #ifdef O_CTG ! /* * Contiguous files (on the Masscomp) have to specify * the size in the open call that creates them. */ ! if (head->header.linkflag == LF_CONTIG) ! fd = open ((longname ? longname : head->header.name) ! + skipcrud, ! openflag | O_CTG, ! hstat.st_mode, hstat.st_size); ! else #endif ! { #ifdef NO_OPEN3 ! /* * On raw V7 we won't let them specify -k (f_keep), but * we just bull ahead and create the files. */ ! fd = creat ((longname ! ? longname ! : head->header.name) + skipcrud, ! hstat.st_mode); #else ! /* * With 3-arg open(), we can do this up right. */ ! fd = open (skipcrud + current_file_name, ! openflag, hstat.st_mode); #endif ! } ! ! if (fd < 0) ! { ! if (make_dirs (skipcrud + current_file_name)) ! goto again_file; ! msg_perror ("Could not create file %s", ! skipcrud + current_file_name); ! if (head->header.isextended) ! skip_extended_headers (); ! skip_file ((long) hstat.st_size); ! goto quit; ! } ! extract_file: ! if (head->header.linkflag == LF_SPARSE) ! { ! char *name; ! int namelen; ! /* * Kludge alert. NAME is assigned to header.name * because during the extraction, the space that * contains the header will get scribbled on, and *************** *** 354,397 **** * that happen to contain the filename will look * REAL interesting unless we do this. */ ! namelen = strlen(skipcrud + current_file_name); ! name = (char *) malloc((sizeof(char)) * namelen); ! bcopy(skipcrud+current_file_name, name, namelen); ! size = hstat.st_size; ! extract_sparse_file(fd, &size, hstat.st_size, name); ! } ! else ! for (size = hstat.st_size; ! size > 0; ! size -= written) { ! /* long offset, numbytes;*/ ! if(f_multivol) { ! save_name=current_file_name; ! save_totsize=hstat.st_size; ! save_sizeleft=size; ! } ! /* * Locate data, determine max length * writeable, write it, record that * we have used the data, then check * if the write worked. */ ! data = findrec()->charptr; ! if (data == NULL) { /* Check it... */ ! msg("Unexpected EOF on archive file"); ! break; ! } ! /* * JK - If the file is sparse, use the sparsearray * that we created before to lseek into the new * file the proper amount, and to see how many * bytes we want to write at that position. */ ! /* if (head->header.linkflag == LF_SPARSE) { off_t pos; pos = lseek(fd, (off_t) sparsearray[sparse_ind].offset, 0); --- 367,413 ---- * that happen to contain the filename will look * REAL interesting unless we do this. */ ! namelen = strlen (skipcrud + current_file_name) + 1; ! name = (char *) ck_malloc ((sizeof (char)) * namelen); ! bcopy (skipcrud + current_file_name, name, namelen); ! size = hstat.st_size; ! extract_sparse_file (fd, &size, hstat.st_size, name); ! } ! else ! for (size = hstat.st_size; ! size > 0; ! size -= written) ! { ! /* long offset, numbytes;*/ ! if (f_multivol) ! { ! save_name = current_file_name; ! save_totsize = hstat.st_size; ! save_sizeleft = size; ! } ! /* * Locate data, determine max length * writeable, write it, record that * we have used the data, then check * if the write worked. */ ! data = findrec ()->charptr; ! if (data == NULL) ! { /* Check it... */ ! msg ("Unexpected EOF on archive file"); ! break; ! } ! /* * JK - If the file is sparse, use the sparsearray * that we created before to lseek into the new * file the proper amount, and to see how many * bytes we want to write at that position. */ ! /* if (head->header.linkflag == LF_SPARSE) { off_t pos; pos = lseek(fd, (off_t) sparsearray[sparse_ind].offset, 0); *************** *** 398,439 **** printf("%d at %d\n", (int) pos, sparse_ind); written = sparsearray[sparse_ind++].numbytes; } else*/ ! written = endofrecs()->charptr - data; ! if (written > size) ! written = size; ! errno = 0; ! check = write(fd, data, written); ! /* * The following is in violation of strict * typing, since the arg to userec * should be a struct rec *. FIXME. */ ! userec((union record *)(data + written - 1)); ! if (check == written) continue; ! /* * Error in writing to file. * Print it, skip to next file in archive. */ ! if(check<0) ! msg_perror("couldn't write to file %s", ! skipcrud + current_file_name); ! else ! msg("could only write %d of %d bytes to file %s", ! written,check,skipcrud + current_file_name); ! skip_file((long)(size - written)); ! break; /* Still do the close, mod time, chmod, etc */ ! } ! if(f_multivol) ! save_name = 0; ! /* If writing to stdout, don't try to do anything to the filename; it doesn't exist, or we don't want to touch it anyway */ ! if(f_exstdout) ! break; ! /* if (head->header.isextended) { register union record *exhdr; register int i; --- 414,456 ---- printf("%d at %d\n", (int) pos, sparse_ind); written = sparsearray[sparse_ind++].numbytes; } else*/ ! written = endofrecs ()->charptr - data; ! if (written > size) ! written = size; ! errno = 0; ! check = write (fd, data, written); ! /* * The following is in violation of strict * typing, since the arg to userec * should be a struct rec *. FIXME. */ ! userec ((union record *) (data + written - 1)); ! if (check == written) ! continue; ! /* * Error in writing to file. * Print it, skip to next file in archive. */ ! if (check < 0) ! msg_perror ("couldn't write to file %s", ! skipcrud + current_file_name); ! else ! msg ("could only write %d of %d bytes to file %s", ! check, written, skipcrud + current_file_name); ! skip_file ((long) (size - written)); ! break; /* Still do the close, mod time, chmod, etc */ ! } ! if (f_multivol) ! save_name = 0; ! /* If writing to stdout, don't try to do anything to the filename; it doesn't exist, or we don't want to touch it anyway */ ! if (f_exstdout) ! break; ! /* if (head->header.isextended) { register union record *exhdr; register int i; *************** *** 454,507 **** }*/ ! check = close(fd); ! if (check < 0) { ! msg_perror("Error while closing %s", ! skipcrud + current_file_name); ! } ! set_filestat: ! /* * If we are root, set the owner and group of the extracted * file. This does what is wanted both on real Unix and on * System V. If we are running as a user, we extract as that * user; if running as root, we extract as the original owner. */ ! if (we_are_root || f_do_chown) { ! if (chown(skipcrud + current_file_name, ! hstat.st_uid, hstat.st_gid) < 0) { ! msg_perror("cannot chown file %s to uid %d gid %d", ! skipcrud + current_file_name, ! hstat.st_uid,hstat.st_gid); ! } ! } ! /* ! * Set the modified time of the file. ! * ! * Note that we set the accessed time to "now", which ! * is really "the time we started extracting files". ! * unless f_gnudump is used, in which case .st_atime is used ! */ ! if (!f_modified) { ! /* fixme if f_gnudump should set ctime too, but how? */ ! if(f_gnudump) ! acc_upd_times.actime=hstat.st_atime; ! else ! acc_upd_times.actime = now; /* Accessed now */ ! acc_upd_times.modtime = hstat.st_mtime; /* Mod'd */ ! if (utime(skipcrud + current_file_name, ! &acc_upd_times) < 0) { ! msg_perror("couldn't change access and modification times of %s",skipcrud + current_file_name); ! } ! } ! /* We do the utime before the chmod because some versions of utime are broken and trash the modes of the file. Since we then change the mode anyway, we don't care. . . */ ! /* * If '-k' is not set, open() or creat() could have saved * the permission bits from a previously created file, * ignoring the ones we specified. --- 471,529 ---- }*/ ! check = close (fd); ! if (check < 0) ! { ! msg_perror ("Error while closing %s", ! skipcrud + current_file_name); ! } ! set_filestat: ! /* * If we are root, set the owner and group of the extracted * file. This does what is wanted both on real Unix and on * System V. If we are running as a user, we extract as that * user; if running as root, we extract as the original owner. */ ! if (we_are_root || f_do_chown) ! { ! if (chown (skipcrud + current_file_name, ! hstat.st_uid, hstat.st_gid) < 0) ! { ! msg_perror ("cannot chown file %s to uid %d gid %d", ! skipcrud + current_file_name, ! hstat.st_uid, hstat.st_gid); ! } ! } ! /* ! * Set the modified time of the file. ! * ! * Note that we set the accessed time to "now", which ! * is really "the time we started extracting files". ! * unless f_gnudump is used, in which case .st_atime is used ! */ ! if (!f_modified) ! { ! /* fixme if f_gnudump should set ctime too, but how? */ ! if (f_gnudump) ! acc_upd_times.actime = hstat.st_atime; ! else ! acc_upd_times.actime = now; /* Accessed now */ ! acc_upd_times.modtime = hstat.st_mtime; /* Mod'd */ ! if (utime (skipcrud + current_file_name, ! &acc_upd_times) < 0) ! { ! msg_perror ("couldn't change access and modification times of %s", skipcrud + current_file_name); ! } ! } ! /* We do the utime before the chmod because some versions of utime are broken and trash the modes of the file. Since we then change the mode anyway, we don't care. . . */ ! /* * If '-k' is not set, open() or creat() could have saved * the permission bits from a previously created file, * ignoring the ones we specified. *************** *** 514,689 **** * skip the chmod. This works because we did umask(0) if -p * is set, so umask will have left the specified mode alone. */ ! if ((!f_keep) ! || (hstat.st_mode & (S_ISUID|S_ISGID|S_ISVTX))) { ! if (chmod(skipcrud + current_file_name, ! notumask & (int)hstat.st_mode) < 0) { ! msg_perror("cannot change mode of file %s to %ld", ! skipcrud + current_file_name, ! notumask & (int)hstat.st_mode); ! } ! } ! ! quit: ! break; ! ! case LF_LINK: ! again_link: { ! struct stat st1,st2; ! check = link (current_link_name, skipcrud + current_file_name); ! if (check == 0) ! break; ! if (make_dirs(skipcrud + current_file_name)) ! goto again_link; ! if(f_gnudump && errno==EEXIST) ! break; ! if(stat(current_link_name, &st1) == 0 ! && stat(current_file_name + skipcrud, &st2)==0 ! && st1.st_dev==st2.st_dev ! && st1.st_ino==st2.st_ino) ! break; ! msg_perror("Could not link %s to %s", ! skipcrud + current_file_name, ! current_link_name); ! } ! break; #ifdef S_ISLNK ! case LF_SYMLINK: ! again_symlink: ! check = symlink(current_link_name, ! skipcrud + current_file_name); ! /* FIXME, don't worry uid, gid, etc... */ ! if (check == 0) ! break; ! if (make_dirs(current_file_name + skipcrud)) ! goto again_symlink; ! msg_perror("Could not create symlink to %s", ! current_link_name); ! break; #endif #ifdef S_IFCHR ! case LF_CHR: ! hstat.st_mode |= S_IFCHR; ! goto make_node; #endif #ifdef S_IFBLK ! case LF_BLK: ! hstat.st_mode |= S_IFBLK; #endif #if defined(S_IFCHR) || defined(S_IFBLK) ! make_node: ! check = mknod(current_file_name + skipcrud, ! (int) hstat.st_mode, (int) hstat.st_rdev); ! if (check != 0) { ! if (make_dirs(skipcrud + current_file_name)) ! goto make_node; ! msg_perror("Could not make %s", ! current_file_name + skipcrud); ! break; ! }; ! goto set_filestat; #endif #ifdef S_ISFIFO ! /* If local system doesn't support FIFOs, use default case */ ! case LF_FIFO: ! make_fifo: ! check = mkfifo(current_file_name + skipcrud, ! (int) hstat.st_mode); ! if (check != 0) { ! if (make_dirs(current_file_name + skipcrud)) ! goto make_fifo; ! msg_perror("Could not make %s", ! skipcrud + current_file_name); ! break; ! }; ! goto set_filestat; ! #endif ! ! case LF_DIR: ! case LF_DUMPDIR: ! namelen = strlen(current_file_name) + skipcrud - 1; ! really_dir: ! /* Check for trailing /, and zap as many as we find. */ ! while (namelen ! && current_file_name[skipcrud+namelen] == '/') ! current_file_name[skipcrud+namelen--] = '\0'; ! if(f_gnudump) { /* Read the entry and delete files that aren't listed in the archive */ ! gnu_restore(skipcrud); ! ! } else if(head->header.linkflag==LF_DUMPDIR) ! skip_file((long)(hstat.st_size)); ! ! ! again_dir: ! check = mkdir(skipcrud+current_file_name, ! (we_are_root ? 0 : 0300) | (int)hstat.st_mode); ! if (check != 0) { ! struct stat st1; ! ! if (make_dirs(skipcrud+current_file_name)) ! goto again_dir; ! /* If we're trying to create '.', let it be. */ ! if (current_file_name[skipcrud+namelen] == '.' && ! (namelen==0 || ! current_file_name[skipcrud+namelen-1]=='/')) ! goto check_perms; ! if( errno==EEXIST ! && stat(skipcrud+current_file_name,&st1)==0 ! && (S_ISDIR(st1.st_mode))) ! break; ! msg_perror("Could not create directory %s",skipcrud+current_file_name); ! break; ! } ! ! check_perms: ! if (!we_are_root && 0300 != (0300 & (int) hstat.st_mode)) { ! hstat.st_mode |= 0300; ! msg("Added write and execute permission to directory %s", ! skipcrud+current_file_name); ! } ! if (f_modified) ! goto set_filestat; ! tmp = (struct saved_dir_info *) malloc (sizeof (struct saved_dir_info)); ! tmp->path = malloc (strlen (skipcrud + current_file_name) + 1); ! strcpy (tmp->path, skipcrud + current_file_name); ! tmp->mode = hstat.st_mode; ! tmp->atime = hstat.st_atime; ! tmp->mtime = hstat.st_mtime; ! tmp->next = saved_dir_info_head; ! saved_dir_info_head = tmp; ! case LF_VOLHDR: ! if(f_verbose) { ! printf("Reading %s\n", current_file_name); } ! break; ! case LF_NAMES: ! extract_mangle(head); ! break; ! case LF_MULTIVOL: ! msg("Can't extract '%s'--file is continued from another volume\n",current_file_name); ! skip_file((long)hstat.st_size); ! break; ! case LF_LONGNAME: ! case LF_LONGLINK: ! msg ("Visible long name error\n"); ! skip_file ((long)hstat.st_size); ! break; ! } ! ! /* We don't need to save it any longer. */ ! saverec((union record **) 0); /* Unsave it */ } /* --- 536,757 ---- * skip the chmod. This works because we did umask(0) if -p * is set, so umask will have left the specified mode alone. */ ! if ((!f_keep) ! || (hstat.st_mode & (S_ISUID | S_ISGID | S_ISVTX))) { ! if (chmod (skipcrud + current_file_name, ! notumask & (int) hstat.st_mode) < 0) ! { ! msg_perror ("cannot change mode of file %s to %ld", ! skipcrud + current_file_name, ! notumask & (int) hstat.st_mode); ! } ! } ! quit: ! break; ! case LF_LINK: ! again_link: ! { ! struct stat st1, st2; ! ! check = link (current_link_name, skipcrud + current_file_name); ! ! if (check == 0) ! break; ! if (make_dirs (skipcrud + current_file_name)) ! goto again_link; ! if (f_gnudump && errno == EEXIST) ! break; ! if (stat (current_link_name, &st1) == 0 ! && stat (current_file_name + skipcrud, &st2) == 0 ! && st1.st_dev == st2.st_dev ! && st1.st_ino == st2.st_ino) ! break; ! msg_perror ("Could not link %s to %s", ! skipcrud + current_file_name, ! current_link_name); ! } ! break; #ifdef S_ISLNK ! case LF_SYMLINK: ! again_symlink: ! check = symlink (current_link_name, ! skipcrud + current_file_name); ! /* FIXME, don't worry uid, gid, etc... */ ! if (check == 0) ! break; ! if (make_dirs (current_file_name + skipcrud)) ! goto again_symlink; ! msg_perror ("Could not create symlink to %s", ! current_link_name); ! break; #endif #ifdef S_IFCHR ! case LF_CHR: ! hstat.st_mode |= S_IFCHR; ! goto make_node; #endif #ifdef S_IFBLK ! case LF_BLK: ! hstat.st_mode |= S_IFBLK; #endif #if defined(S_IFCHR) || defined(S_IFBLK) ! make_node: ! check = mknod (current_file_name + skipcrud, ! (int) hstat.st_mode, (int) hstat.st_rdev); ! if (check != 0) ! { ! if (make_dirs (skipcrud + current_file_name)) ! goto make_node; ! msg_perror ("Could not make %s", ! current_file_name + skipcrud); ! break; ! }; ! goto set_filestat; #endif #ifdef S_ISFIFO ! /* If local system doesn't support FIFOs, use default case */ ! case LF_FIFO: ! make_fifo: ! check = mkfifo (current_file_name + skipcrud, ! (int) hstat.st_mode); ! if (check != 0) ! { ! if (make_dirs (current_file_name + skipcrud)) ! goto make_fifo; ! msg_perror ("Could not make %s", ! skipcrud + current_file_name); ! break; ! }; ! goto set_filestat; ! #endif ! ! case LF_DIR: ! case LF_DUMPDIR: ! namelen = strlen (current_file_name + skipcrud) - 1; ! really_dir: ! /* Check for trailing /, and zap as many as we find. */ ! while (namelen ! && current_file_name[skipcrud + namelen] == '/') ! current_file_name[skipcrud + namelen--] = '\0'; ! if (f_gnudump) ! { /* Read the entry and delete files that aren't listed in the archive */ ! gnu_restore (skipcrud); ! ! } ! else if (head->header.linkflag == LF_DUMPDIR) ! skip_file ((long) (hstat.st_size)); ! ! ! again_dir: ! check = mkdir (skipcrud + current_file_name, ! (we_are_root ? 0 : 0300) | (int) hstat.st_mode); ! if (check != 0) ! { ! struct stat st1; ! ! if (make_dirs (skipcrud + current_file_name)) ! goto again_dir; ! /* If we're trying to create '.', let it be. */ ! if (current_file_name[skipcrud + namelen] == '.' && ! (namelen == 0 || ! current_file_name[skipcrud + namelen - 1] == '/')) ! goto check_perms; ! if (errno == EEXIST ! && stat (skipcrud + current_file_name, &st1) == 0 ! && (S_ISDIR (st1.st_mode))) ! break; ! msg_perror ("Could not create directory %s", skipcrud + current_file_name); ! break; ! } ! ! check_perms: ! if (!we_are_root && 0300 != (0300 & (int) hstat.st_mode)) ! { ! hstat.st_mode |= 0300; ! msg ("Added write and execute permission to directory %s", ! skipcrud + current_file_name); ! } ! ! /* ! * If we are root, set the owner and group of the extracted ! * file. This does what is wanted both on real Unix and on ! * System V. If we are running as a user, we extract as that ! * user; if running as root, we extract as the original owner. ! */ ! if (we_are_root || f_do_chown) ! { ! if (chown (skipcrud + current_file_name, ! hstat.st_uid, hstat.st_gid) < 0) ! { ! msg_perror ("cannot chown file %s to uid %d gid %d", ! skipcrud + current_file_name, ! hstat.st_uid, hstat.st_gid); ! } ! } ! if (!f_modified) ! { ! tmp = ((struct saved_dir_info *) ! ck_malloc (sizeof (struct saved_dir_info))); ! tmp->path = (char *) ck_malloc (strlen (skipcrud ! + current_file_name) + 1); ! strcpy (tmp->path, skipcrud + current_file_name); ! tmp->mode = hstat.st_mode; ! tmp->atime = hstat.st_atime; ! tmp->mtime = hstat.st_mtime; ! tmp->next = saved_dir_info_head; ! saved_dir_info_head = tmp; ! } ! else ! { ! /* This functions exactly as the code for set_filestat above. */ ! if ((!f_keep) ! || (hstat.st_mode & (S_ISUID | S_ISGID | S_ISVTX))) ! { ! if (chmod (skipcrud + current_file_name, ! notumask & (int) hstat.st_mode) < 0) ! { ! msg_perror ("cannot change mode of file %s to %ld", ! skipcrud + current_file_name, ! notumask & (int) hstat.st_mode); } ! } ! } ! break; ! case LF_VOLHDR: ! if (f_verbose) ! { ! printf ("Reading %s\n", current_file_name); ! } ! break; ! case LF_NAMES: ! extract_mangle (head); ! break; ! ! case LF_MULTIVOL: ! msg ("Can't extract '%s'--file is continued from another volume\n", current_file_name); ! skip_file ((long) hstat.st_size); ! break; ! ! case LF_LONGNAME: ! case LF_LONGLINK: ! msg ("Visible long name error\n"); ! skip_file ((long) hstat.st_size); ! break; ! } ! /* We don't need to save it any longer. */ ! saverec ((union record **) 0);/* Unsave it */ } /* *************** *** 692,792 **** * so, create all required dirs. */ int ! make_dirs(pathname) ! char *pathname; { ! char *p; /* Points into path */ ! int madeone = 0; /* Did we do anything yet? */ ! int save_errno = errno; /* Remember caller's errno */ ! int check; ! ! if (errno != ENOENT) ! return 0; /* Not our problem */ ! ! for (p = index(pathname, '/'); p != NULL; p = index(p+1, '/')) { ! /* Avoid mkdir of empty string, if leading or double '/' */ ! if (p == pathname || p[-1] == '/') ! continue; ! /* Avoid mkdir where last part of path is '.' */ ! if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/')) ! continue; ! *p = 0; /* Truncate the path there */ ! check = mkdir (pathname, 0777); /* Try to create it as a dir */ ! if (check == 0) { ! /* Fix ownership */ ! if (we_are_root) { ! if (chown(pathname, hstat.st_uid, ! hstat.st_gid) < 0) { ! msg_perror("cannot change owner of %s to uid %d gid %d",pathname,hstat.st_uid,hstat.st_gid); ! } ! } ! pr_mkdir(pathname, p-pathname, notumask&0777); ! madeone++; /* Remember if we made one */ ! *p = '/'; ! continue; } ! *p = '/'; ! if (errno == EEXIST) /* Directory already exists */ ! continue; ! /* * Some other error in the mkdir. We return to the caller. */ ! break; ! } ! errno = save_errno; /* Restore caller's errno */ ! return madeone; /* Tell them to retry if we made one */ } void ! extract_sparse_file(fd, sizeleft, totalsize, name) ! int fd; ! long *sizeleft, ! totalsize; ! char *name; ! { ! /* register char *data;*/ ! union record *datarec; ! int sparse_ind = 0; ! int written, ! count; ! ! /* assuming sizeleft is initially totalsize */ ! ! ! while (*sizeleft > 0) { ! datarec = findrec(); ! if (datarec == NULL) { ! msg("Unexpected EOF on archive file"); ! return; ! } ! lseek(fd, sparsearray[sparse_ind].offset, 0); ! written = sparsearray[sparse_ind++].numbytes; ! while (written > RECORDSIZE) { ! count = write(fd, datarec->charptr, RECORDSIZE); ! if (count < 0) ! msg_perror("couldn't write to file %s", name); ! written -= count; ! *sizeleft -= count; ! userec(datarec); ! datarec = findrec(); ! } ! count = write(fd, datarec->charptr, written); ! ! if (count < 0) { ! msg_perror("couldn't write to file %s", name); ! } else if (count != written) { ! msg("could only write %d of %d bytes to file %s", totalsize - *sizeleft, totalsize, name); ! skip_file((long) (*sizeleft)); ! } ! written -= count; ! *sizeleft -= count; ! userec(datarec); } ! free(sparsearray); ! /* if (end_nulls) { register int i; printf("%d\n", (int) end_nulls); --- 760,869 ---- * so, create all required dirs. */ int ! make_dirs (pathname) ! char *pathname; { ! char *p; /* Points into path */ ! int madeone = 0; /* Did we do anything yet? */ ! int save_errno = errno; /* Remember caller's errno */ ! int check; ! ! if (errno != ENOENT) ! return 0; /* Not our problem */ ! ! for (p = index (pathname, '/'); p != NULL; p = index (p + 1, '/')) ! { ! /* Avoid mkdir of empty string, if leading or double '/' */ ! if (p == pathname || p[-1] == '/') ! continue; ! /* Avoid mkdir where last part of path is '.' */ ! if (p[-1] == '.' && (p == pathname + 1 || p[-2] == '/')) ! continue; ! *p = 0; /* Truncate the path there */ ! check = mkdir (pathname, 0777); /* Try to create it as a dir */ ! if (check == 0) ! { ! /* Fix ownership */ ! if (we_are_root) ! { ! if (chown (pathname, hstat.st_uid, ! hstat.st_gid) < 0) ! { ! msg_perror ("cannot change owner of %s to uid %d gid %d", pathname, hstat.st_uid, hstat.st_gid); } ! } ! pr_mkdir (pathname, p - pathname, notumask & 0777); ! madeone++; /* Remember if we made one */ ! *p = '/'; ! continue; ! } ! *p = '/'; ! if (errno == EEXIST) /* Directory already exists */ ! continue; ! /* * Some other error in the mkdir. We return to the caller. */ ! break; ! } ! errno = save_errno; /* Restore caller's errno */ ! return madeone; /* Tell them to retry if we made one */ } void ! extract_sparse_file (fd, sizeleft, totalsize, name) ! int fd; ! long *sizeleft, totalsize; ! char *name; ! { ! /* register char *data;*/ ! union record *datarec; ! int sparse_ind = 0; ! int written, count; ! /* assuming sizeleft is initially totalsize */ ! ! ! while (*sizeleft > 0) ! { ! datarec = findrec (); ! if (datarec == NULL) ! { ! msg ("Unexpected EOF on archive file"); ! return; ! } ! lseek (fd, sparsearray[sparse_ind].offset, 0); ! written = sparsearray[sparse_ind++].numbytes; ! while (written > RECORDSIZE) ! { ! count = write (fd, datarec->charptr, RECORDSIZE); ! if (count < 0) ! msg_perror ("couldn't write to file %s", name); ! written -= count; ! *sizeleft -= count; ! userec (datarec); ! datarec = findrec (); ! } ! count = write (fd, datarec->charptr, written); ! ! if (count < 0) ! { ! msg_perror ("couldn't write to file %s", name); ! } ! else if (count != written) ! { ! msg ("could only write %d of %d bytes to file %s", count, ! totalsize, name); ! skip_file ((long) (*sizeleft)); } ! ! written -= count; ! *sizeleft -= count; ! userec (datarec); ! } ! free (sparsearray); ! /* if (end_nulls) { register int i; printf("%d\n", (int) end_nulls); *************** *** 793,828 **** for (i = 0; i < end_nulls; i++) write(fd, "\000", 1); }*/ ! userec(datarec); } /* Set back the utime and mode for all the extracted directories. */ ! void restore_saved_dir_info () { struct utimbuf acc_upd_times; - struct saved_dir_info *tmp; while (saved_dir_info_head != NULL) { /* fixme if f_gnudump should set ctime too, but how? */ ! if(f_gnudump) ! acc_upd_times.actime=saved_dir_info_head -> atime; ! else ! acc_upd_times.actime = now; /* Accessed now */ ! acc_upd_times.modtime = saved_dir_info_head -> mtime; /* Mod'd */ ! if (utime(saved_dir_info_head -> path, &acc_upd_times) < 0) { ! msg_perror("couldn't change access and modification times of %s", ! saved_dir_info_head -> path); ! } ! if ((!f_keep) || (saved_dir_info_head -> mode & (S_ISUID|S_ISGID|S_ISVTX))) { ! if (chmod(saved_dir_info_head -> path, ! notumask & saved_dir_info_head -> mode) < 0) { ! msg_perror("cannot change mode of file %s to %ld", ! saved_dir_info_head -> path, ! notumask & saved_dir_info_head -> mode); ! } } ! saved_dir_info_head = saved_dir_info_head -> next; } } --- 870,907 ---- for (i = 0; i < end_nulls; i++) write(fd, "\000", 1); }*/ ! userec (datarec); } /* Set back the utime and mode for all the extracted directories. */ ! void ! restore_saved_dir_info () { struct utimbuf acc_upd_times; while (saved_dir_info_head != NULL) { /* fixme if f_gnudump should set ctime too, but how? */ ! if (f_gnudump) ! acc_upd_times.actime = saved_dir_info_head->atime; ! else ! acc_upd_times.actime = now; /* Accessed now */ ! acc_upd_times.modtime = saved_dir_info_head->mtime; /* Mod'd */ ! if (utime (saved_dir_info_head->path, &acc_upd_times) < 0) { ! msg_perror ("couldn't change access and modification times of %s", ! saved_dir_info_head->path); ! } ! if ((!f_keep) || (saved_dir_info_head->mode & (S_ISUID | S_ISGID | S_ISVTX))) ! { ! if (chmod (saved_dir_info_head->path, ! notumask & saved_dir_info_head->mode) < 0) ! { ! msg_perror ("cannot change mode of file %s to %ld", ! saved_dir_info_head->path, ! notumask & saved_dir_info_head->mode); ! } } ! saved_dir_info_head = saved_dir_info_head->next; } } diff -c3 tar-1.11.1/fnmatch.c tar-1.11.2/fnmatch.c *** tar-1.11.1/fnmatch.c Fri Sep 11 00:37:48 1992 --- tar-1.11.2/fnmatch.c Thu Mar 25 13:59:42 1993 *************** *** 16,31 **** Cambridge, MA 02139, USA. */ #include ! #include "fnmatch.h" #if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS) extern int errno; #endif - #if !__STDC__ - #define const - #endif - /* Match STRING against the filename pattern PATTERN, returning zero if it matches, nonzero if not. */ int --- 16,27 ---- Cambridge, MA 02139, USA. */ #include ! #include #if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS) extern int errno; #endif /* Match STRING against the filename pattern PATTERN, returning zero if it matches, nonzero if not. */ int *************** *** 166,172 **** ++n; } ! if (*n == '\0' || ((flags & FNM_TARPATH) && *n == '/')) return 0; return FNM_NOMATCH; --- 162,172 ---- ++n; } ! if (*n == '\0') ! return 0; ! ! if ((flags & FNM_LEADING_DIR) && *n == '/') ! /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ return 0; return FNM_NOMATCH; diff -c3 tar-1.11.1/fnmatch.h tar-1.11.2/fnmatch.h *** tar-1.11.1/fnmatch.h Fri Sep 11 00:36:41 1992 --- tar-1.11.2/fnmatch.h Thu Mar 25 13:59:58 1993 *************** *** 20,27 **** #define _FNMATCH_H 1 #ifdef __cplusplus ! extern "C" ! { #endif #if defined (__cplusplus) || (defined (__STDC__) && __STDC__) --- 20,26 ---- #define _FNMATCH_H 1 #ifdef __cplusplus ! extern "C" { #endif #if defined (__cplusplus) || (defined (__STDC__) && __STDC__) *************** *** 38,47 **** #define FNM_PATHNAME (1 << 0)/* No wildcard can ever match `/'. */ #define FNM_NOESCAPE (1 << 1)/* Backslashes don't quote special chars. */ #define FNM_PERIOD (1 << 2)/* Leading `.' is matched only explicitly. */ ! #define FNM_TARPATH (1 << 4)/* Ignore `/...' after a match. */ ! #define __FNM_FLAGS (FNM_PATHNAME|FNM_NOESCAPE|FNM_PERIOD|FNM_TARPATH) #if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_BSD_SOURCE) #define FNM_FILE_NAME FNM_PATHNAME #endif --- 37,46 ---- #define FNM_PATHNAME (1 << 0)/* No wildcard can ever match `/'. */ #define FNM_NOESCAPE (1 << 1)/* Backslashes don't quote special chars. */ #define FNM_PERIOD (1 << 2)/* Leading `.' is matched only explicitly. */ ! #define __FNM_FLAGS (FNM_PATHNAME|FNM_NOESCAPE|FNM_PERIOD|FNM_LEADING_DIR) #if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_BSD_SOURCE) + #define FNM_LEADING_DIR (1 << 3)/* Ignore `/...' after a match. */ #define FNM_FILE_NAME FNM_PATHNAME #endif *************** *** 50,61 **** /* Match STRING against the filename pattern PATTERN, returning zero if it matches, FNM_NOMATCH if not. */ ! extern int fnmatch __P ((const char *__pattern, const char *__string, ! int __flags)); #ifdef __cplusplus } - #endif #endif /* fnmatch.h */ --- 49,59 ---- /* Match STRING against the filename pattern PATTERN, returning zero if it matches, FNM_NOMATCH if not. */ ! extern int fnmatch __P ((const char *__pattern, const char *__string, ! int __flags)); #ifdef __cplusplus } #endif #endif /* fnmatch.h */ Only in tar-1.11.2: getdate.c diff -c3 tar-1.11.1/getdate.y tar-1.11.2/getdate.y *** tar-1.11.1/getdate.y Mon Sep 14 16:41:02 1992 --- tar-1.11.2/getdate.y Tue Feb 16 04:08:58 1993 *************** *** 14,23 **** /* SUPPRESS 287 on yaccpar_sccsid *//* Unusd static variable */ /* SUPPRESS 288 on yyerrlab *//* Label unused */ #ifdef __GNUC__ #define alloca __builtin_alloca #else ! #ifdef sparc #include #else #ifdef _AIX /* for Bison */ --- 14,27 ---- /* SUPPRESS 287 on yaccpar_sccsid *//* Unusd static variable */ /* SUPPRESS 288 on yyerrlab *//* Label unused */ + #ifdef HAVE_CONFIG_H + #include "config.h" + #endif + #ifdef __GNUC__ #define alloca __builtin_alloca #else ! #ifdef HAVE_ALLOCA_H #include #else #ifdef _AIX /* for Bison */ *************** *** 67,73 **** #endif /* defined(USG) && !defined(HAVE_FTIME) */ ! #if defined(BSD4_2) || defined(BSD4_1C) #include #else #if defined(_AIX) --- 71,77 ---- #endif /* defined(USG) && !defined(HAVE_FTIME) */ ! #if defined(BSD4_2) || defined(BSD4_1C) || (defined (hp9000) && !defined (hpux)) #include #else #if defined(_AIX) *************** *** 366,372 **** %% /* Month and day table. */ ! static TABLE MonthDayTable[] = { { "january", tMONTH, 1 }, { "february", tMONTH, 2 }, { "march", tMONTH, 3 }, --- 370,376 ---- %% /* Month and day table. */ ! static TABLE const MonthDayTable[] = { { "january", tMONTH, 1 }, { "february", tMONTH, 2 }, { "march", tMONTH, 3 }, *************** *** 395,401 **** }; /* Time units table. */ ! static TABLE UnitsTable[] = { { "year", tMONTH_UNIT, 12 }, { "month", tMONTH_UNIT, 1 }, { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 }, --- 399,405 ---- }; /* Time units table. */ ! static TABLE const UnitsTable[] = { { "year", tMONTH_UNIT, 12 }, { "month", tMONTH_UNIT, 1 }, { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 }, *************** *** 410,416 **** }; /* Assorted relative-time words. */ ! static TABLE OtherTable[] = { { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 }, { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 }, { "today", tMINUTE_UNIT, 0 }, --- 414,420 ---- }; /* Assorted relative-time words. */ ! static TABLE const OtherTable[] = { { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 }, { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 }, { "today", tMINUTE_UNIT, 0 }, *************** *** 436,442 **** /* The timezone table. */ /* Some of these are commented out because a time_t can't store a float. */ ! static TABLE TimezoneTable[] = { { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */ { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */ { "utc", tZONE, HOUR( 0) }, --- 440,446 ---- /* The timezone table. */ /* Some of these are commented out because a time_t can't store a float. */ ! static TABLE const TimezoneTable[] = { { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */ { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */ { "utc", tZONE, HOUR( 0) }, *************** *** 520,526 **** }; /* Military timezone table. */ ! static TABLE MilitaryTable[] = { { "a", tZONE, HOUR( 1) }, { "b", tZONE, HOUR( 2) }, { "c", tZONE, HOUR( 3) }, --- 524,530 ---- }; /* Military timezone table. */ ! static TABLE const MilitaryTable[] = { { "a", tZONE, HOUR( 1) }, { "b", tZONE, HOUR( 2) }, { "c", tZONE, HOUR( 3) }, *************** *** 553,559 **** /* ARGSUSED */ ! int yyerror(s) char *s; { --- 557,563 ---- /* ARGSUSED */ ! static int yyerror(s) char *s; { *************** *** 599,605 **** MERIDIAN Meridian; DSTMODE DSTmode; { ! static int DaysInMonth[12] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; time_t tod; --- 603,609 ---- MERIDIAN Meridian; DSTMODE DSTmode; { ! static int DaysInMonth[12] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; time_t tod; *************** *** 693,699 **** { register char *p; register char *q; ! register TABLE *tp; int i; int abbrev; --- 697,703 ---- { register char *p; register char *q; ! register const TABLE *tp; int i; int abbrev; *************** *** 794,800 **** } ! int yylex() { register char c; --- 798,804 ---- } ! static int yylex() { register char c; diff -c3 tar-1.11.1/getoldopt.c tar-1.11.2/getoldopt.c *** tar-1.11.1/getoldopt.c Thu Jul 18 01:50:11 1991 --- tar-1.11.2/getoldopt.c Tue Nov 24 08:52:03 1992 *************** *** 29,88 **** #include "getopt.h" #include "tar.h" /* For msg() declaration if STDC_MSG. */ #include ! #include "port.h" /* For index() redefinition if USG. */ int ! getoldopt(argc, argv, optstring, long_options, opt_index) ! int argc; ! char **argv; ! char *optstring; ! struct option *long_options; ! int *opt_index; { ! extern char *optarg; /* Points to next arg */ ! extern int optind; /* Global argv index */ ! static char *key; /* Points to next keyletter */ ! static char use_getopt; /* !=0 if argv[1][0] was '-' */ ! char c; ! char *place; ! ! optarg = NULL; ! ! if (key == NULL) { /* First time */ ! if (argc < 2) return EOF; ! key = argv[1]; ! if ((*key == '-') || (*key == '+')) ! use_getopt++; ! else ! optind = 2; } ! ! if (use_getopt) ! return getopt_long(argc, argv, optstring, ! long_options, opt_index); ! ! c = *key++; ! if (c == '\0') { ! key--; ! return EOF; ! } ! place = index(optstring, c); ! ! if (place == NULL || c == ':') { ! msg("unknown option %c", c); ! return('?'); ! } ! ! place++; ! if (*place == ':') { ! if (optind < argc) { ! optarg = argv[optind]; ! optind++; ! } else { ! msg("%c argument missing", c); ! return('?'); ! } } ! return(c); } --- 29,96 ---- #include "getopt.h" #include "tar.h" /* For msg() declaration if STDC_MSG. */ #include ! #include "port.h" int ! getoldopt (argc, argv, optstring, long_options, opt_index) ! int argc; ! char **argv; ! char *optstring; ! struct option *long_options; ! int *opt_index; { ! extern char *optarg; /* Points to next arg */ ! extern int optind; /* Global argv index */ ! static char *key; /* Points to next keyletter */ ! static char use_getopt; /* !=0 if argv[1][0] was '-' */ ! char c; ! char *place; ! ! optarg = NULL; ! ! if (key == NULL) ! { /* First time */ ! if (argc < 2) ! return EOF; ! key = argv[1]; ! if ((*key == '-') || (*key == '+')) ! use_getopt++; ! else ! optind = 2; ! } ! ! if (use_getopt) ! return getopt_long (argc, argv, optstring, ! long_options, opt_index); ! ! c = *key++; ! if (c == '\0') ! { ! key--; ! return EOF; ! } ! place = index (optstring, c); ! ! if (place == NULL || c == ':') ! { ! msg ("unknown option %c", c); ! return ('?'); ! } ! ! place++; ! if (*place == ':') ! { ! if (optind < argc) ! { ! optarg = argv[optind]; ! optind++; } ! else ! { ! msg ("%c argument missing", c); ! return ('?'); } + } ! return (c); } diff -c3 tar-1.11.1/getopt.c tar-1.11.2/getopt.c *** tar-1.11.1/getopt.c Mon Aug 24 13:00:50 1992 --- tar-1.11.2/getopt.c Mon Mar 15 17:35:05 1993 *************** *** 3,9 **** "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu before changing it! ! Copyright (C) 1987, 88, 89, 90, 91, 1992 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the --- 3,10 ---- "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu before changing it! ! Copyright (C) 1987, 88, 89, 90, 91, 92, 1993 ! Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the *************** *** 19,25 **** along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! /* AIX requires this to be the first thing in the file. */ #ifdef __GNUC__ #define alloca __builtin_alloca #else /* not __GNUC__ */ --- 20,35 ---- along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! /* NOTE!!! AIX requires this to be the first thing in the file. ! Do not put ANYTHING before it! */ ! #if !defined (__GNUC__) && defined (_AIX) ! #pragma alloca ! #endif ! ! #ifdef HAVE_CONFIG_H ! #include "config.h" ! #endif ! #ifdef __GNUC__ #define alloca __builtin_alloca #else /* not __GNUC__ */ *************** *** 26,45 **** #if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__)))) #include #else ! #ifdef _AIX ! #pragma alloca ! #else char *alloca (); #endif #endif /* alloca.h */ #endif /* not __GNUC__ */ ! #include ! ! #if defined(USG) || defined(STDC_HEADERS) || defined(__GNU_LIBRARY__) ! #include #endif /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ --- 36,53 ---- #if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__)))) #include #else ! #ifndef _AIX char *alloca (); #endif #endif /* alloca.h */ #endif /* not __GNUC__ */ ! #if !__STDC__ && !defined(const) && IN_GCC ! #define const #endif + #include + /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ *************** *** 51,64 **** #define __alloca alloca #endif /* GNU C library. */ - #if !__STDC__ - #define const - #endif - /* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a long-named option. Because this is not POSIX.2 compliant, it is being phased out. */ ! #define GETOPT_COMPAT /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user --- 59,68 ---- #define __alloca alloca #endif /* GNU C library. */ /* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a long-named option. Because this is not POSIX.2 compliant, it is being phased out. */ ! /* #define GETOPT_COMPAT */ /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user *************** *** 96,101 **** --- 100,106 ---- Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ + /* XXX 1003.2 says this must be 1 before any call. */ int optind = 0; /* The next char to be scanned in the option-element *************** *** 112,117 **** --- 117,128 ---- int opterr = 1; + /* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + + int optopt = '?'; + /* Describe how to deal with options that follow non-option ARGV-elements. If the caller did not specify anything, *************** *** 147,152 **** --- 158,167 ---- } ordering; #ifdef __GNU_LIBRARY__ + /* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ #include #define my_index strchr #define my_bcopy(src, dst, n) memcpy ((dst), (src), (n)) *************** *** 490,496 **** fprintf (stderr, "%s: option `%s' requires an argument\n", argv[0], argv[optind - 1]); nextchar += strlen (nextchar); ! return '?'; } } nextchar += strlen (nextchar); --- 505,511 ---- fprintf (stderr, "%s: option `%s' requires an argument\n", argv[0], argv[optind - 1]); nextchar += strlen (nextchar); ! return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); *************** *** 544,555 **** --- 559,576 ---- { if (opterr) { + #if 0 if (c < 040 || c >= 0177) fprintf (stderr, "%s: unrecognized option, character code 0%o\n", argv[0], c); else fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c); + #else + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c); + #endif } + optopt = c; return '?'; } if (temp[1] == ':') *************** *** 579,587 **** else if (optind == argc) { if (opterr) ! fprintf (stderr, "%s: option `-%c' requires an argument\n", ! argv[0], c); ! c = '?'; } else /* We already incremented `optind' once; --- 600,620 ---- else if (optind == argc) { if (opterr) ! { ! #if 0 ! fprintf (stderr, "%s: option `-%c' requires an argument\n", ! argv[0], c); ! #else ! /* 1003.2 specifies the format of this message. */ ! fprintf (stderr, "%s: option requires an argument -- %c\n", ! argv[0], c); ! #endif ! } ! optopt = c; ! if (optstring[0] == ':') ! c = ':'; ! else ! c = '?'; } else /* We already incremented `optind' once; diff -c3 tar-1.11.1/getopt.h tar-1.11.2/getopt.h *** tar-1.11.1/getopt.h Fri Sep 11 10:41:55 1992 --- tar-1.11.2/getopt.h Wed Jan 13 15:28:00 1993 *************** *** 86,97 **** /* Names for the values of the `has_arg' field of `struct option'. */ ! enum _argtype ! { ! no_argument, ! required_argument, ! optional_argument ! }; #if __STDC__ #if defined(__GNU_LIBRARY__) --- 86,94 ---- /* Names for the values of the `has_arg' field of `struct option'. */ ! #define no_argument 0 ! #define required_argument 1 ! #define optional_argument 2 #if __STDC__ #if defined(__GNU_LIBRARY__) diff -c3 tar-1.11.1/getopt1.c tar-1.11.2/getopt1.c *** tar-1.11.1/getopt1.c Tue Aug 18 17:33:48 1992 --- tar-1.11.2/getopt1.c Sun Jan 17 19:51:30 1993 *************** *** 15,31 **** along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "getopt.h" ! #ifndef __STDC__ #define const #endif ! #if defined(STDC_HEADERS) || defined(__GNU_LIBRARY__) || defined (LIBC) #include ! #else /* STDC_HEADERS or __GNU_LIBRARY__ */ char *getenv (); ! #endif /* STDC_HEADERS or __GNU_LIBRARY__ */ #ifndef NULL #define NULL 0 --- 15,39 ---- along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + #ifdef HAVE_CONFIG_H + #include "config.h" + #endif + #include "getopt.h" ! #if !__STDC__ && !defined(const) && IN_GCC #define const #endif ! #include ! ! /* This needs to come after some library #include ! to get __GNU_LIBRARY__ defined. */ ! #ifdef __GNU_LIBRARY__ #include ! #else char *getenv (); ! #endif #ifndef NULL #define NULL 0 diff -c3 tar-1.11.1/getpagesize.h tar-1.11.2/getpagesize.h *** tar-1.11.1/getpagesize.h Tue Sep 15 20:13:03 1992 --- tar-1.11.2/getpagesize.h Sun Mar 14 16:39:55 1993 *************** *** 6,12 **** #ifndef HAVE_GETPAGESIZE ! #ifdef _POSIX_VERSION #include #endif --- 6,16 ---- #ifndef HAVE_GETPAGESIZE ! #ifdef VMS ! #define getpagesize() 512 ! #endif ! ! #ifdef HAVE_UNISTD_H #include #endif diff -c3 tar-1.11.1/gnu.c tar-1.11.2/gnu.c *** tar-1.11.1/gnu.c Mon Sep 14 16:38:21 1992 --- tar-1.11.2/gnu.c Mon Mar 15 13:22:58 1993 *************** *** 1,5 **** /* GNU dump extensions to tar. ! Copyright (C) 1988, 1992 Free Software Foundation This file is part of GNU Tar. --- 1,5 ---- /* GNU dump extensions to tar. ! Copyright (C) 1988, 1992, 1993 Free Software Foundation This file is part of GNU Tar. *************** *** 25,57 **** extern int errno; #endif #include ! time_t time(); #include "tar.h" #include "port.h" - #if defined(_POSIX_VERSION) || defined(DIRENT) - #include - #ifdef direct - #undef direct - #endif /* direct */ - #define direct dirent - #define DP_NAMELEN(x) strlen((x)->d_name) - #endif /* _POSIX_VERSION or DIRENT */ - #if !defined(_POSIX_VERSION) && !defined(DIRENT) && defined(BSD42) - #include - #define DP_NAMELEN(x) (x)->d_namlen - #endif /* not _POSIX_VERSION and BSD42 */ - #ifdef __MSDOS__ - #include "msd_dir.h" - #define DP_NAMELEN(x) (x)->d_namlen - #define direct dirent - #endif - #if defined(USG) && !defined(_POSIX_VERSION) && !defined(DIRENT) - #include - #define DP_NAMELEN(x) strlen((x)->d_name) - #endif /* USG and not _POSIX_VERSION and not DIRENT */ - #ifndef S_ISLNK #define lstat stat #endif --- 25,35 ---- extern int errno; #endif #include ! time_t time (); #include "tar.h" #include "port.h" #ifndef S_ISLNK #define lstat stat #endif *************** *** 59,217 **** extern time_t new_time; extern FILE *msg_file; ! void addname(); ! int check_exclude(); ! extern PTR ck_malloc(); ! extern PTR ck_realloc(); ! int confirm(); ! extern PTR init_buffer(); ! extern char *get_buffer(); ! int is_dot_or_dotdot(); ! extern void add_buffer(); ! extern void flush_buffer(); ! void name_gather(); ! int recursively_delete(); ! void skip_file(); ! char *un_quote_string(); ! ! extern char *new_name(); ! ! static void add_dir_name(); ! ! struct dirname { ! struct dirname *next; ! char *name; ! char *dir_text; ! int dev; ! int ino; ! int allnew; ! }; static struct dirname *dir_list; static time_t this_time; void ! add_dir(name,dev,ino,text) ! char *name; ! char *text; ! dev_t dev; ! ino_t ino; ! { ! struct dirname *dp; ! ! dp=(struct dirname *)malloc(sizeof(struct dirname)); ! if(!dp) ! abort(); ! dp->next=dir_list; ! dir_list=dp; ! dp->dev=dev; ! dp->ino=ino; ! dp->name=malloc(strlen(name)+1); ! strcpy(dp->name,name); ! dp->dir_text=text; ! dp->allnew=0; } void ! read_dir_file() { ! int dev; ! int ino; ! char *strp; ! FILE *fp; ! char buf[512]; ! static char *path = 0; ! ! if (path == 0) ! path = ck_malloc(PATH_MAX); ! time(&this_time); ! if(gnu_dumpfile[0]!='/') { ! #if defined(__MSDOS__) || defined(USG) || defined(_POSIX_VERSION) ! if(!getcwd(path,PATH_MAX)) { ! msg("Couldn't get current directory."); ! exit(EX_SYSTEM); ! } #else ! char *getwd(); ! if(!getwd(path)) { ! msg("Couldn't get current directory: %s",path); ! exit(EX_SYSTEM); ! } ! #endif ! /* If this doesn't fit, we're in serious trouble */ ! strcat(path,"/"); ! strcat(path,gnu_dumpfile); ! gnu_dumpfile=path; ! } ! fp=fopen(gnu_dumpfile,"r"); ! if(fp==0 && errno!=ENOENT) { ! msg_perror("Can't open %s",gnu_dumpfile); ! return; ! } ! if(!fp) ! return; ! fgets(buf,sizeof(buf),fp); ! if(!f_new_files) { ! f_new_files++; ! new_time=atol(buf); ! } ! while(fgets(buf,sizeof(buf),fp)) { ! strp= &buf[strlen(buf)]; ! if(strp[-1]=='\n') ! strp[-1]='\0'; ! strp=buf; ! dev=atol(strp); ! while(isdigit(*strp)) ! strp++; ! ino=atol(strp); ! while(isspace(*strp)) ! strp++; ! while(isdigit(*strp)) ! strp++; ! strp++; ! add_dir(un_quote_string(strp),dev,ino,(char *)0); } ! fclose(fp); } void ! write_dir_file() { ! FILE *fp; ! struct dirname *dp; ! char *str; ! extern char *quote_copy_string(); ! ! fp=fopen(gnu_dumpfile,"w"); ! if(fp==0) { ! msg_perror("Can't write to %s",gnu_dumpfile); ! return; ! } ! fprintf(fp,"%lu\n",this_time); ! for(dp=dir_list;dp;dp=dp->next) { ! if(!dp->dir_text) ! continue; ! str=quote_copy_string(dp->name); ! if(str) { ! fprintf(fp,"%u %u %s\n",dp->dev,dp->ino,str); ! free(str); ! } else ! fprintf(fp,"%u %u %s\n",dp->dev,dp->ino,dp->name); ! } ! fclose(fp); } struct dirname * ! get_dir(name) ! char *name; { ! struct dirname *dp; ! for(dp=dir_list;dp;dp=dp->next) { ! if(!strcmp(dp->name,name)) ! return dp; ! } ! return 0; } --- 37,207 ---- extern time_t new_time; extern FILE *msg_file; ! void addname (); ! int check_exclude (); ! extern PTR ck_malloc (); ! extern PTR ck_realloc (); ! int confirm (); ! extern PTR init_buffer (); ! extern char *get_buffer (); ! int is_dot_or_dotdot (); ! extern void add_buffer (); ! extern void flush_buffer (); ! void name_gather (); ! int recursively_delete (); ! void skip_file (); ! char *un_quote_string (); ! ! extern char *new_name (); ! ! static void add_dir_name (); ! ! struct dirname ! { ! struct dirname *next; ! char *name; ! char *dir_text; ! int dev; ! int ino; ! int allnew; ! }; static struct dirname *dir_list; static time_t this_time; void ! add_dir (name, dev, ino, text) ! char *name; ! char *text; ! dev_t dev; ! ino_t ino; ! { ! struct dirname *dp; ! ! dp = (struct dirname *) ck_malloc (sizeof (struct dirname)); ! if (!dp) ! abort (); ! dp->next = dir_list; ! dir_list = dp; ! dp->dev = dev; ! dp->ino = ino; ! dp->name = ck_malloc (strlen (name) + 1); ! strcpy (dp->name, name); ! dp->dir_text = text; ! dp->allnew = 0; } void ! read_dir_file () { ! int dev; ! int ino; ! char *strp; ! FILE *fp; ! char buf[512]; ! static char *path = 0; ! ! if (path == 0) ! path = ck_malloc (PATH_MAX); ! time (&this_time); ! if (gnu_dumpfile[0] != '/') ! { ! #if defined(__MSDOS__) || defined(HAVE_GETCWD) || defined(_POSIX_VERSION) ! if (!getcwd (path, PATH_MAX)) ! { ! msg ("Couldn't get current directory."); ! exit (EX_SYSTEM); ! } #else ! char *getwd (); ! if (!getwd (path)) ! { ! msg ("Couldn't get current directory: %s", path); ! exit (EX_SYSTEM); } ! #endif ! /* If this doesn't fit, we're in serious trouble */ ! strcat (path, "/"); ! strcat (path, gnu_dumpfile); ! gnu_dumpfile = path; ! } ! fp = fopen (gnu_dumpfile, "r"); ! if (fp == 0 && errno != ENOENT) ! { ! msg_perror ("Can't open %s", gnu_dumpfile); ! return; ! } ! if (!fp) ! return; ! fgets (buf, sizeof (buf), fp); ! if (!f_new_files) ! { ! f_new_files++; ! new_time = atol (buf); ! } ! while (fgets (buf, sizeof (buf), fp)) ! { ! strp = &buf[strlen (buf)]; ! if (strp[-1] == '\n') ! strp[-1] = '\0'; ! strp = buf; ! dev = atol (strp); ! while (isdigit (*strp)) ! strp++; ! ino = atol (strp); ! while (isspace (*strp)) ! strp++; ! while (isdigit (*strp)) ! strp++; ! strp++; ! add_dir (un_quote_string (strp), dev, ino, (char *) 0); ! } ! fclose (fp); } void ! write_dir_file () { ! FILE *fp; ! struct dirname *dp; ! char *str; ! extern char *quote_copy_string (); ! ! fp = fopen (gnu_dumpfile, "w"); ! if (fp == 0) ! { ! msg_perror ("Can't write to %s", gnu_dumpfile); ! return; ! } ! fprintf (fp, "%lu\n", this_time); ! for (dp = dir_list; dp; dp = dp->next) ! { ! if (!dp->dir_text) ! continue; ! str = quote_copy_string (dp->name); ! if (str) ! { ! fprintf (fp, "%u %u %s\n", dp->dev, dp->ino, str); ! free (str); ! } ! else ! fprintf (fp, "%u %u %s\n", dp->dev, dp->ino, dp->name); ! } ! fclose (fp); } struct dirname * ! get_dir (name) ! char *name; { ! struct dirname *dp; ! for (dp = dir_list; dp; dp = dp->next) ! { ! if (!strcmp (dp->name, name)) ! return dp; ! } ! return 0; } *************** *** 218,514 **** /* Collect all the names from argv[] (or whatever), then expand them into a directory tree, and put all the directories at the beginning. */ void ! collect_and_sort_names() { ! struct name *n,*n_next; ! int num_names; ! struct stat statbuf; ! int name_cmp(); ! char *merge_sort(); ! ! name_gather(); ! ! if(gnu_dumpfile) ! read_dir_file(); ! if(!namelist) addname("."); ! for(n=namelist;n;n=n_next) { ! n_next=n->next; ! if(n->found || n->dir_contents) ! continue; ! if(n->regexp) /* FIXME just skip regexps for now */ ! continue; ! if(n->change_dir) ! if(chdir(n->change_dir)<0) { ! msg_perror("can't chdir to %s",n->change_dir); ! continue; ! } #ifdef AIX ! if (statx (n->name, &statbuf, STATSIZE, STX_HIDDEN|STX_LINK)) #else ! if(lstat(n->name,&statbuf)<0) #endif /* AIX */ ! { ! msg_perror("can't stat %s",n->name); ! continue; ! } ! if(S_ISDIR(statbuf.st_mode)) { ! n->found++; ! add_dir_name(n->name,statbuf.st_dev); ! } ! } ! ! num_names=0; ! for(n=namelist;n;n=n->next) ! num_names++; ! namelist=(struct name *)merge_sort((PTR)namelist,num_names,(char *)(&(namelist->next))-(char *)namelist,name_cmp); ! ! for(n=namelist;n;n=n->next) { ! n->found=0; ! } ! if(gnu_dumpfile) ! write_dir_file(); } int ! name_cmp(n1,n2) ! struct name *n1,*n2; { ! if(n1->found) { ! if(n2->found) ! return strcmp(n1->name,n2->name); ! else ! return -1; ! } else if(n2->found) ! return 1; ! else ! return strcmp(n1->name,n2->name); } int ! dirent_cmp(p1,p2) ! const PTR p1; ! const PTR p2; { ! char *frst,*scnd; ! frst= (*(char **)p1)+1; ! scnd= (*(char **)p2)+1; ! return strcmp(frst,scnd); } char * ! get_dir_contents(p,device) ! char *p; ! int device; ! { ! DIR *dirp; ! register struct direct *d; ! char *new_buf; ! char *namebuf; ! int bufsiz; ! int len; ! PTR the_buffer; ! char *buf; ! size_t n_strs; ! /* int n_size;*/ ! char *p_buf; ! char **vec,**p_vec; ! ! extern int errno; ! ! errno=0; ! dirp=opendir(p); ! bufsiz=strlen(p)+NAMSIZ; ! namebuf=ck_malloc(bufsiz+2); ! if(!dirp) { ! if(errno) ! msg_perror("can't open directory %s",p); ! else ! msg("error opening directory %s",p); ! new_buf=NULL; ! } else { ! struct dirname *dp; ! int all_children; ! ! dp=get_dir(p); ! all_children= dp ? dp->allnew : 0; ! (void) strcpy(namebuf,p); ! if(p[strlen(p)-1]!='/') ! (void) strcat(namebuf,"/"); ! len=strlen(namebuf); ! ! the_buffer=init_buffer(); ! while(d=readdir(dirp)) { ! struct stat hs; ! ! /* Skip . and .. */ ! if(is_dot_or_dotdot(d->d_name)) ! continue; ! if(DP_NAMELEN(d) + len >=bufsiz) { ! bufsiz+=NAMSIZ; ! namebuf=ck_realloc(namebuf,bufsiz+2); ! } ! (void) strcpy(namebuf+len,d->d_name); #ifdef AIX ! if (0 != f_follow_links? ! statx(namebuf, &hs, STATSIZE, STX_HIDDEN): ! statx(namebuf, &hs, STATSIZE, STX_HIDDEN|STX_LINK)) #else ! if (0 != f_follow_links? stat(namebuf, &hs): lstat(namebuf, &hs)) #endif ! { ! msg_perror("can't stat %s",namebuf); ! continue; ! } ! if( (f_local_filesys && device!=hs.st_dev) ! || (f_exclude && check_exclude(namebuf))) ! add_buffer(the_buffer,"N",1); #ifdef AIX ! else if (S_ISHIDDEN (hs.st_mode)) { ! add_buffer (the_buffer, "D", 1); ! strcat (d->d_name, "A"); ! d->d_namlen++; ! } #endif /* AIX */ ! else if(S_ISDIR(hs.st_mode)) { ! if(dp=get_dir(namebuf)) { ! if( dp->dev!=hs.st_dev ! || dp->ino!=hs.st_ino) { ! if(f_verbose) ! msg("directory %s has been renamed.",namebuf); ! dp->allnew=1; ! dp->dev=hs.st_dev; ! dp->ino=hs.st_ino; ! } ! dp->dir_text=""; ! } else { ! if(f_verbose) ! msg("Directory %s is new",namebuf); ! add_dir(namebuf,hs.st_dev,hs.st_ino,""); ! dp=get_dir(namebuf); ! dp->allnew=1; ! } ! if(all_children) ! dp->allnew=1; ! ! add_buffer(the_buffer,"D",1); ! } else if( !all_children ! && f_new_files ! && new_time>hs.st_mtime ! && ( f_new_files>1 ! || new_time>hs.st_ctime)) ! add_buffer(the_buffer,"N",1); ! else ! add_buffer(the_buffer,"Y",1); ! add_buffer(the_buffer,d->d_name,(int)(DP_NAMELEN(d)+1)); } ! add_buffer(the_buffer,"\000\000",2); ! closedir(dirp); ! ! /* Well, we've read in the contents of the dir, now sort them */ ! buf=get_buffer(the_buffer); ! if(buf[0]=='\0') { ! flush_buffer(the_buffer); ! new_buf=NULL; ! } else { ! n_strs=0; ! for(p_buf=buf;*p_buf;) { ! int tmp; ! ! tmp=strlen(p_buf)+1; ! n_strs++; ! p_buf+=tmp; ! } ! vec=(char **)malloc(sizeof(char *)*(n_strs+1)); ! for(p_vec=vec,p_buf=buf;*p_buf;p_buf+=strlen(p_buf)+1) ! *p_vec++= p_buf; ! *p_vec= 0; ! qsort((PTR)vec,n_strs,sizeof(char *),dirent_cmp); ! new_buf=(char *)malloc(p_buf-buf+2); ! for(p_vec=vec,p_buf=new_buf;*p_vec;p_vec++) { ! char *p_tmp; ! ! for(p_tmp= *p_vec;*p_buf++= *p_tmp++;) ! ; ! } ! *p_buf++='\0'; ! free(vec); ! flush_buffer(the_buffer); } ! } ! free(namebuf); ! return new_buf; } /* p is a directory. Add all the files in P to the namelist. If any of the files is a directory, recurse on the subdirectory. . . */ static void ! add_dir_name(p,device) ! char *p; ! int device; ! { ! char *new_buf; ! char *p_buf; ! ! char *namebuf; ! int buflen; ! register int len; ! int sublen; ! ! /* PTR the_buffer;*/ ! ! /* char *buf;*/ ! /* char **vec,**p_vec;*/ ! /* int n_strs,n_size;*/ ! ! struct name *n; ! ! int dirent_cmp(); ! ! new_buf=get_dir_contents(p,device); ! ! for(n=namelist;n;n=n->next) { ! if(!strcmp(n->name,p)) { ! n->dir_contents = new_buf ? new_buf : "\0\0\0\0"; ! break; ! } ! } ! ! if (new_buf) ! { ! len=strlen(p); ! buflen= NAMSIZ<=len ? len + NAMSIZ : NAMSIZ; ! namebuf= ck_malloc(buflen+1); ! ! (void)strcpy(namebuf,p); ! if(namebuf[len-1]!='/') { ! namebuf[len++]='/'; ! namebuf[len]='\0'; ! } ! for(p_buf=new_buf;*p_buf;p_buf+=sublen+1) { ! sublen=strlen(p_buf); ! if(*p_buf=='D') { ! if(len+sublen>=buflen) { ! buflen+=NAMSIZ; ! namebuf= ck_realloc(namebuf,buflen+1); } ! (void)strcpy(namebuf+len,p_buf+1); ! addname(namebuf); ! add_dir_name(namebuf,device); ! } } ! free(namebuf); ! } } /* Returns non-zero if p is . or .. This could be a macro for speed. */ int ! is_dot_or_dotdot(p) ! char *p; { ! return (p[0]=='.' && (p[1]=='\0' || (p[1]=='.' && p[2]=='\0'))); } --- 208,534 ---- /* Collect all the names from argv[] (or whatever), then expand them into a directory tree, and put all the directories at the beginning. */ void ! collect_and_sort_names () { ! struct name *n, *n_next; ! int num_names; ! struct stat statbuf; ! int name_cmp (); ! char *merge_sort (); ! ! name_gather (); ! ! if (gnu_dumpfile) ! read_dir_file (); ! if (!namelist) ! addname ("."); ! for (n = namelist; n; n = n_next) ! { ! n_next = n->next; ! if (n->found || n->dir_contents) ! continue; ! if (n->regexp) /* FIXME just skip regexps for now */ ! continue; ! if (n->change_dir) ! if (chdir (n->change_dir) < 0) ! { ! msg_perror ("can't chdir to %s", n->change_dir); ! continue; ! } #ifdef AIX ! if (statx (n->name, &statbuf, STATSIZE, STX_HIDDEN | STX_LINK)) #else ! if (lstat (n->name, &statbuf) < 0) #endif /* AIX */ ! { ! msg_perror ("can't stat %s", n->name); ! continue; ! } ! if (S_ISDIR (statbuf.st_mode)) ! { ! n->found++; ! add_dir_name (n->name, statbuf.st_dev); ! } ! } ! ! num_names = 0; ! for (n = namelist; n; n = n->next) ! num_names++; ! namelist = (struct name *) merge_sort ((PTR) namelist, num_names, (char *) (&(namelist->next)) - (char *) namelist, name_cmp); ! ! for (n = namelist; n; n = n->next) ! { ! n->found = 0; ! } ! if (gnu_dumpfile) ! write_dir_file (); } int ! name_cmp (n1, n2) ! struct name *n1, *n2; { ! if (n1->found) ! { ! if (n2->found) ! return strcmp (n1->name, n2->name); ! else ! return -1; ! } ! else if (n2->found) ! return 1; ! else ! return strcmp (n1->name, n2->name); } int ! dirent_cmp (p1, p2) ! const PTR p1; ! const PTR p2; { ! char *frst, *scnd; ! frst = (*(char **) p1) + 1; ! scnd = (*(char **) p2) + 1; ! return strcmp (frst, scnd); } char * ! get_dir_contents (p, device) ! char *p; ! int device; ! { ! DIR *dirp; ! register struct dirent *d; ! char *new_buf; ! char *namebuf; ! int bufsiz; ! int len; ! PTR the_buffer; ! char *buf; ! size_t n_strs; ! /* int n_size;*/ ! char *p_buf; ! char **vec, **p_vec; ! ! extern int errno; ! ! errno = 0; ! dirp = opendir (p); ! bufsiz = strlen (p) + NAMSIZ; ! namebuf = ck_malloc (bufsiz + 2); ! if (!dirp) ! { ! if (errno) ! msg_perror ("can't open directory %s", p); ! else ! msg ("error opening directory %s", p); ! new_buf = NULL; ! } ! else ! { ! struct dirname *dp; ! int all_children; ! ! dp = get_dir (p); ! all_children = dp ? dp->allnew : 0; ! (void) strcpy (namebuf, p); ! if (p[strlen (p) - 1] != '/') ! (void) strcat (namebuf, "/"); ! len = strlen (namebuf); ! ! the_buffer = init_buffer (); ! while (d = readdir (dirp)) ! { ! struct stat hs; ! ! /* Skip . and .. */ ! if (is_dot_or_dotdot (d->d_name)) ! continue; ! if (NLENGTH (d) + len >= bufsiz) ! { ! bufsiz += NAMSIZ; ! namebuf = ck_realloc (namebuf, bufsiz + 2); ! } ! (void) strcpy (namebuf + len, d->d_name); #ifdef AIX ! if (0 != f_follow_links ? ! statx (namebuf, &hs, STATSIZE, STX_HIDDEN) : ! statx (namebuf, &hs, STATSIZE, STX_HIDDEN | STX_LINK)) #else ! if (0 != f_follow_links ? stat (namebuf, &hs) : lstat (namebuf, &hs)) #endif ! { ! msg_perror ("can't stat %s", namebuf); ! continue; ! } ! if ((f_local_filesys && device != hs.st_dev) ! || (f_exclude && check_exclude (namebuf))) ! add_buffer (the_buffer, "N", 1); #ifdef AIX ! else if (S_ISHIDDEN (hs.st_mode)) ! { ! add_buffer (the_buffer, "D", 1); ! strcat (d->d_name, "A"); ! d->d_namlen++; ! } #endif /* AIX */ ! else if (S_ISDIR (hs.st_mode)) ! { ! if (dp = get_dir (namebuf)) ! { ! if (dp->dev != hs.st_dev ! || dp->ino != hs.st_ino) ! { ! if (f_verbose) ! msg ("directory %s has been renamed.", namebuf); ! dp->allnew = 1; ! dp->dev = hs.st_dev; ! dp->ino = hs.st_ino; ! } ! dp->dir_text = ""; } ! else ! { ! if (f_verbose) ! msg ("Directory %s is new", namebuf); ! add_dir (namebuf, hs.st_dev, hs.st_ino, ""); ! dp = get_dir (namebuf); ! dp->allnew = 1; } ! if (all_children) ! dp->allnew = 1; ! ! add_buffer (the_buffer, "D", 1); ! } ! else if (!all_children ! && f_new_files ! && new_time > hs.st_mtime ! && (f_new_files > 1 ! || new_time > hs.st_ctime)) ! add_buffer (the_buffer, "N", 1); ! else ! add_buffer (the_buffer, "Y", 1); ! add_buffer (the_buffer, d->d_name, (int) (NLENGTH (d) + 1)); ! } ! add_buffer (the_buffer, "\000\000", 2); ! closedir (dirp); ! ! /* Well, we've read in the contents of the dir, now sort them */ ! buf = get_buffer (the_buffer); ! if (buf[0] == '\0') ! { ! flush_buffer (the_buffer); ! new_buf = NULL; ! } ! else ! { ! n_strs = 0; ! for (p_buf = buf; *p_buf;) ! { ! int tmp; ! ! tmp = strlen (p_buf) + 1; ! n_strs++; ! p_buf += tmp; ! } ! vec = (char **) ck_malloc (sizeof (char *) * (n_strs + 1)); ! for (p_vec = vec, p_buf = buf; *p_buf; p_buf += strlen (p_buf) + 1) ! *p_vec++ = p_buf; ! *p_vec = 0; ! qsort ((PTR) vec, n_strs, sizeof (char *), dirent_cmp); ! new_buf = (char *) ck_malloc (p_buf - buf + 2); ! for (p_vec = vec, p_buf = new_buf; *p_vec; p_vec++) ! { ! char *p_tmp; ! ! for (p_tmp = *p_vec; *p_buf++ = *p_tmp++;) ! ; ! } ! *p_buf++ = '\0'; ! free (vec); ! flush_buffer (the_buffer); ! } ! } ! free (namebuf); ! return new_buf; } /* p is a directory. Add all the files in P to the namelist. If any of the files is a directory, recurse on the subdirectory. . . */ static void ! add_dir_name (p, device) ! char *p; ! int device; ! { ! char *new_buf; ! char *p_buf; ! ! char *namebuf; ! int buflen; ! register int len; ! int sublen; ! ! /* PTR the_buffer;*/ ! ! /* char *buf;*/ ! /* char **vec,**p_vec;*/ ! /* int n_strs,n_size;*/ ! ! struct name *n; ! ! int dirent_cmp (); ! ! new_buf = get_dir_contents (p, device); ! ! for (n = namelist; n; n = n->next) ! { ! if (!strcmp (n->name, p)) ! { ! n->dir_contents = new_buf ? new_buf : "\0\0\0\0"; ! break; ! } ! } ! ! if (new_buf) ! { ! len = strlen (p); ! buflen = NAMSIZ <= len ? len + NAMSIZ : NAMSIZ; ! namebuf = ck_malloc (buflen + 1); ! ! (void) strcpy (namebuf, p); ! if (namebuf[len - 1] != '/') ! { ! namebuf[len++] = '/'; ! namebuf[len] = '\0'; ! } ! for (p_buf = new_buf; *p_buf; p_buf += sublen + 1) ! { ! sublen = strlen (p_buf); ! if (*p_buf == 'D') ! { ! if (len + sublen >= buflen) ! { ! buflen += NAMSIZ; ! namebuf = ck_realloc (namebuf, buflen + 1); } ! (void) strcpy (namebuf + len, p_buf + 1); ! addname (namebuf); ! add_dir_name (namebuf, device); } ! } ! free (namebuf); ! } } /* Returns non-zero if p is . or .. This could be a macro for speed. */ int ! is_dot_or_dotdot (p) ! char *p; { ! return (p[0] == '.' && (p[1] == '\0' || (p[1] == '.' && p[2] == '\0'))); } *************** *** 517,645 **** void ! gnu_restore(skipcrud) ! int skipcrud; { ! char *current_dir; ! /* int current_dir_length; */ ! ! char *archive_dir; ! /* int archive_dir_length; */ ! PTR the_buffer; ! char *p; ! DIR *dirp; ! struct direct *d; ! char *cur,*arc; ! extern struct stat hstat; /* Stat struct corresponding */ ! long size,copied; ! char *from,*to; ! extern union record *head; ! dirp=opendir(skipcrud+current_file_name); ! ! if(!dirp) { ! /* The directory doesn't exist now. It'll be created. In any case, we don't have to delete any files out of it */ ! skip_file((long)hstat.st_size); ! return; ! } ! ! the_buffer=init_buffer(); ! while(d=readdir(dirp)) { ! if(is_dot_or_dotdot(d->d_name)) ! continue; ! ! add_buffer(the_buffer,d->d_name,(int)(DP_NAMELEN(d)+1)); ! } ! closedir(dirp); ! add_buffer(the_buffer,"",1); ! ! current_dir=get_buffer(the_buffer); ! archive_dir=(char *)malloc(hstat.st_size); ! if(archive_dir==0) { ! msg("Can't allocate %d bytes for restore",hstat.st_size); ! skip_file((long)hstat.st_size); ! return; ! } ! to=archive_dir; ! for(size=hstat.st_size;size>0;size-=copied) { ! from=findrec()->charptr; ! if(!from) { ! msg("Unexpected EOF in archive\n"); ! break; ! } ! copied=endofrecs()->charptr - from; ! if(copied>size) ! copied=size; ! bcopy((PTR)from,(PTR)to,(int)copied); ! to+=copied; ! userec((union record *)(from+copied-1)); } ! for(cur=current_dir;*cur;cur+=strlen(cur)+1) { ! for(arc=archive_dir;*arc;arc+=strlen(arc)+1) { ! arc++; ! if(!strcmp(arc,cur)) ! break; ! } ! if(*arc=='\0') { ! p=new_name(skipcrud+current_file_name,cur); ! if(f_confirm && !confirm("delete",p)) { ! free(p); ! continue; ! } ! if(f_verbose) ! fprintf(msg_file,"%s: deleting %s\n",tar,p); ! if(recursively_delete(p)) { ! msg("%s: Error while deleting %s\n",tar,p); ! } ! free(p); ! } ! ! } ! flush_buffer(the_buffer); ! free(archive_dir); } int ! recursively_delete(path) ! char *path; { ! struct stat sbuf; ! DIR *dirp; ! struct direct *dp; ! char *path_buf; ! /* int path_len; */ ! ! ! if(lstat(path,&sbuf)<0) ! return 1; ! if(S_ISDIR(sbuf.st_mode)) { ! ! /* path_len=strlen(path); */ ! dirp=opendir(path); ! if(dirp==0) ! return 1; ! while(dp=readdir(dirp)) { ! if(is_dot_or_dotdot(dp->d_name)) ! continue; ! path_buf=new_name(path,dp->d_name); ! if(recursively_delete(path_buf)) { ! free(path_buf); ! closedir(dirp); ! return 1; ! } ! free(path_buf); ! } ! closedir(dirp); ! if(rmdir(path)<0) ! return 1; ! return 0; ! } ! if(unlink(path)<0) ! return 1; ! return 0; } - --- 537,677 ---- void ! gnu_restore (skipcrud) ! int skipcrud; { ! char *current_dir; ! /* int current_dir_length; */ ! char *archive_dir; ! /* int archive_dir_length; */ ! PTR the_buffer; ! char *p; ! DIR *dirp; ! struct dirent *d; ! char *cur, *arc; ! extern struct stat hstat; /* Stat struct corresponding */ ! long size, copied; ! char *from, *to; ! extern union record *head; ! ! dirp = opendir (skipcrud + current_file_name); ! ! if (!dirp) ! { ! /* The directory doesn't exist now. It'll be created. In any case, we don't have to delete any files out of it */ ! skip_file ((long) hstat.st_size); ! return; ! } ! ! the_buffer = init_buffer (); ! while (d = readdir (dirp)) ! { ! if (is_dot_or_dotdot (d->d_name)) ! continue; ! ! add_buffer (the_buffer, d->d_name, (int) (NLENGTH (d) + 1)); ! } ! closedir (dirp); ! add_buffer (the_buffer, "", 1); ! ! current_dir = get_buffer (the_buffer); ! archive_dir = (char *) ck_malloc (hstat.st_size); ! if (archive_dir == 0) ! { ! msg ("Can't allocate %d bytes for restore", hstat.st_size); ! skip_file ((long) hstat.st_size); ! return; ! } ! to = archive_dir; ! for (size = hstat.st_size; size > 0; size -= copied) ! { ! from = findrec ()->charptr; ! if (!from) ! { ! msg ("Unexpected EOF in archive\n"); ! break; ! } ! copied = endofrecs ()->charptr - from; ! if (copied > size) ! copied = size; ! bcopy ((PTR) from, (PTR) to, (int) copied); ! to += copied; ! userec ((union record *) (from + copied - 1)); ! } ! ! for (cur = current_dir; *cur; cur += strlen (cur) + 1) ! { ! for (arc = archive_dir; *arc; arc += strlen (arc) + 1) ! { ! arc++; ! if (!strcmp (arc, cur)) ! break; ! } ! if (*arc == '\0') ! { ! p = new_name (skipcrud + current_file_name, cur); ! if (f_confirm && !confirm ("delete", p)) ! { ! free (p); ! continue; ! } ! if (f_verbose) ! fprintf (msg_file, "%s: deleting %s\n", tar, p); ! if (recursively_delete (p)) ! { ! msg ("%s: Error while deleting %s\n", tar, p); ! } ! free (p); } ! } ! flush_buffer (the_buffer); ! free (archive_dir); } int ! recursively_delete (path) ! char *path; { ! struct stat sbuf; ! DIR *dirp; ! struct dirent *dp; ! char *path_buf; ! /* int path_len; */ ! ! ! if (lstat (path, &sbuf) < 0) ! return 1; ! if (S_ISDIR (sbuf.st_mode)) ! { ! ! /* path_len=strlen(path); */ ! dirp = opendir (path); ! if (dirp == 0) ! return 1; ! while (dp = readdir (dirp)) ! { ! if (is_dot_or_dotdot (dp->d_name)) ! continue; ! path_buf = new_name (path, dp->d_name); ! if (recursively_delete (path_buf)) ! { ! free (path_buf); ! closedir (dirp); ! return 1; ! } ! free (path_buf); ! } ! closedir (dirp); ! if (rmdir (path) < 0) ! return 1; ! return 0; ! } ! if (unlink (path) < 0) ! return 1; ! return 0; } diff -c3 tar-1.11.1/level-0 tar-1.11.2/level-0 *** tar-1.11.1/level-0 Thu Sep 10 06:09:01 1992 --- tar-1.11.2/level-0 Thu Mar 25 11:54:39 1993 *************** *** 1,7 **** #!/bin/sh # # Run this script as root on the machine that has the tape drive, to make a ! # full dump. # # If you give `now' as an argument, the dump is done immediately. # Otherwise, it waits until 1am, or until the hour given as argument. --- 1,7 ---- #!/bin/sh # # Run this script as root on the machine that has the tape drive, to make a ! # full (level-0) dump. # # If you give `now' as an argument, the dump is done immediately. # Otherwise, it waits until 1am, or until the hour given as argument. *************** *** 9,143 **** # # You must edit the file `backup-specs' to set the parameters for your site. if [ ! -w / ]; then ! echo The backup must be run as root, ! echo or else some files will fail to be dumped. exit 1 - else - false fi ! # This is undesirable -- rms. ! # rsh albert /usr/local/adm/motd-backup-start ! ! # Get the values of BACKUP_DIRS and BACKUP_FILES, and other variables. . ./backup-specs # Maybe sleep until around specified or default hour. ! # ! if [ "$1" != "now" ]; then ! if [ "$1"x != x ]; then ! spec=$1 else ! spec=$BACKUP_HOUR fi ! pausetime=`date | awk '{hr=substr($4,1,2);\\ ! mn=substr($4,4,2);\\ ! if((hr+0)<(spec+0))\\ ! print 3600*(spec-hr)-60*mn;\\ ! else\\ ! print 3600*(spec+(24-hr))-60*mn; }' spec=$spec` clear ! cat ./dont_touch ! sleep $pausetime fi # start doing things ! here=`pwd` ! LOGFILE=log-`date | awk '{print $2 "-" $3 "-" $6}'`-full ! HOST=`hostname | sed 's/\..*//'` ! TAR_PART1="/usr/local/bin/tar -c --multi-volume --one-file-system --block=$BLOCKING --sparse --volno-file=$VOLNO_FILE --atime-preserve" # Make sure the log file did not already exist. Create it. ! if [ -f $LOGFILE ] ; then ! echo Log file $LOGFILE already exists. exit 1 else ! touch $LOGFILE fi ! mt -f $TAPE_FILE rewind ! rm $VOLNO_FILE ! ! set $BACKUP_DIRS ! while [ $# -ne 0 ] ; do ! host=`echo $1 | sed 's/:.*$//'` ! fs=`echo $1 | sed 's/^.*://'` ! date=`date` ! fsname=`echo $1 | sed 's/\//:/g'` ! ! TAR_PART2="--listed=/etc/tar-backup/temp.level-0" ! TAR_PART3="--label='Full backup of $fs on $host at $date' -C $fs ." ! ! echo Backing up $1 at $date | tee -a $LOGFILE ! ! # Actually back things up. ! ! if [ $HOST != $host ] ; then ! # Removed 2>&1/dev/null cruft since that's incorrect sh syntax. ! rsh $host mkdir /etc/tar-backup > /dev/null 2>&1 ! rsh $host rm -f /etc/tar-backup/temp.level-0 ! rsh $host $TAR_PART1 -f $HOST:$TAPE_FILE $TAR_PART2 $TAR_PART3 2>&1 | tee -a $LOGFILE ! else ! mkdir /etc/tar-backup > /dev/null 2>&1 ! rm -f /etc/tar-backup/temp.level-0 ! # Using `sh -c exec' causes nested quoting and shell substitution ! # to be handled here in the same way rsh handles it. ! sh -c "exec $TAR_PART1 -f $TAPE_FILE $TAR_PART2 $TAR_PART3" 2>&1 | tee -a $LOGFILE ! fi ! if [ $? -ne 0 ] ; then ! echo Backup of $1 failed. | tee -a $LOGFILE # I'm assuming that the tar will have written an empty # file to the tape, otherwise I should do a cat here. ! else ! if [ $HOST != $host ] ; then ! rsh $host "mv -f /etc/tar-backup/temp.level-0 /etc/tar-backup/$fsname.level-0" 2>&1 | tee -a $LOGFILE ! else ! mv -f /etc/tar-backup/temp.level-0 /etc/tar-backup/$fsname.level-0 2>&1 | tee -a $LOGFILE ! fi ! fi ! $TAPE_STATUS | tee -a $LOGFILE ! sleep 60 ! shift ! done ! ! # Dump any individual files requested. ! ! if [ x != "x$BACKUP_FILES" ] ; then ! date=`date` ! ! TAR_PART2="--listed=/etc/tar-backup/temp.level-0" ! TAR_PART3="--label='Full backup of miscellaneous files at $date'" ! ! mkdir /etc/tar-backup > /dev/null 2>&1 ! rm -f /etc/tar-backup/temp.level-0 ! ! echo Backing up miscellaneous files at $date | tee -a $LOGFILE ! # Using `sh -c exec' causes nested quoting and shell substitution ! # to be handled here in the same way rsh handles it. ! sh -c "exec $TAR_PART1 -f $TAPE_FILE $TAR_PART2 $TAR_PART3 \ ! $BACKUP_FILES" 2>&1 | tee -a $LOGFILE ! if [ $? -ne 0 ] ; then ! echo Backup of miscellaneous files failed. | tee -a $LOGFILE ! # I'm assuming that the tar will have written an empty ! # file to the tape, otherwise I should do a cat here. ! else ! mv -f /etc/tar-backup/temp.level-0 /etc/tar-backup/misc.level-0 2>&1 | tee -a $LOGFILE ! fi ! $TAPE_STATUS | tee -a $LOGFILE ! else ! echo No miscellaneous files specified | tee -a $LOGFILE ! false ! fi ! mt -f $TAPE_FILE rewind ! mt -f $TAPE_FILE offl ! echo Sending the dump log to $ADMINISTRATOR ! cat $LOGFILE | sed -f logfile.sed > $LOGFILE.tmp ! /usr/ucb/mail -s "Results of backup on `date`" $ADMINISTRATOR < $LOGFILE.tmp ! # This is undesirable -- rms. ! #rsh albert /usr/local/adm/motd-backup-done & --- 9,199 ---- # # You must edit the file `backup-specs' to set the parameters for your site. + # Useful for backup-specs, in case things have to be done slightly + # differently for different dump levels. + DUMP_LEVEL=0 + + # Insure `mail' is in PATH. + PATH="/usr/ucb:${PATH}" + export PATH + + # This is not the most reliable test in the world. The following might be + # more predictable: + # + # whoami="`whoami`" + # euid="`sed -ne '/^'\"${whoami}\"':/{s/^[^:]*:[^:]*://;s/:.*//p;q;}' /etc/passwd`" + # if [ "${euid}" != 0 ]; then ... + # if [ ! -w / ]; then ! echo "The backup must be run as root or else some files will fail to be dumped." exit 1 fi ! # Get the values of BACKUP_DIRS, BACKUP_FILES, and other variables. . ./backup-specs # Maybe sleep until around specified or default hour. ! if [ "${1}" != "now" ]; then ! if [ "${1}x" != "x" ]; then ! spec="${1}" else ! spec="${BACKUP_HOUR}" fi ! ! pausetime="`date | awk ' ! { ! hr = substr($4, 1, 2); ! mn = substr($4, 4, 2); ! if((hr + 0) < (spec + 0)) ! print 3600 * (spec - hr) - 60 * mn; ! else ! print 3600 * (spec + (24 - hr)) - 60 * mn; ! }' spec=\"${spec}\"`" ! clear ! echo "${SLEEP_MESSAGE}" ! sleep "${pausetime}" fi # start doing things ! # Put startdate in the subject line of mailed report, since if it happens ! # to run longer than 24 hours (as may be the case if someone forgets to put ! # in the next volume of the tape in adequate time), the backup date won't ! # appear too misleading. ! startdate="`date`" ! ! here="`pwd`" ! ! # Logfile name should be in the form ``log-1993-03-18-level-0'' ! # i.e. year-month-date. This format is useful for sorting by name, since ! # logfiles are intentionally kept online for future reference. ! LOGFILE="log-`date | sed -ne ' ! s/[^ ]* *\([^ ]*\) *\([^ ]*\).* \([^ ]*\)$/\3-\1-\2/ ! /-[0-9]$/s/\([0-9]\)$/0\1/ ! /Jan/{s/Jan/01/p;q;} ! /Feb/{s/Feb/02/p;q;} ! /Mar/{s/Mar/03/p;q;} ! /Apr/{s/Apr/04/p;q;} ! /May/{s/May/05/p;q;} ! /Jun/{s/Jun/06/p;q;} ! /Jul/{s/Jul/07/p;q;} ! /Aug/{s/Aug/08/p;q;} ! /Sep/{s/Sep/09/p;q;} ! /Oct/{s/Oct/10/p;q;} ! /Nov/{s/Nov/11/p;q;} ! /Dec/{s/Dec/12/p;q;}'`-level-${DUMP_LEVEL}" ! ! localhost="`hostname | sed -e 's/\..*//'`" ! ! TAR_PART1="${TAR} -c --multi-volume --one-file-system --block-size=${BLOCKING} --sparse --volno-file=${VOLNO_FILE}" ! ! # Only use --info-script if DUMP_REMIND_SCRIPT was defined in backup-specs ! if [ "x${DUMP_REMIND_SCRIPT}" != "x" ]; then ! TAR_PART1="${TAR_PART1} --info-script='${DUMP_REMIND_SCRIPT}'" ! fi # Make sure the log file did not already exist. Create it. ! if [ -f "${LOGFILE}" ] ; then ! echo "Log file ${LOGFILE} already exists." 1>&2 exit 1 else ! touch "${LOGFILE}" fi ! # Most everything below here is run in a subshell for which all output is ! # piped through `tee' to the logfile. Doing this, instead of having ! # multiple pipelines all over the place, is cleaner and allows access to ! # the exit value from various commands more easily. ! ( ! # Caveat: Some version of `mt' require `-t', not `-f'. ! mt -f "${TAPE_FILE}" rewind ! rm -f "${VOLNO_FILE}" ! ! set - ${BACKUP_DIRS} ! while [ $# -ne 0 ] ; do ! date="`date`" ! remotehost="`echo \"${1}\" | sed -e 's/:.*$//'`" ! fs="`echo \"${1}\" | sed -e 's/^.*://'`" ! fsname="`echo \"${1}\" | sed -e 's/\//:/g'`" ! ! # This filename must be absolute; it is opened on the machine that runs tar. ! TAR_PART2="--listed=/etc/tar-backup/temp.level-0" ! TAR_PART3="--label='Full backup of ${fs} on ${remotehost} at ${date}' -C ${fs} ." ! ! echo "Backing up ${1} at ${date}" ! ! # Actually back things up. ! ! if [ "z${localhost}" != "z${remotehost}" ] ; then ! rsh "${remotehost}" mkdir /etc/tar-backup > /dev/null 2>&1 ! rsh "${remotehost}" rm -f /etc/tar-backup/temp.level-0 ! rsh "${remotehost}" ${TAR_PART1} -f "${localhost}:${TAPE_FILE}" ${TAR_PART2} ${TAR_PART3} ! else ! mkdir /etc/tar-backup > /dev/null 2>&1 ! rm -f /etc/tar-backup/temp.level-0 ! # Using `sh -c exec' causes nested quoting and shell substitution ! # to be handled here in the same way rsh handles it. ! sh -c "exec ${TAR_PART1} -f \"${TAPE_FILE}\" ${TAR_PART2} ${TAR_PART3}" ! fi ! ! # `rsh' doesn't exit with the exit status of the remote command. What ! # stupid lossage. TODO: think of a reliable workaround. ! if [ $? -ne 0 ] ; then ! echo "Backup of ${1} failed." 1>&2 ! # I'm assuming that the tar will have written an empty ! # file to the tape, otherwise I should do a cat here. ! else ! if [ "z${localhost}" != "z${remotehost}" ] ; then ! rsh "${remotehost}" mv -f /etc/tar-backup/temp.level-0 "/etc/tar-backup/${fsname}.level-0" ! else ! mv -f /etc/tar-backup/temp.level-0 "/etc/tar-backup/${fsname}.level-0" ! fi ! fi ! ${TAPE_STATUS} ! sleep 60 ! shift ! done ! ! # Dump any individual files requested. ! ! if [ "x${BACKUP_FILES}" != "x" ] ; then ! date="`date`" ! ! TAR_PART2="--listed=/etc/tar-backup/temp.level-0" ! TAR_PART3="--label='Full backup of miscellaneous files at ${date}'" ! ! mkdir /etc/tar-backup > /dev/null 2>&1 ! rm -f /etc/tar-backup/temp.level-0 ! ! echo "Backing up miscellaneous files at ${date}" ! ! # Using `sh -c exec' causes nested quoting and shell substitution ! # to be handled here in the same way rsh handles it. ! sh -c "exec ${TAR_PART1} -f \"${TAPE_FILE}\" ${TAR_PART2} ${TAR_PART3} ${BACKUP_FILES}" ! ! # `rsh' doesn't exit with the exit status of the remote command. What ! # lossage. TODO: think of a reliable workaround. ! if [ $? -ne 0 ] ; then ! echo "Backup of miscellaneous files failed." # I'm assuming that the tar will have written an empty # file to the tape, otherwise I should do a cat here. ! else ! mv -f /etc/tar-backup/temp.level-0 /etc/tar-backup/misc.level-0 ! fi ! ${TAPE_STATUS} ! else ! echo "No miscellaneous files specified" ! fi ! ! # Caveat: some versions of `mt' use `-t' instead of `-f'. ! mt -f "${TAPE_FILE}" rewind ! mt -f "${TAPE_FILE}" offl ! ) 2>&1 | tee -a "${LOGFILE}" ! echo "Sending the dump log to ${ADMINISTRATOR}" ! mail -s "Results of backup started ${startdate}" ${ADMINISTRATOR} < "${LOGFILE}" ! # eof diff -c3 tar-1.11.1/level-1 tar-1.11.2/level-1 *** tar-1.11.1/level-1 Thu Sep 10 06:09:13 1992 --- tar-1.11.2/level-1 Thu Mar 25 11:54:59 1993 *************** *** 8,145 **** # # You must edit the file `backup-specs' to set the parameters for your site. if [ ! -w / ]; then ! echo The backup must be run as root, ! echo or else some files will fail to be dumped. exit 1 - else - false fi ! # Get the values of BACKUP_DIRS and BACKUP_FILES, and other variables. . ./backup-specs # Maybe sleep until around specified or default hour. ! # ! if [ "$1" != "now" ]; then ! if [ "$1"x != x ]; then ! spec=$1 else ! spec=$BACKUP_HOUR fi ! pausetime=`date | awk '{hr=substr($4,1,2);\\ ! mn=substr($4,4,2);\\ ! if((hr+0)&1 | tee -a $LOGFILE ! else ! ls -l /etc/tar-backup/$fsname.level-0 2>&1 | tee -a $LOGFILE ! cp /etc/tar-backup/$fsname.level-0 /etc/tar-backup/temp.level-1 2>&1 | tee -a $LOGFILE ! fi ! ! # Actually back things up. ! if [ $HOST != $host ] ; then ! rsh $host $TAR_PART1 -f $HOST:$TAPE_FILE $TAR_PART2 $TAR_PART3 2>&1 | tee -a $LOGFILE ! else ! # Using `sh -c exec' causes nested quoting and shell substitution ! # to be handled here in the same way rsh handles it. ! sh -c "exec $TAR_PART1 -f $TAPE_FILE $TAR_PART2 $TAR_PART3" 2>&1 | tee -a $LOGFILE ! fi ! if [ $? -ne 0 ] ; then ! echo Backup of $1 failed. | tee -a $LOGFILE # I'm assuming that the tar will have written an empty # file to the tape, otherwise I should do a cat here. ! else ! if [ $HOST != $host ] ; then ! rsh $host mv -f /etc/tar-backup/temp.level-1 /etc/tar-backup/$fsname.level-1 2>&1 | tee -a $LOGFILE ! else ! mv -f /etc/tar-backup/temp.level-1 /etc/tar-backup/$fsname.level-1 2>&1 | tee -a $LOGFILE ! fi ! fi ! $TAPE_STATUS | tee -a $LOGFILE ! sleep 60 ! shift ! done ! ! # Dump any individual files requested. ! ! if [ x != "x$BACKUP_FILES" ] ; then ! date=`date` ! TAR_PART2="--listed=/etc/tar-backup/temp.level-1" ! TAR_PART3="--label='Incremental backup of miscellaneous files at $date'" ! ! echo Backing up miscellaneous files at $date | tee -a $LOGFILE ! echo Last full dump of these files: | tee -a $LOGFILE ! ls -l /etc/tar-backup/misc.level-0 2>&1 | tee -a $LOGFILE ! ! rm -f /etc/tar-backup/temp.level-1 2>&1 | tee -a $LOGFILE ! cp /etc/tar-backup/misc.level-0 /etc/tar-backup/temp.level-1 2>&1 | tee -a $LOGFILE ! ! echo Backing up miscellaneous files at $date | tee -a $LOGFILE ! # Using `sh -c exec' causes nested quoting and shell substitution ! # to be handled here in the same way rsh handles it. ! sh -c "exec $TAR_PART1 -f $TAPE_FILE $TAR_PART2 $TAR_PART3 \ ! $BACKUP_FILES" 2>&1 | tee -a $LOGFILE ! if [ $? -ne 0 ] ; then ! echo Backup of miscellaneous files failed. | tee -a $LOGFILE ! # I'm assuming that the tar will have written an empty ! # file to the tape, otherwise I should do a cat here. ! else ! mv -f /etc/tar-backup/temp.level-1 /etc/tar-backup/misc.level-1 2>&1 | tee -a $LOGFILE ! fi ! $TAPE_STATUS | tee -a $LOGFILE ! else ! echo No miscellaneous files specified | tee -a $LOGFILE ! false ! fi ! mt -f $TAPE_FILE rewind ! mt -f $TAPE_FILE offl ! echo Sending the dump log to $ADMINISTRATOR ! cat $LOGFILE | sed -f logfile.sed > $LOGFILE.tmp ! /usr/ucb/mail -s "Results of backup on `date`" $ADMINISTRATOR < $LOGFILE.tmp --- 8,202 ---- # # You must edit the file `backup-specs' to set the parameters for your site. + # Useful for backup-specs, in case things have to be done slightly + # differently for different dump levels. + DUMP_LEVEL=1 + + # Insure `mail' is in PATH. + PATH="/usr/ucb:${PATH}" + export PATH + + # This is not the most reliable test in the world. The following might be + # more predictable: + # + # whoami="`whoami`" + # euid="`sed -ne '/^'\"${whoami}\"':/{s/^[^:]*:[^:]*://;s/:.*//p;q;}' /etc/passwd`" + # if [ "${euid}" != 0 ]; then ... + # if [ ! -w / ]; then ! echo "The backup must be run as root or else some files will fail to be dumped." exit 1 fi ! # Get the values of BACKUP_DIRS, BACKUP_FILES, and other variables. . ./backup-specs # Maybe sleep until around specified or default hour. ! if [ "z${1}" != "znow" ]; then ! if [ "${1}x" != "x" ]; then ! spec="${1}" else ! spec="${BACKUP_HOUR}" fi ! ! pausetime="`date | awk ' ! { ! hr = substr($4, 1, 2); ! mn = substr($4, 4, 2); ! if((hr + 0) < (spec + 0)) ! print 3600 * (spec - hr) - 60 * mn; ! else ! print 3600 * (spec + (24 - hr)) - 60 * mn; ! }' spec=\"${spec}\"`" ! clear ! echo "${SLEEP_MESSAGE}" ! sleep "${pausetime}" fi # start doing things ! # Put startdate in the subject line of mailed report, since if it happens ! # to run longer than 24 hours (as may be the case if someone forgets to put ! # in the next volume of the tape in adequate time), the backup date won't ! # appear too misleading. ! startdate="`date`" ! ! here="`pwd`" ! ! # Logfile name should be in the form ``log-1993-03-18-level-1'' ! # i.e. year-month-date. This format is useful for sorting by name, since ! # logfiles are intentionally kept online for future reference. ! LOGFILE="log-`date | sed -ne ' ! s/[^ ]* *\([^ ]*\) *\([^ ]*\).* \([^ ]*\)$/\3-\1-\2/ ! /-[0-9]$/s/\([0-9]\)$/0\1/ ! /Jan/{s/Jan/01/p;q;} ! /Feb/{s/Feb/02/p;q;} ! /Mar/{s/Mar/03/p;q;} ! /Apr/{s/Apr/04/p;q;} ! /May/{s/May/05/p;q;} ! /Jun/{s/Jun/06/p;q;} ! /Jul/{s/Jul/07/p;q;} ! /Aug/{s/Aug/08/p;q;} ! /Sep/{s/Sep/09/p;q;} ! /Oct/{s/Oct/10/p;q;} ! /Nov/{s/Nov/11/p;q;} ! /Dec/{s/Dec/12/p;q;}'`-level-${DUMP_LEVEL}" ! ! localhost="`hostname | sed -e 's/\..*//'`" ! ! TAR_PART1="${TAR} -c --multi-volume --one-file-system --block-size=${BLOCKING} --sparse --volno-file=${VOLNO_FILE}" ! ! # Only use --info-script if DUMP_REMIND_SCRIPT was defined in backup-specs ! if [ "x${DUMP_REMIND_SCRIPT}" != "x" ]; then ! TAR_PART1="${TAR_PART1} --info-script='${DUMP_REMIND_SCRIPT}'" ! fi # Make sure the log file did not already exist. Create it. ! if [ -f "${LOGFILE}" ] ; then ! echo "Log file ${LOGFILE} already exists." 1>&2 exit 1 else ! touch "${LOGFILE}" fi ! # Most everything below here is run in a subshell for which all output is ! # piped through `tee' to the logfile. Doing this, instead of having ! # multiple pipelines all over the place, is cleaner and allows access to ! # the exit value from various commands more easily. ! ( ! # Caveat: Some version of `mt' require `-t', not `-f'. ! mt -f "${TAPE_FILE}" rewind ! rm -f "${VOLNO_FILE}" ! ! set - ${BACKUP_DIRS} ! while [ $# -ne 0 ] ; do ! date="`date`" ! remotehost="`echo \"${1}\" | sed -e 's/:.*$//'`" ! fs="`echo \"${1}\" | sed -e 's/^.*://'`" ! fsname="`echo \"${1}\" | sed -e 's/\//:/g'`" ! ! # This filename must be absolute; it is opened on the machine that runs tar. ! TAR_PART2="--listed=/etc/tar-backup/temp.level-1" ! TAR_PART3="--label='level 1 backup of ${fs} on ${remotehost} at ${date}' -C ${fs} ." ! ! echo "Backing up ${1} at ${date}" ! echo "Last full dump on this filesystem:" ! ! if [ "z${remotehost}" != "z${localhost}" ] ; then ! rsh "${remotehost}" "ls -l /etc/tar-backup/${fsname}.level-0; \ ! cp /etc/tar-backup/${fsname}.level-0 /etc/tar-backup/temp.level-1" ! else ! ls -l "/etc/tar-backup/${fsname}.level-0" ! cp "/etc/tar-backup/${fsname}.level-0" /etc/tar-backup/temp.level-1 ! fi ! ! # Actually back things up. ! ! if [ "z${remotehost}" != "z${localhost}" ] ; then ! rsh "${remotehost}" ${TAR_PART1} -f "${localhost}:${TAPE_FILE}" ${TAR_PART2} ${TAR_PART3} ! else ! # Using `sh -c exec' causes nested quoting and shell substitution ! # to be handled here in the same way rsh handles it. ! sh -c "exec ${TAR_PART1} -f \"${TAPE_FILE}\" ${TAR_PART2} ${TAR_PART3}" ! fi ! ! # `rsh' doesn't exit with the exit status of the remote command. What ! # stupid lossage. TODO: think of a reliable workaround. ! if [ $? -ne 0 ] ; then ! echo "Backup of ${1} failed." ! # I'm assuming that the tar will have written an empty ! # file to the tape, otherwise I should do a cat here. ! else ! if [ "z${localhost}" != "z${remotehost}" ] ; then ! rsh "${remotehost}" mv -f /etc/tar-backup/temp.level-1 "/etc/tar-backup/${fsname}.level-1" ! else ! mv -f /etc/tar-backup/temp.level-1 "/etc/tar-backup/${fsname}.level-1" ! fi ! fi ! ${TAPE_STATUS} ! sleep 60 ! shift ! done ! ! # Dump any individual files requested. ! ! if [ "x${BACKUP_FILES}" != "x" ] ; then ! date="`date`" ! TAR_PART2="--listed=/etc/tar-backup/temp.level-1" ! TAR_PART3="--label='Incremental backup of miscellaneous files at ${date}'" ! ! echo "Backing up miscellaneous files at ${date}" ! echo "Last full dump of these files:" ! ls -l /etc/tar-backup/misc.level-0 ! ! rm -f /etc/tar-backup/temp.level-1 ! cp /etc/tar-backup/misc.level-0 /etc/tar-backup/temp.level-1 ! ! # Using `sh -c exec' causes nested quoting and shell substitution ! # to be handled here in the same way rsh handles it. ! sh -c "exec ${TAR_PART1} -f \"${TAPE_FILE}\" ${TAR_PART2} ${TAR_PART3} ${BACKUP_FILES}" ! if [ $? -ne 0 ] ; then ! echo "Backup of miscellaneous files failed." 1>&2 # I'm assuming that the tar will have written an empty # file to the tape, otherwise I should do a cat here. ! else ! mv -f /etc/tar-backup/temp.level-1 /etc/tar-backup/misc.level-1 ! fi ! ${TAPE_STATUS} ! else ! echo "No miscellaneous files specified" ! fi ! ! # Caveat: some versions of `mt' use `-t' instead of `-f'. ! mt -f "${TAPE_FILE}" rewind ! mt -f "${TAPE_FILE}" offl ! ! ) 2>&1 | tee -a "${LOGFILE}" ! echo "Sending the dump log to ${ADMINISTRATOR}" ! mail -s "Results of backup started ${startdate}" ${ADMINISTRATOR} < "${LOGFILE}" ! # eof diff -c3 tar-1.11.1/list.c tar-1.11.2/list.c *** tar-1.11.1/list.c Mon Sep 14 17:04:03 1992 --- tar-1.11.2/list.c Tue Mar 16 14:56:01 1993 *************** *** 1,5 **** /* List a tar archive. ! Copyright (C) 1988, 1992 Free Software Foundation This file is part of GNU Tar. --- 1,5 ---- /* List a tar archive. ! Copyright (C) 1988, 1992, 1993 Free Software Foundation This file is part of GNU Tar. *************** *** 49,125 **** extern FILE *msg_file; ! long from_oct(); /* Decode octal number */ ! void demode(); /* Print file mode */ ! union record *head; /* Points to current archive header */ ! struct stat hstat; /* Stat struct corresponding */ ! int head_standard; /* Tape header is in ANSI format */ ! ! int check_exclude(); ! void close_archive(); ! void decode_header(); ! int findgid(); ! int finduid(); ! void name_gather(); ! int name_match(); ! void names_notfound(); ! void open_archive(); ! void print_header(); ! int read_header(); ! void saverec(); ! void skip_file(); ! void skip_extended_headers(); - extern char *quote_copy_string(); - /* * Main loop for reading an archive. */ void ! read_and(do_something) ! void (*do_something)(); { ! int status = 3; /* Initial status at start of archive */ ! int prev_status; ! extern time_t new_time; ! char save_linkflag; ! ! name_gather(); /* Gather all the names */ ! open_archive(1); /* Open for reading */ ! ! for(;;) { ! prev_status = status; ! status = read_header(); ! switch (status) { ! ! case 1: /* Valid header */ ! /* We should decode next field (mode) first... */ ! /* Ensure incoming names are null terminated. */ ! ! if ( !name_match(current_file_name) ! || (f_new_files && hstat.st_mtimeheader.linkflag==LF_VOLHDR ! || head->header.linkflag==LF_MULTIVOL ! || head->header.linkflag==LF_NAMES) { ! (*do_something)(); ! continue; ! } ! if (f_show_omitted_dirs ! && head->header.linkflag == LF_DIR) ! msg ("Omitting %s\n", current_file_name); ! /* Skip past it in the archive */ ! if (head->header.isextended) ! isextended = 1; ! save_linkflag = head->header.linkflag; ! userec(head); ! if (isextended) { ! /* register union record *exhdr; for (;;) { exhdr = findrec(); --- 49,132 ---- extern FILE *msg_file; ! long from_oct (); /* Decode octal number */ ! void demode (); /* Print file mode */ ! void restore_saved_dir_info (); ! PTR ck_malloc (); ! ! union record *head; /* Points to current archive header */ ! struct stat hstat; /* Stat struct corresponding */ ! int head_standard; /* Tape header is in ANSI format */ ! ! int check_exclude (); ! void close_archive (); ! void decode_header (); ! int findgid (); ! int finduid (); ! void name_gather (); ! int name_match (); ! void names_notfound (); ! void open_archive (); ! void print_header (); ! int read_header (); ! void saverec (); ! void skip_file (); ! void skip_extended_headers (); ! extern char *quote_copy_string (); /* * Main loop for reading an archive. */ void ! read_and (do_something) ! void (*do_something) (); { ! int status = 3; /* Initial status at start of archive */ ! int prev_status; ! extern time_t new_time; ! char save_linkflag; ! ! name_gather (); /* Gather all the names */ ! open_archive (1); /* Open for reading */ ! ! for (;;) ! { ! prev_status = status; ! status = read_header (); ! switch (status) ! { ! ! case 1: /* Valid header */ ! /* We should decode next field (mode) first... */ ! /* Ensure incoming names are null terminated. */ ! ! if (!name_match (current_file_name) ! || (f_new_files && hstat.st_mtime < new_time) ! || (f_exclude && check_exclude (current_file_name))) ! { ! ! int isextended = 0; ! ! if (head->header.linkflag == LF_VOLHDR ! || head->header.linkflag == LF_MULTIVOL ! || head->header.linkflag == LF_NAMES) ! { ! (*do_something) (); ! continue; ! } ! if (f_show_omitted_dirs ! && head->header.linkflag == LF_DIR) ! msg ("Omitting %s\n", current_file_name); ! /* Skip past it in the archive */ ! if (head->header.isextended) ! isextended = 1; ! save_linkflag = head->header.linkflag; ! userec (head); ! if (isextended) ! { ! /* register union record *exhdr; for (;;) { exhdr = findrec(); *************** *** 129,180 **** } } userec(exhdr);*/ ! skip_extended_headers(); ! } ! /* Skip to the next header on the archive */ ! if(save_linkflag != LF_DIR) ! skip_file((long)hstat.st_size); ! continue; ! } ! (*do_something)(); ! continue; ! /* * If the previous header was good, tell them * that we are skipping bad ones. */ ! case 0: /* Invalid header */ ! userec(head); ! switch (prev_status) { ! case 3: /* Error on first record */ ! msg("Hmm, this doesn't look like a tar archive."); ! /* FALL THRU */ ! case 2: /* Error after record of zeroes */ ! case 1: /* Error after header rec */ ! msg("Skipping to next file header..."); ! case 0: /* Error after error */ ! break; ! } ! continue; ! ! case 2: /* Record of zeroes */ ! userec(head); ! status = prev_status; /* If error after 0's */ ! if (f_ignorez) ! continue; ! /* FALL THRU */ ! case EOF: /* End of archive */ ! break; ! } ! break; ! }; ! restore_saved_dir_info (); ! close_archive(); ! names_notfound(); /* Print names not found */ ! } /* --- 136,188 ---- } } userec(exhdr);*/ ! skip_extended_headers (); ! } ! /* Skip to the next header on the archive */ ! if (save_linkflag != LF_DIR) ! skip_file ((long) hstat.st_size); ! continue; ! } ! (*do_something) (); ! continue; ! /* * If the previous header was good, tell them * that we are skipping bad ones. */ ! case 0: /* Invalid header */ ! userec (head); ! switch (prev_status) ! { ! case 3: /* Error on first record */ ! msg ("Hmm, this doesn't look like a tar archive."); ! /* FALL THRU */ ! case 2: /* Error after record of zeroes */ ! case 1: /* Error after header rec */ ! msg ("Skipping to next file header..."); ! case 0: /* Error after error */ ! break; ! } ! continue; ! case 2: /* Record of zeroes */ ! userec (head); ! status = prev_status; /* If error after 0's */ ! if (f_ignorez) ! continue; ! /* FALL THRU */ ! case EOF: /* End of archive */ ! break; ! } ! break; ! }; ! ! restore_saved_dir_info (); ! close_archive (); ! names_notfound (); /* Print names not found */ ! } /* *************** *** 181,255 **** * Print a header record, based on tar options. */ void ! list_archive() { ! extern char *save_name; ! int isextended = 0; /* Flag to remember if head is extended */ ! ! /* Save the record */ ! saverec(&head); ! ! /* Print the header record */ ! if (f_verbose) { ! if (f_verbose > 1) ! decode_header(head, &hstat, &head_standard, 0); ! print_header(); ! } ! ! if(f_gnudump && head->header.linkflag==LF_DUMPDIR) { ! size_t size, written, check; ! char *data; ! extern long save_totsize; ! extern long save_sizeleft; ! ! userec(head); ! if(f_multivol) { ! save_name = current_file_name; ! save_totsize=hstat.st_size; ! } ! for(size = hstat.st_size;size>0;size-=written) { ! if(f_multivol) ! save_sizeleft=size; ! data = findrec()->charptr; ! if(data==NULL) { ! msg("EOF in archive file?"); ! break; ! } ! written = endofrecs()->charptr - data; ! if(written>size) ! written=size; ! errno=0; ! check=fwrite(data,sizeof(char), written, msg_file); ! userec((union record *)(data+written - 1)); ! if(check!=written) { ! msg_perror("only wrote %ld of %ld bytes to file %s",check, written,current_file_name); ! skip_file((long)(size)-written); ! break; ! } ! } ! if(f_multivol) ! save_name = 0; ! saverec((union record **) 0); /* Unsave it */ ! fputc('\n',msg_file); ! fflush(msg_file); ! return; } ! saverec((union record **) 0); /* Unsave it */ ! /* Check to see if we have an extended header to skip over also */ ! if (head->header.isextended) ! isextended = 1; ! ! /* Skip past the header in the archive */ ! userec(head); ! /* * If we needed to skip any extended headers, do so now, by ! * reading extended headers and skipping past them in the * archive. */ ! if (isextended) { ! /* register union record *exhdr; for (;;) { exhdr = findrec(); --- 189,270 ---- * Print a header record, based on tar options. */ void ! list_archive () { ! extern char *save_name; ! int isextended = 0; /* Flag to remember if head is extended */ + /* Save the record */ + saverec (&head); + + /* Print the header record */ + if (f_verbose) + { + if (f_verbose > 1) + decode_header (head, &hstat, &head_standard, 0); + print_header (); + } + + if (f_gnudump && head->header.linkflag == LF_DUMPDIR) + { + size_t size, written, check; + char *data; + extern long save_totsize; + extern long save_sizeleft; + + userec (head); + if (f_multivol) + { + save_name = current_file_name; + save_totsize = hstat.st_size; + } + for (size = hstat.st_size; size > 0; size -= written) + { + if (f_multivol) + save_sizeleft = size; + data = findrec ()->charptr; + if (data == NULL) + { + msg ("EOF in archive file?"); + break; + } + written = endofrecs ()->charptr - data; + if (written > size) + written = size; + errno = 0; + check = fwrite (data, sizeof (char), written, msg_file); + userec ((union record *) (data + written - 1)); + if (check != written) + { + msg_perror ("only wrote %ld of %ld bytes to file %s", check, written, current_file_name); + skip_file ((long) (size) - written); + break; + } } ! if (f_multivol) ! save_name = 0; ! saverec ((union record **) 0); /* Unsave it */ ! fputc ('\n', msg_file); ! fflush (msg_file); ! return; ! ! } ! saverec ((union record **) 0);/* Unsave it */ ! /* Check to see if we have an extended header to skip over also */ ! if (head->header.isextended) ! isextended = 1; ! /* Skip past the header in the archive */ ! userec (head); ! ! /* * If we needed to skip any extended headers, do so now, by ! * reading extended headers and skipping past them in the * archive. */ ! if (isextended) ! { ! /* register union record *exhdr; for (;;) { exhdr = findrec(); *************** *** 260,276 **** } userec(exhdr); }*/ ! skip_extended_headers(); ! } ! ! if(f_multivol) ! save_name=current_file_name; ! /* Skip to the next header on the archive */ ! ! skip_file((long) hstat.st_size); ! ! if(f_multivol) ! save_name = 0; } --- 275,291 ---- } userec(exhdr); }*/ ! skip_extended_headers (); ! } ! ! if (f_multivol) ! save_name = current_file_name; ! /* Skip to the next header on the archive */ ! ! skip_file ((long) hstat.st_size); ! ! if (f_multivol) ! save_name = 0; } *************** *** 286,410 **** * routine reads. */ int ! read_header() { ! register int i; ! register long sum, signed_sum, recsum; ! register char *p; ! register union record *header; ! long from_oct(); ! char **longp; ! char *bp, *data; ! int size, written; ! static char *next_long_name, *next_long_link; ! char *name; ! ! recurse: ! ! header = findrec(); ! head = header; /* This is our current header */ ! if (NULL == header) ! return EOF; ! ! recsum = from_oct(8, header->header.chksum); ! ! sum = 0; ! p = header->charptr; ! for (i = sizeof(*header); --i >= 0;) { ! /* * We can't use unsigned char here because of old compilers, * e.g. V7. */ ! signed_sum += *p; ! sum += 0xFF & *p++; ! } ! ! /* Adjust checksum to count the "chksum" field as blanks. */ ! for (i = sizeof(header->header.chksum); --i >= 0;) ! { ! sum -= 0xFF & header->header.chksum[i]; ! signed_sum -= (char) header->header.chksum[i]; ! } ! sum += ' '* sizeof header->header.chksum; ! signed_sum += ' ' * sizeof header->header.chksum; ! ! if (sum == 8*' ') { ! /* * This is a zeroed record...whole record is 0's except * for the 8 blanks we faked for the checksum field. */ ! return 2; ! } ! if (sum != recsum && signed_sum != recsum) ! return 0; ! ! /* * Good record. Decode file size and return. */ ! if (header->header.linkflag == LF_LINK) ! hstat.st_size = 0; /* Links 0 size on tape */ ! else ! hstat.st_size = from_oct(1+12, header->header.size); ! ! header->header.arch_name[NAMSIZ-1] = '\0'; ! if (header->header.linkflag == LF_LONGNAME ! || header->header.linkflag == LF_LONGLINK) ! { ! longp = ((header->header.linkflag == LF_LONGNAME) ! ? &next_long_name ! : &next_long_link); ! ! userec (header); ! if (*longp) ! free (*longp); ! bp = *longp = (char *) ck_malloc (hstat.st_size); ! ! for (size = hstat.st_size; ! size > 0; ! size -= written) ! { ! data = findrec ()->charptr; ! if (data == NULL) ! { ! msg ("Unexpected EOF on archive file"); ! break; ! } ! written = endofrecs () ->charptr - data; ! if (written > size) ! written = size; ! ! bcopy (data, bp, written); ! bp += written; ! userec ((union record *) (data + written - 1)); ! } ! goto recurse; ! } ! else ! { ! name = (next_long_name ! ? next_long_name ! : head->header.arch_name); ! if (current_file_name) ! free (current_file_name); ! current_file_name = malloc (strlen (name) + 1); ! strcpy (current_file_name, name); ! ! name = (next_long_link ! ? next_long_link ! : head->header.arch_linkname); ! if (current_link_name) ! free (current_link_name); ! current_link_name = malloc (strlen (name) + 1); ! strcpy (current_link_name, name); ! ! next_long_link = next_long_name = 0; ! return 1; ! } } ! /* * Decode things from a file header record into a "struct stat". * Also set "*stdp" to !=0 or ==0 depending whether header record is "Unix * Standard" tar format or regular old tar format. --- 301,427 ---- * routine reads. */ int ! read_header () { ! register int i; ! register long sum, signed_sum, recsum; ! register char *p; ! register union record *header; ! long from_oct (); ! char **longp; ! char *bp, *data; ! int size, written; ! static char *next_long_name, *next_long_link; ! char *name; ! ! recurse: ! ! header = findrec (); ! head = header; /* This is our current header */ ! if (NULL == header) ! return EOF; ! ! recsum = from_oct (8, header->header.chksum); ! ! sum = 0; ! p = header->charptr; ! for (i = sizeof (*header); --i >= 0;) ! { ! /* * We can't use unsigned char here because of old compilers, * e.g. V7. */ ! signed_sum += *p; ! sum += 0xFF & *p++; ! } ! ! /* Adjust checksum to count the "chksum" field as blanks. */ ! for (i = sizeof (header->header.chksum); --i >= 0;) ! { ! sum -= 0xFF & header->header.chksum[i]; ! signed_sum -= (char) header->header.chksum[i]; ! } ! sum += ' ' * sizeof header->header.chksum; ! signed_sum += ' ' * sizeof header->header.chksum; ! ! if (sum == 8 * ' ') ! { ! /* * This is a zeroed record...whole record is 0's except * for the 8 blanks we faked for the checksum field. */ ! return 2; ! } ! if (sum != recsum && signed_sum != recsum) ! return 0; ! ! /* * Good record. Decode file size and return. */ ! if (header->header.linkflag == LF_LINK) ! hstat.st_size = 0; /* Links 0 size on tape */ ! else ! hstat.st_size = from_oct (1 + 12, header->header.size); ! ! header->header.arch_name[NAMSIZ - 1] = '\0'; ! if (header->header.linkflag == LF_LONGNAME ! || header->header.linkflag == LF_LONGLINK) ! { ! longp = ((header->header.linkflag == LF_LONGNAME) ! ? &next_long_name ! : &next_long_link); ! ! userec (header); ! if (*longp) ! free (*longp); ! bp = *longp = (char *) ck_malloc (hstat.st_size); ! ! for (size = hstat.st_size; ! size > 0; ! size -= written) ! { ! data = findrec ()->charptr; ! if (data == NULL) ! { ! msg ("Unexpected EOF on archive file"); ! break; ! } ! written = endofrecs ()->charptr - data; ! if (written > size) ! written = size; ! ! bcopy (data, bp, written); ! bp += written; ! userec ((union record *) (data + written - 1)); ! } ! goto recurse; ! } ! else ! { ! name = (next_long_name ! ? next_long_name ! : head->header.arch_name); ! if (current_file_name) ! free (current_file_name); ! current_file_name = ck_malloc (strlen (name) + 1); ! strcpy (current_file_name, name); ! ! name = (next_long_link ! ? next_long_link ! : head->header.arch_linkname); ! if (current_link_name) ! free (current_link_name); ! current_link_name = ck_malloc (strlen (name) + 1); ! strcpy (current_link_name, name); ! ! next_long_link = next_long_name = 0; ! return 1; ! } } ! /* * Decode things from a file header record into a "struct stat". * Also set "*stdp" to !=0 or ==0 depending whether header record is "Unix * Standard" tar format or regular old tar format. *************** *** 421,476 **** * before calling a routine, e.g. print_header, that assumes decoded data. */ void ! decode_header(header, st, stdp, wantug) ! register union record *header; ! register struct stat *st; ! int *stdp; ! int wantug; { ! long from_oct(); ! char **longp; ! char *bp, *data; ! int size, written; ! ! st->st_mode = from_oct(8, header->header.mode); ! st->st_mtime = from_oct(1+12, header->header.mtime); ! if(f_gnudump) { ! st->st_atime = from_oct(1+12, header->header.atime); ! st->st_ctime = from_oct(1+12, header->header.ctime); ! } ! ! if (0==strcmp(header->header.magic, TMAGIC)) { ! /* Unix Standard tar archive */ ! *stdp = 1; ! if (wantug) { #ifdef NONAMES ! st->st_uid = from_oct(8, header->header.uid); ! st->st_gid = from_oct(8, header->header.gid); #else ! st->st_uid = ! (*header->header.uname ! ? finduid (header->header.uname) ! : from_oct (8, header->header.uid)); ! st->st_gid = ! (*header->header.gname ! ? findgid (header->header.gname) ! : from_oct (8, header->header.gid)); #endif ! } #if defined(S_IFBLK) || defined(S_IFCHR) ! switch (header->header.linkflag) { ! case LF_BLK: case LF_CHR: ! st->st_rdev = makedev(from_oct(8, header->header.devmajor), ! from_oct(8, header->header.devminor)); ! } ! #endif ! } else { ! /* Old fashioned tar archive */ ! *stdp = 0; ! st->st_uid = from_oct(8, header->header.uid); ! st->st_gid = from_oct(8, header->header.gid); ! st->st_rdev = 0; } } --- 438,498 ---- * before calling a routine, e.g. print_header, that assumes decoded data. */ void ! decode_header (header, st, stdp, wantug) ! register union record *header; ! register struct stat *st; ! int *stdp; ! int wantug; { ! long from_oct (); ! ! st->st_mode = from_oct (8, header->header.mode); ! st->st_mode &= 07777; ! st->st_mtime = from_oct (1 + 12, header->header.mtime); ! if (f_gnudump) ! { ! st->st_atime = from_oct (1 + 12, header->header.atime); ! st->st_ctime = from_oct (1 + 12, header->header.ctime); ! } ! ! if (0 == strcmp (header->header.magic, TMAGIC)) ! { ! /* Unix Standard tar archive */ ! *stdp = 1; ! if (wantug) ! { #ifdef NONAMES ! st->st_uid = from_oct (8, header->header.uid); ! st->st_gid = from_oct (8, header->header.gid); #else ! st->st_uid = ! (*header->header.uname ! ? finduid (header->header.uname) ! : from_oct (8, header->header.uid)); ! st->st_gid = ! (*header->header.gname ! ? findgid (header->header.gname) ! : from_oct (8, header->header.gid)); #endif ! } #if defined(S_IFBLK) || defined(S_IFCHR) ! switch (header->header.linkflag) ! { ! case LF_BLK: ! case LF_CHR: ! st->st_rdev = makedev (from_oct (8, header->header.devmajor), ! from_oct (8, header->header.devminor)); } + #endif + } + else + { + /* Old fashioned tar archive */ + *stdp = 0; + st->st_uid = from_oct (8, header->header.uid); + st->st_gid = from_oct (8, header->header.gid); + st->st_rdev = 0; + } } *************** *** 480,506 **** * Result is -1 if the field is invalid (all blank, or nonoctal). */ long ! from_oct(digs, where) ! register int digs; ! register char *where; { ! register long value; ! while (isspace(*where)) { /* Skip spaces */ ! where++; ! if (--digs <= 0) ! return -1; /* All blank field */ ! } ! value = 0; ! while (digs > 0 && isodigit(*where)) { /* Scan til nonoctal */ ! value = (value << 3) | (*where++ - '0'); ! --digs; ! } ! if (digs > 0 && *where && !isspace(*where)) ! return -1; /* Ended on non-space/nul */ ! return value; } --- 502,530 ---- * Result is -1 if the field is invalid (all blank, or nonoctal). */ long ! from_oct (digs, where) ! register int digs; ! register char *where; { ! register long value; ! while (isspace (*where)) ! { /* Skip spaces */ ! where++; ! if (--digs <= 0) ! return -1; /* All blank field */ ! } ! value = 0; ! while (digs > 0 && isodigit (*where)) ! { /* Scan til nonoctal */ ! value = (value << 3) | (*where++ - '0'); ! --digs; ! } ! if (digs > 0 && *where && !isspace (*where)) ! return -1; /* Ended on non-space/nul */ ! return value; } *************** *** 519,709 **** * , which must be set up in advance. This is not very clean * and should be cleaned up. FIXME. */ ! #define UGSWIDTH 18 /* min width of User, group, size */ /* UGSWIDTH of 18 means that with user and group names <= 8 chars the columns never shift during the listing. */ ! #define DATEWIDTH 19 /* Last mod date */ ! static int ugswidth = UGSWIDTH; /* Max width encountered so far */ void ! print_header() { ! char modes[11]; ! char *timestamp; ! char uform[11], gform[11]; /* These hold formatted ints */ ! char *user, *group; ! char size[24]; /* Holds a formatted long or maj, min */ ! time_t longie; /* To make ctime() call portable */ ! int pad; ! char *name; ! extern long baserec; ! static char *longname; ! static char *longlink; ! int bumplongs; ! ! if(f_sayblock) ! fprintf(msg_file,"rec %10d: ",baserec + (ar_record - ar_block)); ! /* annofile(msg_file, (char *)NULL); */ ! ! if (f_verbose <= 1) { ! /* Just the fax, mam. */ ! char *name; ! ! name=quote_copy_string(current_file_name); ! if(name==0) ! name=current_file_name; ! fprintf(msg_file, "%s\n", name); ! if(name!=current_file_name) ! free(name); ! } else { ! /* File type and modes */ ! modes[0] = '?'; ! switch (head->header.linkflag) { ! case LF_VOLHDR: ! modes[0]='V'; ! break; ! ! case LF_MULTIVOL: ! modes[0]='M'; ! break; ! ! case LF_NAMES: ! modes[0]='N'; ! break; ! ! case LF_LONGNAME: ! case LF_LONGLINK: ! msg ("Visible longname error\n"); ! break; ! ! case LF_SPARSE: ! case LF_NORMAL: ! case LF_OLDNORMAL: ! case LF_LINK: ! modes[0] = '-'; ! if ('/' == current_file_name[strlen(current_file_name)-1]) ! modes[0] = 'd'; ! break; ! case LF_DUMPDIR:modes[0] = 'd'; break; ! case LF_DIR: modes[0] = 'd'; break; ! case LF_SYMLINK:modes[0] = 'l'; break; ! case LF_BLK: modes[0] = 'b'; break; ! case LF_CHR: modes[0] = 'c'; break; ! case LF_FIFO: modes[0] = 'p'; break; ! case LF_CONTIG: modes[0] = 'C'; break; ! } ! ! demode((unsigned)hstat.st_mode, modes+1); ! ! /* Timestamp */ ! longie = hstat.st_mtime; ! timestamp = ctime(&longie); ! timestamp[16] = '\0'; ! timestamp[24] = '\0'; ! ! /* User and group names */ ! if (*head->header.uname && head_standard) { ! user = head->header.uname; ! } else { ! user = uform; ! (void)sprintf(uform, "%d", ! from_oct (8, head->header.uid)); ! } ! if (*head->header.gname && head_standard) { ! group = head->header.gname; ! } else { ! group = gform; ! (void)sprintf(gform, "%d", ! from_oct (8, head->header.gid)); ! } ! ! /* Format the file size or major/minor device numbers */ ! switch (head->header.linkflag) { #if defined(S_IFBLK) || defined(S_IFCHR) ! case LF_CHR: ! case LF_BLK: ! (void)sprintf(size, "%d,%d", ! major(hstat.st_rdev), ! minor(hstat.st_rdev)); ! break; #endif ! case LF_SPARSE: ! (void)sprintf(size, "%ld", ! from_oct(1+12, head->header.realsize)); ! break; ! default: ! (void)sprintf(size, "%ld", (long)hstat.st_size); ! } ! ! /* Figure out padding and print the whole line. */ ! pad = strlen(user) + strlen(group) + strlen(size) + 1; ! if (pad > ugswidth) ugswidth = pad; ! ! name = quote_copy_string(current_file_name); ! if(!name) ! name=current_file_name; ! fprintf(msg_file, "%s %s/%s %*s%s %s %s %s", ! modes, ! user, ! group, ! ugswidth - pad, ! "", ! size, ! timestamp+4, timestamp+20, ! name); ! ! if(name!=current_file_name) ! free(name); ! switch (head->header.linkflag) { ! case LF_SYMLINK: ! name=quote_copy_string(current_link_name); ! if(!name) ! name=current_link_name; ! fprintf(msg_file, " -> %s\n", name); ! if(name!=current_link_name) ! free(name); ! break; ! ! case LF_LINK: ! name=quote_copy_string(current_link_name); ! if(!name) ! name=current_link_name; ! fprintf(msg_file, " link to %s\n", current_link_name); ! if(name!=current_link_name) ! free(name); ! break; ! ! default: ! fprintf(msg_file, " unknown file type '%c'\n", ! head->header.linkflag); ! break; ! ! case LF_OLDNORMAL: ! case LF_NORMAL: ! case LF_SPARSE: ! case LF_CHR: ! case LF_BLK: ! case LF_DIR: ! case LF_FIFO: ! case LF_CONTIG: ! case LF_DUMPDIR: ! putc('\n', msg_file); ! break; ! ! case LF_VOLHDR: ! fprintf(msg_file, "--Volume Header--\n"); ! break; ! ! case LF_MULTIVOL: ! fprintf(msg_file, "--Continued at byte %ld--\n",from_oct(1+12,head->header.offset)); ! break; ! ! case LF_NAMES: ! fprintf(msg_file,"--Mangled file names--\n"); ! break; ! } } ! fflush(msg_file); } /* --- 543,757 ---- * , which must be set up in advance. This is not very clean * and should be cleaned up. FIXME. */ ! #define UGSWIDTH 18 /* min width of User, group, size */ /* UGSWIDTH of 18 means that with user and group names <= 8 chars the columns never shift during the listing. */ ! #define DATEWIDTH 19 /* Last mod date */ ! static int ugswidth = UGSWIDTH; /* Max width encountered so far */ void ! print_header () { ! char modes[11]; ! char *timestamp; ! char uform[11], gform[11]; /* These hold formatted ints */ ! char *user, *group; ! char size[24]; /* Holds a formatted long or maj, min */ ! time_t longie; /* To make ctime() call portable */ ! int pad; ! char *name; ! extern long baserec; ! ! if (f_sayblock) ! fprintf (msg_file, "rec %10d: ", baserec + (ar_record - ar_block)); ! /* annofile(msg_file, (char *)NULL); */ ! ! if (f_verbose <= 1) ! { ! /* Just the fax, mam. */ ! char *name; ! ! name = quote_copy_string (current_file_name); ! if (name == 0) ! name = current_file_name; ! fprintf (msg_file, "%s\n", name); ! if (name != current_file_name) ! free (name); ! } ! else ! { ! /* File type and modes */ ! modes[0] = '?'; ! switch (head->header.linkflag) ! { ! case LF_VOLHDR: ! modes[0] = 'V'; ! break; ! ! case LF_MULTIVOL: ! modes[0] = 'M'; ! break; ! ! case LF_NAMES: ! modes[0] = 'N'; ! break; ! ! case LF_LONGNAME: ! case LF_LONGLINK: ! msg ("Visible longname error\n"); ! break; ! ! case LF_SPARSE: ! case LF_NORMAL: ! case LF_OLDNORMAL: ! case LF_LINK: ! modes[0] = '-'; ! if ('/' == current_file_name[strlen (current_file_name) - 1]) ! modes[0] = 'd'; ! break; ! case LF_DUMPDIR: ! modes[0] = 'd'; ! break; ! case LF_DIR: ! modes[0] = 'd'; ! break; ! case LF_SYMLINK: ! modes[0] = 'l'; ! break; ! case LF_BLK: ! modes[0] = 'b'; ! break; ! case LF_CHR: ! modes[0] = 'c'; ! break; ! case LF_FIFO: ! modes[0] = 'p'; ! break; ! case LF_CONTIG: ! modes[0] = 'C'; ! break; ! } ! ! demode ((unsigned) hstat.st_mode, modes + 1); ! ! /* Timestamp */ ! longie = hstat.st_mtime; ! timestamp = ctime (&longie); ! timestamp[16] = '\0'; ! timestamp[24] = '\0'; ! ! /* User and group names */ ! if (*head->header.uname && head_standard) ! { ! user = head->header.uname; ! } ! else ! { ! user = uform; ! (void) sprintf (uform, "%d", ! from_oct (8, head->header.uid)); ! } ! if (*head->header.gname && head_standard) ! { ! group = head->header.gname; ! } ! else ! { ! group = gform; ! (void) sprintf (gform, "%d", ! from_oct (8, head->header.gid)); ! } ! ! /* Format the file size or major/minor device numbers */ ! switch (head->header.linkflag) ! { #if defined(S_IFBLK) || defined(S_IFCHR) ! case LF_CHR: ! case LF_BLK: ! (void) sprintf (size, "%d,%d", ! major (hstat.st_rdev), ! minor (hstat.st_rdev)); ! break; #endif ! case LF_SPARSE: ! (void) sprintf (size, "%ld", ! from_oct (1 + 12, head->header.realsize)); ! break; ! default: ! (void) sprintf (size, "%ld", (long) hstat.st_size); ! } ! ! /* Figure out padding and print the whole line. */ ! pad = strlen (user) + strlen (group) + strlen (size) + 1; ! if (pad > ugswidth) ! ugswidth = pad; ! ! name = quote_copy_string (current_file_name); ! if (!name) ! name = current_file_name; ! fprintf (msg_file, "%s %s/%s %*s%s %s %s %s", ! modes, ! user, ! group, ! ugswidth - pad, ! "", ! size, ! timestamp + 4, timestamp + 20, ! name); ! ! if (name != current_file_name) ! free (name); ! switch (head->header.linkflag) ! { ! case LF_SYMLINK: ! name = quote_copy_string (current_link_name); ! if (!name) ! name = current_link_name; ! fprintf (msg_file, " -> %s\n", name); ! if (name != current_link_name) ! free (name); ! break; ! ! case LF_LINK: ! name = quote_copy_string (current_link_name); ! if (!name) ! name = current_link_name; ! fprintf (msg_file, " link to %s\n", current_link_name); ! if (name != current_link_name) ! free (name); ! break; ! ! default: ! fprintf (msg_file, " unknown file type '%c'\n", ! head->header.linkflag); ! break; ! ! case LF_OLDNORMAL: ! case LF_NORMAL: ! case LF_SPARSE: ! case LF_CHR: ! case LF_BLK: ! case LF_DIR: ! case LF_FIFO: ! case LF_CONTIG: ! case LF_DUMPDIR: ! putc ('\n', msg_file); ! break; ! ! case LF_VOLHDR: ! fprintf (msg_file, "--Volume Header--\n"); ! break; ! ! case LF_MULTIVOL: ! fprintf (msg_file, "--Continued at byte %ld--\n", from_oct (1 + 12, head->header.offset)); ! break; ! ! case LF_NAMES: ! fprintf (msg_file, "--Mangled file names--\n"); ! break; } ! } ! fflush (msg_file); } /* *************** *** 710,744 **** * Print a similar line when we make a directory automatically. */ void ! pr_mkdir(pathname, length, mode) ! char *pathname; ! int length; ! int mode; { ! char modes[11]; ! char *name; ! extern long baserec; ! ! if (f_verbose > 1) { ! /* File type and modes */ ! modes[0] = 'd'; ! demode((unsigned)mode, modes+1); ! ! if(f_sayblock) ! fprintf(msg_file,"rec %10d: ",baserec + (ar_record - ar_block)); ! /* annofile(msg_file, (char *)NULL); */ ! name=quote_copy_string(pathname); ! if(!name) ! name=pathname; ! fprintf(msg_file, "%s %*s %.*s\n", ! modes, ! ugswidth+DATEWIDTH, ! "Creating directory:", ! length, ! pathname); ! if(name!=pathname) ! free(name); ! } } --- 758,793 ---- * Print a similar line when we make a directory automatically. */ void ! pr_mkdir (pathname, length, mode) ! char *pathname; ! int length; ! int mode; { ! char modes[11]; ! char *name; ! extern long baserec; ! ! if (f_verbose > 1) ! { ! /* File type and modes */ ! modes[0] = 'd'; ! demode ((unsigned) mode, modes + 1); ! ! if (f_sayblock) ! fprintf (msg_file, "rec %10d: ", baserec + (ar_record - ar_block)); ! /* annofile(msg_file, (char *)NULL); */ ! name = quote_copy_string (pathname); ! if (!name) ! name = pathname; ! fprintf (msg_file, "%s %*s %.*s\n", ! modes, ! ugswidth + DATEWIDTH, ! "Creating directory:", ! length, ! pathname); ! if (name != pathname) ! free (name); ! } } *************** *** 746,789 **** * Skip over bytes of data in records in the archive. */ void ! skip_file(size) ! register long size; { ! union record *x; ! extern long save_totsize; ! extern long save_sizeleft; ! ! if(f_multivol) { ! save_totsize=size; ! save_sizeleft=size; ! } ! ! while (size > 0) { ! x = findrec(); ! if (x == NULL) { /* Check it... */ ! msg("Unexpected EOF on archive file"); ! exit(EX_BADARCH); ! } ! userec(x); ! size -= RECORDSIZE; ! if(f_multivol) ! save_sizeleft-=RECORDSIZE; ! } } void ! skip_extended_headers() { ! register union record *exhdr; ! for (;;) { ! exhdr = findrec(); ! if (!exhdr->ext_hdr.isextended) { ! userec(exhdr); ! break; ! } ! userec (exhdr); } } /* --- 795,843 ---- * Skip over bytes of data in records in the archive. */ void ! skip_file (size) ! register long size; { ! union record *x; ! extern long save_totsize; ! extern long save_sizeleft; ! ! if (f_multivol) ! { ! save_totsize = size; ! save_sizeleft = size; ! } ! ! while (size > 0) ! { ! x = findrec (); ! if (x == NULL) ! { /* Check it... */ ! msg ("Unexpected EOF on archive file"); ! exit (EX_BADARCH); ! } ! userec (x); ! size -= RECORDSIZE; ! if (f_multivol) ! save_sizeleft -= RECORDSIZE; ! } } void ! skip_extended_headers () { ! register union record *exhdr; ! for (;;) ! { ! exhdr = findrec (); ! if (!exhdr->ext_hdr.isextended) ! { ! userec (exhdr); ! break; } + userec (exhdr); + } } /* *************** *** 790,825 **** * Decode the mode string from a stat entry into a 9-char string and a null. */ void ! demode(mode, string) ! register unsigned mode; ! register char *string; { ! register unsigned mask; ! register char *rwx = "rwxrwxrwx"; ! ! for (mask = 0400; mask != 0; mask >>= 1) { ! if (mode & mask) ! *string++ = *rwx++; ! else { ! *string++ = '-'; ! rwx++; ! } ! } ! if (mode & S_ISUID) ! if (string[-7] == 'x') ! string[-7] = 's'; ! else ! string[-7] = 'S'; ! if (mode & S_ISGID) ! if (string[-4] == 'x') ! string[-4] = 's'; ! else ! string[-4] = 'S'; ! if (mode & S_ISVTX) ! if (string[-1] == 'x') ! string[-1] = 't'; ! else ! string[-1] = 'T'; ! *string = '\0'; } --- 844,881 ---- * Decode the mode string from a stat entry into a 9-char string and a null. */ void ! demode (mode, string) ! register unsigned mode; ! register char *string; { ! register unsigned mask; ! register char *rwx = "rwxrwxrwx"; ! for (mask = 0400; mask != 0; mask >>= 1) ! { ! if (mode & mask) ! *string++ = *rwx++; ! else ! { ! *string++ = '-'; ! rwx++; ! } ! } ! ! if (mode & S_ISUID) ! if (string[-7] == 'x') ! string[-7] = 's'; ! else ! string[-7] = 'S'; ! if (mode & S_ISGID) ! if (string[-4] == 'x') ! string[-4] = 's'; ! else ! string[-4] = 'S'; ! if (mode & S_ISVTX) ! if (string[-1] == 'x') ! string[-1] = 't'; ! else ! string[-1] = 'T'; ! *string = '\0'; } diff -c3 tar-1.11.1/makefile.pc tar-1.11.2/makefile.pc *** tar-1.11.1/makefile.pc Fri Sep 11 01:03:40 1992 --- tar-1.11.2/makefile.pc Thu Oct 1 23:33:23 1992 *************** *** 1,4 **** ! # Makefile for GNU tar on MS-DOS using Turbo C 2.0. # Copyright (C) 1991 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify --- 1,4 ---- ! # Makefile for GNU tar on MS-DOS. # Copyright (C) 1991 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify *************** *** 15,32 **** # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! CC = tcc RM = rm -f MODEL = m ! DEFS = -DNONAMES -DNO_REMOTE -DNO_MTIO -DSTDC_HEADERS -m$(MODEL) -Dmain=_main LIBS = - DEF_AR_FILE = tar.out - DEFBLOCKING = 20 ! CFLAGS = -I. $(DEFS) \ ! -DDEF_AR_FILE="$(DEF_AR_FILE)" \ ! -DDEFBLOCKING=$(DEFBLOCKING) LDFLAGS = -m$(MODEL) OBJ1 = tar.obj create.obj extract.obj buffer.obj getoldopt.obj update.obj gnu.obj mangle.obj --- 15,28 ---- # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! CC = bcc RM = rm -f MODEL = m ! DEFS = -DNONAMES -DNO_REMOTE -DSTDC_HEADERS=1 -m$(MODEL) -Dmain=_main LIBS = ! CFLAGS = $(DEFS) LDFLAGS = -m$(MODEL) OBJ1 = tar.obj create.obj extract.obj buffer.obj getoldopt.obj update.obj gnu.obj mangle.obj *************** *** 42,47 **** --- 38,48 ---- .c.obj: $(CC) -c $(CFLAGS) $< + + # For some reason, Borland C++ 3.1 chokes on this file when given + # the full set of -D options. + getoldopt.obj: getoldopt.c + $(CC) -c -m$(MODEL) -DSTDC_HEADERS getoldopt.c testpad.h: testpad.exe testpad diff -c3 tar-1.11.1/malloc.c tar-1.11.2/malloc.c *** tar-1.11.1/malloc.c Tue Sep 15 00:57:33 1992 --- tar-1.11.2/malloc.c Thu Mar 25 13:59:48 1993 *************** *** 1,830 **** ! /* dynamic memory allocation for GNU. ! Copyright (C) 1985, 1987, 1992 Free Software Foundation, Inc. ! This program is free software; you can redistribute it and/or modify ! it under the terms of the GNU General Public License as published by ! the Free Software Foundation; either version 2, or (at your option) ! any later version. ! ! This program is distributed in the hope that it will be useful, ! but WITHOUT ANY WARRANTY; without even the implied warranty of ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! GNU General Public License for more details. ! ! You should have received a copy of the GNU General Public License ! along with this program; if not, write to the Free Software ! Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ ! ! /* ! * @(#)nmalloc.c 1 (Caltech) 2/21/82 ! * ! * U of M Modified: 20 Jun 1983 ACT: strange hacks for Emacs ! * ! * Nov 1983, Mike@BRL, Added support for 4.1C/4.2 BSD. ! * ! * This is a very fast storage allocator. It allocates blocks of a small ! * number of different sizes, and keeps free lists of each size. Blocks ! * that don't exactly fit are passed up to the next larger size. In this ! * implementation, the available sizes are (2^n)-4 (or -16) bytes long. ! * This is designed for use in a program that uses vast quantities of ! * memory, but bombs when it runs out. To make it a little better, it ! * warns the user when he starts to get near the end. ! * ! * June 84, ACT: modified rcheck code to check the range given to malloc, ! * rather than the range determined by the 2-power used. ! * ! * Jan 85, RMS: calls malloc_warning to issue warning on nearly full. ! * No longer Emacs-specific; can serve as all-purpose malloc for GNU. ! * You should call malloc_init to reinitialize after loading dumped Emacs. ! * Call malloc_stats to get info on memory stats if MSTATS turned on. ! * realloc knows how to return same block given, just changing its size, ! * if the power of 2 is correct. ! */ ! ! /* ! * nextf[i] is the pointer to the next free block of size 2^(i+3). The ! * smallest allocatable block is 8 bytes. The overhead information will ! * go in the first int of the block, and the returned pointer will point ! * to the second. ! * ! #ifdef MSTATS ! * nmalloc[i] is the difference between the number of mallocs and frees ! * for a given block size. ! #endif ! */ ! #ifdef emacs ! /* config.h specifies which kind of system this is. */ ! #include "config.h" ! #else ! /* Determine which kind of system this is. */ ! #include ! #ifndef SIGTSTP ! #ifndef VMS ! #ifndef USG ! #define USG ! #endif ! #endif /* not VMS */ ! #else /* SIGTSTP */ ! #ifdef SIGIO ! #define BSD4_2 ! #endif /* SIGIO */ ! #endif /* SIGTSTP */ ! ! #if defined(hpux) && !defined(USG) ! #define USG ! #endif ! ! #endif /* not emacs */ ! ! /* Define getpagesize () if the system does not. */ ! #include "getpagesize.h" ! ! #ifndef BSD4_2 ! #ifndef USG ! #include /* warn the user when near the end */ ! #endif /* not USG */ ! #else /* if BSD4_2 */ ! #include ! #include ! #endif /* BSD4_2 */ ! ! #ifdef USG ! #define bcopy(s, d, n) memcpy(d, s, n) ! #define bzero(s, n) memset(s, 0, n) ! #endif /* USG */ ! ! #ifdef VMS ! #include "vlimit.h" ! #endif ! ! extern char *start_of_data (); ! ! #ifdef BSD ! #ifndef DATA_SEG_BITS ! #define start_of_data() &etext ! #endif ! #endif ! ! #ifndef emacs ! #define start_of_data() &etext ! #endif ! ! #define ISALLOC ((char) 0xf7) /* magic byte that implies allocation */ ! #define ISFREE ((char) 0x54) /* magic byte that implies free block */ ! /* this is for error checking only */ ! #define ISMEMALIGN ((char) 0xd6) /* Stored before the value returned by ! memalign, with the rest of the word ! being the distance to the true ! beginning of the block. */ ! ! extern char etext; ! ! /* These two are for user programs to look at, when they are interested. */ ! ! unsigned int malloc_sbrk_used; /* amount of data space used now */ ! unsigned int malloc_sbrk_unused; /* amount more we can have */ ! ! /* start of data space; can be changed by calling init_malloc */ ! static char *data_space_start; ! ! #ifdef MSTATS ! static int nmalloc[30]; ! static int nmal, nfre; ! #endif /* MSTATS */ ! ! /* If range checking is not turned on, all we have is a flag indicating ! whether memory is allocated, an index in nextf[], and a size field; to ! realloc() memory we copy either size bytes or 1<<(index+3) bytes depending ! on whether the former can hold the exact size (given the value of ! 'index'). If range checking is on, we always need to know how much space ! is allocated, so the 'size' field is never used. */ ! ! struct mhead { ! char mh_alloc; /* ISALLOC or ISFREE */ ! char mh_index; /* index in nextf[] */ ! /* Remainder are valid only when block is allocated */ ! unsigned short mh_size; /* size, if < 0x10000 */ ! #ifdef rcheck ! unsigned mh_nbytes; /* number of bytes allocated */ ! int mh_magic4; /* should be == MAGIC4 */ ! #endif /* rcheck */ ! }; ! ! /* Access free-list pointer of a block. ! It is stored at block + 4. ! This is not a field in the mhead structure ! because we want sizeof (struct mhead) ! to describe the overhead for when the block is in use, ! and we do not want the free-list pointer to count in that. */ ! ! #define CHAIN(a) \ ! (*(struct mhead **) (sizeof (char *) + (char *) (a))) ! ! #ifdef rcheck ! ! /* To implement range checking, we write magic values in at the beginning and ! end of each allocated block, and make sure they are undisturbed whenever a ! free or a realloc occurs. */ ! /* Written in each of the 4 bytes following the block's real space */ ! #define MAGIC1 0x55 ! /* Written in the 4 bytes before the block's real space */ ! #define MAGIC4 0x55555555 ! #define ASSERT(p) if (!(p)) botch("p"); else ! #define EXTRA 4 /* 4 bytes extra for MAGIC1s */ ! #else ! #define ASSERT(p) ! #define EXTRA 0 ! #endif /* rcheck */ ! /* nextf[i] is free list of blocks of size 2**(i + 3) */ ! static struct mhead *nextf[30]; ! /* busy[i] is nonzero while allocation of block size i is in progress. */ ! static char busy[30]; ! /* Number of bytes of writable memory we can expect to be able to get */ ! static unsigned int lim_data; ! /* Level number of warnings already issued. ! 0 -- no warnings issued. ! 1 -- 75% warning already issued. ! 2 -- 85% warning already issued. ! */ ! static int warnlevel; ! /* Function to call to issue a warning; ! 0 means don't issue them. */ ! static void (*warnfunction) (); ! /* nonzero once initial bunch of free blocks made */ ! static int gotpool; ! char *_malloc_base; ! static void getpool (); - /* Cause reinitialization based on job parameters; - also declare where the end of pure storage is. */ - void - malloc_init (start, warnfun) - char *start; - void (*warnfun) (); - { - if (start) - data_space_start = start; - lim_data = 0; - warnlevel = 0; - warnfunction = warnfun; - } ! /* Return the maximum size to which MEM can be realloc'd ! without actually requiring copying. */ ! int ! malloc_usable_size (mem) ! char *mem; ! { ! int blocksize = 8 << (((struct mhead *) mem) - 1) -> mh_index; - return blocksize - sizeof (struct mhead) - EXTRA; - } - - static void get_lim_data (); ! static void ! morecore (nu) /* ask system for more memory */ ! register int nu; /* size index to get more of */ ! { ! char *sbrk (); ! register char *cp; ! register int nblks; ! register unsigned int siz; ! int oldmask; ! #ifdef BSD ! #ifndef BSD4_1 ! /* ?? There was a suggestion not to block SIGILL, somehow for GDB's sake. */ ! oldmask = sigsetmask (-1); #endif #endif - if (!data_space_start) - { - data_space_start = start_of_data (); - } ! if (lim_data == 0) ! get_lim_data (); ! /* On initial startup, get two blocks of each size up to 1k bytes */ ! if (!gotpool) ! { getpool (); getpool (); gotpool = 1; } ! ! /* Find current end of memory and issue warning if getting near max */ ! ! #ifndef VMS ! /* Maximum virtual memory on VMS is difficult to calculate since it ! * depends on several dynmacially changing things. Also, alignment ! * isn't that important. That is why much of the code here is ifdef'ed ! * out for VMS systems. ! */ ! cp = sbrk (0); ! siz = cp - data_space_start; ! if (warnfunction) ! switch (warnlevel) { ! case 0: ! if (siz > (lim_data / 4) * 3) ! { ! warnlevel++; ! (*warnfunction) ("Warning: past 75% of memory limit"); ! } ! break; ! case 1: ! if (siz > (lim_data / 20) * 17) ! { ! warnlevel++; ! (*warnfunction) ("Warning: past 85% of memory limit"); ! } ! break; ! case 2: ! if (siz > (lim_data / 20) * 19) { ! warnlevel++; ! (*warnfunction) ("Warning: past 95% of memory limit"); ! } ! break; ! } ! if ((int) cp & 0x3ff) /* land on 1K boundaries */ ! sbrk (1024 - ((int) cp & 0x3ff)); ! #endif /* not VMS */ ! ! /* Take at least 2k, and figure out how many blocks of the desired size ! we're about to get */ ! nblks = 1; ! if ((siz = nu) < 8) ! nblks = 1 << ((siz = 8) - nu); ! if ((cp = sbrk (1 << (siz + 3))) == (char *) -1) ! { ! #ifdef BSD ! #ifndef BSD4_1 ! sigsetmask (oldmask); ! #endif ! #endif ! return; /* no more room! */ ! } ! malloc_sbrk_used = siz; ! malloc_sbrk_unused = lim_data - siz; ! #ifndef VMS ! if ((int) cp & 7) ! { /* shouldn't happen, but just in case */ ! cp = (char *) (((int) cp + 8) & ~7); ! nblks--; ! } ! #endif /* not VMS */ ! /* save new header and link the nblks blocks together */ ! nextf[nu] = (struct mhead *) cp; ! siz = 1 << (nu + 3); ! while (1) ! { ! ((struct mhead *) cp) -> mh_alloc = ISFREE; ! ((struct mhead *) cp) -> mh_index = nu; ! if (--nblks <= 0) break; ! CHAIN ((struct mhead *) cp) = (struct mhead *) (cp + siz); ! cp += siz; ! } ! CHAIN ((struct mhead *) cp) = 0; ! #ifdef BSD ! #ifndef BSD4_1 ! sigsetmask (oldmask); ! #endif ! #endif ! } ! static void ! getpool () ! { ! register int nu; ! char * sbrk (); ! register char *cp = sbrk (0); ! if ((int) cp & 0x3ff) /* land on 1K boundaries */ ! sbrk (1024 - ((int) cp & 0x3ff)); ! /* Record address of start of space allocated by malloc. */ ! if (_malloc_base == 0) ! _malloc_base = cp; ! /* Get 2k of storage */ ! cp = sbrk (04000); ! if (cp == (char *) -1) ! return; ! /* Divide it into an initial 8-word block ! plus one block of size 2**nu for nu = 3 ... 10. */ ! CHAIN (cp) = nextf[0]; ! nextf[0] = (struct mhead *) cp; ! ((struct mhead *) cp) -> mh_alloc = ISFREE; ! ((struct mhead *) cp) -> mh_index = 0; ! cp += 8; ! for (nu = 0; nu < 7; nu++) ! { ! CHAIN (cp) = nextf[nu]; ! nextf[nu] = (struct mhead *) cp; ! ((struct mhead *) cp) -> mh_alloc = ISFREE; ! ((struct mhead *) cp) -> mh_index = nu; ! cp += 8 << nu; ! } ! } ! ! char * ! malloc (n) /* get a block */ ! unsigned n; ! { ! register struct mhead *p; ! register unsigned int nbytes; ! register int nunits = 0; ! ! /* Figure out how many bytes are required, rounding up to the nearest ! multiple of 8, then figure out which nestf[] area to use. ! Both the beginning of the header and the beginning of the ! block should be on an eight byte boundary. */ ! nbytes = (n + ((sizeof *p + 7) & ~7) + EXTRA + 7) & ~7; ! { ! register unsigned int shiftr = (nbytes - 1) >> 2; ! while (shiftr >>= 1) ! nunits++; ! } ! ! /* In case this is reentrant use of malloc from signal handler, ! pick a block size that no other malloc level is currently ! trying to allocate. That's the easiest harmless way not to ! interfere with the other level of execution. */ ! while (busy[nunits]) nunits++; ! busy[nunits] = 1; ! ! /* If there are no blocks of the appropriate size, go get some */ ! /* COULD SPLIT UP A LARGER BLOCK HERE ... ACT */ ! if (nextf[nunits] == 0) ! morecore (nunits); ! /* Get one block off the list, and set the new list head */ ! if ((p = nextf[nunits]) == 0) ! { ! busy[nunits] = 0; ! return 0; ! } ! nextf[nunits] = CHAIN (p); ! busy[nunits] = 0; ! /* Check for free block clobbered */ ! /* If not for this check, we would gobble a clobbered free chain ptr */ ! /* and bomb out on the NEXT allocate of this size block */ ! if (p -> mh_alloc != ISFREE || p -> mh_index != nunits) ! #ifdef rcheck ! botch ("block on free list clobbered"); ! #else /* not rcheck */ ! abort (); ! #endif /* not rcheck */ ! ! /* Fill in the info, and if range checking, set up the magic numbers */ ! p -> mh_alloc = ISALLOC; ! #ifdef rcheck ! p -> mh_nbytes = n; ! p -> mh_magic4 = MAGIC4; { ! /* Get the location n after the beginning of the user's space. */ ! register char *m = (char *) p + ((sizeof *p + 7) & ~7) + n; ! *m++ = MAGIC1, *m++ = MAGIC1, *m++ = MAGIC1, *m = MAGIC1; ! } ! #else /* not rcheck */ ! p -> mh_size = n; ! #endif /* not rcheck */ ! #ifdef MSTATS ! nmalloc[nunits]++; ! nmal++; ! #endif /* MSTATS */ ! return (char *) p + ((sizeof *p + 7) & ~7); ! } ! void ! free (mem) ! char *mem; ! { ! register struct mhead *p; ! { ! register char *ap = mem; - if (ap == 0) - return; ! p = (struct mhead *) (ap - ((sizeof *p + 7) & ~7)); ! if (p -> mh_alloc == ISMEMALIGN) ! { ! ap -= p->mh_size; ! p = (struct mhead *) (ap - ((sizeof *p + 7) & ~7)); ! } ! #ifndef rcheck ! if (p -> mh_alloc != ISALLOC) ! abort (); ! #else /* rcheck */ ! if (p -> mh_alloc != ISALLOC) ! { ! if (p -> mh_alloc == ISFREE) ! botch ("free: Called with already freed block argument\n"); ! else ! botch ("free: Called with bad argument\n"); ! } ! ASSERT (p -> mh_magic4 == MAGIC4); ! ap += p -> mh_nbytes; ! ASSERT (*ap++ == MAGIC1); ASSERT (*ap++ == MAGIC1); ! ASSERT (*ap++ == MAGIC1); ASSERT (*ap == MAGIC1); ! #endif /* rcheck */ ! } ! { ! register int nunits = p -> mh_index; - ASSERT (nunits <= 29); - p -> mh_alloc = ISFREE; ! /* Protect against signal handlers calling malloc. */ ! busy[nunits] = 1; ! /* Put this block on the free list. */ ! CHAIN (p) = nextf[nunits]; ! nextf[nunits] = p; ! busy[nunits] = 0; ! ! #ifdef MSTATS ! nmalloc[nunits]--; ! nfre++; ! #endif /* MSTATS */ ! } } ! ! char * ! realloc (mem, n) ! char *mem; ! register unsigned n; ! { ! register struct mhead *p; ! register unsigned int tocopy; ! register unsigned int nbytes; ! register int nunits; ! ! if (mem == 0) ! return malloc (n); ! p = (struct mhead *) (mem - ((sizeof *p + 7) & ~7)); ! nunits = p -> mh_index; ! ASSERT (p -> mh_alloc == ISALLOC); ! #ifdef rcheck ! ASSERT (p -> mh_magic4 == MAGIC4); ! { ! register char *m = mem + (tocopy = p -> mh_nbytes); ! ASSERT (*m++ == MAGIC1); ASSERT (*m++ == MAGIC1); ! ASSERT (*m++ == MAGIC1); ASSERT (*m == MAGIC1); ! } ! #else /* not rcheck */ ! if (p -> mh_index >= 13) ! tocopy = (1 << (p -> mh_index + 3)) - ((sizeof *p + 7) & ~7); ! else ! tocopy = p -> mh_size; ! #endif /* not rcheck */ ! /* See if desired size rounds to same power of 2 as actual size. */ ! nbytes = (n + ((sizeof *p + 7) & ~7) + EXTRA + 7) & ~7; ! /* If ok, use the same block, just marking its size as changed. */ ! if (nbytes > (4 << nunits) && nbytes <= (8 << nunits)) ! { ! #ifdef rcheck ! register char *m = mem + tocopy; ! *m++ = 0; *m++ = 0; *m++ = 0; *m++ = 0; ! p-> mh_nbytes = n; ! m = mem + n; ! *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1; ! #else /* not rcheck */ ! p -> mh_size = n; ! #endif /* not rcheck */ ! return mem; ! } ! if (n < tocopy) ! tocopy = n; ! { ! register char *new; ! if ((new = malloc (n)) == 0) ! return 0; ! bcopy (mem, new, tocopy); ! free (mem); ! return new; ! } ! } ! /* This is in case something linked with Emacs calls calloc. */ ! char * ! calloc (num, size) ! unsigned num, size; ! { ! register char *mem; ! num *= size; ! mem = malloc (num); ! if (mem != 0) ! bzero (mem, num); ! return mem; ! } ! #ifndef VMS ! char * ! memalign (alignment, size) ! unsigned alignment, size; ! { ! register char *ptr = malloc (size + alignment); ! register char *aligned; ! register struct mhead *p; ! if (ptr == 0) ! return 0; ! /* If entire block has the desired alignment, just accept it. */ ! if (((int) ptr & (alignment - 1)) == 0) ! return ptr; ! /* Otherwise, get address of byte in the block that has that alignment. */ ! aligned = (char *) (((int) ptr + alignment - 1) & -alignment); ! ! /* Store a suitable indication of how to free the block, ! so that free can find the true beginning of it. */ ! p = (struct mhead *) aligned - 1; ! p -> mh_size = aligned - ptr; ! p -> mh_alloc = ISMEMALIGN; ! return aligned; ! } ! #ifndef hpux ! /* This runs into trouble with getpagesize on HPUX. ! Patching out seems cleaner than the ugly fix needed. */ ! char * ! valloc (size) ! unsigned size; ! { ! return memalign (getpagesize (), size); ! } ! #endif /* not hpux */ ! #endif /* not VMS */ ! ! #ifdef MSTATS ! /* Return statistics describing allocation of blocks of size 2**n. */ ! struct mstats_value ! { ! int blocksize; ! int nfree; ! int nused; ! }; ! struct mstats_value ! malloc_stats (size) ! int size; { ! struct mstats_value v; ! register int i; ! register struct mhead *p; ! v.nfree = 0; ! ! if (size < 0 || size >= 30) { ! v.blocksize = 0; ! v.nused = 0; ! return v; } ! v.blocksize = 1 << (size + 3); ! v.nused = nmalloc[size]; ! for (p = nextf[size]; p; p = CHAIN (p)) ! v.nfree++; ! return v; } ! int ! malloc_mem_used () { ! int i; ! int size_used; ! size_used = 0; ! ! for (i = 0; i < 30; i++) { ! int allocation_size = 1 << (i + 3); ! struct mhead *p; ! ! size_used += nmalloc[i] * allocation_size; } ! return size_used; } ! int ! malloc_mem_free () { ! int i; ! int size_unused; ! size_unused = 0; ! ! for (i = 0; i < 30; i++) { ! int allocation_size = 1 << (i + 3); ! struct mhead *p; ! ! for (p = nextf[i]; p ; p = CHAIN (p)) ! size_unused += allocation_size; } ! return size_unused; } ! #endif /* MSTATS */ ! ! /* ! * This function returns the total number of bytes that the process ! * will be allowed to allocate via the sbrk(2) system call. On ! * BSD systems this is the total space allocatable to stack and ! * data. On USG systems this is the data space only. ! */ ! #ifdef USG ! static void ! get_lim_data () { ! extern long ulimit (); ! ! #ifdef ULIMIT_BREAK_VALUE ! lim_data = ULIMIT_BREAK_VALUE; ! #else ! lim_data = ulimit (3, 0); ! #endif ! lim_data -= (long) data_space_start; ! } ! #else /* not USG */ ! #ifdef BSD4_2 ! static void ! get_lim_data () ! { ! struct rlimit XXrlimit; ! getrlimit (RLIMIT_DATA, &XXrlimit); ! #ifdef RLIM_INFINITY ! lim_data = XXrlimit.rlim_cur & RLIM_INFINITY; /* soft limit */ ! #else ! lim_data = XXrlimit.rlim_cur; /* soft limit */ ! #endif } ! #else /* not BSD4_2 */ ! static void ! get_lim_data () { ! lim_data = vlimit (LIM_DATA, -1); } ! #endif /* not BSD4_2 */ ! #endif /* not USG */ ! ! #ifdef VMS ! /* There is a problem when dumping and restoring things on VMS. Calls ! * to SBRK don't necessarily result in contiguous allocation. Dumping ! * doesn't work when it isn't. Therefore, we make the initial ! * allocation contiguous by allocating a big chunk, and do SBRKs from ! * there. Once Emacs has dumped there is no reason to continue ! * contiguous allocation, malloc doesn't depend on it. ! * ! * There is a further problem of using brk and sbrk while using VMS C ! * run time library routines malloc, calloc, etc. The documentation ! * says that this is a no-no, although I'm not sure why this would be ! * a problem. In any case, we remove the necessity to call brk and ! * sbrk, by calling calloc (to assure zero filled data) rather than ! * sbrk. ! * ! * VMS_ALLOCATION_SIZE is the size of the allocation array. This ! * should be larger than the malloc size before dumping. Making this ! * too large will result in the startup procedure slowing down since ! * it will require more space and time to map it in. ! * ! * The value for VMS_ALLOCATION_SIZE in the following define was determined ! * by running emacs linked (and a large allocation) with the debugger and ! * looking to see how much storage was used. The allocation was 201 pages, ! * so I rounded it up to a power of two. ! */ ! #ifndef VMS_ALLOCATION_SIZE ! #define VMS_ALLOCATION_SIZE (512*256) ! #endif ! ! /* Use VMS RTL definitions */ ! #undef sbrk ! #undef brk ! #undef malloc ! int vms_out_initial = 0; ! char vms_initial_buffer[VMS_ALLOCATION_SIZE]; ! static char *vms_current_brk = &vms_initial_buffer; ! static char *vms_end_brk = &vms_initial_buffer[VMS_ALLOCATION_SIZE-1]; ! #include ! char * ! sys_sbrk (incr) ! int incr; { ! char *sbrk(), *temp, *ptr; ! if (vms_out_initial) { ! /* out of initial allocation... */ ! if (!(temp = malloc (incr))) ! temp = (char *) -1; } ! else { ! /* otherwise, go out of our area */ ! ptr = vms_current_brk + incr; /* new current_brk */ ! if (ptr <= vms_end_brk) { ! temp = vms_current_brk; ! vms_current_brk = ptr; } else { ! vms_out_initial = 1; /* mark as out of initial allocation */ ! if (!(temp = malloc (incr))) ! temp = (char *) -1; } } ! return temp; } - #endif /* VMS */ --- 1,1036 ---- ! /* DO NOT EDIT THIS FILE -- it is automagically generated. -*- C -*- */ ! #define _MALLOC_INTERNAL ! /* The malloc headers and source files from the C library follow here. */ ! /* Declarations for `malloc' and friends. ! Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. ! Written May 1989 by Mike Haertel. + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. ! This library is distributed in the hope that it will be useful, ! but WITHOUT ANY WARRANTY; without even the implied warranty of ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! Library General Public License for more details. ! You should have received a copy of the GNU Library General Public ! License along with this library; see the file COPYING.LIB. If ! not, write to the Free Software Foundation, Inc., 675 Mass Ave, ! Cambridge, MA 02139, USA. ! The author may be reached (Email) at the address mike@ai.mit.edu, ! or (US mail) as Mike Haertel c/o Free Software Foundation. */ ! #ifndef _MALLOC_H ! #define _MALLOC_H 1 ! #ifdef _MALLOC_INTERNAL ! /* Harmless, gets __GNU_LIBRARY__ defined. ! We must do this before #defining size_t and ptrdiff_t ! because tries to typedef them on some systems. */ ! #include ! #endif ! #ifdef __cplusplus ! extern "C" ! { ! #endif ! #if defined (__cplusplus) || (defined (__STDC__) && __STDC__) ! #undef __P ! #define __P(args) args ! #undef __ptr_t ! #define __ptr_t void * ! #else /* Not C++ or ANSI C. */ ! #undef __P ! #define __P(args) () ! #undef const ! #define const ! #undef __ptr_t ! #define __ptr_t char * ! #endif /* C++ or ANSI C. */ ! #ifndef NULL ! #define NULL 0 ! #endif ! #ifdef __STDC__ ! #include ! #else ! #undef size_t ! #define size_t unsigned int ! #undef ptrdiff_t ! #define ptrdiff_t int ! #endif ! /* Allocate SIZE bytes of memory. */ ! extern __ptr_t malloc __P ((size_t __size)); ! /* Re-allocate the previously allocated block ! in __ptr_t, making the new block SIZE bytes long. */ ! extern __ptr_t realloc __P ((__ptr_t __ptr, size_t __size)); ! /* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */ ! extern __ptr_t calloc __P ((size_t __nmemb, size_t __size)); ! /* Free a block allocated by `malloc', `realloc' or `calloc'. */ ! extern void free __P ((__ptr_t __ptr)); ! ! /* Allocate SIZE bytes allocated to ALIGNMENT bytes. */ ! extern __ptr_t memalign __P ((size_t __alignment, size_t __size)); ! /* Allocate SIZE bytes on a page boundary. */ ! extern __ptr_t valloc __P ((size_t __size)); ! #ifdef _MALLOC_INTERNAL ! ! #ifdef HAVE_CONFIG_H ! #include "config.h" ! #endif ! #if defined(__GNU_LIBRARY__) || defined(STDC_HEADERS) || defined(USG) ! #include ! #else ! #ifndef memset ! #define memset(s, zero, n) bzero ((s), (n)) ! #endif ! #ifndef memcpy ! #define memcpy(d, s, n) bcopy ((s), (d), (n)) #endif + #ifndef memmove + #define memmove(d, s, n) bcopy ((s), (d), (n)) #endif + #endif ! #if defined(__GNU_LIBRARY__) || defined(__STDC__) ! #include ! #else ! #define CHAR_BIT 8 ! #endif ! /* The allocator divides the heap into blocks of fixed size; large ! requests receive one or more whole blocks, and small requests ! receive a fragment of a block. Fragment sizes are powers of two, ! and all fragments of a block are the same size. When all the ! fragments in a block have been freed, the block itself is freed. */ ! #define INT_BIT (CHAR_BIT * sizeof(int)) ! #define BLOCKLOG (INT_BIT > 16 ? 12 : 9) ! #define BLOCKSIZE (1 << BLOCKLOG) ! #define BLOCKIFY(SIZE) (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE) ! ! /* Determine the amount of memory spanned by the initial heap table ! (not an absolute limit). */ ! #define HEAP (INT_BIT > 16 ? 4194304 : 65536) ! ! /* Number of contiguous free blocks allowed to build up at the end of ! memory before they will be returned to the system. */ ! #define FINAL_FREE_BLOCKS 8 ! ! /* Where to start searching the free list when looking for new memory. ! The two possible values are 0 and _heapindex. Starting at 0 seems ! to reduce total memory usage, while starting at _heapindex seems to ! run faster. */ ! #define MALLOC_SEARCH_START _heapindex ! /* Data structure giving per-block information. */ ! typedef union ! { ! /* Heap information for a busy block. */ ! struct { ! /* Zero for a large block, or positive giving the ! logarithm to the base two of the fragment size. */ ! int type; ! union { ! struct ! { ! size_t nfree; /* Free fragments in a fragmented block. */ ! size_t first; /* First free fragment of the block. */ ! } frag; ! /* Size (in blocks) of a large cluster. */ ! size_t size; ! } info; ! } busy; ! /* Heap information for a free block ! (that may be the first of a free cluster). */ ! struct ! { ! size_t size; /* Size (in blocks) of a free cluster. */ ! size_t next; /* Index of next free cluster. */ ! size_t prev; /* Index of previous free cluster. */ ! } free; ! } malloc_info; ! ! /* Pointer to first block of the heap. */ ! extern char *_heapbase; ! ! /* Table indexed by block number giving per-block information. */ ! extern malloc_info *_heapinfo; ! ! /* Address to block number and vice versa. */ ! #define BLOCK(A) (((char *) (A) - _heapbase) / BLOCKSIZE + 1) ! #define ADDRESS(B) ((__ptr_t) (((B) - 1) * BLOCKSIZE + _heapbase)) ! /* Current search index for the heap table. */ ! extern size_t _heapindex; ! /* Limit of valid info table indices. */ ! extern size_t _heaplimit; ! /* Doubly linked lists of free fragments. */ ! struct list ! { ! struct list *next; ! struct list *prev; ! }; ! /* Free list headers for each fragment size. */ ! extern struct list _fraghead[]; ! /* List of blocks allocated with `memalign' (or `valloc'). */ ! struct alignlist ! { ! struct alignlist *next; ! __ptr_t aligned; /* The address that memaligned returned. */ ! __ptr_t exact; /* The address that malloc returned. */ ! }; ! extern struct alignlist *_aligned_blocks; ! /* Instrumentation. */ ! extern size_t _chunks_used; ! extern size_t _bytes_used; ! extern size_t _chunks_free; ! extern size_t _bytes_free; ! /* Internal version of `free' used in `morecore' (malloc.c). */ ! extern void _free_internal __P ((__ptr_t __ptr)); ! #endif /* _MALLOC_INTERNAL. */ ! /* Underlying allocation function; successive calls should ! return contiguous pieces of memory. */ ! extern __ptr_t (*__morecore) __P ((ptrdiff_t __size)); ! /* Default value of `__morecore'. */ ! extern __ptr_t __default_morecore __P ((ptrdiff_t __size)); ! /* If not NULL, this function is called after each time ! `__morecore' is called to increase the data size. */ ! extern void (*__after_morecore_hook) __P ((void)); ! /* Nonzero if `malloc' has been called and done its initialization. */ ! extern int __malloc_initialized; ! /* Hooks for debugging versions. */ ! extern void (*__free_hook) __P ((__ptr_t __ptr)); ! extern __ptr_t (*__malloc_hook) __P ((size_t __size)); ! extern __ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, size_t __size)); ! /* Activate a standard collection of debugging hooks. */ ! extern int mcheck __P ((void (*__func) __P ((void)))); ! /* Activate a standard collection of tracing hooks. */ ! extern void mtrace __P ((void)); ! /* Statistics available to the user. */ ! struct mstats { ! size_t bytes_total; /* Total size of the heap. */ ! size_t chunks_used; /* Chunks allocated by the user. */ ! size_t bytes_used; /* Byte total of user-allocated chunks. */ ! size_t chunks_free; /* Chunks in the free list. */ ! size_t bytes_free; /* Byte total of chunks in the free list. */ ! }; ! /* Pick up the current statistics. */ ! extern struct mstats mstats __P ((void)); ! /* Call WARNFUN with a warning message when memory usage is high. */ ! extern void memory_warnings __P ((__ptr_t __start, ! void (*__warnfun) __P ((__const char *)))); ! /* Relocating allocator. */ ! /* Allocate SIZE bytes, and store the address in *HANDLEPTR. */ ! extern __ptr_t r_alloc __P ((__ptr_t *__handleptr, size_t __size)); ! /* Free the storage allocated in HANDLEPTR. */ ! extern void r_alloc_free __P ((__ptr_t *__handleptr)); ! /* Adjust the block at HANDLEPTR to be SIZE bytes long. */ ! extern __ptr_t r_re_alloc __P ((__ptr_t *__handleptr, size_t __size)); ! #ifdef __cplusplus } ! #endif ! #endif /* malloc.h */ ! /* Memory allocator `malloc'. ! Copyright 1990, 1991, 1992 Free Software Foundation ! Written May 1989 by Mike Haertel. ! ! This library is free software; you can redistribute it and/or ! modify it under the terms of the GNU Library General Public License as ! published by the Free Software Foundation; either version 2 of the ! License, or (at your option) any later version. ! ! This library is distributed in the hope that it will be useful, ! but WITHOUT ANY WARRANTY; without even the implied warranty of ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! Library General Public License for more details. ! ! You should have received a copy of the GNU Library General Public ! License along with this library; see the file COPYING.LIB. If ! not, write to the Free Software Foundation, Inc., 675 Mass Ave, ! Cambridge, MA 02139, USA. ! ! The author may be reached (Email) at the address mike@ai.mit.edu, ! or (US mail) as Mike Haertel c/o Free Software Foundation. */ ! ! #ifndef _MALLOC_INTERNAL ! #define _MALLOC_INTERNAL ! #include ! #endif ! /* How to really get more memory. */ ! __ptr_t (*__morecore) __P ((ptrdiff_t __size)) = __default_morecore; ! /* Debugging hook for `malloc'. */ ! __ptr_t (*__malloc_hook) __P ((size_t __size)); ! /* Pointer to the base of the first block. */ ! char *_heapbase; ! /* Block information table. Allocated with align/__free (not malloc/free). */ ! malloc_info *_heapinfo; ! /* Number of info entries. */ ! static size_t heapsize; ! /* Search index in the info table. */ ! size_t _heapindex; ! /* Limit of valid info table indices. */ ! size_t _heaplimit; ! /* Free lists for each fragment size. */ ! struct list _fraghead[BLOCKLOG]; ! /* Instrumentation. */ ! size_t _chunks_used; ! size_t _bytes_used; ! size_t _chunks_free; ! size_t _bytes_free; ! /* Are you experienced? */ ! int __malloc_initialized; ! void (*__after_morecore_hook) __P ((void)); ! /* Aligned allocation. */ ! static __ptr_t align __P ((size_t)); ! static __ptr_t ! align (size) ! size_t size; { ! __ptr_t result; ! unsigned long int adj; ! result = (*__morecore) (size); ! adj = (unsigned long int) ((unsigned long int) ((char *) result - ! (char *) NULL)) % BLOCKSIZE; ! if (adj != 0) { ! adj = BLOCKSIZE - adj; ! (void) (*__morecore) (adj); ! result = (char *) result + adj; } ! if (__after_morecore_hook) ! (*__after_morecore_hook) (); ! return result; ! } ! /* Set everything up and remember that we have. */ ! static int initialize __P ((void)); ! static int ! initialize () ! { ! heapsize = HEAP / BLOCKSIZE; ! _heapinfo = (malloc_info *) align (heapsize * sizeof (malloc_info)); ! if (_heapinfo == NULL) ! return 0; ! memset (_heapinfo, 0, heapsize * sizeof (malloc_info)); ! _heapinfo[0].free.size = 0; ! _heapinfo[0].free.next = _heapinfo[0].free.prev = 0; ! _heapindex = 0; ! _heapbase = (char *) _heapinfo; ! __malloc_initialized = 1; ! return 1; } ! ! /* Get neatly aligned memory, initializing or ! growing the heap info table as necessary. */ ! static __ptr_t morecore __P ((size_t)); ! static __ptr_t ! morecore (size) ! size_t size; { ! __ptr_t result; ! malloc_info *newinfo, *oldinfo; ! size_t newsize; ! ! result = align (size); ! if (result == NULL) ! return NULL; ! /* Check if we need to grow the info table. */ ! if ((size_t) BLOCK ((char *) result + size) > heapsize) { ! newsize = heapsize; ! while ((size_t) BLOCK ((char *) result + size) > newsize) ! newsize *= 2; ! newinfo = (malloc_info *) align (newsize * sizeof (malloc_info)); ! if (newinfo == NULL) ! { ! (*__morecore) (-size); ! return NULL; ! } ! memset (newinfo, 0, newsize * sizeof (malloc_info)); ! memcpy (newinfo, _heapinfo, heapsize * sizeof (malloc_info)); ! oldinfo = _heapinfo; ! newinfo[BLOCK (oldinfo)].busy.type = 0; ! newinfo[BLOCK (oldinfo)].busy.info.size ! = BLOCKIFY (heapsize * sizeof (malloc_info)); ! _heapinfo = newinfo; ! _free_internal (oldinfo); ! heapsize = newsize; } ! _heaplimit = BLOCK ((char *) result + size); ! return result; } ! /* Allocate memory from the heap. */ ! __ptr_t ! malloc (size) ! size_t size; { ! __ptr_t result; ! size_t block, blocks, lastblocks, start; ! register size_t i; ! struct list *next; ! ! if (size == 0) ! return NULL; ! ! if (__malloc_hook != NULL) ! return (*__malloc_hook) (size); ! ! if (!__malloc_initialized) ! if (!initialize ()) ! return NULL; ! ! if (size < sizeof (struct list)) ! size = sizeof (struct list); ! /* Determine the allocation policy based on the request size. */ ! if (size <= BLOCKSIZE / 2) ! { ! /* Small allocation to receive a fragment of a block. ! Determine the logarithm to base two of the fragment size. */ ! register size_t log = 1; ! --size; ! while ((size /= 2) != 0) ! ++log; ! ! /* Look in the fragment lists for a ! free fragment of the desired size. */ ! next = _fraghead[log].next; ! if (next != NULL) ! { ! /* There are free fragments of this size. ! Pop a fragment out of the fragment list and return it. ! Update the block's nfree and first counters. */ ! result = (__ptr_t) next; ! next->prev->next = next->next; ! if (next->next != NULL) ! next->next->prev = next->prev; ! block = BLOCK (result); ! if (--_heapinfo[block].busy.info.frag.nfree != 0) ! _heapinfo[block].busy.info.frag.first = (unsigned long int) ! ((unsigned long int) ((char *) next->next - (char *) NULL) ! % BLOCKSIZE) >> log; ! ! /* Update the statistics. */ ! ++_chunks_used; ! _bytes_used += 1 << log; ! --_chunks_free; ! _bytes_free -= 1 << log; ! } ! else ! { ! /* No free fragments of the desired size, so get a new block ! and break it into fragments, returning the first. */ ! result = malloc (BLOCKSIZE); ! if (result == NULL) ! return NULL; ! ! /* Link all fragments but the first into the free list. */ ! for (i = 1; i < (size_t) (BLOCKSIZE >> log); ++i) ! { ! next = (struct list *) ((char *) result + (i << log)); ! next->next = _fraghead[log].next; ! next->prev = &_fraghead[log]; ! next->prev->next = next; ! if (next->next != NULL) ! next->next->prev = next; ! } ! ! /* Initialize the nfree and first counters for this block. */ ! block = BLOCK (result); ! _heapinfo[block].busy.type = log; ! _heapinfo[block].busy.info.frag.nfree = i - 1; ! _heapinfo[block].busy.info.frag.first = i - 1; ! ! _chunks_free += (BLOCKSIZE >> log) - 1; ! _bytes_free += BLOCKSIZE - (1 << log); ! _bytes_used -= BLOCKSIZE - (1 << log); ! } ! } ! else { ! /* Large allocation to receive one or more blocks. ! Search the free list in a circle starting at the last place visited. ! If we loop completely around without finding a large enough ! space we will have to get more memory from the system. */ ! blocks = BLOCKIFY (size); ! start = block = MALLOC_SEARCH_START; ! while (_heapinfo[block].free.size < blocks) ! { ! block = _heapinfo[block].free.next; ! if (block == start) ! { ! /* Need to get more from the system. Check to see if ! the new core will be contiguous with the final free ! block; if so we don't need to get as much. */ ! block = _heapinfo[0].free.prev; ! lastblocks = _heapinfo[block].free.size; ! if (_heaplimit != 0 && block + lastblocks == _heaplimit && ! (*__morecore) (0) == ADDRESS (block + lastblocks) && ! (morecore ((blocks - lastblocks) * BLOCKSIZE)) != NULL) ! { ! _heapinfo[block].free.size = blocks; ! _bytes_free += (blocks - lastblocks) * BLOCKSIZE; ! continue; ! } ! result = morecore (blocks * BLOCKSIZE); ! if (result == NULL) ! return NULL; ! block = BLOCK (result); ! _heapinfo[block].busy.type = 0; ! _heapinfo[block].busy.info.size = blocks; ! ++_chunks_used; ! _bytes_used += blocks * BLOCKSIZE; ! return result; ! } ! } ! ! /* At this point we have found a suitable free list entry. ! Figure out how to remove what we need from the list. */ ! result = ADDRESS (block); ! if (_heapinfo[block].free.size > blocks) ! { ! /* The block we found has a bit left over, ! so relink the tail end back into the free list. */ ! _heapinfo[block + blocks].free.size ! = _heapinfo[block].free.size - blocks; ! _heapinfo[block + blocks].free.next ! = _heapinfo[block].free.next; ! _heapinfo[block + blocks].free.prev ! = _heapinfo[block].free.prev; ! _heapinfo[_heapinfo[block].free.prev].free.next ! = _heapinfo[_heapinfo[block].free.next].free.prev ! = _heapindex = block + blocks; ! } ! else ! { ! /* The block exactly matches our requirements, ! so just remove it from the list. */ ! _heapinfo[_heapinfo[block].free.next].free.prev ! = _heapinfo[block].free.prev; ! _heapinfo[_heapinfo[block].free.prev].free.next ! = _heapindex = _heapinfo[block].free.next; ! --_chunks_free; ! } ! ! _heapinfo[block].busy.type = 0; ! _heapinfo[block].busy.info.size = blocks; ! ++_chunks_used; ! _bytes_used += blocks * BLOCKSIZE; ! _bytes_free -= blocks * BLOCKSIZE; } ! return result; } ! /* Free a block of memory allocated by `malloc'. ! Copyright 1990, 1991, 1992 Free Software Foundation ! Written May 1989 by Mike Haertel. ! ! This library is free software; you can redistribute it and/or ! modify it under the terms of the GNU Library General Public License as ! published by the Free Software Foundation; either version 2 of the ! License, or (at your option) any later version. ! ! This library is distributed in the hope that it will be useful, ! but WITHOUT ANY WARRANTY; without even the implied warranty of ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! Library General Public License for more details. ! ! You should have received a copy of the GNU Library General Public ! License along with this library; see the file COPYING.LIB. If ! not, write to the Free Software Foundation, Inc., 675 Mass Ave, ! Cambridge, MA 02139, USA. ! ! The author may be reached (Email) at the address mike@ai.mit.edu, ! or (US mail) as Mike Haertel c/o Free Software Foundation. */ ! ! #ifndef _MALLOC_INTERNAL ! #define _MALLOC_INTERNAL ! #include ! #endif ! ! /* Debugging hook for free. */ ! void (*__free_hook) __P ((__ptr_t __ptr)); ! /* List of blocks allocated by memalign. */ ! struct alignlist *_aligned_blocks = NULL; ! /* Return memory to the heap. ! Like `free' but don't call a __free_hook if there is one. */ ! void ! _free_internal (ptr) ! __ptr_t ptr; { ! int type; ! size_t block, blocks; ! register size_t i; ! struct list *prev, *next; ! block = BLOCK (ptr); ! ! type = _heapinfo[block].busy.type; ! switch (type) ! { ! case 0: ! /* Get as many statistics as early as we can. */ ! --_chunks_used; ! _bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE; ! _bytes_free += _heapinfo[block].busy.info.size * BLOCKSIZE; ! ! /* Find the free cluster previous to this one in the free list. ! Start searching at the last block referenced; this may benefit ! programs with locality of allocation. */ ! i = _heapindex; ! if (i > block) ! while (i > block) ! i = _heapinfo[i].free.prev; ! else ! { ! do ! i = _heapinfo[i].free.next; ! while (i > 0 && i < block); ! i = _heapinfo[i].free.prev; ! } ! /* Determine how to link this block into the free list. */ ! if (block == i + _heapinfo[i].free.size) ! { ! /* Coalesce this block with its predecessor. */ ! _heapinfo[i].free.size += _heapinfo[block].busy.info.size; ! block = i; ! } ! else ! { ! /* Really link this block back into the free list. */ ! _heapinfo[block].free.size = _heapinfo[block].busy.info.size; ! _heapinfo[block].free.next = _heapinfo[i].free.next; ! _heapinfo[block].free.prev = i; ! _heapinfo[i].free.next = block; ! _heapinfo[_heapinfo[block].free.next].free.prev = block; ! ++_chunks_free; ! } ! /* Now that the block is linked in, see if we can coalesce it ! with its successor (by deleting its successor from the list ! and adding in its size). */ ! if (block + _heapinfo[block].free.size == _heapinfo[block].free.next) ! { ! _heapinfo[block].free.size ! += _heapinfo[_heapinfo[block].free.next].free.size; ! _heapinfo[block].free.next ! = _heapinfo[_heapinfo[block].free.next].free.next; ! _heapinfo[_heapinfo[block].free.next].free.prev = block; ! --_chunks_free; ! } ! /* Now see if we can return stuff to the system. */ ! blocks = _heapinfo[block].free.size; ! if (blocks >= FINAL_FREE_BLOCKS && block + blocks == _heaplimit ! && (*__morecore) (0) == ADDRESS (block + blocks)) ! { ! register size_t bytes = blocks * BLOCKSIZE; ! _heaplimit -= blocks; ! (*__morecore) (-bytes); ! _heapinfo[_heapinfo[block].free.prev].free.next ! = _heapinfo[block].free.next; ! _heapinfo[_heapinfo[block].free.next].free.prev ! = _heapinfo[block].free.prev; ! block = _heapinfo[block].free.prev; ! --_chunks_free; ! _bytes_free -= bytes; ! } ! ! /* Set the next search to begin at this block. */ ! _heapindex = block; ! break; ! ! default: ! /* Do some of the statistics. */ ! --_chunks_used; ! _bytes_used -= 1 << type; ! ++_chunks_free; ! _bytes_free += 1 << type; ! ! /* Get the address of the first free fragment in this block. */ ! prev = (struct list *) ((char *) ADDRESS (block) + ! (_heapinfo[block].busy.info.frag.first << type)); ! ! if (_heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1) ! { ! /* If all fragments of this block are free, remove them ! from the fragment list and free the whole block. */ ! next = prev; ! for (i = 1; i < (size_t) (BLOCKSIZE >> type); ++i) ! next = next->next; ! prev->prev->next = next; ! if (next != NULL) ! next->prev = prev->prev; ! _heapinfo[block].busy.type = 0; ! _heapinfo[block].busy.info.size = 1; ! ! /* Keep the statistics accurate. */ ! ++_chunks_used; ! _bytes_used += BLOCKSIZE; ! _chunks_free -= BLOCKSIZE >> type; ! _bytes_free -= BLOCKSIZE; ! ! free (ADDRESS (block)); ! } ! else if (_heapinfo[block].busy.info.frag.nfree != 0) ! { ! /* If some fragments of this block are free, link this ! fragment into the fragment list after the first free ! fragment of this block. */ ! next = (struct list *) ptr; ! next->next = prev->next; ! next->prev = prev; ! prev->next = next; ! if (next->next != NULL) ! next->next->prev = next; ! ++_heapinfo[block].busy.info.frag.nfree; ! } ! else ! { ! /* No fragments of this block are free, so link this ! fragment into the fragment list and announce that ! it is the first free fragment of this block. */ ! prev = (struct list *) ptr; ! _heapinfo[block].busy.info.frag.nfree = 1; ! _heapinfo[block].busy.info.frag.first = (unsigned long int) ! ((unsigned long int) ((char *) ptr - (char *) NULL) ! % BLOCKSIZE >> type); ! prev->next = _fraghead[type].next; ! prev->prev = &_fraghead[type]; ! prev->prev->next = prev; ! if (prev->next != NULL) ! prev->next->prev = prev; ! } ! break; ! } } ! /* Return memory to the heap. */ ! void ! free (ptr) ! __ptr_t ptr; { ! register struct alignlist *l; ! ! if (ptr == NULL) ! return; ! ! for (l = _aligned_blocks; l != NULL; l = l->next) ! if (l->aligned == ptr) ! { ! l->aligned = NULL; /* Mark the slot in the list as free. */ ! ptr = l->exact; ! break; ! } ! ! if (__free_hook != NULL) ! (*__free_hook) (ptr); ! else ! _free_internal (ptr); } + /* Change the size of a block allocated by `malloc'. + Copyright 1990, 1991, 1992 Free Software Foundation, Inc. + Written May 1989 by Mike Haertel. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. If + not, write to the Free Software Foundation, Inc., 675 Mass Ave, + Cambridge, MA 02139, USA. + + The author may be reached (Email) at the address mike@ai.mit.edu, + or (US mail) as Mike Haertel c/o Free Software Foundation. */ + + #ifndef _MALLOC_INTERNAL + #define _MALLOC_INTERNAL + #include + #endif ! #define min(A, B) ((A) < (B) ? (A) : (B)) ! /* Debugging hook for realloc. */ ! __ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, size_t __size)); ! /* Resize the given region to the new size, returning a pointer ! to the (possibly moved) region. This is optimized for speed; ! some benchmarks seem to indicate that greater compactness is ! achieved by unconditionally allocating and copying to a ! new region. This module has incestuous knowledge of the ! internals of both free and malloc. */ ! __ptr_t ! realloc (ptr, size) ! __ptr_t ptr; ! size_t size; { ! __ptr_t result; ! int type; ! size_t block, blocks, oldlimit; ! if (size == 0) { ! free (ptr); ! return malloc (0); } ! else if (ptr == NULL) ! return malloc (size); ! ! if (__realloc_hook != NULL) ! return (*__realloc_hook) (ptr, size); ! ! block = BLOCK (ptr); ! ! type = _heapinfo[block].busy.type; ! switch (type) { ! case 0: ! /* Maybe reallocate a large block to a small fragment. */ ! if (size <= BLOCKSIZE / 2) ! { ! result = malloc (size); ! if (result != NULL) ! { ! memcpy (result, ptr, size); ! free (ptr); ! return result; ! } ! } ! ! /* The new size is a large allocation as well; ! see if we can hold it in place. */ ! blocks = BLOCKIFY (size); ! if (blocks < _heapinfo[block].busy.info.size) ! { ! /* The new size is smaller; return ! excess memory to the free list. */ ! _heapinfo[block + blocks].busy.type = 0; ! _heapinfo[block + blocks].busy.info.size ! = _heapinfo[block].busy.info.size - blocks; ! _heapinfo[block].busy.info.size = blocks; ! free (ADDRESS (block + blocks)); ! result = ptr; ! } ! else if (blocks == _heapinfo[block].busy.info.size) ! /* No size change necessary. */ ! result = ptr; ! else { ! /* Won't fit, so allocate a new region that will. ! Free the old region first in case there is sufficient ! adjacent free space to grow without moving. */ ! blocks = _heapinfo[block].busy.info.size; ! /* Prevent free from actually returning memory to the system. */ ! oldlimit = _heaplimit; ! _heaplimit = 0; ! free (ptr); ! _heaplimit = oldlimit; ! result = malloc (size); ! if (result == NULL) ! { ! (void) malloc (blocks * BLOCKSIZE); ! return NULL; ! } ! if (ptr != result) ! memmove (result, ptr, blocks * BLOCKSIZE); } + break; + + default: + /* Old size is a fragment; type is logarithm + to base two of the fragment size. */ + if (size > (size_t) (1 << (type - 1)) && size <= (size_t) (1 << type)) + /* The new size is the same kind of fragment. */ + result = ptr; else { ! /* The new size is different; allocate a new space, ! and copy the lesser of the new size and the old. */ ! result = malloc (size); ! if (result == NULL) ! return NULL; ! memcpy (result, ptr, min (size, (size_t) 1 << type)); ! free (ptr); } + break; } ! ! return result; ! } ! /* Copyright (C) 1991, 1992 Free Software Foundation, Inc. ! This file is part of the GNU C Library. ! ! The GNU C Library is free software; you can redistribute it and/or modify ! it under the terms of the GNU General Public License as published by ! the Free Software Foundation; either version 2, or (at your option) ! any later version. ! ! The GNU C Library is distributed in the hope that it will be useful, ! but WITHOUT ANY WARRANTY; without even the implied warranty of ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! GNU General Public License for more details. ! ! You should have received a copy of the GNU General Public License ! along with the GNU C Library; see the file COPYING. If not, write to ! the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! ! #ifndef _MALLOC_INTERNAL ! #define _MALLOC_INTERNAL ! #include ! #endif ! ! #ifndef __GNU_LIBRARY__ ! #define __sbrk sbrk ! #endif ! ! extern __ptr_t __sbrk __P ((int increment)); ! ! #ifndef NULL ! #define NULL 0 ! #endif ! ! /* Allocate INCREMENT more bytes of data space, ! and return the start of data space, or NULL on errors. ! If INCREMENT is negative, shrink data space. */ ! __ptr_t ! __default_morecore (increment) ! ptrdiff_t increment; ! { ! __ptr_t result = __sbrk ((int) increment); ! if (result == (__ptr_t) -1) ! return NULL; ! return result; ! } ! /* Copyright (C) 1991, 1992 Free Software Foundation, Inc. ! ! This library is free software; you can redistribute it and/or ! modify it under the terms of the GNU Library General Public License as ! published by the Free Software Foundation; either version 2 of the ! License, or (at your option) any later version. ! ! This library is distributed in the hope that it will be useful, ! but WITHOUT ANY WARRANTY; without even the implied warranty of ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! Library General Public License for more details. ! ! You should have received a copy of the GNU Library General Public ! License along with this library; see the file COPYING.LIB. If ! not, write to the Free Software Foundation, Inc., 675 Mass Ave, ! Cambridge, MA 02139, USA. */ ! ! #ifndef _MALLOC_INTERNAL ! #define _MALLOC_INTERNAL ! #include ! #endif ! ! __ptr_t ! memalign (alignment, size) ! size_t alignment; ! size_t size; ! { ! __ptr_t result; ! unsigned long int adj; ! ! size = ((size + alignment - 1) / alignment) * alignment; ! ! result = malloc (size); ! if (result == NULL) ! return NULL; ! adj = (unsigned long int) ((unsigned long int) ((char *) result - ! (char *) NULL)) % alignment; ! if (adj != 0) ! { ! struct alignlist *l; ! for (l = _aligned_blocks; l != NULL; l = l->next) ! if (l->aligned == NULL) ! /* This slot is free. Use it. */ ! break; ! if (l == NULL) ! { ! l = (struct alignlist *) malloc (sizeof (struct alignlist)); ! if (l == NULL) ! { ! free (result); ! return NULL; ! } ! } ! l->exact = result; ! result = l->aligned = (char *) result + alignment - adj; ! l->next = _aligned_blocks; ! _aligned_blocks = l; ! } ! ! return result; } diff -c3 tar-1.11.1/mangle.c tar-1.11.2/mangle.c *** tar-1.11.1/mangle.c Tue Sep 15 20:20:47 1992 --- tar-1.11.2/mangle.c Fri Sep 18 14:44:55 1992 *************** *** 20,49 **** #include #include #include ! time_t time(); #include "tar.h" #include "port.h" ! void add_buffer(); ! extern PTR ck_malloc(); ! void finish_header(); ! extern PTR init_buffer(); ! extern char *quote_copy_string(); ! extern char *get_buffer(); ! char *un_quote_string(); ! ! extern union record *start_header(); ! ! extern struct stat hstat; /* Stat struct corresponding */ ! ! struct mangled { ! struct mangled *next; ! int type; ! char mangled[NAMSIZ]; ! char *linked_to; ! char normal[1]; ! }; /* Should use a hash table, etc. . */ --- 20,50 ---- #include #include #include ! time_t time (); #include "tar.h" #include "port.h" ! void add_buffer (); ! extern PTR ck_malloc (); ! void finish_header (); ! extern PTR init_buffer (); ! extern char *quote_copy_string (); ! extern char *get_buffer (); ! char *un_quote_string (); ! ! extern union record *start_header (); ! ! extern struct stat hstat; /* Stat struct corresponding */ ! ! struct mangled ! { ! struct mangled *next; ! int type; ! char mangled[NAMSIZ]; ! char *linked_to; ! char normal[1]; ! }; /* Should use a hash table, etc. . */ *************** *** 50,252 **** struct mangled *first_mangle; int mangled_num = 0; ! #if 0 /* Deleted because there is now a better way to do all this */ char * find_mangled (name) ! char *name; { ! struct mangled *munge; ! for(munge=first_mangle;munge;munge=munge->next) ! if(!strcmp(name,munge->normal)) ! return munge->mangled; ! return 0; } #ifdef S_ISLNK void ! add_symlink_mangle(symlink, linkto, buffer) ! char *symlink; ! char *linkto; ! char *buffer; { ! struct mangled *munge,*kludge; ! munge=(struct mangled *)ck_malloc(sizeof(struct mangled)+strlen(symlink)+strlen(linkto)+2); ! if(!first_mangle) ! first_mangle=munge; ! else { ! for(kludge=first_mangle;kludge->next;kludge=kludge->next) ! ; ! kludge->next=munge; ! } ! munge->type=1; ! munge->next=0; ! strcpy(munge->normal,symlink); ! munge->linked_to=munge->normal+strlen(symlink)+1; ! strcpy(munge->linked_to,linkto); ! sprintf(munge->mangled,"@@MaNgLeD.%d",mangled_num++); ! strncpy(buffer,munge->mangled,NAMSIZ); } #endif void add_mangle (name, buffer) ! char *name; ! char *buffer; { ! struct mangled *munge,*kludge; ! munge=(struct mangled *)ck_malloc(sizeof(struct mangled)+strlen(name)); ! if(!first_mangle) ! first_mangle=munge; ! else { ! for(kludge=first_mangle;kludge->next;kludge=kludge->next) ! ; ! kludge->next=munge; ! } ! munge->next=0; ! munge->type=0; ! strcpy(munge->normal,name); ! sprintf(munge->mangled,"@@MaNgLeD.%d",mangled_num++); ! strncpy(buffer,munge->mangled,NAMSIZ); } void ! write_mangled() { ! struct mangled *munge; ! struct stat hstat; ! union record *header; ! char *ptr1,*ptr2; ! PTR the_buffer; ! int size; ! int bufsize; ! ! if(!first_mangle) ! return; ! the_buffer=init_buffer(); ! for(munge=first_mangle,size=0;munge;munge=munge->next) { ! ptr1=quote_copy_string(munge->normal); ! if(!ptr1) ! ptr1=munge->normal; ! if(munge->type) { ! add_buffer(the_buffer,"Symlink ",8); ! add_buffer(the_buffer,ptr1,strlen(ptr1)); ! add_buffer(the_buffer," to ",4); ! ! if(ptr2=quote_copy_string(munge->linked_to)) { ! add_buffer(the_buffer,ptr2,strlen(ptr2)); ! free(ptr2); ! } else ! add_buffer(the_buffer,munge->linked_to,strlen(munge->linked_to)); ! } else { ! add_buffer(the_buffer,"Rename ",7); ! add_buffer(the_buffer,munge->mangled,strlen(munge->mangled)); ! add_buffer(the_buffer," to ",4); ! add_buffer(the_buffer,ptr1,strlen(ptr1)); ! } ! add_buffer(the_buffer,"\n",1); ! if(ptr1!=munge->normal) ! free(ptr1); ! } ! ! bzero(&hstat,sizeof(struct stat)); ! hstat.st_atime=hstat.st_mtime=hstat.st_ctime=time(0); ! ptr1=get_buffer(the_buffer); ! hstat.st_size=strlen(ptr1); ! ! header=start_header("././@MaNgLeD_NaMeS",&hstat); ! header->header.linkflag=LF_NAMES; ! finish_header(header); ! size=hstat.st_size; ! header=findrec(); ! bufsize = endofrecs()->charptr - header->charptr; ! ! while(bufsizecharptr,bufsize); ! ptr1+=bufsize; ! size-=bufsize; ! userec(header+(bufsize-1)/RECORDSIZE); ! header=findrec(); ! bufsize = endofrecs()->charptr - header->charptr; ! } ! bcopy(ptr1,header->charptr,size); ! bzero(header->charptr+size,bufsize-size); ! userec(header+(size-1)/RECORDSIZE); } #endif void ! extract_mangle(head) ! union record *head; { ! char *buf; ! char *fromtape; ! char *to; ! char *ptr,*ptrend; ! char *nam1,*nam1end; ! int size; ! int copied; ! ! size=hstat.st_size; ! buf=to=ck_malloc(size+1); ! buf[size]='\0'; ! while(size>0) { ! fromtape=findrec()->charptr; ! if(fromtape==0) { ! msg("Unexpected EOF in mangled names!"); ! return; ! } ! copied=endofrecs()->charptr-fromtape; ! if(copied>size) ! copied=size; ! bcopy(fromtape,to,copied); ! to+=copied; ! size-=copied; ! userec((union record *)(fromtape+copied-1)); } - for(ptr=buf;*ptr;ptr=ptrend) { - ptrend=index(ptr,'\n'); - *ptrend++='\0'; - - if(!strncmp(ptr,"Rename ",7)) { - nam1=ptr+7; - nam1end=index(nam1,' '); - while(strncmp(nam1end," to ",4)) { - nam1end++; - nam1end=index(nam1end,' '); - } - *nam1end='\0'; - if(ptrend[-2]=='/') - ptrend[-2]='\0'; - un_quote_string(nam1end+4); - if(rename(nam1,nam1end+4)) - msg_perror("Can't rename %s to %s",nam1,nam1end+4); - else if(f_verbose) - msg("Renamed %s to %s",nam1,nam1end+4); - } #ifdef S_ISLNK ! else if(!strncmp(ptr,"Symlink ",8)) { ! nam1=ptr+8; ! nam1end=index(nam1,' '); ! while(strncmp(nam1end," to ",4)) { ! nam1end++; ! nam1end=index(nam1end,' '); ! } ! *nam1end = '\0'; ! un_quote_string(nam1); ! un_quote_string(nam1end+4); ! if(symlink(nam1,nam1end+4) && (unlink(nam1end+4) || symlink(nam1,nam1end+4))) ! msg_perror("Can't symlink %s to %s",nam1,nam1end+4); ! else if(f_verbose) ! msg("Symlinkd %s to %s",nam1,nam1end+4); ! } ! #endif ! else ! msg("Unknown demangling command %s",ptr); } } --- 51,270 ---- struct mangled *first_mangle; int mangled_num = 0; ! #if 0 /* Deleted because there is now a better way to do all this */ char * find_mangled (name) ! char *name; { ! struct mangled *munge; ! for (munge = first_mangle; munge; munge = munge->next) ! if (!strcmp (name, munge->normal)) ! return munge->mangled; ! return 0; } #ifdef S_ISLNK void ! add_symlink_mangle (symlink, linkto, buffer) ! char *symlink; ! char *linkto; ! char *buffer; { ! struct mangled *munge, *kludge; ! munge = (struct mangled *) ck_malloc (sizeof (struct mangled) + strlen (symlink) + strlen (linkto) + 2); ! if (!first_mangle) ! first_mangle = munge; ! else ! { ! for (kludge = first_mangle; kludge->next; kludge = kludge->next) ! ; ! kludge->next = munge; ! } ! munge->type = 1; ! munge->next = 0; ! strcpy (munge->normal, symlink); ! munge->linked_to = munge->normal + strlen (symlink) + 1; ! strcpy (munge->linked_to, linkto); ! sprintf (munge->mangled, "@@MaNgLeD.%d", mangled_num++); ! strncpy (buffer, munge->mangled, NAMSIZ); } + #endif void add_mangle (name, buffer) ! char *name; ! char *buffer; { ! struct mangled *munge, *kludge; ! munge = (struct mangled *) ck_malloc (sizeof (struct mangled) + strlen (name)); ! if (!first_mangle) ! first_mangle = munge; ! else ! { ! for (kludge = first_mangle; kludge->next; kludge = kludge->next) ! ; ! kludge->next = munge; ! } ! munge->next = 0; ! munge->type = 0; ! strcpy (munge->normal, name); ! sprintf (munge->mangled, "@@MaNgLeD.%d", mangled_num++); ! strncpy (buffer, munge->mangled, NAMSIZ); } void ! write_mangled () { ! struct mangled *munge; ! struct stat hstat; ! union record *header; ! char *ptr1, *ptr2; ! PTR the_buffer; ! int size; ! int bufsize; ! ! if (!first_mangle) ! return; ! the_buffer = init_buffer (); ! for (munge = first_mangle, size = 0; munge; munge = munge->next) ! { ! ptr1 = quote_copy_string (munge->normal); ! if (!ptr1) ! ptr1 = munge->normal; ! if (munge->type) ! { ! add_buffer (the_buffer, "Symlink ", 8); ! add_buffer (the_buffer, ptr1, strlen (ptr1)); ! add_buffer (the_buffer, " to ", 4); ! ! if (ptr2 = quote_copy_string (munge->linked_to)) ! { ! add_buffer (the_buffer, ptr2, strlen (ptr2)); ! free (ptr2); ! } ! else ! add_buffer (the_buffer, munge->linked_to, strlen (munge->linked_to)); ! } ! else ! { ! add_buffer (the_buffer, "Rename ", 7); ! add_buffer (the_buffer, munge->mangled, strlen (munge->mangled)); ! add_buffer (the_buffer, " to ", 4); ! add_buffer (the_buffer, ptr1, strlen (ptr1)); ! } ! add_buffer (the_buffer, "\n", 1); ! if (ptr1 != munge->normal) ! free (ptr1); ! } ! ! bzero (&hstat, sizeof (struct stat)); ! hstat.st_atime = hstat.st_mtime = hstat.st_ctime = time (0); ! ptr1 = get_buffer (the_buffer); ! hstat.st_size = strlen (ptr1); ! ! header = start_header ("././@MaNgLeD_NaMeS", &hstat); ! header->header.linkflag = LF_NAMES; ! finish_header (header); ! size = hstat.st_size; ! header = findrec (); ! bufsize = endofrecs ()->charptr - header->charptr; ! ! while (bufsize < size) ! { ! bcopy (ptr1, header->charptr, bufsize); ! ptr1 += bufsize; ! size -= bufsize; ! userec (header + (bufsize - 1) / RECORDSIZE); ! header = findrec (); ! bufsize = endofrecs ()->charptr - header->charptr; ! } ! bcopy (ptr1, header->charptr, size); ! bzero (header->charptr + size, bufsize - size); ! userec (header + (size - 1) / RECORDSIZE); } #endif void ! extract_mangle (head) ! union record *head; { ! char *buf; ! char *fromtape; ! char *to; ! char *ptr, *ptrend; ! char *nam1, *nam1end; ! int size; ! int copied; ! ! size = hstat.st_size; ! buf = to = ck_malloc (size + 1); ! buf[size] = '\0'; ! while (size > 0) ! { ! fromtape = findrec ()->charptr; ! if (fromtape == 0) ! { ! msg ("Unexpected EOF in mangled names!"); ! return; ! } ! copied = endofrecs ()->charptr - fromtape; ! if (copied > size) ! copied = size; ! bcopy (fromtape, to, copied); ! to += copied; ! size -= copied; ! userec ((union record *) (fromtape + copied - 1)); ! } ! for (ptr = buf; *ptr; ptr = ptrend) ! { ! ptrend = index (ptr, '\n'); ! *ptrend++ = '\0'; ! ! if (!strncmp (ptr, "Rename ", 7)) ! { ! nam1 = ptr + 7; ! nam1end = index (nam1, ' '); ! while (strncmp (nam1end, " to ", 4)) ! { ! nam1end++; ! nam1end = index (nam1end, ' '); ! } ! *nam1end = '\0'; ! if (ptrend[-2] == '/') ! ptrend[-2] = '\0'; ! un_quote_string (nam1end + 4); ! if (rename (nam1, nam1end + 4)) ! msg_perror ("Can't rename %s to %s", nam1, nam1end + 4); ! else if (f_verbose) ! msg ("Renamed %s to %s", nam1, nam1end + 4); } #ifdef S_ISLNK ! else if (!strncmp (ptr, "Symlink ", 8)) ! { ! nam1 = ptr + 8; ! nam1end = index (nam1, ' '); ! while (strncmp (nam1end, " to ", 4)) ! { ! nam1end++; ! nam1end = index (nam1end, ' '); ! } ! *nam1end = '\0'; ! un_quote_string (nam1); ! un_quote_string (nam1end + 4); ! if (symlink (nam1, nam1end + 4) && (unlink (nam1end + 4) || symlink (nam1, nam1end + 4))) ! msg_perror ("Can't symlink %s to %s", nam1, nam1end + 4); ! else if (f_verbose) ! msg ("Symlinkd %s to %s", nam1, nam1end + 4); } + #endif + else + msg ("Unknown demangling command %s", ptr); + } } diff -c3 tar-1.11.1/msd_dir.c tar-1.11.2/msd_dir.c *** tar-1.11.1/msd_dir.c Fri Jul 26 01:02:47 1991 --- tar-1.11.2/msd_dir.c Fri Sep 18 14:44:59 1992 *************** *** 19,29 **** #ifndef NULL # define NULL 0 ! #endif /* NULL */ #ifndef MAXPATHLEN # define MAXPATHLEN 255 ! #endif /* MAXPATHLEN */ /* attribute stuff */ #define A_RONLY 0x01 --- 19,29 ---- #ifndef NULL # define NULL 0 ! #endif /* NULL */ #ifndef MAXPATHLEN # define MAXPATHLEN 255 ! #endif /* MAXPATHLEN */ /* attribute stuff */ #define A_RONLY 0x01 *************** *** 43,220 **** #define ATTRIBUTES (A_RONLY | A_SYSTEM | A_DIR) /* what find first/next calls look use */ ! typedef struct { ! char d_buf[21]; ! char d_attribute; ! unsigned short d_time; ! unsigned short d_date; ! long d_size; ! char d_name[13]; ! } Dta_buf; ! ! static char *getdirent(); ! static void mysetdta(); ! static void free_dircontents(); ! ! static Dta_buf dtabuf; ! static Dta_buf *dtapnt = &dtabuf; ! static union REGS reg, nreg; #if defined(M_I86LM) ! static struct SREGS sreg; #endif ! DIR * ! opendir(name) ! char *name; ! { ! struct stat statb; ! DIR *dirp; ! char c; ! char *s; ! struct _dircontents *dp; ! char nbuf[MAXPATHLEN + 1]; ! ! if (stat(name, &statb) < 0 || (statb.st_mode & S_IFMT) != S_IFDIR) ! return (DIR *) NULL; ! if (Newisnull(dirp, DIR)) ! return (DIR *) NULL; ! if (*name && (c = name[strlen(name) - 1]) != '\\' && c != '/') ! (void) strcat(strcpy(nbuf, name), "\\*.*"); ! else ! (void) strcat(strcpy(nbuf, name), "*.*"); ! dirp->dd_loc = 0; ! mysetdta(); ! dirp->dd_contents = dirp->dd_cp = (struct _dircontents *) NULL; ! if ((s = getdirent(nbuf)) == (char *) NULL) ! return dirp; ! do { ! if (Newisnull(dp, struct _dircontents) || (dp->_d_entry = ! malloc((unsigned) (strlen(s) + 1))) == (char *) NULL) ! { ! if (dp) ! free((char *) dp); ! free_dircontents(dirp->dd_contents); ! return (DIR *) NULL; ! } ! if (dirp->dd_contents) ! dirp->dd_cp = dirp->dd_cp->_d_next = dp; ! else ! dirp->dd_contents = dirp->dd_cp = dp; ! (void) strcpy(dp->_d_entry, s); ! dp->_d_next = (struct _dircontents *) NULL; ! } while ((s = getdirent((char *) NULL)) != (char *) NULL); ! dirp->dd_cp = dirp->dd_contents; ! return dirp; } void ! closedir(dirp) ! DIR *dirp; { ! free_dircontents(dirp->dd_contents); ! free((char *) dirp); } ! struct dirent * ! readdir(dirp) ! DIR *dirp; ! { ! static struct dirent dp; ! ! if (dirp->dd_cp == (struct _dircontents *) NULL) ! return (struct dirent *) NULL; ! dp.d_namlen = dp.d_reclen = ! strlen(strcpy(dp.d_name, dirp->dd_cp->_d_entry)); ! strlwr(dp.d_name); /* JF */ ! dp.d_ino = 0; ! dirp->dd_cp = dirp->dd_cp->_d_next; ! dirp->dd_loc++; ! return &dp; } void ! seekdir(dirp, off) ! DIR *dirp; ! long off; ! { ! long i = off; ! struct _dircontents *dp; ! ! if (off < 0) ! return; ! for (dp = dirp->dd_contents ; --i >= 0 && dp ; dp = dp->_d_next) ! ; ! dirp->dd_loc = off - (i + 1); ! dirp->dd_cp = dp; } long ! telldir(dirp) ! DIR *dirp; { ! return dirp->dd_loc; } ! static void ! free_dircontents(dp) ! struct _dircontents *dp; { ! struct _dircontents *odp; ! while (dp) { ! if (dp->_d_entry) ! free(dp->_d_entry); ! dp = (odp = dp)->_d_next; ! free((char *) odp); ! } } ! static char * ! getdirent(dir) ! char *dir; ! { ! if (dir != (char *) NULL) { /* get first entry */ ! reg.h.ah = DOSI_FINDF; ! reg.h.cl = ATTRIBUTES; #if defined(M_I86LM) ! reg.x.dx = FP_OFF(dir); ! sreg.ds = FP_SEG(dir); #else ! reg.x.dx = (unsigned) dir; #endif ! } else { /* get next entry */ ! reg.h.ah = DOSI_FINDN; #if defined(M_I86LM) ! reg.x.dx = FP_OFF(dtapnt); ! sreg.ds = FP_SEG(dtapnt); #else ! reg.x.dx = (unsigned) dtapnt; #endif ! } #if defined(M_I86LM) ! intdosx(®, &nreg, &sreg); #else ! intdos(®, &nreg); #endif ! if (nreg.x.cflag) ! return (char *) NULL; ! return dtabuf.d_name; } ! static void ! mysetdta() { ! reg.h.ah = DOSI_SDTA; #if defined(M_I86LM) ! reg.x.dx = FP_OFF(dtapnt); ! sreg.ds = FP_SEG(dtapnt); ! intdosx(®, &nreg, &sreg); #else ! reg.x.dx = (int) dtapnt; ! intdos(®, &nreg); #endif } --- 43,229 ---- #define ATTRIBUTES (A_RONLY | A_SYSTEM | A_DIR) /* what find first/next calls look use */ ! typedef struct ! { ! char d_buf[21]; ! char d_attribute; ! unsigned short d_time; ! unsigned short d_date; ! long d_size; ! char d_name[13]; ! } ! ! Dta_buf; ! ! static char *getdirent (); ! static void mysetdta (); ! static void free_dircontents (); ! ! static Dta_buf dtabuf; ! static Dta_buf *dtapnt = &dtabuf; ! static union REGS reg, nreg; #if defined(M_I86LM) ! static struct SREGS sreg; #endif ! DIR * ! opendir (name) ! char *name; ! { ! struct stat statb; ! DIR *dirp; ! char c; ! char *s; ! struct _dircontents *dp; ! char nbuf[MAXPATHLEN + 1]; ! ! if (stat (name, &statb) < 0 || (statb.st_mode & S_IFMT) != S_IFDIR) ! return (DIR *) NULL; ! if (Newisnull (dirp, DIR)) ! return (DIR *) NULL; ! if (*name && (c = name[strlen (name) - 1]) != '\\' && c != '/') ! (void) strcat (strcpy (nbuf, name), "\\*.*"); ! else ! (void) strcat (strcpy (nbuf, name), "*.*"); ! dirp->dd_loc = 0; ! mysetdta (); ! dirp->dd_contents = dirp->dd_cp = (struct _dircontents *) NULL; ! if ((s = getdirent (nbuf)) == (char *) NULL) ! return dirp; ! do ! { ! if (Newisnull (dp, struct _dircontents) || (dp->_d_entry = ! malloc ((unsigned) (strlen (s) + 1))) == (char *) NULL) ! { ! if (dp) ! free ((char *) dp); ! free_dircontents (dirp->dd_contents); ! return (DIR *) NULL; ! } ! if (dirp->dd_contents) ! dirp->dd_cp = dirp->dd_cp->_d_next = dp; ! else ! dirp->dd_contents = dirp->dd_cp = dp; ! (void) strcpy (dp->_d_entry, s); ! dp->_d_next = (struct _dircontents *) NULL; ! } ! while ((s = getdirent ((char *) NULL)) != (char *) NULL); ! dirp->dd_cp = dirp->dd_contents; ! return dirp; } void ! closedir (dirp) ! DIR *dirp; { ! free_dircontents (dirp->dd_contents); ! free ((char *) dirp); } ! struct dirent * ! readdir (dirp) ! DIR *dirp; ! { ! static struct dirent dp; ! ! if (dirp->dd_cp == (struct _dircontents *) NULL) ! return (struct dirent *) NULL; ! dp.d_namlen = dp.d_reclen = ! strlen (strcpy (dp.d_name, dirp->dd_cp->_d_entry)); ! strlwr (dp.d_name); /* JF */ ! dp.d_ino = 0; ! dirp->dd_cp = dirp->dd_cp->_d_next; ! dirp->dd_loc++; ! return &dp; } void ! seekdir (dirp, off) ! DIR *dirp; ! long off; ! { ! long i = off; ! struct _dircontents *dp; ! ! if (off < 0) ! return; ! for (dp = dirp->dd_contents; --i >= 0 && dp; dp = dp->_d_next) ! ; ! dirp->dd_loc = off - (i + 1); ! dirp->dd_cp = dp; } long ! telldir (dirp) ! DIR *dirp; { ! return dirp->dd_loc; } ! static void ! free_dircontents (dp) ! struct _dircontents *dp; { ! struct _dircontents *odp; ! while (dp) ! { ! if (dp->_d_entry) ! free (dp->_d_entry); ! dp = (odp = dp)->_d_next; ! free ((char *) odp); ! } } ! static char * ! getdirent (dir) ! char *dir; ! { ! if (dir != (char *) NULL) ! { /* get first entry */ ! reg.h.ah = DOSI_FINDF; ! reg.h.cl = ATTRIBUTES; #if defined(M_I86LM) ! reg.x.dx = FP_OFF (dir); ! sreg.ds = FP_SEG (dir); #else ! reg.x.dx = (unsigned) dir; #endif ! } ! else ! { /* get next entry */ ! reg.h.ah = DOSI_FINDN; #if defined(M_I86LM) ! reg.x.dx = FP_OFF (dtapnt); ! sreg.ds = FP_SEG (dtapnt); #else ! reg.x.dx = (unsigned) dtapnt; #endif ! } #if defined(M_I86LM) ! intdosx (®, &nreg, &sreg); #else ! intdos (®, &nreg); #endif ! if (nreg.x.cflag) ! return (char *) NULL; ! return dtabuf.d_name; } ! static void ! mysetdta () { ! reg.h.ah = DOSI_SDTA; #if defined(M_I86LM) ! reg.x.dx = FP_OFF (dtapnt); ! sreg.ds = FP_SEG (dtapnt); ! intdosx (®, &nreg, &sreg); #else ! reg.x.dx = (int) dtapnt; ! intdos (®, &nreg); #endif } diff -c3 tar-1.11.1/msd_dir.h tar-1.11.2/msd_dir.h *** tar-1.11.1/msd_dir.h Sat Jul 20 00:03:02 1991 --- tar-1.11.2/msd_dir.h Fri Sep 18 14:45:01 1992 *************** *** 15,41 **** typedef int dev_t; #endif ! struct dirent { ! ino_t d_ino; /* a bit of a farce */ ! int d_reclen; /* more farce */ ! int d_namlen; /* length of d_name */ ! char d_name[MAXNAMLEN + 1]; /* garentee null termination */ ! }; ! struct _dircontents { ! char *_d_entry; ! struct _dircontents *_d_next; ! }; ! typedef struct _dirdesc { ! int dd_id; /* uniquely identify each open directory */ ! long dd_loc; /* where we are in directory entry is this */ ! struct _dircontents *dd_contents; /* pointer to contents of dir */ ! struct _dircontents *dd_cp; /* pointer to current position */ ! } DIR; ! extern DIR *opendir(); ! extern struct dirent *readdir(); ! extern void seekdir(); ! extern long telldir(); ! extern void closedir(); --- 15,44 ---- typedef int dev_t; #endif ! struct dirent ! { ! ino_t d_ino; /* a bit of a farce */ ! int d_reclen; /* more farce */ ! int d_namlen; /* length of d_name */ ! char d_name[MAXNAMLEN + 1]; /* garentee null termination */ ! }; ! struct _dircontents ! { ! char *_d_entry; ! struct _dircontents *_d_next; ! }; ! typedef struct _dirdesc ! { ! int dd_id; /* uniquely identify each open directory */ ! long dd_loc; /* where we are in directory entry is this */ ! struct _dircontents *dd_contents; /* pointer to contents of dir */ ! struct _dircontents *dd_cp; /* pointer to current position */ ! } DIR; ! extern DIR *opendir (); ! extern struct dirent *readdir (); ! extern void seekdir (); ! extern long telldir (); ! extern void closedir (); diff -c3 tar-1.11.1/names.c tar-1.11.2/names.c *** tar-1.11.1/names.c Tue Sep 15 19:58:17 1992 --- tar-1.11.2/names.c Fri Sep 18 14:45:08 1992 *************** *** 22,28 **** * * This file should be modified for non-unix systems to do something * reasonable. ! */ #include #include "tar.h" --- 22,28 ---- * * This file should be modified for non-unix systems to do something * reasonable. ! */ #include #include "tar.h" *************** *** 34,46 **** #include #include ! static int saveuid = -993; ! static char saveuname[TUNMLEN]; ! static int my_uid = -993; ! ! static int savegid = -993; ! static char savegname[TGNMLEN]; ! static int my_gid = -993; #define myuid ( my_uid < 0? (my_uid = getuid()): my_uid ) #define mygid ( my_gid < 0? (my_gid = getgid()): my_gid ) --- 34,46 ---- #include #include ! static int saveuid = -993; ! static char saveuname[TUNMLEN]; ! static int my_uid = -993; ! ! static int savegid = -993; ! static char savegname[TGNMLEN]; ! static int my_gid = -993; #define myuid ( my_uid < 0? (my_uid = getuid()): my_uid ) #define mygid ( my_gid < 0? (my_gid = getgid()): my_gid ) *************** *** 54,138 **** * pages" code, roughly doubling the program size. Thanks guys. */ void ! finduname(uname, uid) ! char uname[TUNMLEN]; ! int uid; { ! struct passwd *pw; #ifndef HAVE_GETPWUID ! extern struct passwd *getpwuid (); #endif ! if (uid != saveuid) { ! saveuid = uid; ! saveuname[0] = '\0'; ! pw = getpwuid(uid); ! if (pw) ! strncpy(saveuname, pw->pw_name, TUNMLEN); ! } ! strncpy(uname, saveuname, TUNMLEN); } int ! finduid(uname) ! char uname[TUNMLEN]; { ! struct passwd *pw; ! extern struct passwd *getpwnam(); ! if (uname[0] != saveuname[0] /* Quick test w/o proc call */ ! || 0!=strncmp(uname, saveuname, TUNMLEN)) { ! strncpy(saveuname, uname, TUNMLEN); ! pw = getpwnam(uname); ! if (pw) { ! saveuid = pw->pw_uid; ! } else { ! saveuid = myuid; ! } } ! return saveuid; } void ! findgname(gname, gid) ! char gname[TGNMLEN]; ! int gid; { ! struct group *gr; #ifndef HAVE_GETGRGID ! extern struct group *getgrgid (); #endif ! if (gid != savegid) { ! savegid = gid; ! savegname[0] = '\0'; ! (void)setgrent(); ! gr = getgrgid(gid); ! if (gr) ! strncpy(savegname, gr->gr_name, TGNMLEN); ! } ! (void) strncpy(gname, savegname, TGNMLEN); } int ! findgid(gname) ! char gname[TUNMLEN]; { ! struct group *gr; ! extern struct group *getgrnam(); ! if (gname[0] != savegname[0] /* Quick test w/o proc call */ ! || 0!=strncmp(gname, savegname, TUNMLEN)) { ! strncpy(savegname, gname, TUNMLEN); ! gr = getgrnam(gname); ! if (gr) { ! savegid = gr->gr_gid; ! } else { ! savegid = mygid; ! } } ! return savegid; } #endif --- 54,149 ---- * pages" code, roughly doubling the program size. Thanks guys. */ void ! finduname (uname, uid) ! char uname[TUNMLEN]; ! int uid; { ! struct passwd *pw; #ifndef HAVE_GETPWUID ! extern struct passwd *getpwuid (); #endif ! if (uid != saveuid) ! { ! saveuid = uid; ! saveuname[0] = '\0'; ! pw = getpwuid (uid); ! if (pw) ! strncpy (saveuname, pw->pw_name, TUNMLEN); ! } ! strncpy (uname, saveuname, TUNMLEN); } int ! finduid (uname) ! char uname[TUNMLEN]; { ! struct passwd *pw; ! extern struct passwd *getpwnam (); ! if (uname[0] != saveuname[0] /* Quick test w/o proc call */ ! || 0 != strncmp (uname, saveuname, TUNMLEN)) ! { ! strncpy (saveuname, uname, TUNMLEN); ! pw = getpwnam (uname); ! if (pw) ! { ! saveuid = pw->pw_uid; ! } ! else ! { ! saveuid = myuid; } ! } ! return saveuid; } void ! findgname (gname, gid) ! char gname[TGNMLEN]; ! int gid; { ! struct group *gr; #ifndef HAVE_GETGRGID ! extern struct group *getgrgid (); #endif ! if (gid != savegid) ! { ! savegid = gid; ! savegname[0] = '\0'; ! (void) setgrent (); ! gr = getgrgid (gid); ! if (gr) ! strncpy (savegname, gr->gr_name, TGNMLEN); ! } ! (void) strncpy (gname, savegname, TGNMLEN); } int ! findgid (gname) ! char gname[TUNMLEN]; { ! struct group *gr; ! extern struct group *getgrnam (); ! if (gname[0] != savegname[0] /* Quick test w/o proc call */ ! || 0 != strncmp (gname, savegname, TUNMLEN)) ! { ! strncpy (savegname, gname, TUNMLEN); ! gr = getgrnam (gname); ! if (gr) ! { ! savegid = gr->gr_gid; ! } ! else ! { ! savegid = mygid; } ! } ! return savegid; } + #endif diff -c3 tar-1.11.1/open3.h tar-1.11.2/open3.h *** tar-1.11.1/open3.h Thu Jul 18 00:20:37 1991 --- tar-1.11.2/open3.h Fri Sep 18 14:45:18 1992 *************** *** 22,28 **** * open() call. On BSD or System 5, the system already has this in an * include file. This file is needed for V7 and MINIX systems for the * benefit of open3() in port.c, a routine that emulates the 3-argument ! * call using system calls available on V7/MINIX. * * This file is needed by PD tar even if we aren't using the * emulator, since the #defines for O_WRONLY, etc. are used in --- 22,28 ---- * open() call. On BSD or System 5, the system already has this in an * include file. This file is needed for V7 and MINIX systems for the * benefit of open3() in port.c, a routine that emulates the 3-argument ! * call using system calls available on V7/MINIX. * * This file is needed by PD tar even if we aren't using the * emulator, since the #defines for O_WRONLY, etc. are used in *************** *** 38,46 **** */ /* Only one of the next three should be specified */ ! #define O_RDONLY 0 /* only allow read */ ! #define O_WRONLY 1 /* only allow write */ ! #define O_RDWR 2 /* both are allowed */ /* The rest of these can be OR-ed in to the above. */ /* --- 38,46 ---- */ /* Only one of the next three should be specified */ ! #define O_RDONLY 0 /* only allow read */ ! #define O_WRONLY 1 /* only allow write */ ! #define O_RDWR 2 /* both are allowed */ /* The rest of these can be OR-ed in to the above. */ /* *************** *** 50,62 **** * it defined. */ #ifndef O_NDELAY ! #define O_NDELAY 4 /* don't block on opening devices that would * block on open -- ignored by emulator. */ #endif ! #define O_CREAT 8 /* create file if needed */ ! #define O_EXCL 16 /* file cannot already exist */ ! #define O_TRUNC 32 /* truncate file on open */ ! #define O_APPEND 64 /* always write at end of file -- ignored by emul */ #ifdef EMUL_OPEN3 /* --- 50,62 ---- * it defined. */ #ifndef O_NDELAY ! #define O_NDELAY 4 /* don't block on opening devices that would * block on open -- ignored by emulator. */ #endif ! #define O_CREAT 8 /* create file if needed */ ! #define O_EXCL 16 /* file cannot already exist */ ! #define O_TRUNC 32 /* truncate file on open */ ! #define O_APPEND 64 /* always write at end of file -- ignored by emul */ #ifdef EMUL_OPEN3 /* diff -c3 tar-1.11.1/pathmax.h tar-1.11.2/pathmax.h *** tar-1.11.1/pathmax.h Thu Jul 23 17:35:42 1992 --- tar-1.11.2/pathmax.h Thu Oct 1 23:33:48 1992 *************** *** 38,44 **** #endif /* Don't include sys/param.h if it already has been. */ ! #if !defined(PATH_MAX) && !defined(MAXPATHLEN) #include #endif --- 38,44 ---- #endif /* Don't include sys/param.h if it already has been. */ ! #if !defined(PATH_MAX) && !defined(MAXPATHLEN) && !defined(__MSDOS__) #include #endif diff -c3 tar-1.11.1/port.c tar-1.11.2/port.c *** tar-1.11.1/port.c Sun Jul 19 04:37:41 1992 --- tar-1.11.2/port.c Fri Oct 2 00:35:19 1992 *************** *** 1,5 **** /* Supporting routines which may sometimes be missing. ! Copyright (C) 1988 Free Software Foundation This file is part of GNU Tar. --- 1,5 ---- /* Supporting routines which may sometimes be missing. ! Copyright (C) 1988, 1992 Free Software Foundation This file is part of GNU Tar. *************** *** 45,56 **** #ifdef __MSDOS__ char TTY_NAME[] = "con"; ! ! #else /* not __MSDOS__ */ ! ! char TTY_NAME[] ="/dev/tty"; ! ! #endif /* not __MSDOS__ */ /* End of system-dependent #ifdefs */ --- 45,56 ---- #ifdef __MSDOS__ char TTY_NAME[] = "con"; ! #define HAVE_STRSTR ! #define HAVE_RENAME ! #define HAVE_MKDIR ! #else ! char TTY_NAME[] = "/dev/tty"; ! #endif /* End of system-dependent #ifdefs */ *************** *** 62,76 **** */ char * valloc (size) ! unsigned size; { ! return (malloc (size)); } #endif /* !HAVE_VALLOC */ #ifndef HAVE_MKDIR /* ! * Written by Robert Rother, Mariah Corporation, August 1985. * * If you want it, it's yours. All I ask in return is that if you * figure out how to do this in a Bourne Shell script you send me --- 62,77 ---- */ char * valloc (size) ! unsigned size; { ! return (malloc (size)); } + #endif /* !HAVE_VALLOC */ #ifndef HAVE_MKDIR /* ! * Written by Robert Rother, Mariah Corporation, August 1985. * * If you want it, it's yours. All I ask in return is that if you * figure out how to do this in a Bourne Shell script you send me *************** *** 88,169 **** * Make a directory. */ int ! mkdir(dpath, dmode) ! char *dpath; ! int dmode; ! { ! int cpid, status; ! struct stat statbuf; ! ! if (stat(dpath,&statbuf) == 0) { ! errno = EEXIST; /* Stat worked, so it already exists */ ! return -1; ! } ! /* If stat fails for a reason other than non-existence, return error */ ! if (errno != ENOENT) return -1; ! switch (cpid = fork()) { ! case -1: /* Error in fork() */ ! return(-1); /* Errno is set already */ ! case 0: /* Child process */ ! /* * Cheap hack to set mode of new directory. Since this * child process is going away anyway, we zap its umask. * FIXME, this won't suffice to set SUID, SGID, etc. on this * directory. Does anybody care? */ ! status = umask(0); /* Get current umask */ ! status = umask(status | (0777 & ~dmode)); /* Set for mkdir */ ! execl("/bin/mkdir", "mkdir", dpath, (char *)0); ! _exit(-1); /* Can't exec /bin/mkdir */ ! ! default: /* Parent process */ ! while (cpid != wait(&status)) ; /* Wait for kid to finish */ ! } ! if (WTERMSIG(status) != 0 || WEXITSTATUS(status) != 0) { ! errno = EIO; /* We don't know why, but */ ! return -1; /* /bin/mkdir failed */ ! } ! return 0; } int ! rmdir(dpath) ! char *dpath; { ! int cpid, status; ! struct stat statbuf; ! if (stat(dpath,&statbuf) != 0) { ! /* Stat just set errno. We don't have to */ ! return -1; ! } ! switch (cpid = fork()) { ! case -1: /* Error in fork() */ ! return(-1); /* Errno is set already */ ! case 0: /* Child process */ ! execl("/bin/rmdir", "rmdir", dpath, (char *)0); ! _exit(-1); /* Can't exec /bin/mkdir */ ! ! default: /* Parent process */ ! while (cpid != wait(&status)) ; /* Wait for kid to finish */ ! } ! if (WTERMSIG(status) != 0 || WEXITSTATUS(status) != 0) { ! errno = EIO; /* We don't know why, but */ ! return -1; /* /bin/mkdir failed */ ! } ! return 0; } #endif /* !HAVE_MKDIR */ #ifndef HAVE_RENAME --- 89,178 ---- * Make a directory. */ int ! mkdir (dpath, dmode) ! char *dpath; ! int dmode; ! { ! int cpid, status; ! struct stat statbuf; ! ! if (stat (dpath, &statbuf) == 0) ! { ! errno = EEXIST; /* Stat worked, so it already exists */ ! return -1; ! } ! /* If stat fails for a reason other than non-existence, return error */ ! if (errno != ENOENT) ! return -1; ! switch (cpid = fork ()) ! { ! case -1: /* Error in fork() */ ! return (-1); /* Errno is set already */ ! case 0: /* Child process */ ! /* * Cheap hack to set mode of new directory. Since this * child process is going away anyway, we zap its umask. * FIXME, this won't suffice to set SUID, SGID, etc. on this * directory. Does anybody care? */ ! status = umask (0); /* Get current umask */ ! status = umask (status | (0777 & ~dmode)); /* Set for mkdir */ ! execl ("/bin/mkdir", "mkdir", dpath, (char *) 0); ! _exit (-1); /* Can't exec /bin/mkdir */ ! default: /* Parent process */ ! while (cpid != wait (&status)); /* Wait for kid to finish */ ! } ! ! if (WIFSIGNALED (status) || WEXITSTATUS (status) != 0) ! { ! errno = EIO; /* We don't know why, but */ ! return -1; /* /bin/mkdir failed */ ! } ! return 0; } int ! rmdir (dpath) ! char *dpath; { ! int cpid, status; ! struct stat statbuf; ! if (stat (dpath, &statbuf) != 0) ! { ! /* Stat just set errno. We don't have to */ ! return -1; ! } ! switch (cpid = fork ()) ! { ! case -1: /* Error in fork() */ ! return (-1); /* Errno is set already */ ! case 0: /* Child process */ ! execl ("/bin/rmdir", "rmdir", dpath, (char *) 0); ! _exit (-1); /* Can't exec /bin/mkdir */ ! default: /* Parent process */ ! while (cpid != wait (&status)); /* Wait for kid to finish */ ! } ! ! if (WIFSIGNALED (status) || WEXITSTATUS (status) != 0) ! { ! errno = EIO; /* We don't know why, but */ ! return -1; /* /bin/mkdir failed */ ! } ! return 0; } + #endif /* !HAVE_MKDIR */ #ifndef HAVE_RENAME *************** *** 194,199 **** --- 203,209 ---- return 0; } + #endif /* !HAVE_RENAME */ #ifdef minix *************** *** 200,221 **** /* Minix has bcopy but not bzero, and no memset. Thanks, Andy. */ void bzero (s1, n) ! register char *s1; ! register int n; { ! while (n--) *s1++ = '\0'; } /* It also has no bcmp() */ int ! bcmp (s1, s2, n) ! register char *s1,*s2; ! register int n; { ! for ( ; n-- ; ++s1, ++s2) { ! if (*s1 != *s2) return *s1 - *s2; ! } ! return 0; } /* --- 210,234 ---- /* Minix has bcopy but not bzero, and no memset. Thanks, Andy. */ void bzero (s1, n) ! register char *s1; ! register int n; { ! while (n--) ! *s1++ = '\0'; } /* It also has no bcmp() */ int ! bcmp (s1, s2, n) ! register char *s1, *s2; ! register int n; { ! for (; n--; ++s1, ++s2) ! { ! if (*s1 != *s2) ! return *s1 - *s2; ! } ! return 0; } /* *************** *** 230,295 **** * *and* doesn't have execlp, YOU get to fix it. */ int ! execlp(filename, arg0) ! char *filename, *arg0; { ! register char *p, *path; ! register char *fnbuffer; ! char **argstart = &arg0; ! struct stat statbuf; ! extern char **environ; ! ! if ((p = getenv("PATH")) == NULL) { ! /* couldn't find path variable -- try to exec given filename */ ! return execve(filename, argstart, environ); ! } ! /* * make a place to build the filename. We malloc larger than we * need, but we know it will fit in this. */ ! fnbuffer = malloc( strlen(p) + 1 + strlen(filename) ); ! if (fnbuffer == NULL) { ! errno = ENOMEM; ! return -1; ! } ! /* * try each component of the path to see if the file's there * and executable. */ ! for (path = p ; path ; path = p) { ! /* construct full path name to try */ ! if ((p = index(path,':')) == NULL) { ! strcpy(fnbuffer, path); ! } else { ! strncpy(fnbuffer, path, p-path); ! fnbuffer[p-path] = '\0'; ! p++; /* Skip : for next time */ ! } ! if (strlen(fnbuffer) != 0) ! strcat(fnbuffer,"/"); ! strcat(fnbuffer,filename); ! ! /* check to see if file is there and is a normal file */ ! if (stat(fnbuffer, &statbuf) < 0) { ! if (errno == ENOENT) ! continue; /* file not there,keep on looking */ ! else ! goto fail; /* failed for some reason, return */ ! } ! if (!S_ISREG(statbuf.st_mode)) continue; ! ! if (execve(fnbuffer, argstart, environ) < 0 ! && errno != ENOENT ! && errno != ENOEXEC) { ! /* failed, for some other reason besides "file * not found" or "not a.out format" */ ! goto fail; ! } ! /* * If we got error ENOEXEC, the file is executable but is * not an object file. Try to execute it as a shell script, * returning error if we can't execute /bin/sh. --- 243,317 ---- * *and* doesn't have execlp, YOU get to fix it. */ int ! execlp (filename, arg0) ! char *filename, *arg0; { ! register char *p, *path; ! register char *fnbuffer; ! char **argstart = &arg0; ! struct stat statbuf; ! extern char **environ; ! if ((p = getenv ("PATH")) == NULL) ! { ! /* couldn't find path variable -- try to exec given filename */ ! return execve (filename, argstart, environ); ! } ! ! /* * make a place to build the filename. We malloc larger than we * need, but we know it will fit in this. */ ! fnbuffer = malloc (strlen (p) + 1 + strlen (filename)); ! if (fnbuffer == NULL) ! { ! errno = ENOMEM; ! return -1; ! } ! /* * try each component of the path to see if the file's there * and executable. */ ! for (path = p; path; path = p) ! { ! /* construct full path name to try */ ! if ((p = index (path, ':')) == NULL) ! { ! strcpy (fnbuffer, path); ! } ! else ! { ! strncpy (fnbuffer, path, p - path); ! fnbuffer[p - path] = '\0'; ! p++; /* Skip : for next time */ ! } ! if (strlen (fnbuffer) != 0) ! strcat (fnbuffer, "/"); ! strcat (fnbuffer, filename); ! ! /* check to see if file is there and is a normal file */ ! if (stat (fnbuffer, &statbuf) < 0) ! { ! if (errno == ENOENT) ! continue; /* file not there,keep on looking */ ! else ! goto fail; /* failed for some reason, return */ ! } ! if (!S_ISREG (statbuf.st_mode)) ! continue; ! ! if (execve (fnbuffer, argstart, environ) < 0 ! && errno != ENOENT ! && errno != ENOEXEC) ! { ! /* failed, for some other reason besides "file * not found" or "not a.out format" */ ! goto fail; ! } ! /* * If we got error ENOEXEC, the file is executable but is * not an object file. Try to execute it as a shell script, * returning error if we can't execute /bin/sh. *************** *** 301,332 **** * code clobbers argstart[-1] if the exec of the shell * fails. */ ! if (errno == ENOEXEC) { ! char *shell; ! /* Try to execute command "sh arg0 arg1 ..." */ ! if ((shell = getenv("SHELL")) == NULL) ! shell = "/bin/sh"; ! argstart[-1] = shell; ! argstart[0] = fnbuffer; ! execve(shell, &argstart[-1], environ); ! goto fail; /* Exec didn't work */ ! } ! /* * If we succeeded, the execve() doesn't return, so we * can only be here is if the file hasn't been found yet. * Try the next place on the path. */ ! } ! /* all attempts failed to locate the file. Give up. */ ! errno = ENOENT; fail: ! free(fnbuffer); ! return -1; } #endif /* minix */ --- 323,356 ---- * code clobbers argstart[-1] if the exec of the shell * fails. */ ! if (errno == ENOEXEC) ! { ! char *shell; ! /* Try to execute command "sh arg0 arg1 ..." */ ! if ((shell = getenv ("SHELL")) == NULL) ! shell = "/bin/sh"; ! argstart[-1] = shell; ! argstart[0] = fnbuffer; ! execve (shell, &argstart[-1], environ); ! goto fail; /* Exec didn't work */ ! } ! /* * If we succeeded, the execve() doesn't return, so we * can only be here is if the file hasn't been found yet. * Try the next place on the path. */ ! } ! /* all attempts failed to locate the file. Give up. */ ! errno = ENOENT; fail: ! free (fnbuffer); ! return -1; } + #endif /* minix */ *************** *** 362,393 **** * and also contains integers (args to 'access') that should be #define's. */ static int modes[] = ! { ! 04, /* O_RDONLY */ ! 02, /* O_WRONLY */ ! 06, /* O_RDWR */ ! 06, /* invalid but we'd better cope -- O_WRONLY+O_RDWR */ ! }; /* Shut off the automatic emulation of open(), we'll need it. */ #undef open int ! open3(path, flags, mode) ! char *path; ! int flags, mode; ! { ! int exists = 1; ! int call_creat = 0; ! int fd; ! /* * We actually do the work by calling the open() or creat() system ! * call, depending on the flags. Call_creat is true if we will use * creat(), false if we will use open(). */ ! /* ! * See if the file exists and is accessible in the requested mode. * * Strictly speaking we shouldn't be using access, since access checks * against real uid, and the open call should check against euid. --- 386,417 ---- * and also contains integers (args to 'access') that should be #define's. */ static int modes[] = ! { ! 04, /* O_RDONLY */ ! 02, /* O_WRONLY */ ! 06, /* O_RDWR */ ! 06, /* invalid but we'd better cope -- O_WRONLY+O_RDWR */ ! }; /* Shut off the automatic emulation of open(), we'll need it. */ #undef open int ! open3 (path, flags, mode) ! char *path; ! int flags, mode; ! { ! int exists = 1; ! int call_creat = 0; ! int fd; ! /* * We actually do the work by calling the open() or creat() system ! * call, depending on the flags. Call_creat is true if we will use * creat(), false if we will use open(). */ ! /* ! * See if the file exists and is accessible in the requested mode. * * Strictly speaking we shouldn't be using access, since access checks * against real uid, and the open call should check against euid. *************** *** 395,436 **** * FIXME, the construction "flags & 3" and the modes table depends * on the specific integer values of the O_XXX #define's. Foo! */ ! if (access(path,modes[flags & 3]) < 0) { ! if (errno == ENOENT) { ! /* the file does not exist */ ! exists = 0; ! } else { ! /* probably permission violation */ ! if (flags & O_EXCL) { ! /* Oops, the file exists, we didn't want it. */ ! /* No matter what the error, claim EEXIST. */ ! errno = EEXIST; ! } ! return -1; ! } } ! /* if we have the O_CREAT bit set, check for O_EXCL */ ! if (flags & O_CREAT) { ! if ((flags & O_EXCL) && exists) { ! /* Oops, the file exists and we didn't want it to. */ ! errno = EEXIST; ! return -1; ! } ! /* * If the file doesn't exist, be sure to call creat() so that * it will be created with the proper mode. */ ! if (!exists) call_creat = 1; ! } else { ! /* If O_CREAT isn't set and the file doesn't exist, error. */ ! if (!exists) { ! errno = ENOENT; ! return -1; ! } } ! /* * If the O_TRUNC flag is set and the file exists, we want to call * creat() anyway, since creat() guarantees that the file will be * truncated and open()-for-writing doesn't. --- 419,471 ---- * FIXME, the construction "flags & 3" and the modes table depends * on the specific integer values of the O_XXX #define's. Foo! */ ! if (access (path, modes[flags & 3]) < 0) ! { ! if (errno == ENOENT) ! { ! /* the file does not exist */ ! exists = 0; ! } ! else ! { ! /* probably permission violation */ ! if (flags & O_EXCL) ! { ! /* Oops, the file exists, we didn't want it. */ ! /* No matter what the error, claim EEXIST. */ ! errno = EEXIST; ! } ! return -1; } + } ! /* if we have the O_CREAT bit set, check for O_EXCL */ ! if (flags & O_CREAT) ! { ! if ((flags & O_EXCL) && exists) ! { ! /* Oops, the file exists and we didn't want it to. */ ! errno = EEXIST; ! return -1; ! } ! /* * If the file doesn't exist, be sure to call creat() so that * it will be created with the proper mode. */ ! if (!exists) ! call_creat = 1; ! } ! else ! { ! /* If O_CREAT isn't set and the file doesn't exist, error. */ ! if (!exists) ! { ! errno = ENOENT; ! return -1; } + } ! /* * If the O_TRUNC flag is set and the file exists, we want to call * creat() anyway, since creat() guarantees that the file will be * truncated and open()-for-writing doesn't. *************** *** 437,461 **** * (If the file doesn't exist, we're calling creat() anyway and the * file will be created with zero length.) */ ! if ((flags & O_TRUNC) && exists) call_creat = 1; ! /* actually do the call */ ! if (call_creat) { ! /* * call creat. May have to close and reopen the file if we * want O_RDONLY or O_RDWR access -- creat() only gives * O_WRONLY. */ ! fd = creat(path,mode); ! if (fd < 0 || (flags & O_WRONLY)) return fd; ! if (close(fd) < 0) return -1; ! /* Fall out to reopen the file we've created */ ! } ! /* * calling old open, we strip most of the new flags just in case. */ ! return open(path, flags & (O_RDONLY|O_WRONLY|O_RDWR|O_BINARY)); } #endif /* EMUL_OPEN3 */ #ifndef HAVE_MKNOD --- 472,501 ---- * (If the file doesn't exist, we're calling creat() anyway and the * file will be created with zero length.) */ ! if ((flags & O_TRUNC) && exists) ! call_creat = 1; ! /* actually do the call */ ! if (call_creat) ! { ! /* * call creat. May have to close and reopen the file if we * want O_RDONLY or O_RDWR access -- creat() only gives * O_WRONLY. */ ! fd = creat (path, mode); ! if (fd < 0 || (flags & O_WRONLY)) ! return fd; ! if (close (fd) < 0) ! return -1; ! /* Fall out to reopen the file we've created */ ! } ! /* * calling old open, we strip most of the new flags just in case. */ ! return open (path, flags & (O_RDONLY | O_WRONLY | O_RDWR | O_BINARY)); } + #endif /* EMUL_OPEN3 */ #ifndef HAVE_MKNOD *************** *** 464,530 **** #endif /* Fake mknod by complaining */ int ! mknod(path, mode, dev) ! char *path; ! unsigned short mode; ! dev_t dev; ! { ! int fd; ! ! errno = ENXIO; /* No such device or address */ ! return -1; /* Just give an error */ } /* Fake links by copying */ int ! link(path1, path2) ! char *path1; ! char *path2; ! { ! char buf[256]; ! int ifd, ofd; ! int nrbytes; ! int nwbytes; ! ! fprintf(stderr, "%s: %s: cannot link to %s, copying instead\n", ! tar, path1, path2); ! if ((ifd = open(path1, O_RDONLY|O_BINARY)) < 0) ! return -1; ! if ((ofd = creat(path2, 0666)) < 0) ! return -1; ! setmode(ofd, O_BINARY); ! while ((nrbytes = read(ifd, buf, sizeof(buf))) > 0) { ! if ((nwbytes = write(ofd, buf, nrbytes)) != nrbytes) { ! nrbytes = -1; ! break; ! } } ! /* Note use of "|" rather than "||" below: we want to close * the files even if an error occurs. */ ! if ((nrbytes < 0) | (0 != close(ifd)) | (0 != close(ofd))) { ! unlink(path2); ! return -1; ! } ! return 0; } /* everyone owns everything on MS-DOS (or is it no one owns anything?) */ int ! chown(path, uid, gid) ! char *path; ! int uid; ! int gid; { ! return 0; } int ! geteuid() { ! return 0; } ! #endif /* !HAVE_MKNOD */ #ifdef __TURBOC__ #include --- 504,574 ---- #endif /* Fake mknod by complaining */ int ! mknod (path, mode, dev) ! char *path; ! unsigned short mode; ! dev_t dev; ! { ! int fd; ! ! errno = ENXIO; /* No such device or address */ ! return -1; /* Just give an error */ } /* Fake links by copying */ int ! link (path1, path2) ! char *path1; ! char *path2; ! { ! char buf[256]; ! int ifd, ofd; ! int nrbytes; ! int nwbytes; ! ! fprintf (stderr, "%s: %s: cannot link to %s, copying instead\n", ! tar, path1, path2); ! if ((ifd = open (path1, O_RDONLY | O_BINARY)) < 0) ! return -1; ! if ((ofd = creat (path2, 0666)) < 0) ! return -1; ! setmode (ofd, O_BINARY); ! while ((nrbytes = read (ifd, buf, sizeof (buf))) > 0) ! { ! if ((nwbytes = write (ofd, buf, nrbytes)) != nrbytes) ! { ! nrbytes = -1; ! break; } ! } ! /* Note use of "|" rather than "||" below: we want to close * the files even if an error occurs. */ ! if ((nrbytes < 0) | (0 != close (ifd)) | (0 != close (ofd))) ! { ! unlink (path2); ! return -1; ! } ! return 0; } /* everyone owns everything on MS-DOS (or is it no one owns anything?) */ int ! chown (path, uid, gid) ! char *path; ! int uid; ! int gid; { ! return 0; } int ! geteuid () { ! return 0; } ! ! #endif /* !HAVE_MKNOD */ #ifdef __TURBOC__ #include *************** *** 533,540 **** struct utimbuf { ! time_t actime; /* Access time. */ ! time_t modtime; /* Modification time. */ }; int --- 577,584 ---- struct utimbuf { ! time_t actime; /* Access time. */ ! time_t modtime; /* Modification time. */ }; int *************** *** 573,578 **** --- 617,623 ---- _close (fd); return status; } + #endif /* __TURBOC__ */ /* Stash argv[0] here so panic will know what the program is called */ *************** *** 579,631 **** char *myname = 0; void ! panic(s) ! char *s; { ! if(myname) ! fprintf(stderr,"%s:",myname); ! fprintf(stderr,s); ! putc('\n',stderr); ! exit(12); } PTR ! ck_malloc(size) ! size_t size; { ! PTR ret; ! if(!size) ! size++; ! ret=malloc(size); ! if(ret==0) ! panic("Couldn't allocate memory"); ! return ret; } /* Used by alloca.c and bison.simple. */ char * ! xmalloc(size) ! size_t size; { ! return (char *) ck_malloc(size); } PTR ! ck_realloc(ptr,size) ! PTR ptr; ! size_t size; ! { ! PTR ret; ! ! if(!ptr) ! ret=ck_malloc(size); ! else ! ret=realloc(ptr,size); ! if(ret==0) ! panic("Couldn't re-allocate memory"); ! return ret; } /* Implement a variable sized buffer of 'stuff'. We don't know what it is, --- 624,676 ---- char *myname = 0; void ! panic (s) ! char *s; { ! if (myname) ! fprintf (stderr, "%s:", myname); ! fprintf (stderr, s); ! putc ('\n', stderr); ! exit (12); } PTR ! ck_malloc (size) ! size_t size; { ! PTR ret; ! if (!size) ! size++; ! ret = malloc (size); ! if (ret == 0) ! panic ("Couldn't allocate memory"); ! return ret; } /* Used by alloca.c and bison.simple. */ char * ! xmalloc (size) ! size_t size; { ! return (char *) ck_malloc (size); } PTR ! ck_realloc (ptr, size) ! PTR ptr; ! size_t size; ! { ! PTR ret; ! ! if (!ptr) ! ret = ck_malloc (size); ! else ! ret = realloc (ptr, size); ! if (ret == 0) ! panic ("Couldn't re-allocate memory"); ! return ret; } /* Implement a variable sized buffer of 'stuff'. We don't know what it is, *************** *** 632,765 **** nor do we care, as long as it doesn't mind being aligned on a char boundry. */ ! struct buffer { ! int allocated; ! int length; ! char *b; ! }; #define MIN_ALLOCATE 50 char * ! init_buffer() { ! struct buffer *b; ! b=(struct buffer *)ck_malloc(sizeof(struct buffer)); ! b->allocated=MIN_ALLOCATE; ! b->b=(char *)ck_malloc(MIN_ALLOCATE); ! b->length=0; ! return (char *)b; } void ! flush_buffer(bb) ! char *bb; { ! struct buffer *b; ! b=(struct buffer *)bb; ! free(b->b); ! b->b=0; ! b->allocated=0; ! b->length=0; ! free((void *)b); } void ! add_buffer(bb,p,n) ! char *bb; ! char *p; ! int n; ! { ! struct buffer *b; ! ! b=(struct buffer *)bb; ! if(b->length+n>b->allocated) { ! b->allocated=b->length+n+MIN_ALLOCATE; ! b->b=(char *)ck_realloc(b->b,b->allocated); ! } ! bcopy(p,b->b+b->length,n); ! b->length+=n; } char * ! get_buffer(bb) ! char *bb; { ! struct buffer *b; ! b=(struct buffer *)bb; ! return b->b; } char * ! merge_sort(list,n,off,cmp) ! char *list; ! int (*cmp)(); ! unsigned n; ! int off; ! { ! char *ret; ! ! char *alist,*blist; ! unsigned alength,blength; ! ! char *tptr; ! int tmp; ! char **prev; #define NEXTOF(ptr) (* ((char **)(((char *)(ptr))+off) ) ) ! if(n==1) ! return list; ! if(n==2) { ! if((*cmp)(list,NEXTOF(list))>0) { ! ret=NEXTOF(list); ! NEXTOF(ret)=list; ! NEXTOF(list)=0; ! return ret; ! } ! return list; } ! alist=list; ! alength=(n+1)/2; ! blength=n/2; ! for(tptr=list,tmp=(n-1)/2;tmp;tptr=NEXTOF(tptr),tmp--) ! ; ! blist=NEXTOF(tptr); ! NEXTOF(tptr)=0; ! ! alist=merge_sort(alist,alength,off,cmp); ! blist=merge_sort(blist,blength,off,cmp); ! prev = &ret; ! for(;alist && blist;) { ! if((*cmp)(alist,blist)<0) { ! tptr=NEXTOF(alist); ! *prev = alist; ! prev = &(NEXTOF(alist)); ! alist=tptr; ! } else { ! tptr=NEXTOF(blist); ! *prev = blist; ! prev = &(NEXTOF(blist)); ! blist=tptr; ! } } ! if(alist) ! *prev = alist; ! else ! *prev = blist; ! return ret; } void ! ck_close(fd) ! int fd; { ! if(close(fd)<0) { ! msg_perror("can't close a file #%d",fd); ! exit(EX_SYSTEM); ! } } #include --- 677,819 ---- nor do we care, as long as it doesn't mind being aligned on a char boundry. */ ! struct buffer ! { ! int allocated; ! int length; ! char *b; ! }; #define MIN_ALLOCATE 50 char * ! init_buffer () { ! struct buffer *b; ! b = (struct buffer *) ck_malloc (sizeof (struct buffer)); ! b->allocated = MIN_ALLOCATE; ! b->b = (char *) ck_malloc (MIN_ALLOCATE); ! b->length = 0; ! return (char *) b; } void ! flush_buffer (bb) ! char *bb; { ! struct buffer *b; ! b = (struct buffer *) bb; ! free (b->b); ! b->b = 0; ! b->allocated = 0; ! b->length = 0; ! free ((void *) b); } void ! add_buffer (bb, p, n) ! char *bb; ! char *p; ! int n; ! { ! struct buffer *b; ! ! b = (struct buffer *) bb; ! if (b->length + n > b->allocated) ! { ! b->allocated = b->length + n + MIN_ALLOCATE; ! b->b = (char *) ck_realloc (b->b, b->allocated); ! } ! bcopy (p, b->b + b->length, n); ! b->length += n; } char * ! get_buffer (bb) ! char *bb; { ! struct buffer *b; ! b = (struct buffer *) bb; ! return b->b; } char * ! merge_sort (list, n, off, cmp) ! char *list; ! int (*cmp) (); ! unsigned n; ! int off; ! { ! char *ret; ! ! char *alist, *blist; ! unsigned alength, blength; ! ! char *tptr; ! int tmp; ! char **prev; #define NEXTOF(ptr) (* ((char **)(((char *)(ptr))+off) ) ) ! if (n == 1) ! return list; ! if (n == 2) ! { ! if ((*cmp) (list, NEXTOF (list)) > 0) ! { ! ret = NEXTOF (list); ! NEXTOF (ret) = list; ! NEXTOF (list) = 0; ! return ret; ! } ! return list; ! } ! alist = list; ! alength = (n + 1) / 2; ! blength = n / 2; ! for (tptr = list, tmp = (n - 1) / 2; tmp; tptr = NEXTOF (tptr), tmp--) ! ; ! blist = NEXTOF (tptr); ! NEXTOF (tptr) = 0; ! ! alist = merge_sort (alist, alength, off, cmp); ! blist = merge_sort (blist, blength, off, cmp); ! prev = &ret; ! for (; alist && blist;) ! { ! if ((*cmp) (alist, blist) < 0) ! { ! tptr = NEXTOF (alist); ! *prev = alist; ! prev = &(NEXTOF (alist)); ! alist = tptr; } ! else ! { ! tptr = NEXTOF (blist); ! *prev = blist; ! prev = &(NEXTOF (blist)); ! blist = tptr; } ! } ! if (alist) ! *prev = alist; ! else ! *prev = blist; ! return ret; } void ! ck_close (fd) ! int fd; { ! if (close (fd) < 0) ! { ! msg_perror ("can't close a file #%d", fd); ! exit (EX_SYSTEM); ! } } #include *************** *** 771,837 **** caller is done with it. */ char * ! quote_copy_string(string) ! char *string; { ! char *from_here; ! char *to_there = 0; ! char *copy_buf = 0; ! int c; ! int copying = 0; ! ! from_here=string; ! while(*from_here) { ! c= *from_here++; ! if(c=='\\') { ! if(!copying) { ! int n; ! ! n=(from_here-string)-1; ! copying++; ! copy_buf=(char *)malloc(n+5+strlen(from_here)*4); ! if(!copy_buf) ! return 0; ! bcopy(string,copy_buf,n); ! to_there=copy_buf+n; ! } ! *to_there++='\\'; ! *to_there++='\\'; ! } else if(isprint(c)) { ! if(copying) ! *to_there++= c; ! } else { ! if(!copying) { ! int n; ! ! n=(from_here-string)-1; ! copying++; ! copy_buf=(char *)malloc(n+5+strlen(from_here)*4); ! if(!copy_buf) ! return 0; ! bcopy(string,copy_buf,n); ! to_there=copy_buf+n; ! } ! *to_there++='\\'; ! if(c=='\n') *to_there++='n'; ! else if(c=='\t') *to_there++='t'; ! else if(c=='\f') *to_there++='f'; ! else if(c=='\b') *to_there++='b'; ! else if(c=='\r') *to_there++='r'; ! else if(c=='\177') *to_there++='?'; ! else { ! to_there[0]=(c>>6)+'0'; ! to_there[1]=((c>>3)&07)+'0'; ! to_there[2]=(c&07)+'0'; ! to_there+=3; ! } ! } } ! if(copying) { ! *to_there='\0'; ! return copy_buf; } ! return (char *)0; } --- 825,907 ---- caller is done with it. */ char * ! quote_copy_string (string) ! char *string; { ! char *from_here; ! char *to_there = 0; ! char *copy_buf = 0; ! int c; ! int copying = 0; ! ! from_here = string; ! while (*from_here) ! { ! c = *from_here++; ! if (c == '\\') ! { ! if (!copying) ! { ! int n; ! ! n = (from_here - string) - 1; ! copying++; ! copy_buf = (char *) malloc (n + 5 + strlen (from_here) * 4); ! if (!copy_buf) ! return 0; ! bcopy (string, copy_buf, n); ! to_there = copy_buf + n; ! } ! *to_there++ = '\\'; ! *to_there++ = '\\'; ! } ! else if (isprint (c)) ! { ! if (copying) ! *to_there++ = c; } ! else ! { ! if (!copying) ! { ! int n; ! ! n = (from_here - string) - 1; ! copying++; ! copy_buf = (char *) malloc (n + 5 + strlen (from_here) * 4); ! if (!copy_buf) ! return 0; ! bcopy (string, copy_buf, n); ! to_there = copy_buf + n; ! } ! *to_there++ = '\\'; ! if (c == '\n') ! *to_there++ = 'n'; ! else if (c == '\t') ! *to_there++ = 't'; ! else if (c == '\f') ! *to_there++ = 'f'; ! else if (c == '\b') ! *to_there++ = 'b'; ! else if (c == '\r') ! *to_there++ = 'r'; ! else if (c == '\177') ! *to_there++ = '?'; ! else ! { ! to_there[0] = (c >> 6) + '0'; ! to_there[1] = ((c >> 3) & 07) + '0'; ! to_there[2] = (c & 07) + '0'; ! to_there += 3; ! } } ! } ! if (copying) ! { ! *to_there = '\0'; ! return copy_buf; ! } ! return (char *) 0; } *************** *** 843,941 **** /* There is no un-quote-copy-string. Write it yourself */ char * ! un_quote_string(string) ! char *string; { ! char *ret; ! char *from_here; ! char *to_there; ! int tmp; ! ! ret=string; ! to_there=string; ! from_here=string; ! while(*from_here) { ! if(*from_here!='\\') { ! if(from_here!=to_there) ! *to_there++= *from_here++; ! else ! from_here++,to_there++; ! continue; ! } ! switch(*++from_here) { ! case '\\': ! *to_there++= *from_here++; ! break; ! case 'n': ! *to_there++= '\n'; ! from_here++; ! break; ! case 't': ! *to_there++= '\t'; ! from_here++; ! break; ! case 'f': ! *to_there++= '\f'; ! from_here++; ! break; ! case 'b': ! *to_there++= '\b'; ! from_here++; ! break; ! case 'r': ! *to_there++= '\r'; ! from_here++; ! break; ! case '?': ! *to_there++= 0177; ! from_here++; ! break; ! case '0': ! case '1': ! case '2': ! case '3': ! case '4': ! case '5': ! case '6': ! case '7': ! tmp= *from_here - '0'; ! from_here++; ! if(*from_here<'0' || *from_here>'7') { ! *to_there++= tmp; ! break; ! } ! tmp= tmp*8 + *from_here-'0'; ! from_here++; ! if(*from_here<'0' || *from_here>'7') { ! *to_there++= tmp; ! break; ! } ! tmp=tmp*8 + *from_here-'0'; ! from_here++; ! *to_there=tmp; ! break; ! default: ! ret=0; ! *to_there++='\\'; ! *to_there++= *from_here++; ! break; ! } } ! if(*to_there) ! *to_there++='\0'; ! return ret; } ! void ck_pipe(pipes) ! int *pipes; { ! if(pipe(pipes)<0) { ! msg_perror("can't open a pipe"); ! exit(EX_SYSTEM); ! } } - #ifndef HAVE_STRSTR /* * strstr - find first occurrence of wanted in s --- 913,1019 ---- /* There is no un-quote-copy-string. Write it yourself */ char * ! un_quote_string (string) ! char *string; { ! char *ret; ! char *from_here; ! char *to_there; ! int tmp; ! ! ret = string; ! to_there = string; ! from_here = string; ! while (*from_here) ! { ! if (*from_here != '\\') ! { ! if (from_here != to_there) ! *to_there++ = *from_here++; ! else ! from_here++, to_there++; ! continue; ! } ! switch (*++from_here) ! { ! case '\\': ! *to_there++ = *from_here++; ! break; ! case 'n': ! *to_there++ = '\n'; ! from_here++; ! break; ! case 't': ! *to_there++ = '\t'; ! from_here++; ! break; ! case 'f': ! *to_there++ = '\f'; ! from_here++; ! break; ! case 'b': ! *to_there++ = '\b'; ! from_here++; ! break; ! case 'r': ! *to_there++ = '\r'; ! from_here++; ! break; ! case '?': ! *to_there++ = 0177; ! from_here++; ! break; ! case '0': ! case '1': ! case '2': ! case '3': ! case '4': ! case '5': ! case '6': ! case '7': ! tmp = *from_here - '0'; ! from_here++; ! if (*from_here < '0' || *from_here > '7') ! { ! *to_there++ = tmp; ! break; ! } ! tmp = tmp * 8 + *from_here - '0'; ! from_here++; ! if (*from_here < '0' || *from_here > '7') ! { ! *to_there++ = tmp; ! break; ! } ! tmp = tmp * 8 + *from_here - '0'; ! from_here++; ! *to_there = tmp; ! break; ! default: ! ret = 0; ! *to_there++ = '\\'; ! *to_there++ = *from_here++; ! break; } ! } ! if (*to_there) ! *to_there++ = '\0'; ! return ret; } ! #ifndef __MSDOS__ ! void ! ck_pipe (pipes) ! int *pipes; { ! if (pipe (pipes) < 0) ! { ! msg_perror ("can't open a pipe"); ! exit (EX_SYSTEM); ! } } + #endif /* !__MSDOS__ */ #ifndef HAVE_STRSTR /* * strstr - find first occurrence of wanted in s *************** *** 942,969 **** */ char * /* found string, or NULL if none */ ! strstr(s, wanted) ! char *s; ! char *wanted; ! { ! register char *scan; ! register size_t len; ! register char firstc; ! ! if (*wanted == '\0') ! return (char *)0; ! /* * The odd placement of the two tests is so "" is findable. * Also, we inline the first char for speed. * The ++ on scan has been moved down for optimization. */ ! firstc = *wanted; ! len = strlen(wanted); ! for (scan = s; *scan != firstc || strncmp(scan, wanted, len) != 0; ) ! if (*scan++ == '\0') ! return (char *)0; ! return scan; } #endif /* !HAVE_STRSTR */ #ifndef HAVE_FTRUNCATE --- 1020,1048 ---- */ char * /* found string, or NULL if none */ ! strstr (s, wanted) ! char *s; ! char *wanted; ! { ! register char *scan; ! register size_t len; ! register char firstc; ! ! if (*wanted == '\0') ! return (char *) 0; ! /* * The odd placement of the two tests is so "" is findable. * Also, we inline the first char for speed. * The ++ on scan has been moved down for optimization. */ ! firstc = *wanted; ! len = strlen (wanted); ! for (scan = s; *scan != firstc || strncmp (scan, wanted, len) != 0;) ! if (*scan++ == '\0') ! return (char *) 0; ! return scan; } + #endif /* !HAVE_STRSTR */ #ifndef HAVE_FTRUNCATE *************** *** 976,998 **** { return fcntl (fd, F_CHSIZE, length); } #else /* !F_CHSIZE */ #ifdef F_FREESP /* code courtesy of William Kucharski, kucharsk@Solbourne.com */ int ! ftruncate(fd, length) ! int fd; /* file descriptor */ ! off_t length; /* length to set file to */ ! { ! struct flock fl; ! ! fl.l_whence = 0; ! fl.l_len = 0; ! fl.l_start = length; ! fl.l_type = F_WRLCK; /* write lock on file space */ ! /* * This relies on the UNDOCUMENTED F_FREESP argument to * fcntl(2), which truncates the file so that it ends at the * position indicated by fl.l_start. --- 1055,1078 ---- { return fcntl (fd, F_CHSIZE, length); } + #else /* !F_CHSIZE */ #ifdef F_FREESP /* code courtesy of William Kucharski, kucharsk@Solbourne.com */ int ! ftruncate (fd, length) ! int fd; /* file descriptor */ ! off_t length; /* length to set file to */ ! { ! struct flock fl; ! fl.l_whence = 0; ! fl.l_len = 0; ! fl.l_start = length; ! fl.l_type = F_WRLCK; /* write lock on file space */ ! ! /* * This relies on the UNDOCUMENTED F_FREESP argument to * fcntl(2), which truncates the file so that it ends at the * position indicated by fl.l_start. *************** *** 1000,1021 **** * Will minor miracles never cease? */ ! if (fcntl(fd, F_FREESP, &fl) < 0) ! return -1; ! return 0; } #else /* !F_FREESP */ int ! ftruncate(fd, length) ! int fd; ! off_t length; { ! errno = EIO; ! return -1; } #endif /* !F_FREESP */ #endif /* !F_CHSIZE */ #endif /* !HAVE_FTRUNCATE */ --- 1080,1102 ---- * Will minor miracles never cease? */ ! if (fcntl (fd, F_FREESP, &fl) < 0) ! return -1; ! return 0; } #else /* !F_FREESP */ int ! ftruncate (fd, length) ! int fd; ! off_t length; { ! errno = EIO; ! return -1; } + #endif /* !F_FREESP */ #endif /* !F_CHSIZE */ #endif /* !HAVE_FTRUNCATE */ *************** *** 1027,1169 **** #include void ! msg(char *str,...) { ! va_list args; ! va_start(args,str); ! fflush(msg_file); ! fprintf(stderr,"%s: ",tar); ! if(f_sayblock) ! fprintf(stderr,"rec %d: ",baserec + (ar_record - ar_block)); ! vfprintf(stderr,str,args); ! va_end(args); ! putc('\n',stderr); ! fflush(stderr); } void ! msg_perror(char *str,...) { ! va_list args; ! int save_e; ! save_e=errno; ! fflush(msg_file); ! fprintf(stderr,"%s: ",tar); ! if(f_sayblock) ! fprintf(stderr,"rec %d: ",baserec + (ar_record - ar_block)); ! va_start(args,str); ! vfprintf(stderr,str,args); ! va_end(args); ! errno=save_e; ! perror(" "); ! fflush(stderr); } #endif /* HAVE_VPRINTF and __STDC__ */ #if defined(HAVE_VPRINTF) && !__STDC__ #include void ! msg(str,va_alist) ! char *str; ! va_dcl ! { ! va_list args; ! ! fflush(msg_file); ! fprintf(stderr,"%s: ",tar); ! if(f_sayblock) ! fprintf(stderr,"rec %d: ",baserec + (ar_record - ar_block)); ! va_start(args); ! vfprintf(stderr,str,args); ! va_end(args); ! putc('\n',stderr); ! fflush(stderr); } void ! msg_perror(str,va_alist) ! char *str; ! va_dcl ! { ! va_list args; ! int save_e; ! ! save_e=errno; ! fflush(msg_file); ! fprintf(stderr,"%s: ",tar); ! if(f_sayblock) ! fprintf(stderr,"rec %d: ",baserec + (ar_record - ar_block)); ! va_start(args); ! vfprintf(stderr,str,args); ! va_end(args); ! errno=save_e; ! perror(" "); ! fflush(stderr); } #endif /* HAVE_VPRINTF and not __STDC__ */ #if !defined(HAVE_VPRINTF) && defined(HAVE_DOPRNT) void ! msg(str,args) ! char *str; ! int args; ! { ! fflush(msg_file); ! fprintf(stderr,"%s: ",tar); ! if(f_sayblock) ! fprintf(stderr,"rec %d: ",baserec + (ar_record - ar_block)); ! _doprnt(str, &args, stderr); ! putc('\n',stderr); ! fflush(stderr); } void ! msg_perror(str,args) ! char *str; ! { ! int save_e; ! ! save_e=errno; ! fflush(msg_file); ! fprintf(stderr,"%s: ",tar); ! if(f_sayblock) ! fprintf(stderr,"rec %d: ",baserec + (ar_record - ar_block)); ! _doprnt(str, &args, stderr); ! errno=save_e; ! perror(" "); ! fflush(stderr); } #endif /* !HAVE_VPRINTF and HAVE_DOPRNT */ #if !defined(HAVE_VPRINTF) && !defined(HAVE_DOPRNT) ! void msg(str,a1,a2,a3,a4,a5,a6) ! char *str; ! { ! fflush(msg_file); ! fprintf(stderr,"%s: ",tar); ! if(f_sayblock) ! fprintf(stderr,"rec %d: ",baserec + (ar_record - ar_block)); ! fprintf(stderr,str,a1,a2,a3,a4,a5,a6); ! putc('\n',stderr); ! fflush(stderr); } void ! msg_perror(str,a1,a2,a3,a4,a5,a6) ! char *str; { ! int save_e; ! save_e=errno; ! fflush(msg_file); ! fprintf(stderr,"%s: ",tar); ! if(f_sayblock) ! fprintf(stderr,"rec %d: ",baserec + (ar_record - ar_block)); ! fprintf(stderr,str,a1,a2,a3,a4,a5,a6); ! fprintf(stderr,": "); ! errno=save_e; ! perror(" "); } #endif /* !HAVE_VPRINTF and !HAVE_DOPRNT */ --- 1108,1256 ---- #include void ! msg (char *str,...) { ! va_list args; ! va_start (args, str); ! fflush (msg_file); ! fprintf (stderr, "%s: ", tar); ! if (f_sayblock) ! fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block)); ! vfprintf (stderr, str, args); ! va_end (args); ! putc ('\n', stderr); ! fflush (stderr); } void ! msg_perror (char *str,...) { ! va_list args; ! int save_e; ! save_e = errno; ! fflush (msg_file); ! fprintf (stderr, "%s: ", tar); ! if (f_sayblock) ! fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block)); ! va_start (args, str); ! vfprintf (stderr, str, args); ! va_end (args); ! errno = save_e; ! perror (" "); ! fflush (stderr); } + #endif /* HAVE_VPRINTF and __STDC__ */ #if defined(HAVE_VPRINTF) && !__STDC__ #include void ! msg (str, va_alist) ! char *str; ! va_dcl ! { ! va_list args; ! ! fflush (msg_file); ! fprintf (stderr, "%s: ", tar); ! if (f_sayblock) ! fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block)); ! va_start (args); ! vfprintf (stderr, str, args); ! va_end (args); ! putc ('\n', stderr); ! fflush (stderr); } void ! msg_perror (str, va_alist) ! char *str; ! va_dcl ! { ! va_list args; ! int save_e; ! ! save_e = errno; ! fflush (msg_file); ! fprintf (stderr, "%s: ", tar); ! if (f_sayblock) ! fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block)); ! va_start (args); ! vfprintf (stderr, str, args); ! va_end (args); ! errno = save_e; ! perror (" "); ! fflush (stderr); } + #endif /* HAVE_VPRINTF and not __STDC__ */ #if !defined(HAVE_VPRINTF) && defined(HAVE_DOPRNT) void ! msg (str, args) ! char *str; ! int args; ! { ! fflush (msg_file); ! fprintf (stderr, "%s: ", tar); ! if (f_sayblock) ! fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block)); ! _doprnt (str, &args, stderr); ! putc ('\n', stderr); ! fflush (stderr); } void ! msg_perror (str, args) ! char *str; ! int args; ! { ! int save_e; ! ! save_e = errno; ! fflush (msg_file); ! fprintf (stderr, "%s: ", tar); ! if (f_sayblock) ! fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block)); ! _doprnt (str, &args, stderr); ! errno = save_e; ! perror (" "); ! fflush (stderr); } + #endif /* !HAVE_VPRINTF and HAVE_DOPRNT */ #if !defined(HAVE_VPRINTF) && !defined(HAVE_DOPRNT) ! void ! msg (str, a1, a2, a3, a4, a5, a6) ! char *str; ! { ! fflush (msg_file); ! fprintf (stderr, "%s: ", tar); ! if (f_sayblock) ! fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block)); ! fprintf (stderr, str, a1, a2, a3, a4, a5, a6); ! putc ('\n', stderr); ! fflush (stderr); } void ! msg_perror (str, a1, a2, a3, a4, a5, a6) ! char *str; { ! int save_e; ! save_e = errno; ! fflush (msg_file); ! fprintf (stderr, "%s: ", tar); ! if (f_sayblock) ! fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block)); ! fprintf (stderr, str, a1, a2, a3, a4, a5, a6); ! fprintf (stderr, ": "); ! errno = save_e; ! perror (" "); } + #endif /* !HAVE_VPRINTF and !HAVE_DOPRNT */ diff -c3 tar-1.11.1/port.h tar-1.11.2/port.h *** tar-1.11.1/port.h Tue Sep 15 19:59:51 1992 --- tar-1.11.2/port.h Tue Nov 24 08:52:28 1992 *************** *** 62,68 **** #define major(dev) (dev) #define minor(dev) (dev) typedef long off_t; ! #endif /* __MSDOS__ */ #if defined(__STDC__) || defined(__TURBOC__) #define PTR void * --- 62,68 ---- #define major(dev) (dev) #define minor(dev) (dev) typedef long off_t; ! #endif /* __MSDOS__ */ #if defined(__STDC__) || defined(__TURBOC__) #define PTR void * *************** *** 93,99 **** #endif #undef HAVE_MAJOR ! #if defined(STDC_HEADERS) || defined(USG) #include #if !defined(__MSDOS__) && !defined(STDC_HEADERS) #include --- 93,99 ---- #endif #undef HAVE_MAJOR ! #if defined(STDC_HEADERS) || defined(HAVE_STRING_H) #include #if !defined(__MSDOS__) && !defined(STDC_HEADERS) #include *************** *** 116,132 **** #if defined(STDC_HEADERS) #include #else ! char *malloc(), *realloc(); ! char *getenv(); #endif #ifndef _POSIX_VERSION #ifdef __MSDOS__ #include ! #else /* !__MSDOS__ */ ! off_t lseek(); ! #endif /* !__MSDOS__ */ ! char *getcwd(); #endif /* !_POSIX_VERSION */ #ifndef NULL --- 116,132 ---- #if defined(STDC_HEADERS) #include #else ! char *malloc (), *realloc (); ! char *getenv (); #endif #ifndef _POSIX_VERSION #ifdef __MSDOS__ #include ! #else /* !__MSDOS__ */ ! off_t lseek (); ! #endif /* !__MSDOS__ */ ! char *getcwd (); #endif /* !_POSIX_VERSION */ #ifndef NULL *************** *** 175,190 **** #if !defined(S_ISSOCK) && defined(S_IFSOCK) #define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) #endif ! #if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */ #define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB) #define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC) #endif ! #if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */ #define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK) #endif ! #if !defined(S_ISCTG) && defined(S_IFCTG) /* contiguous file */ #define S_ISCTG(m) (((m) & S_IFMT) == S_IFCTG) #endif #if !defined(S_ISVTX) #define S_ISVTX 0001000 #endif --- 175,215 ---- #if !defined(S_ISSOCK) && defined(S_IFSOCK) #define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) #endif ! #if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */ #define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB) #define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC) #endif ! #if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */ #define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK) #endif ! #if !defined(S_ISCTG) && defined(S_IFCTG) /* contiguous file */ #define S_ISCTG(m) (((m) & S_IFMT) == S_IFCTG) #endif #if !defined(S_ISVTX) #define S_ISVTX 0001000 #endif + + #ifdef __MSDOS__ + #include "msd_dir.h" + #define NLENGTH(direct) ((direct)->d_namlen) + + #else /* not __MSDOS__ */ + + #if defined(DIRENT) || defined(_POSIX_VERSION) + #include + #define NLENGTH(direct) (strlen((direct)->d_name)) + #else /* not (DIRENT or _POSIX_VERSION) */ + #define dirent direct + #define NLENGTH(direct) ((direct)->d_namlen) + #ifdef SYSNDIR + #include + #endif /* SYSNDIR */ + #ifdef SYSDIR + #include + #endif /* SYSDIR */ + #ifdef NDIR + #include + #endif /* NDIR */ + #endif /* DIRENT or _POSIX_VERSION */ + + #endif /* not __MSDOS__ */ diff -c3 tar-1.11.1/regex.c tar-1.11.2/regex.c *** tar-1.11.1/regex.c Fri Sep 11 00:57:41 1992 --- tar-1.11.2/regex.c Tue Mar 9 12:03:08 1993 *************** *** 1,9 **** /* Extended regular expression matching and search library, ! version 0.10. (Implements POSIX draft P10003.2/D11.2, except for internationalization features.) ! Copyright (C) 1985, 89, 90, 91, 92 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by --- 1,9 ---- /* Extended regular expression matching and search library, ! version 0.11. (Implements POSIX draft P10003.2/D11.2, except for internationalization features.) ! Copyright (C) 1993 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by *************** *** 29,39 **** /* We need this for `regex.h', and perhaps for the Emacs include files. */ #include /* The `emacs' switch turns on certain matching commands that make sense only in Emacs. */ #ifdef emacs - #include "config.h" #include "lisp.h" #include "buffer.h" #include "syntax.h" --- 29,42 ---- /* We need this for `regex.h', and perhaps for the Emacs include files. */ #include + #ifdef HAVE_CONFIG_H + #include "config.h" + #endif + /* The `emacs' switch turns on certain matching commands that make sense only in Emacs. */ #ifdef emacs #include "lisp.h" #include "buffer.h" #include "syntax.h" *************** *** 45,55 **** /* We used to test for `BSTRING' here, but only GCC and Emacs define `BSTRING', as far as I know, and neither of them use this code. */ ! #if USG || STDC_HEADERS #include #define bcmp(s1, s2, n) memcmp ((s1), (s2), (n)) #define bcopy(s, d, n) memcpy ((d), (s), (n)) #define bzero(s, n) memset ((s), 0, (n)) #else #include #endif --- 48,64 ---- /* We used to test for `BSTRING' here, but only GCC and Emacs define `BSTRING', as far as I know, and neither of them use this code. */ ! #if HAVE_STRING_H || STDC_HEADERS #include + #ifndef bcmp #define bcmp(s1, s2, n) memcmp ((s1), (s2), (n)) + #endif + #ifndef bcopy #define bcopy(s, d, n) memcpy ((d), (s), (n)) + #endif + #ifndef bzero #define bzero(s, n) memset ((s), 0, (n)) + #endif #else #include #endif *************** *** 115,130 **** /* Get the interface, including the syntax bits. */ #include "regex.h" - /* isalpha etc. are used for the character classes. */ #include ! #ifndef isgraph ! #define isgraph(c) (isprint (c) && !isspace (c)) #endif ! #ifndef isblank ! #define isblank(c) ((c) == ' ' || (c) == '\t') #endif #ifndef NULL #define NULL 0 #endif --- 124,158 ---- /* Get the interface, including the syntax bits. */ #include "regex.h" /* isalpha etc. are used for the character classes. */ #include ! ! #ifndef isascii ! #define isascii(c) 1 ! #endif ! ! #ifdef isblank ! #define ISBLANK(c) (isascii (c) && isblank (c)) ! #else ! #define ISBLANK(c) ((c) == ' ' || (c) == '\t') #endif ! #ifdef isgraph ! #define ISGRAPH(c) (isascii (c) && isgraph (c)) ! #else ! #define ISGRAPH(c) (isascii (c) && isprint (c) && !isspace (c)) #endif + #define ISPRINT(c) (isascii (c) && isprint (c)) + #define ISDIGIT(c) (isascii (c) && isdigit (c)) + #define ISALNUM(c) (isascii (c) && isalnum (c)) + #define ISALPHA(c) (isascii (c) && isalpha (c)) + #define ISCNTRL(c) (isascii (c) && iscntrl (c)) + #define ISLOWER(c) (isascii (c) && islower (c)) + #define ISPUNCT(c) (isascii (c) && ispunct (c)) + #define ISSPACE(c) (isascii (c) && isspace (c)) + #define ISUPPER(c) (isascii (c) && isupper (c)) + #define ISXDIGIT(c) (isascii (c) && isxdigit (c)) + #ifndef NULL #define NULL 0 #endif *************** *** 136,142 **** #undef SIGN_EXTEND_CHAR #if __STDC__ #define SIGN_EXTEND_CHAR(c) ((signed char) (c)) ! #else /* As in Harbison and Steele. */ #define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128) #endif --- 164,170 ---- #undef SIGN_EXTEND_CHAR #if __STDC__ #define SIGN_EXTEND_CHAR(c) ((signed char) (c)) ! #else /* not __STDC__ */ /* As in Harbison and Steele. */ #define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128) #endif *************** *** 443,448 **** --- 471,477 ---- #define DEBUG_PRINT1(x) if (debug) printf (x) #define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2) #define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3) + #define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4) #define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \ if (debug) print_partial_compiled_pattern (s, e) #define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \ *************** *** 756,761 **** --- 785,791 ---- #define DEBUG_PRINT1(x) #define DEBUG_PRINT2(x1, x2) #define DEBUG_PRINT3(x1, x2, x3) + #define DEBUG_PRINT4(x1, x2, x3, x4) #define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) #define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) *************** *** 811,817 **** static void store_op1 (), store_op2 (); static void insert_op1 (), insert_op2 (); ! static boolean at_endline_op_p (), group_in_compile_stack (); static reg_errcode_t compile_range (); /* Fetch the next character in the uncompiled pattern---translating it --- 841,848 ---- static void store_op1 (), store_op2 (); static void insert_op1 (), insert_op2 (); ! static boolean at_begline_loc_p (), at_endline_loc_p (); ! static boolean group_in_compile_stack (); static reg_errcode_t compile_range (); /* Fetch the next character in the uncompiled pattern---translating it *************** *** 977,984 **** /* Set the bit for character C in a list. */ ! #define SET_LIST_BIT(c) \ ! (b[((unsigned char) (c)) / BYTEWIDTH] \ |= 1 << (((unsigned char) c) % BYTEWIDTH)) --- 1008,1015 ---- /* Set the bit for character C in a list. */ ! #define SET_LIST_BIT(c) \ ! (b[((unsigned char) (c)) / BYTEWIDTH] \ |= 1 << (((unsigned char) c) % BYTEWIDTH)) *************** *** 987,993 **** { if (p != pend) \ { \ PATFETCH (c); \ ! while (isdigit (c)) \ { \ if (num < 0) \ num = 0; \ --- 1018,1024 ---- { if (p != pend) \ { \ PATFETCH (c); \ ! while (ISDIGIT (c)) \ { \ if (num < 0) \ num = 0; \ *************** *** 1020,1028 **** `buffer' is the compiled pattern; `syntax' is set to SYNTAX; `used' is set to the length of the compiled pattern; ! `fastmap_accurate' is set to zero; ! `re_nsub' is set to the number of groups in PATTERN; ! `not_bol' and `not_eol' are set to zero. The `fastmap' and `newline_anchor' fields are neither examined nor set. */ --- 1051,1059 ---- `buffer' is the compiled pattern; `syntax' is set to SYNTAX; `used' is set to the length of the compiled pattern; ! `fastmap_accurate' is zero; ! `re_nsub' is the number of subexpressions in PATTERN; ! `not_bol' and `not_eol' are zero; The `fastmap' and `newline_anchor' fields are neither examined nor set. */ *************** *** 1147,1170 **** switch (c) { - /* ^ matches the empty string at the beginning of a string (or - possibly a line). If RE_CONTEXT_INDEP_ANCHORS is set, ^ is - always an operator (and foo^bar is unmatchable). If that bit - isn't set, it's an operator only at the beginning of the - pattern or after an alternation or open-group operator, or, - if RE_NEWLINE_ORDINARY is not set, after a newline (except it - can be preceded by other operators that match the empty - string); otherwise, it's a normal character. */ case '^': { ! if ( /* If at start of (sub)pattern, it's an operator. */ ! laststart == 0 /* If context independent, it's an operator. */ || syntax & RE_CONTEXT_INDEP_ANCHORS ! /* If after a newline, might be an operator. (Since ! laststart is nonzero here, we know we have at ! least one byte before the ^.) */ ! || (!(syntax & RE_NEWLINE_ORDINARY) && p[-2] == '\n')) BUF_PUSH (begline); else goto normal_char; --- 1178,1191 ---- switch (c) { case '^': { ! if ( /* If at start of pattern, it's an operator. */ ! p == pattern + 1 /* If context independent, it's an operator. */ || syntax & RE_CONTEXT_INDEP_ANCHORS ! /* Otherwise, depends on what's come before. */ ! || at_begline_loc_p (pattern, p, syntax)) BUF_PUSH (begline); else goto normal_char; *************** *** 1172,1179 **** break; - /* $ matches the empty string following the end of the string (or - possibly a line). It follows rules dual to those for ^. */ case '$': { if ( /* If at end of pattern, it's an operator. */ --- 1193,1198 ---- *************** *** 1181,1187 **** /* If context independent, it's an operator. */ || syntax & RE_CONTEXT_INDEP_ANCHORS /* Otherwise, depends on what's next. */ ! || at_endline_op_p (p, pend, syntax)) BUF_PUSH (endline); else goto normal_char; --- 1200,1206 ---- /* If context independent, it's an operator. */ || syntax & RE_CONTEXT_INDEP_ANCHORS /* Otherwise, depends on what's next. */ ! || at_endline_loc_p (p, pend, syntax)) BUF_PUSH (endline); else goto normal_char; *************** *** 1464,1481 **** for (ch = 0; ch < 1 << BYTEWIDTH; ch++) { ! if ( (is_alnum && isalnum (ch)) ! || (is_alpha && isalpha (ch)) ! || (is_blank && isblank (ch)) ! || (is_cntrl && iscntrl (ch)) ! || (is_digit && isdigit (ch)) ! || (is_graph && isgraph (ch)) ! || (is_lower && islower (ch)) ! || (is_print && isprint (ch)) ! || (is_punct && ispunct (ch)) ! || (is_space && isspace (ch)) ! || (is_upper && isupper (ch)) ! || (is_xdigit && isxdigit (ch))) SET_LIST_BIT (ch); } had_char_class = true; --- 1483,1500 ---- for (ch = 0; ch < 1 << BYTEWIDTH; ch++) { ! if ( (is_alnum && ISALNUM (ch)) ! || (is_alpha && ISALPHA (ch)) ! || (is_blank && ISBLANK (ch)) ! || (is_cntrl && ISCNTRL (ch)) ! || (is_digit && ISDIGIT (ch)) ! || (is_graph && ISGRAPH (ch)) ! || (is_lower && ISLOWER (ch)) ! || (is_print && ISPRINT (ch)) ! || (is_punct && ISPUNCT (ch)) ! || (is_space && ISSPACE (ch)) ! || (is_upper && ISUPPER (ch)) ! || (is_xdigit && ISXDIGIT (ch))) SET_LIST_BIT (ch); } had_char_class = true; *************** *** 1554,1569 **** case '(': if (syntax & RE_NO_BK_PARENS) goto normal_backslash; - handle_open: - if (syntax & RE_NO_EMPTY_GROUPS) - { - p1 = p; - if (!(syntax & RE_NO_BK_PARENS) && *p1 == '\\') p1++; - - /* If found an empty group... */ - if (*p1 == ')') return REG_BADPAT; - } bufp->re_nsub++; regnum++; --- 1573,1580 ---- case '(': if (syntax & RE_NO_BK_PARENS) goto normal_backslash; + handle_open: bufp->re_nsub++; regnum++; *************** *** 1673,1695 **** if (syntax & RE_LIMITED_OPS) goto normal_char; - #if 0 - /* Nobody needs to disallow empty alternatives any more. */ - /* Disallow empty alternatives if RE_NO_EMPTY_ALTS is set. - Caveat: can't detect if the vbar is followed by a - trailing '$' yet, unless it's the last thing in a - pattern; the routine for verifying endlines has to do - the rest. */ - if ((syntax & RE_NO_EMPTY_ALTS) - && (!laststart - || p == pend - || (*p == '$' && p + 1 == pend) - || ((syntax & RE_NO_BK_PARENS) - ? (p < pend && *p == ')') - : (p + 1 < pend && p[0] == '\\' && p[1] == ')')))) - return REG_BADPAT; - #endif - /* Insert before the previous alternative a jump which jumps to this alternative if the former fails. */ GET_BUFFER_SPACE (3); --- 1684,1689 ---- *************** *** 1708,1717 **** | v | v a | b | c ! If we are at `b,' then fixup_alt_jump right now points to a ! three-byte space after `a.' We'll put in the jump, set ! fixup_alt_jump to right after `b,' and leave behind three ! bytes which we'll fill in when we get to after `c.' */ if (fixup_alt_jump) STORE_JUMP (jump_past_alt, fixup_alt_jump, b); --- 1702,1711 ---- | v | v a | b | c ! If we are at `b', then fixup_alt_jump right now points to a ! three-byte space after `a'. We'll put in the jump, set ! fixup_alt_jump to right after `b', and leave behind three ! bytes which we'll fill in when we get to after `c'. */ if (fixup_alt_jump) STORE_JUMP (jump_past_alt, fixup_alt_jump, b); *************** *** 1954,1968 **** BUF_PUSH (endbuf); break; ! case '1': ! case '2': ! case '3': ! case '4': ! case '5': ! case '6': ! case '7': ! case '8': ! case '9': if (syntax & RE_NO_BK_REFS) goto normal_char; --- 1948,1955 ---- BUF_PUSH (endbuf); break; ! case '1': case '2': case '3': case '4': case '5': ! case '6': case '7': case '8': case '9': if (syntax & RE_NO_BK_REFS) goto normal_char; *************** *** 1969,1980 **** c1 = c - '0'; if (c1 > regnum) ! { ! if (syntax & RE_NO_MISSING_BK_REF) ! return REG_ESUBREG; ! else ! goto normal_char; ! } /* Can't back reference to a subexpression if inside of it. */ if (group_in_compile_stack (compile_stack, c1)) --- 1956,1962 ---- c1 = c - '0'; if (c1 > regnum) ! return REG_ESUBREG; /* Can't back reference to a subexpression if inside of it. */ if (group_in_compile_stack (compile_stack, c1)) *************** *** 2132,2192 **** } ! /* Return true if the pattern position P is at a close-group or ! alternation operator, or if it is a newline and RE_NEWLINE_ORDINARY ! is not set in SYNTAX. Before checking, though, we skip past all ! operators that match the empty string. ! ! This is not quite the dual of what happens with ^. There, we can ! easily check if the (sub)pattern so far can match only the empty ! string, because we have seen the pattern, and `laststart' is set to ! exactly that. But we cannot easily look at the pattern yet to come ! to see if it matches the empty string; that would require us to compile ! the pattern, then go back and analyze the pattern after every ! endline. POSIX required this at one point (that $ be in a ! ``trailing'' position to be considered an anchor), so we implemented ! it, but it was slow and took lots of code, and we were never really ! convinced it worked in all cases. So now it's gone, and we live with ! the slight inconsistency between ^ and $. */ static boolean ! at_endline_op_p (p, pend, syntax) const char *p, *pend; int syntax; { ! boolean context_indep = !!(syntax & RE_CONTEXT_INDEP_ANCHORS); ! /* Skip past operators that match the empty string. (Except we don't ! handle empty groups.) */ ! while (p < pend) ! { ! if (context_indep && (*p == '^' || *p == '$')) ! p++; ! ! /* All others start with \. */ ! else if (*p == '\\' && p + 1 < pend ! && (p[1] == 'b' || p[1] == 'B' ! || p[1] == '<' || p[1] == '>' ! || p[1] == '`' || p[1] == '\'' ! #ifdef emacs ! || p[1] == '=' ! #endif ! )) ! p += 2; ! ! else /* Not an empty string operator. */ ! break; ! } ! ! /* See what we're at now. */ ! return p < pend ! && ((!(syntax & RE_NEWLINE_ORDINARY) && *p == '\n') ! || (syntax & RE_NO_BK_PARENS ! ? *p == ')' ! : *p == '\\' && p + 1 < pend && p[1] == ')') ! || (syntax & RE_NO_BK_VBAR ! ? *p == '|' ! : (*p == '\\' && p + 1 < pend && p[1] == '|'))); } --- 2114,2158 ---- } ! /* P points to just after a ^ in PATTERN. Return true if that ^ comes ! after an alternative or a begin-subexpression. We assume there is at ! least one character before the ^. */ ! ! static boolean ! at_begline_loc_p (pattern, p, syntax) ! const char *pattern, *p; ! reg_syntax_t syntax; ! { ! const char *prev = p - 2; ! boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\'; ! ! return ! /* After a subexpression? */ ! (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash)) ! /* After an alternative? */ ! || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash)); ! } ! + /* The dual of at_begline_loc_p. This one is for $. We assume there is + at least one character after the $, i.e., `P < PEND'. */ + static boolean ! at_endline_loc_p (p, pend, syntax) const char *p, *pend; int syntax; { ! const char *next = p; ! boolean next_backslash = *next == '\\'; ! const char *next_next = p + 1 < pend ? p + 1 : NULL; ! return ! /* Before a subexpression? */ ! (syntax & RE_NO_BK_PARENS ? *next == ')' ! : next_backslash && next_next && *next_next == ')') ! /* Before an alternative? */ ! || (syntax & RE_NO_BK_VBAR ? *next == '|' ! : next_backslash && next_next && *next_next == '|'); } *************** *** 2231,2248 **** unsigned this_char; const char *p = *p_ptr; - /* Even though the pattern is a signed `char *', we need to fetch into - `unsigned char's. Reason: if the high bit of the pattern character - is set, the range endpoints will be negative if we fetch into a - signed `char *'. */ - unsigned char range_end; - unsigned char range_start = p[-2]; - if (p == pend) return REG_ERANGE; ! PATFETCH (range_end); /* Have to increment the pointer into the pattern string, so the caller isn't still at the ending character. */ --- 2197,2216 ---- unsigned this_char; const char *p = *p_ptr; + int range_start, range_end; if (p == pend) return REG_ERANGE; ! /* Even though the pattern is a signed `char *', we need to fetch ! with unsigned char *'s; if the high bit of the pattern character ! is set, the range endpoints will be negative if we fetch using a ! signed char *. ! ! We also want to fetch the endpoints without translating them; the ! appropriate translation is done in the bit-setting loop below. */ ! range_start = ((unsigned char *) p)[-2]; ! range_end = ((unsigned char *) p)[0]; /* Have to increment the pointer into the pattern string, so the caller isn't still at the ending character. */ *************** *** 2297,2312 **** #define FAIL_STACK_TOP() (fail_stack.stack[fail_stack.avail]) ! /* Initialize FAIL_STACK. Return 1 if success, 0 if not. */ ! #define INIT_FAIL_STACK(fail_stack) \ ! ((fail_stack).stack = (fail_stack_elt_t *) \ ! REGEX_ALLOCATE (INIT_FAILURE_ALLOC * sizeof (fail_stack_elt_t)), \ ! (fail_stack).stack == NULL \ ! ? 0 \ ! : ((fail_stack).size = INIT_FAILURE_ALLOC, \ ! (fail_stack).avail = 0, \ ! 1)) /* Double the size of FAIL_STACK, up to approximately `re_max_failures' items. --- 2265,2283 ---- #define FAIL_STACK_TOP() (fail_stack.stack[fail_stack.avail]) ! /* Initialize `fail_stack'. Do `return -2' if the alloc fails. */ ! #define INIT_FAIL_STACK() \ ! do { \ ! fail_stack.stack = (fail_stack_elt_t *) \ ! REGEX_ALLOCATE (INIT_FAILURE_ALLOC * sizeof (fail_stack_elt_t)); \ ! \ ! if (fail_stack.stack == NULL) \ ! return -2; \ ! \ ! fail_stack.size = INIT_FAILURE_ALLOC; \ ! fail_stack.avail = 0; \ ! } while (0) /* Double the size of FAIL_STACK, up to approximately `re_max_failures' items. *************** *** 2347,2356 **** #define PUSH_FAILURE_ITEM(item) \ fail_stack.stack[fail_stack.avail++] = (fail_stack_elt_t) item ! /* The complement operation. Assumes stack is nonempty, and pointed to ! `fail_stack_ptr'. */ ! #define POP_FAILURE_ITEM() \ ! fail_stack_ptr->stack[--fail_stack_ptr->avail] /* Used to omit pushing failure point id's when we're not debugging. */ #ifdef DEBUG --- 2318,2325 ---- #define PUSH_FAILURE_ITEM(item) \ fail_stack.stack[fail_stack.avail++] = (fail_stack_elt_t) item ! /* The complement operation. Assumes `fail_stack' is nonempty. */ ! #define POP_FAILURE_ITEM() fail_stack.stack[--fail_stack.avail] /* Used to omit pushing failure point id's when we're not debugging. */ #ifdef DEBUG *************** *** 2379,2384 **** --- 2348,2354 ---- int this_reg; \ \ DEBUG_STATEMENT (failure_id++); \ + DEBUG_STATEMENT (nfailure_points_pushed++); \ DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id); \ DEBUG_PRINT2 (" Before push, next avail: %d\n", (fail_stack).avail);\ DEBUG_PRINT2 (" size: %d\n", (fail_stack).size);\ *************** *** 2465,2470 **** --- 2435,2510 ---- /* How many items can still be added to the stack without overflowing it. */ #define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail) + + + /* Pops what PUSH_FAIL_STACK pushes. + + We restore into the parameters, all of which should be lvalues: + STR -- the saved data position. + PAT -- the saved pattern position. + LOW_REG, HIGH_REG -- the highest and lowest active registers. + REGSTART, REGEND -- arrays of string positions. + REG_INFO -- array of information about each subexpression. + + Also assumes the variables `fail_stack' and (if debugging), `bufp', + `pend', `string1', `size1', `string2', and `size2'. */ + + #define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\ + { \ + DEBUG_STATEMENT (fail_stack_elt_t failure_id;) \ + int this_reg; \ + const unsigned char *string_temp; \ + \ + assert (!FAIL_STACK_EMPTY ()); \ + \ + /* Remove failure points and point to how many regs pushed. */ \ + DEBUG_PRINT1 ("POP_FAILURE_POINT:\n"); \ + DEBUG_PRINT2 (" Before pop, next avail: %d\n", fail_stack.avail); \ + DEBUG_PRINT2 (" size: %d\n", fail_stack.size); \ + \ + assert (fail_stack.avail >= NUM_NONREG_ITEMS); \ + \ + DEBUG_POP (&failure_id); \ + DEBUG_PRINT2 (" Popping failure id: %u\n", failure_id); \ + \ + /* If the saved string location is NULL, it came from an \ + on_failure_keep_string_jump opcode, and we want to throw away the \ + saved NULL, thus retaining our current position in the string. */ \ + string_temp = POP_FAILURE_ITEM (); \ + if (string_temp != NULL) \ + str = (const char *) string_temp; \ + \ + DEBUG_PRINT2 (" Popping string 0x%x: `", str); \ + DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2); \ + DEBUG_PRINT1 ("'\n"); \ + \ + pat = (unsigned char *) POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" Popping pattern 0x%x: ", pat); \ + DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend); \ + \ + /* Restore register info. */ \ + high_reg = (unsigned) POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" Popping high active reg: %d\n", high_reg); \ + \ + low_reg = (unsigned) POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" Popping low active reg: %d\n", low_reg); \ + \ + for (this_reg = high_reg; this_reg >= low_reg; this_reg--) \ + { \ + DEBUG_PRINT2 (" Popping reg: %d\n", this_reg); \ + \ + reg_info[this_reg].word = POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" info: 0x%x\n", reg_info[this_reg]); \ + \ + regend[this_reg] = (const char *) POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \ + \ + regstart[this_reg] = (const char *) POP_FAILURE_ITEM (); \ + DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \ + } \ + \ + DEBUG_STATEMENT (nfailure_points_popped++); \ + } /* POP_FAILURE_POINT */ /* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in BUFP. A fastmap records which of the (1 << BYTEWIDTH) possible *************** *** 2508,2514 **** assert (fastmap != NULL && p != NULL); ! INIT_FAIL_STACK (fail_stack); bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */ bufp->fastmap_accurate = 1; /* It will be when we're done. */ bufp->can_be_null = 0; --- 2548,2554 ---- assert (fastmap != NULL && p != NULL); ! INIT_FAIL_STACK (); bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */ bufp->fastmap_accurate = 1; /* It will be when we're done. */ bufp->can_be_null = 0; *************** *** 2594,2600 **** if (!(bufp->syntax & RE_DOT_NEWLINE)) fastmap['\n'] = 0; ! /* Return if we have already set `can_be_null' and fastmap['\n']. */ else if (bufp->can_be_null) return 0; --- 2634,2641 ---- if (!(bufp->syntax & RE_DOT_NEWLINE)) fastmap['\n'] = 0; ! /* Return if we have already set `can_be_null'; if we have, ! then the fastmap is irrelevant. Something's wrong here. */ else if (bufp->can_be_null) return 0; *************** *** 2850,2864 **** else if (endpos > total_size) range = total_size - startpos; - /* Update the fastmap now if not correct already. */ - if (fastmap && !bufp->fastmap_accurate) - if (re_compile_fastmap (bufp) == -2) - return -2; - /* If the search isn't to be a backwards one, don't waste time in a ! long search for a pattern that says it is anchored. */ ! if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == begbuf ! && range > 0) { if (startpos > 0) return -1; --- 2891,2899 ---- else if (endpos > total_size) range = total_size - startpos; /* If the search isn't to be a backwards one, don't waste time in a ! search for a pattern that must be anchored. */ ! if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == begbuf && range > 0) { if (startpos > 0) return -1; *************** *** 2866,2871 **** --- 2901,2912 ---- range = 1; } + /* Update the fastmap now if not correct already. */ + if (fastmap && !bufp->fastmap_accurate) + if (re_compile_fastmap (bufp) == -2) + return -2; + + /* Loop through the string, looking for a place to start matching. */ for (;;) { /* If a fastmap is supplied, skip quickly over characters that *************** *** 2889,2895 **** inside the loop. */ if (translate) while (range > lim ! && !fastmap[(unsigned char) translate[*d++]]) range--; else while (range > lim && !fastmap[(unsigned char) *d++]) --- 2930,2937 ---- inside the loop. */ if (translate) while (range > lim ! && !fastmap[(unsigned char) ! translate[(unsigned char) *d++]]) range--; else while (range > lim && !fastmap[(unsigned char) *d++]) *************** *** 2903,2909 **** ? string2[startpos - size1] : string1[startpos]); ! if (!fastmap[TRANSLATE (c)]) goto advance; } } --- 2945,2951 ---- ? string2[startpos - size1] : string1[startpos]); ! if (!fastmap[(unsigned char) TRANSLATE (c)]) goto advance; } } *************** *** 2944,2952 **** static boolean alt_match_null_string_p (), common_op_match_null_string_p (), group_match_null_string_p (); - static void pop_failure_point (); - /* Structure for per-register (a.k.a. per-group) information. This must not be longer than one word, because we push this value onto the failure stack. Other register information, such as the --- 2986,2992 ---- *************** *** 2979,2990 **** #define EVER_MATCHED_SOMETHING(R) ((R).bits.ever_matched_something) ! /* Call this when have matched something; it sets `matched' flags for the ! registers corresponding to the group of which we currently are inside. ! Also records whether this group ever matched something. We only care ! about this information at `stop_memory', and then only about the ! previous time through the loop (if the group is starred or whatever). ! So it is ok to clear all the nonactive registers here. */ #define SET_REGS_MATCHED() \ do \ { \ --- 3019,3027 ---- #define EVER_MATCHED_SOMETHING(R) ((R).bits.ever_matched_something) ! /* Call this when have matched a real character; it sets `matched' flags ! for the subexpressions which we are currently inside. Also records ! that those subexprs have matched. */ #define SET_REGS_MATCHED() \ do \ { \ *************** *** 3029,3052 **** /* Test if at very beginning or at very end of the virtual concatenation of `string1' and `string2'. If only one string, it's `string2'. */ ! #define AT_STRINGS_BEG() (d == (size1 ? string1 : string2) || !size2) ! #define AT_STRINGS_END() (d == end2) /* Test if D points to a character which is word-constituent. We have two special cases to check for: if past the end of string1, look at the first character in string2; and if before the beginning of ! string2, look at the last character in string1. ! ! Assumes `string1' exists, so use in conjunction with AT_STRINGS_BEG (). */ ! #define LETTER_P(d) \ (SYNTAX ((d) == end1 ? *string2 \ ! : (d) == string2 - 1 ? *(end1 - 1) : *(d)) == Sword) /* Test if the character before D and the one at D differ with respect to being word-constituent. */ #define AT_WORD_BOUNDARY(d) \ ! (AT_STRINGS_BEG () || AT_STRINGS_END () || LETTER_P (d - 1) != LETTER_P (d)) /* Free everything we malloc. */ --- 3066,3089 ---- /* Test if at very beginning or at very end of the virtual concatenation of `string1' and `string2'. If only one string, it's `string2'. */ ! #define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2) ! #define AT_STRINGS_END(d) ((d) == end2) /* Test if D points to a character which is word-constituent. We have two special cases to check for: if past the end of string1, look at the first character in string2; and if before the beginning of ! string2, look at the last character in string1. */ ! #define WORDCHAR_P(d) \ (SYNTAX ((d) == end1 ? *string2 \ ! : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \ ! == Sword) /* Test if the character before D and the one at D differ with respect to being word-constituent. */ #define AT_WORD_BOUNDARY(d) \ ! (AT_STRINGS_BEG (d) || AT_STRINGS_END (d) \ ! || WORDCHAR_P (d - 1) != WORDCHAR_P (d)) /* Free everything we malloc. */ *************** *** 3066,3072 **** FREE_VAR (reg_info_dummy); \ } while (0) #else /* not REGEX_MALLOC */ ! #define FREE_VARIABLES() /* As nothing, since we are using alloca. */ #endif /* not REGEX_MALLOC */ --- 3103,3110 ---- FREE_VAR (reg_info_dummy); \ } while (0) #else /* not REGEX_MALLOC */ ! /* Some MIPS systems (at least) want this to free alloca'd storage. */ ! #define FREE_VARIABLES() alloca (0) #endif /* not REGEX_MALLOC */ *************** *** 3152,3157 **** --- 3190,3196 ---- fail_stack_type fail_stack; #ifdef DEBUG static unsigned failure_id = 0; + unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0; #endif /* We fill all the registers internally, independent of what we *************** *** 3215,3222 **** DEBUG_PRINT1 ("\n\nEntering re_match_2.\n"); ! if (!INIT_FAIL_STACK (fail_stack)) ! return -2; /* Do not bother to initialize all the register variables if there are no groups in the pattern, as it takes a fair amount of time. If --- 3254,3260 ---- DEBUG_PRINT1 ("\n\nEntering re_match_2.\n"); ! INIT_FAIL_STACK (); /* Do not bother to initialize all the register variables if there are no groups in the pattern, as it takes a fair amount of time. If *************** *** 3246,3253 **** else { /* We must initialize all our variables to NULL, so that ! `FREE_VARIABLES' doesn't try to free them. Too bad this isn't ! Lisp, so we could have a list of variables. As it is, */ regstart = regend = old_regstart = old_regend = best_regstart = best_regend = reg_dummy = NULL; reg_info = reg_info_dummy = (register_info_type *) NULL; --- 3284,3290 ---- else { /* We must initialize all our variables to NULL, so that ! `FREE_VARIABLES' doesn't try to free them. */ regstart = regend = old_regstart = old_regend = best_regstart = best_regend = reg_dummy = NULL; reg_info = reg_info_dummy = (register_info_type *) NULL; *************** *** 3331,3338 **** if (p == pend) { /* End of pattern means we might have succeeded. */ ! DEBUG_PRINT1 ("End of pattern: "); ! /* If not end of string, try backtracking. Otherwise done. */ if (d != end_match_2) { DEBUG_PRINT1 ("backtracking.\n"); --- 3368,3377 ---- if (p == pend) { /* End of pattern means we might have succeeded. */ ! DEBUG_PRINT1 ("end of pattern ... "); ! ! /* If we haven't matched the entire string, and we want the ! longest match, try backtracking. */ if (d != end_match_2) { DEBUG_PRINT1 ("backtracking.\n"); *************** *** 3370,3375 **** --- 3409,3416 ---- For example, the pattern `x.*y.*z' against the strings `x-' and `y-z-', if the two strings are not consecutive in memory. */ + DEBUG_PRINT1 ("Restoring best registers.\n"); + d = match_end; dend = ((d >= string1 && d <= end1) ? end_match_1 : end_match_2); *************** *** 3382,3388 **** } } /* d != end_match_2 */ ! DEBUG_PRINT1 ("\nAccepting match.\n"); /* If caller wants register contents data back, do it. */ if (regs && !bufp->no_sub) --- 3423,3429 ---- } } /* d != end_match_2 */ ! DEBUG_PRINT1 ("Accepting match.\n"); /* If caller wants register contents data back, do it. */ if (regs && !bufp->no_sub) *************** *** 3448,3454 **** } /* regs && !bufp->no_sub */ FREE_VARIABLES (); ! DEBUG_PRINT2 ("%d registers pushed.\n", num_regs_pushed); mcnt = d - pos - (MATCHING_IN_FIRST_STRING ? string1 --- 3489,3498 ---- } /* regs && !bufp->no_sub */ FREE_VARIABLES (); ! DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n", ! nfailure_points_pushed, nfailure_points_popped, ! nfailure_points_pushed - nfailure_points_popped); ! DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed); mcnt = d - pos - (MATCHING_IN_FIRST_STRING ? string1 *************** *** 3650,3656 **** /* If just failed to match something this time around with a group that's operated on by a repetition operator, try to ! force exit from the ``loop,'' and restore the register information for this group that we had before trying this last match. */ if ((!MATCHED_SOMETHING (reg_info[*p]) --- 3694,3700 ---- /* If just failed to match something this time around with a group that's operated on by a repetition operator, try to ! force exit from the ``loop'', and restore the register information for this group that we had before trying this last match. */ if ((!MATCHED_SOMETHING (reg_info[*p]) *************** *** 3794,3800 **** case begline: DEBUG_PRINT1 ("EXECUTING begline.\n"); ! if (AT_STRINGS_BEG ()) { if (!bufp->not_bol) break; } --- 3838,3844 ---- case begline: DEBUG_PRINT1 ("EXECUTING begline.\n"); ! if (AT_STRINGS_BEG (d)) { if (!bufp->not_bol) break; } *************** *** 3810,3816 **** case endline: DEBUG_PRINT1 ("EXECUTING endline.\n"); ! if (AT_STRINGS_END ()) { if (!bufp->not_eol) break; } --- 3854,3860 ---- case endline: DEBUG_PRINT1 ("EXECUTING endline.\n"); ! if (AT_STRINGS_END (d)) { if (!bufp->not_eol) break; } *************** *** 3827,3833 **** /* Match at the very beginning of the data. */ case begbuf: DEBUG_PRINT1 ("EXECUTING begbuf.\n"); ! if (AT_STRINGS_BEG ()) break; goto fail; --- 3871,3877 ---- /* Match at the very beginning of the data. */ case begbuf: DEBUG_PRINT1 ("EXECUTING begbuf.\n"); ! if (AT_STRINGS_BEG (d)) break; goto fail; *************** *** 3835,3841 **** /* Match at the very end of the data. */ case endbuf: DEBUG_PRINT1 ("EXECUTING endbuf.\n"); ! if (AT_STRINGS_END ()) break; goto fail; --- 3879,3885 ---- /* Match at the very end of the data. */ case endbuf: DEBUG_PRINT1 ("EXECUTING endbuf.\n"); ! if (AT_STRINGS_END (d)) break; goto fail; *************** *** 3889,3895 **** the original * applied to a group), save the information for that group and all inner ones, so that if we fail back to this point, the group's information will be correct. ! For example, in \(a*\)*\1, we only need the preceding group, and in \(\(a*\)b*\)\2, we need the inner group. */ /* We can't use `p' to check ahead because we push --- 3933,3939 ---- the original * applied to a group), save the information for that group and all inner ones, so that if we fail back to this point, the group's information will be correct. ! For example, in \(a*\)*\1, we need the preceding group, and in \(\(a*\)b*\)\2, we need the inner group. */ /* We can't use `p' to check ahead because we push *************** *** 3919,3926 **** break; ! /* A smart repeat ends with a maybe_pop_jump. ! We change it either to a pop_failure_jump or a jump. */ case maybe_pop_jump: EXTRACT_NUMBER_AND_INCR (mcnt, p); DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt); --- 3963,3970 ---- break; ! /* A smart repeat ends with `maybe_pop_jump'. ! We change it to either `pop_failure_jump' or `jump'. */ case maybe_pop_jump: EXTRACT_NUMBER_AND_INCR (mcnt, p); DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt); *************** *** 3948,3954 **** /* If we're at the end of the pattern, we can change. */ if (p2 == pend) ! { p[-3] = (unsigned char) pop_failure_jump; DEBUG_PRINT1 (" End of pattern: change to `pop_failure_jump'.\n"); --- 3992,4001 ---- /* If we're at the end of the pattern, we can change. */ if (p2 == pend) ! { ! /* Consider what happens when matching ":\(.*\)" ! against ":/". I don't really understand this code ! yet. */ p[-3] = (unsigned char) pop_failure_jump; DEBUG_PRINT1 (" End of pattern: change to `pop_failure_jump'.\n"); *************** *** 3965,3971 **** to the `maybe_finalize_jump' of this case. Examine what follows. */ if ((re_opcode_t) p1[3] == exactn && p1[5] != c) ! p[-3] = (unsigned char) pop_failure_jump; else if ((re_opcode_t) p1[3] == charset || (re_opcode_t) p1[3] == charset_not) { --- 4012,4023 ---- to the `maybe_finalize_jump' of this case. Examine what follows. */ if ((re_opcode_t) p1[3] == exactn && p1[5] != c) ! { ! p[-3] = (unsigned char) pop_failure_jump; ! DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n", ! c, p1[5]); ! } ! else if ((re_opcode_t) p1[3] == charset || (re_opcode_t) p1[3] == charset_not) { *************** *** 3980,3988 **** if (!not) { p[-3] = (unsigned char) pop_failure_jump; ! DEBUG_PRINT1 ! (" No match: change to `pop_failure_jump'.\n"); ! } } } --- 4032,4038 ---- if (!not) { p[-3] = (unsigned char) pop_failure_jump; ! DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); } } } *************** *** 3991,3996 **** --- 4041,4047 ---- if ((re_opcode_t) p[-1] != pop_failure_jump) { p[-1] = (unsigned char) jump; + DEBUG_PRINT1 (" Match => jump.\n"); goto unconditional_jump; } /* Note fall through. */ *************** *** 4009,4025 **** actual values. Otherwise, we will restore only one register from the stack, since lowest will == highest in `pop_failure_point'. */ ! unsigned dummy_low, dummy_high; ! unsigned char *pdummy = NULL; DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n"); ! pop_failure_point (bufp, pend, ! #ifdef DEBUG ! string1, size1, string2, size2, ! #endif ! &fail_stack, &pdummy, &pdummy, ! &dummy_low, &dummy_high, ! ®_dummy, ®_dummy, ®_info_dummy); } /* Note fall through. */ --- 4060,4073 ---- actual values. Otherwise, we will restore only one register from the stack, since lowest will == highest in `pop_failure_point'. */ ! unsigned dummy_low_reg, dummy_high_reg; ! unsigned char *pdummy; ! const char *sdummy; DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n"); ! POP_FAILURE_POINT (sdummy, pdummy, ! dummy_low_reg, dummy_high_reg, ! reg_dummy, reg_dummy, reg_info_dummy); } /* Note fall through. */ *************** *** 4055,4061 **** /* At the end of an alternative, we need to push a dummy failure ! point in case we are followed by a pop_failure_jump', because we don't want the failure point for the alternative to be popped. For example, matching `(a|ab)*' against `aab' requires that we match the `ab' alternative. */ --- 4103,4109 ---- /* At the end of an alternative, we need to push a dummy failure ! point in case we are followed by a `pop_failure_jump', because we don't want the failure point for the alternative to be popped. For example, matching `(a|ab)*' against `aab' requires that we match the `ab' alternative. */ *************** *** 4132,4145 **** case wordbeg: DEBUG_PRINT1 ("EXECUTING wordbeg.\n"); ! if (LETTER_P (d) && (AT_STRINGS_BEG () || !LETTER_P (d - 1))) break; goto fail; case wordend: DEBUG_PRINT1 ("EXECUTING wordend.\n"); ! if (!AT_STRINGS_BEG () && LETTER_P (d - 1) ! && (!LETTER_P (d) || AT_STRINGS_END ())) break; goto fail; --- 4180,4193 ---- case wordbeg: DEBUG_PRINT1 ("EXECUTING wordbeg.\n"); ! if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1))) break; goto fail; case wordend: DEBUG_PRINT1 ("EXECUTING wordend.\n"); ! if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1) ! && (!WORDCHAR_P (d) || AT_STRINGS_END (d))) break; goto fail; *************** *** 4176,4186 **** goto matchsyntax; case wordchar: ! DEBUG_PRINT1 ("EXECUTING wordchar.\n"); mcnt = (int) Sword; matchsyntax: PREFETCH (); ! if (SYNTAX (*d++) != (enum syntaxcode) mcnt) goto fail; SET_REGS_MATCHED (); break; --- 4224,4235 ---- goto matchsyntax; case wordchar: ! DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n"); mcnt = (int) Sword; matchsyntax: PREFETCH (); ! if (SYNTAX (*d++) != (enum syntaxcode) mcnt) ! goto fail; SET_REGS_MATCHED (); break; *************** *** 4190,4200 **** goto matchnotsyntax; case notwordchar: ! DEBUG_PRINT1 ("EXECUTING notwordchar.\n"); mcnt = (int) Sword; ! matchnotsyntax: /* We goto here from notsyntaxspec. */ PREFETCH (); ! if (SYNTAX (*d++) == (enum syntaxcode) mcnt) goto fail; SET_REGS_MATCHED (); break; --- 4239,4250 ---- goto matchnotsyntax; case notwordchar: ! DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n"); mcnt = (int) Sword; ! matchnotsyntax: PREFETCH (); ! if (SYNTAX (*d++) == (enum syntaxcode) mcnt) ! goto fail; SET_REGS_MATCHED (); break; *************** *** 4202,4218 **** case wordchar: DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n"); PREFETCH (); ! if (!LETTER_P (d)) goto fail; SET_REGS_MATCHED (); break; case notwordchar: DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n"); PREFETCH (); ! if (LETTER_P (d)) goto fail; SET_REGS_MATCHED (); break; #endif /* not emacs */ --- 4252,4270 ---- case wordchar: DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n"); PREFETCH (); ! if (!WORDCHAR_P (d)) goto fail; SET_REGS_MATCHED (); + d++; break; case notwordchar: DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n"); PREFETCH (); ! if (WORDCHAR_P (d)) goto fail; SET_REGS_MATCHED (); + d++; break; #endif /* not emacs */ *************** *** 4227,4239 **** if (!FAIL_STACK_EMPTY ()) { /* A restart point is known. Restore to that state. */ DEBUG_PRINT1 ("\nFAIL:\n"); ! pop_failure_point (bufp, pend, ! #ifdef DEBUG ! string1, size1, string2, size2, ! #endif ! &fail_stack, &p, &d, &lowest_active_reg, ! &highest_active_reg, ®start, ®end, ! ®_info); /* If this failure point is a dummy, try the next one. */ if (!p) --- 4279,4287 ---- if (!FAIL_STACK_EMPTY ()) { /* A restart point is known. Restore to that state. */ DEBUG_PRINT1 ("\nFAIL:\n"); ! POP_FAILURE_POINT (d, p, ! lowest_active_reg, highest_active_reg, ! regstart, regend, reg_info); /* If this failure point is a dummy, try the next one. */ if (!p) *************** *** 4286,4374 **** /* Subroutine definitions for re_match_2. */ - /* Pops what PUSH_FAIL_STACK pushes. */ - - static void - pop_failure_point (bufp, pattern_end, - #ifdef DEBUG - string1, size1, string2, size2, - #endif - fail_stack_ptr, pattern_place, string_place, - lowest_active_reg, highest_active_reg, - regstart, regend, reg_info) - const struct re_pattern_buffer *bufp; /* These not modified. */ - unsigned char *pattern_end; - #ifdef DEBUG - const char *string1, *string2; - int size1, size2; - #endif - fail_stack_type *fail_stack_ptr; /* These get modified. */ - const unsigned char **pattern_place; - const char **string_place; - unsigned *lowest_active_reg, *highest_active_reg; - const unsigned char ***regstart; - const unsigned char ***regend; - register_info_type **reg_info; - { - #ifdef DEBUG - /* Data type is really unsigned; it's declared this way just to avoid - a compiler warning. */ - fail_stack_elt_t failure_id; - #endif - int this_reg; - const unsigned char *string_temp; - - assert (!FAIL_STACK_PTR_EMPTY ()); - - /* Remove failure points and point to how many regs pushed. */ - DEBUG_PRINT1 ("pop_failure_point:\n"); - DEBUG_PRINT2 (" Before pop, next avail: %d\n", fail_stack_ptr->avail); - DEBUG_PRINT2 (" size: %d\n", fail_stack_ptr->size); - - assert (fail_stack_ptr->avail >= NUM_NONREG_ITEMS); - - DEBUG_POP (&failure_id); - DEBUG_PRINT2 (" Popping failure id: %u\n", failure_id); - - /* If the saved string location is NULL, it came from an - on_failure_keep_string_jump opcode, and we want to throw away the - saved NULL, thus retaining our current position in the string. */ - string_temp = POP_FAILURE_ITEM (); - if (string_temp != NULL) - *string_place = (const char *) string_temp; - - DEBUG_PRINT2 (" Popping string 0x%x: `", *string_place); - DEBUG_PRINT_DOUBLE_STRING (*string_place, string1, size1, string2, size2); - DEBUG_PRINT1 ("'\n"); - - *pattern_place = POP_FAILURE_ITEM (); - DEBUG_PRINT2 (" Popping pattern 0x%x: ", *pattern_place); - DEBUG_PRINT_COMPILED_PATTERN (bufp, *pattern_place, pattern_end); - - /* Restore register info. */ - *highest_active_reg = (unsigned) POP_FAILURE_ITEM (); - DEBUG_PRINT2 (" Popping high active reg: %d\n", *highest_active_reg); - - *lowest_active_reg = (unsigned) POP_FAILURE_ITEM (); - DEBUG_PRINT2 (" Popping low active reg: %d\n", *lowest_active_reg); - - for (this_reg = *highest_active_reg; this_reg >= *lowest_active_reg; - this_reg--) - { - DEBUG_PRINT2 (" Popping reg: %d\n", this_reg); - - (*reg_info)[this_reg].word = POP_FAILURE_ITEM (); - DEBUG_PRINT2 (" info: 0x%x\n", (*reg_info)[this_reg]); - - (*regend)[this_reg] = POP_FAILURE_ITEM (); - DEBUG_PRINT2 (" end: 0x%x\n", (*regend)[this_reg]); - - (*regstart)[this_reg] = POP_FAILURE_ITEM (); - DEBUG_PRINT2 (" start: 0x%x\n", (*regstart)[this_reg]); - } - } /* pop_failure_point */ - - /* We are passed P pointing to a register number after a start_memory. Return true if the pattern up to the corresponding stop_memory can --- 4334,4339 ---- *************** *** 4766,4775 **** { reg_errcode_t ret; unsigned syntax ! = cflags & REG_EXTENDED ? RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC; /* regex_compile will allocate the space for the compiled pattern. */ preg->buffer = 0; /* Don't bother to use a fastmap when searching. This simplifies the REG_NEWLINE case: if we used a fastmap, we'd have to put all the --- 4731,4742 ---- { reg_errcode_t ret; unsigned syntax ! = (cflags & REG_EXTENDED) ? ! RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC; /* regex_compile will allocate the space for the compiled pattern. */ preg->buffer = 0; + preg->allocated = 0; /* Don't bother to use a fastmap when searching. This simplifies the REG_NEWLINE case: if we used a fastmap, we'd have to put all the *************** *** 4787,4793 **** /* Map uppercase characters to corresponding lowercase ones. */ for (i = 0; i < CHAR_SET_SIZE; i++) ! preg->translate[i] = isupper (i) ? tolower (i) : i; } else preg->translate = NULL; --- 4754,4760 ---- /* Map uppercase characters to corresponding lowercase ones. */ for (i = 0; i < CHAR_SET_SIZE; i++) ! preg->translate[i] = ISUPPER (i) ? tolower (i) : i; } else preg->translate = NULL; *************** *** 4894,4900 **** /* Returns a message corresponding to an error code, ERRCODE, returned ! from either regcomp or regexec. */ size_t regerror (errcode, preg, errbuf, errbuf_size) --- 4861,4867 ---- /* Returns a message corresponding to an error code, ERRCODE, returned ! from either regcomp or regexec. We don't use PREG here. */ size_t regerror (errcode, preg, errbuf, errbuf_size) *************** *** 4903,4911 **** char *errbuf; size_t errbuf_size; { ! const char *msg ! = re_error_msg[errcode] == NULL ? "Success" : re_error_msg[errcode]; ! size_t msg_size = strlen (msg) + 1; /* Includes the null. */ if (errbuf_size != 0) { --- 4870,4887 ---- char *errbuf; size_t errbuf_size; { ! const char *msg; ! size_t msg_size; ! ! if (errcode < 0 ! || errcode >= (sizeof (re_error_msg) / sizeof (re_error_msg[0]))) ! /* Only error codes returned by the rest of the code should be passed ! to this routine. If we are given anything else, or if other regex ! code generates an invalid error code, then the program has a bug. ! Dump core so we can fix it. */ ! abort (); ! ! msg_size = strlen (msg) + 1; /* Includes the null. */ if (errbuf_size != 0) { diff -c3 tar-1.11.1/regex.h tar-1.11.2/regex.h *** tar-1.11.1/regex.h Fri Sep 11 07:46:59 1992 --- tar-1.11.2/regex.h Thu Jan 14 15:38:21 1993 *************** *** 1,5 **** /* Definitions for data structures and routines for the regular ! expression library, version 0.10a. Copyright (C) 1985, 89, 90, 91, 92 Free Software Foundation, Inc. --- 1,5 ---- /* Definitions for data structures and routines for the regular ! expression library, version 0.11. Copyright (C) 1985, 89, 90, 91, 92 Free Software Foundation, Inc. *************** *** 20,27 **** #ifndef __REGEXP_LIBRARY_H__ #define __REGEXP_LIBRARY_H__ ! /* POSIX says that must be included before . */ /* The following bits are used to determine the regexp syntax we recognize. The set/not-set meanings are chosen so that Emacs syntax remains the value 0. The bits are given in alphabetical order, and --- 20,35 ---- #ifndef __REGEXP_LIBRARY_H__ #define __REGEXP_LIBRARY_H__ ! /* POSIX says that must be included (by the caller) before ! . */ + #ifdef VMS + /* VMS doesn't have `size_t' in , even though POSIX says it + should be there. */ + #include + #endif + + /* The following bits are used to determine the regexp syntax we recognize. The set/not-set meanings are chosen so that Emacs syntax remains the value 0. The bits are given in alphabetical order, and *************** *** 95,108 **** If not set, newline is literal. */ #define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1) - /* If this bit is set, newline in the pattern is an ordinary character. - If not set, a ^ after a newline or $ before might be an anchor. */ - #define RE_NEWLINE_ORDINARY (RE_NEWLINE_ALT << 1) - /* If this bit is set, then `{...}' defines an interval, and \{ and \} are literals. If not set, then `\{...\}' defines an interval. */ ! #define RE_NO_BK_BRACES (RE_NEWLINE_ORDINARY << 1) /* If this bit is set, (...) defines a group, and \( and \) are literals. If not set, \(...\) defines a group, and ( and ) are literals. */ --- 103,112 ---- If not set, newline is literal. */ #define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1) /* If this bit is set, then `{...}' defines an interval, and \{ and \} are literals. If not set, then `\{...\}' defines an interval. */ ! #define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1) /* If this bit is set, (...) defines a group, and \( and \) are literals. If not set, \(...\) defines a group, and ( and ) are literals. */ *************** *** 116,140 **** If not set, then \| is an alternation operator, and | is literal. */ #define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1) - /* If this bit is set, then you can't have empty groups. - If not set, then you can. */ - #define RE_NO_EMPTY_GROUPS (RE_NO_BK_VBAR << 1) - /* If this bit is set, then an ending range point collating higher than the starting range point, as in [z-a], is invalid. If not set, then when ending range point collates higher than the starting range point, the range is ignored. */ ! #define RE_NO_EMPTY_RANGES (RE_NO_EMPTY_GROUPS << 1) ! ! /* If this bit is set, then \ where the pattern has no preceding ! th subexpression is invalid. ! If not set, then a back reference to a nonexistent subexpression is ! treated as literal characters. */ ! #define RE_NO_MISSING_BK_REF (RE_NO_EMPTY_RANGES << 1) /* If this bit is set, then an unmatched ) is ordinary. If not set, then an unmatched ) is invalid. */ ! #define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_MISSING_BK_REF << 1) /* This global variable defines the particular regexp syntax to use (for some interfaces). When a regexp is compiled, the syntax used is --- 120,134 ---- If not set, then \| is an alternation operator, and | is literal. */ #define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1) /* If this bit is set, then an ending range point collating higher than the starting range point, as in [z-a], is invalid. If not set, then when ending range point collates higher than the starting range point, the range is ignored. */ ! #define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1) /* If this bit is set, then an unmatched ) is ordinary. If not set, then an unmatched ) is invalid. */ ! #define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1) /* This global variable defines the particular regexp syntax to use (for some interfaces). When a regexp is compiled, the syntax used is *************** *** 150,158 **** #define RE_SYNTAX_AWK \ (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \ ! | RE_NEWLINE_ORDINARY | RE_NO_BK_PARENS \ ! | RE_NO_BK_REFS | RE_NO_BK_VAR \ ! | RE_NO_EMPTY_RANGES | RE_UNMATCHED_RIGHT_PAREN_ORD) #define RE_SYNTAX_POSIX_AWK \ (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS) --- 144,152 ---- #define RE_SYNTAX_AWK \ (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \ ! | RE_NO_BK_PARENS | RE_NO_BK_REFS \ ! | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \ ! | RE_UNMATCHED_RIGHT_PAREN_ORD) #define RE_SYNTAX_POSIX_AWK \ (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS) *************** *** 171,195 **** #define RE_SYNTAX_POSIX_EGREP \ (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES) /* Syntax bits common to both basic and extended POSIX regex syntax. */ #define _RE_SYNTAX_POSIX_COMMON \ (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \ ! | RE_INTERVALS | RE_NEWLINE_ORDINARY | RE_NO_EMPTY_RANGES) #define RE_SYNTAX_POSIX_BASIC \ ! (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM | RE_NO_MISSING_BK_REF) /* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this isn't minimal, since other operators, such as \`, aren't disabled. */ #define RE_SYNTAX_POSIX_MINIMAL_BASIC \ ! (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS | RE_NO_MISSING_BK_REF) #define RE_SYNTAX_POSIX_EXTENDED \ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \ | RE_NO_BK_PARENS | RE_NO_BK_VBAR \ ! | RE_NO_EMPTY_GROUPS | RE_UNMATCHED_RIGHT_PAREN_ORD) /* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */ --- 165,194 ---- #define RE_SYNTAX_POSIX_EGREP \ (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES) + /* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */ + #define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC + + #define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC + /* Syntax bits common to both basic and extended POSIX regex syntax. */ #define _RE_SYNTAX_POSIX_COMMON \ (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \ ! | RE_INTERVALS | RE_NO_EMPTY_RANGES) #define RE_SYNTAX_POSIX_BASIC \ ! (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM) /* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this isn't minimal, since other operators, such as \`, aren't disabled. */ #define RE_SYNTAX_POSIX_MINIMAL_BASIC \ ! (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS) #define RE_SYNTAX_POSIX_EXTENDED \ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \ | RE_NO_BK_PARENS | RE_NO_BK_VBAR \ ! | RE_UNMATCHED_RIGHT_PAREN_ORD) /* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */ *************** *** 197,204 **** (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \ | RE_NO_BK_PARENS | RE_NO_BK_REFS \ ! | RE_NO_BK_VBAR | RE_NO_EMPTY_GROUPS \ ! | RE_UNMATCHED_RIGHT_PAREN_ORD) /* [[[end syntaxes]]] */ /* Maximum number of duplicates an interval can allow. Some systems --- 196,202 ---- (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \ | RE_NO_BK_PARENS | RE_NO_BK_REFS \ ! | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD) /* [[[end syntaxes]]] */ /* Maximum number of duplicates an interval can allow. Some systems *************** *** 324,335 **** #define REGS_FIXED 2 unsigned regs_allocated : 2; ! /* Set to zero when regex_compile compiles a pattern; set to one ! by re_compile_fastmap when it updates the fastmap, if any. */ unsigned fastmap_accurate : 1; ! /* If set, regexec reports only success or failure and does not ! return anything in pmatch. */ unsigned no_sub : 1; /* If set, a beginning-of-line anchor doesn't match at the --- 322,333 ---- #define REGS_FIXED 2 unsigned regs_allocated : 2; ! /* Set to zero when `regex_compile' compiles a pattern; set to one ! by `re_compile_fastmap' if it updates the fastmap. */ unsigned fastmap_accurate : 1; ! /* If set, `re_match_2' does not return information about ! subexpressions. */ unsigned no_sub : 1; /* If set, a beginning-of-line anchor doesn't match at the *************** *** 389,404 **** prototype (if we are ANSI), and once without (if we aren't) -- we use the following macro to declare argument types. This unfortunately clutters up the declarations a bit, but I think it's ! worth it. ! ! We also have to undo `const' if we are not ANSI. */ #if __STDC__ #define _RE_ARGS(args) args ! #else #define _RE_ARGS(args) () ! #define const ! #endif /* Sets the current default syntax to SYNTAX, and return the old syntax. You can also simply assign to the `re_syntax_options' variable. */ --- 387,403 ---- prototype (if we are ANSI), and once without (if we aren't) -- we use the following macro to declare argument types. This unfortunately clutters up the declarations a bit, but I think it's ! worth it. */ #if __STDC__ + #define _RE_ARGS(args) args ! ! #else /* not __STDC__ */ ! #define _RE_ARGS(args) () ! ! #endif /* not __STDC__ */ /* Sets the current default syntax to SYNTAX, and return the old syntax. You can also simply assign to the `re_syntax_options' variable. */ diff -c3 tar-1.11.1/rmt.c tar-1.11.2/rmt.c *** tar-1.11.1/rmt.c Tue Sep 15 20:06:58 1992 --- tar-1.11.2/rmt.c Fri Sep 18 14:45:31 1992 *************** *** 42,48 **** #ifdef HAVE_UNISTD_H #include #else ! long lseek(); #endif #ifdef STDC_HEADERS --- 42,48 ---- #ifdef HAVE_UNISTD_H #include #else ! long lseek (); #endif #ifdef STDC_HEADERS *************** *** 49,271 **** #include #include #else ! extern char *malloc(); #endif ! int tape = -1; ! char *record; ! int maxrecsize = -1; ! char *checkbuf(); ! void getstring(); ! void error(); #define SSIZE 64 ! char device[SSIZE]; ! char count[SSIZE], mode[SSIZE], pos[SSIZE], op[SSIZE]; ! extern errno; ! extern char *sys_errlist[]; ! char resp[BUFSIZ]; ! FILE *debug; #define DEBUG(f) if (debug) fprintf(debug, f) #define DEBUG1(f,a) if (debug) fprintf(debug, f, a) #define DEBUG2(f,a1,a2) if (debug) fprintf(debug, f, a1, a2) int ! main(argc, argv) ! int argc; ! char **argv; { ! int rval; ! char c; ! int n, i, cc; ! ! argc--, argv++; ! if (argc > 0) { ! debug = fopen(*argv, "w"); ! if (debug == 0) ! exit(1); ! (void) setbuf(debug, (char *)0); ! } top: ! errno = 0; ! rval = 0; ! if (read(0, &c, 1) != 1) ! exit(0); ! switch (c) { ! ! case 'O': ! if (tape >= 0) ! (void) close(tape); ! getstring(device); getstring(mode); ! DEBUG2("rmtd: O %s %s\n", device, mode); #if defined (i386) && defined (AIX) ! /* This is alleged to fix a byte ordering problem. */ ! /* I'm quite suspicious if it's right. -- mib */ ! { ! int oflag = atoi (mode); ! int nflag = 0; ! if ((oflag & 3) == 0) ! nflag |= O_RDONLY; ! if (oflag & 1) ! nflag |= O_WRONLY; ! if (oflag & 2) ! nflag |= O_RDWR; ! if (oflag & 0x0008) ! nflag |= O_APPEND; ! if (oflag & 0x0200) ! nflag |= O_CREAT; ! if (oflag & 0x0400) ! nflag |= O_TRUNC; ! if (oflag & 0x0800) ! nflag |= O_EXCL; ! tape = open (device, nflag, 0666); ! } ! #else ! tape = open(device, atoi(mode),0666); ! #endif ! if (tape < 0) ! goto ioerror; ! goto respond; ! ! case 'C': ! DEBUG("rmtd: C\n"); ! getstring(device); /* discard */ ! if (close(tape) < 0) ! goto ioerror; ! tape = -1; ! goto respond; ! ! case 'L': ! getstring(count); getstring(pos); ! DEBUG2("rmtd: L %s %s\n", count, pos); ! rval = lseek(tape, (long) atoi(count), atoi(pos)); ! if (rval < 0) ! goto ioerror; ! goto respond; ! ! case 'W': ! getstring(count); ! n = atoi(count); ! DEBUG1("rmtd: W %s\n", count); ! record = checkbuf(record, n); ! for (i = 0; i < n; i += cc) { ! cc = read(0, &record[i], n - i); ! if (cc <= 0) { ! DEBUG("rmtd: premature eof\n"); ! exit(2); ! } ! } ! rval = write(tape, record, n); ! if (rval < 0) ! goto ioerror; ! goto respond; ! ! case 'R': ! getstring(count); ! DEBUG1("rmtd: R %s\n", count); ! n = atoi(count); ! record = checkbuf(record, n); ! rval = read(tape, record, n); ! if (rval < 0) ! goto ioerror; ! (void) sprintf(resp, "A%d\n", rval); ! (void) write(1, resp, strlen(resp)); ! (void) write(1, record, rval); ! goto top; ! ! case 'I': ! getstring(op); getstring(count); ! DEBUG2("rmtd: I %s %s\n", op, count); #ifdef MTIOCTOP ! { struct mtop mtop; ! mtop.mt_op = atoi(op); ! mtop.mt_count = atoi(count); ! if (ioctl(tape, MTIOCTOP, (char *)&mtop) < 0) ! goto ioerror; ! rval = mtop.mt_count; ! } ! #endif ! goto respond; ! ! case 'S': /* status */ ! DEBUG("rmtd: S\n"); ! { #ifdef MTIOCGET ! struct mtget mtget; ! if (ioctl(tape, MTIOCGET, (char *)&mtget) < 0) ! goto ioerror; ! rval = sizeof (mtget); ! (void) sprintf(resp, "A%d\n", rval); ! (void) write(1, resp, strlen(resp)); ! (void) write(1, (char *)&mtget, sizeof (mtget)); ! #endif ! goto top; ! } ! ! default: ! DEBUG1("rmtd: garbage command %c\n", c); ! exit(3); ! } ! respond: ! DEBUG1("rmtd: A %d\n", rval); ! (void) sprintf(resp, "A%d\n", rval); ! (void) write(1, resp, strlen(resp)); goto top; ioerror: ! error(errno); ! goto top; } void ! getstring(bp) ! char *bp; { ! int i; ! char *cp = bp; ! for (i = 0; i < SSIZE; i++) { ! if (read(0, cp+i, 1) != 1) ! exit(0); ! if (cp[i] == '\n') ! break; ! } ! cp[i] = '\0'; } char * ! checkbuf(record, size) ! char *record; ! int size; { ! if (size <= maxrecsize) ! return (record); ! if (record != 0) ! free(record); ! record = malloc(size); ! if (record == 0) { ! DEBUG("rmtd: cannot allocate buffer space\n"); ! exit(4); ! } ! maxrecsize = size; #ifdef SO_RCVBUF ! while (size > 1024 && ! setsockopt(0, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof (size)) < 0) ! size -= 1024; #else ! size= 1+((size-1)%1024); #endif ! return (record); } void ! error(num) ! int num; { ! DEBUG2("rmtd: E %d (%s)\n", num, sys_errlist[num]); ! (void) sprintf(resp, "E%d\n%s\n", num, sys_errlist[num]); ! (void) write(1, resp, strlen (resp)); } --- 49,281 ---- #include #include #else ! extern char *malloc (); #endif ! int tape = -1; ! char *record; ! int maxrecsize = -1; ! char *checkbuf (); ! void getstring (); ! void error (); #define SSIZE 64 ! char device[SSIZE]; ! char count[SSIZE], mode[SSIZE], pos[SSIZE], op[SSIZE]; ! extern errno; ! extern char *sys_errlist[]; ! char resp[BUFSIZ]; ! FILE *debug; #define DEBUG(f) if (debug) fprintf(debug, f) #define DEBUG1(f,a) if (debug) fprintf(debug, f, a) #define DEBUG2(f,a1,a2) if (debug) fprintf(debug, f, a1, a2) int ! main (argc, argv) ! int argc; ! char **argv; { ! int rval; ! char c; ! int n, i, cc; ! ! argc--, argv++; ! if (argc > 0) ! { ! debug = fopen (*argv, "w"); ! if (debug == 0) ! exit (1); ! (void) setbuf (debug, (char *) 0); ! } top: ! errno = 0; ! rval = 0; ! if (read (0, &c, 1) != 1) ! exit (0); ! switch (c) ! { ! ! case 'O': ! if (tape >= 0) ! (void) close (tape); ! getstring (device); ! getstring (mode); ! DEBUG2 ("rmtd: O %s %s\n", device, mode); #if defined (i386) && defined (AIX) ! /* This is alleged to fix a byte ordering problem. */ ! /* I'm quite suspicious if it's right. -- mib */ ! { ! int oflag = atoi (mode); ! int nflag = 0; ! if ((oflag & 3) == 0) ! nflag |= O_RDONLY; ! if (oflag & 1) ! nflag |= O_WRONLY; ! if (oflag & 2) ! nflag |= O_RDWR; ! if (oflag & 0x0008) ! nflag |= O_APPEND; ! if (oflag & 0x0200) ! nflag |= O_CREAT; ! if (oflag & 0x0400) ! nflag |= O_TRUNC; ! if (oflag & 0x0800) ! nflag |= O_EXCL; ! tape = open (device, nflag, 0666); ! } ! #else ! tape = open (device, atoi (mode), 0666); ! #endif ! if (tape < 0) ! goto ioerror; ! goto respond; ! ! case 'C': ! DEBUG ("rmtd: C\n"); ! getstring (device); /* discard */ ! if (close (tape) < 0) ! goto ioerror; ! tape = -1; ! goto respond; ! ! case 'L': ! getstring (count); ! getstring (pos); ! DEBUG2 ("rmtd: L %s %s\n", count, pos); ! rval = lseek (tape, (long) atoi (count), atoi (pos)); ! if (rval < 0) ! goto ioerror; ! goto respond; ! ! case 'W': ! getstring (count); ! n = atoi (count); ! DEBUG1 ("rmtd: W %s\n", count); ! record = checkbuf (record, n); ! for (i = 0; i < n; i += cc) ! { ! cc = read (0, &record[i], n - i); ! if (cc <= 0) ! { ! DEBUG ("rmtd: premature eof\n"); ! exit (2); ! } ! } ! rval = write (tape, record, n); ! if (rval < 0) ! goto ioerror; ! goto respond; ! ! case 'R': ! getstring (count); ! DEBUG1 ("rmtd: R %s\n", count); ! n = atoi (count); ! record = checkbuf (record, n); ! rval = read (tape, record, n); ! if (rval < 0) ! goto ioerror; ! (void) sprintf (resp, "A%d\n", rval); ! (void) write (1, resp, strlen (resp)); ! (void) write (1, record, rval); ! goto top; ! ! case 'I': ! getstring (op); ! getstring (count); ! DEBUG2 ("rmtd: I %s %s\n", op, count); #ifdef MTIOCTOP ! { ! struct mtop mtop; ! mtop.mt_op = atoi (op); ! mtop.mt_count = atoi (count); ! if (ioctl (tape, MTIOCTOP, (char *) &mtop) < 0) ! goto ioerror; ! rval = mtop.mt_count; ! } ! #endif ! goto respond; ! ! case 'S': /* status */ ! DEBUG ("rmtd: S\n"); ! { #ifdef MTIOCGET ! struct mtget mtget; ! if (ioctl (tape, MTIOCGET, (char *) &mtget) < 0) ! goto ioerror; ! rval = sizeof (mtget); ! (void) sprintf (resp, "A%d\n", rval); ! (void) write (1, resp, strlen (resp)); ! (void) write (1, (char *) &mtget, sizeof (mtget)); ! #endif goto top; + } + + default: + DEBUG1 ("rmtd: garbage command %c\n", c); + exit (3); + } + respond: + DEBUG1 ("rmtd: A %d\n", rval); + (void) sprintf (resp, "A%d\n", rval); + (void) write (1, resp, strlen (resp)); + goto top; ioerror: ! error (errno); ! goto top; } void ! getstring (bp) ! char *bp; { ! int i; ! char *cp = bp; ! for (i = 0; i < SSIZE; i++) ! { ! if (read (0, cp + i, 1) != 1) ! exit (0); ! if (cp[i] == '\n') ! break; ! } ! cp[i] = '\0'; } char * ! checkbuf (record, size) ! char *record; ! int size; { ! if (size <= maxrecsize) ! return (record); ! if (record != 0) ! free (record); ! record = malloc (size); ! if (record == 0) ! { ! DEBUG ("rmtd: cannot allocate buffer space\n"); ! exit (4); ! } ! maxrecsize = size; #ifdef SO_RCVBUF ! while (size > 1024 && ! setsockopt (0, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof (size)) < 0) ! size -= 1024; #else ! size = 1 + ((size - 1) % 1024); #endif ! return (record); } void ! error (num) ! int num; { ! DEBUG2 ("rmtd: E %d (%s)\n", num, sys_errlist[num]); ! (void) sprintf (resp, "E%d\n%s\n", num, sys_errlist[num]); ! (void) write (1, resp, strlen (resp)); } diff -c3 tar-1.11.1/rmt.h tar-1.11.2/rmt.h *** tar-1.11.1/rmt.h Thu Sep 3 14:32:03 1992 --- tar-1.11.2/rmt.h Tue Nov 24 10:38:14 1992 *************** *** 23,29 **** #ifdef __MSDOS__ #include #else /* !__MSDOS__ */ ! extern off_t lseek(); #endif /* __MSDOS__ */ #endif /* _POSIX_VERSION */ --- 23,29 ---- #ifdef __MSDOS__ #include #else /* !__MSDOS__ */ ! extern off_t lseek (); #endif /* __MSDOS__ */ #endif /* _POSIX_VERSION */ *************** *** 55,65 **** extern char *__rmt_path; ! #if defined(USG) || defined(STDC_HEADERS) #include #define index strchr #else ! extern char *index(); #endif #define _remdev(path) (!f_force_local && (__rmt_path=index(path, ':'))) --- 55,67 ---- extern char *__rmt_path; ! #if defined(STDC_HEADERS) || defined(HAVE_STRING_H) #include + #ifndef index #define index strchr + #endif #else ! extern char *index (); #endif #define _remdev(path) (!f_force_local && (__rmt_path=index(path, ':'))) *************** *** 91,96 **** int __rmt_close (); int __rmt_read (); int __rmt_write (); ! long __rmt_lseek(); int __rmt_ioctl (); #endif /* !NO_REMOTE */ --- 93,98 ---- int __rmt_close (); int __rmt_read (); int __rmt_write (); ! long __rmt_lseek (); int __rmt_ioctl (); #endif /* !NO_REMOTE */ diff -c3 tar-1.11.1/rtapelib.c tar-1.11.2/rtapelib.c *** tar-1.11.1/rtapelib.c Sun Jul 19 02:16:23 1992 --- tar-1.11.2/rtapelib.c Fri Sep 18 14:45:37 1992 *************** *** 24,30 **** and to separate the various arguments with \n instead of a space. I personally don't think that this is much of a problem, but I wanted to point it out. -- Arnold Robbins ! Originally written by Jeff Lee, modified some by Arnold Robbins. Redone as a library that can replace open, read, write, etc., by Fred Fish, with some additional work by Arnold Robbins. --- 24,30 ---- and to separate the various arguments with \n instead of a space. I personally don't think that this is much of a problem, but I wanted to point it out. -- Arnold Robbins ! Originally written by Jeff Lee, modified some by Arnold Robbins. Redone as a library that can replace open, read, write, etc., by Fred Fish, with some additional work by Arnold Robbins. *************** *** 82,91 **** #define WRITE(fildes) (to_rmt[fildes][1]) /* The pipes for receiving data from remote tape drives. */ ! static int from_rmt[MAXUNIT][2] = {-1, -1, -1, -1, -1, -1, -1, -1}; /* The pipes for sending data to remote tape drives. */ ! static int to_rmt[MAXUNIT][2] = {-1, -1, -1, -1, -1, -1, -1, -1}; /* Temporary variable used by macros in rmt.h. */ char *__rmt_path; --- 82,93 ---- #define WRITE(fildes) (to_rmt[fildes][1]) /* The pipes for receiving data from remote tape drives. */ ! static int from_rmt[MAXUNIT][2] = ! {-1, -1, -1, -1, -1, -1, -1, -1}; /* The pipes for sending data to remote tape drives. */ ! static int to_rmt[MAXUNIT][2] = ! {-1, -1, -1, -1, -1, -1, -1, -1}; /* Temporary variable used by macros in rmt.h. */ char *__rmt_path; *************** *** 92,98 **** /* Close remote tape connection FILDES. */ ! static void _rmt_shutdown (fildes) int fildes; { --- 94,100 ---- /* Close remote tape connection FILDES. */ ! static void _rmt_shutdown (fildes) int fildes; { *************** *** 106,112 **** on remote tape connection FILDES. Return 0 if successful, -1 on error. */ ! static int command (fildes, buf) int fildes; char *buf; --- 108,114 ---- on remote tape connection FILDES. Return 0 if successful, -1 on error. */ ! static int command (fildes, buf) int fildes; char *buf; *************** *** 135,141 **** /* Read and return the status from remote tape connection FILDES. If an error occurred, return -1 and set errno. */ ! static int status (fildes) int fildes; { --- 137,143 ---- /* Read and return the status from remote tape connection FILDES. If an error occurred, return -1 and set errno. */ ! static int status (fildes) int fildes; { *************** *** 248,253 **** --- 250,256 ---- return tape_fd; } + #endif /* HAVE_NETDB_H */ /* Open a magtape device on the system specified in PATH, as the given user. *************** *** 260,266 **** If successful, return the remote tape pipe number plus BIAS. On error, return -1. */ ! int __rmt_open (path, oflag, mode, bias) char *path; int oflag; --- 263,269 ---- If successful, return the remote tape pipe number plus BIAS. On error, return -1. */ ! int __rmt_open (path, oflag, mode, bias) char *path; int oflag; *************** *** 271,277 **** char buffer[CMDBUFSIZE]; /* Command buffer. */ char system[MAXHOSTLEN]; /* The remote host name. */ char device[CMDBUFSIZE]; /* The remote device name. */ ! char login[CMDBUFSIZE]; /* The remote user name. */ char *sys, *dev, *user; /* For copying into the above buffers. */ sys = system; --- 274,280 ---- char buffer[CMDBUFSIZE]; /* Command buffer. */ char system[MAXHOSTLEN]; /* The remote host name. */ char device[CMDBUFSIZE]; /* The remote device name. */ ! char login[CMDBUFSIZE]; /* The remote user name. */ char *sys, *dev, *user; /* For copying into the above buffers. */ sys = system; *************** *** 417,423 **** /* Close remote tape connection FILDES and shut down. Return 0 if successful, -1 on error. */ ! int __rmt_close (fildes) int fildes; { --- 420,426 ---- /* Close remote tape connection FILDES and shut down. Return 0 if successful, -1 on error. */ ! int __rmt_close (fildes) int fildes; { *************** *** 434,440 **** /* Read up to NBYTE bytes into BUF from remote tape connection FILDES. Return the number of bytes read on success, -1 on error. */ ! int __rmt_read (fildes, buf, nbyte) int fildes; char *buf; --- 437,443 ---- /* Read up to NBYTE bytes into BUF from remote tape connection FILDES. Return the number of bytes read on success, -1 on error. */ ! int __rmt_read (fildes, buf, nbyte) int fildes; char *buf; *************** *** 449,455 **** for (i = 0; i < rc; i += nbyte, buf += nbyte) { ! nbyte = read (READ (fildes), buf, rc); if (nbyte <= 0) { _rmt_shutdown (fildes); --- 452,458 ---- for (i = 0; i < rc; i += nbyte, buf += nbyte) { ! nbyte = read (READ (fildes), buf, rc - i); if (nbyte <= 0) { _rmt_shutdown (fildes); *************** *** 464,470 **** /* Write NBYTE bytes from BUF to remote tape connection FILDES. Return the number of bytes written on success, -1 on error. */ ! int __rmt_write (fildes, buf, nbyte) int fildes; char *buf; --- 467,473 ---- /* Write NBYTE bytes from BUF to remote tape connection FILDES. Return the number of bytes written on success, -1 on error. */ ! int __rmt_write (fildes, buf, nbyte) int fildes; char *buf; *************** *** 494,500 **** /* Perform an imitation lseek operation on remote tape connection FILDES. Return the new file offset if successful, -1 if on error. */ ! long __rmt_lseek (fildes, offset, whence) int fildes; long offset; --- 497,503 ---- /* Perform an imitation lseek operation on remote tape connection FILDES. Return the new file offset if successful, -1 if on error. */ ! long __rmt_lseek (fildes, offset, whence) int fildes; long offset; *************** *** 575,578 **** --- 578,582 ---- return 0; } } + #endif diff -c3 tar-1.11.1/tar.c tar-1.11.2/tar.c *** tar-1.11.1/tar.c Mon Sep 14 17:31:38 1992 --- tar-1.11.2/tar.c Wed Mar 17 10:30:46 1993 *************** *** 1,5 **** /* Tar -- a tape archiver. ! Copyright (C) 1988, 1992 Free Software Foundation This file is part of GNU Tar. --- 1,5 ---- /* Tar -- a tape archiver. ! Copyright (C) 1988, 1992, 1993 Free Software Foundation This file is part of GNU Tar. *************** *** 27,64 **** #include /* Needed for typedefs in tar.h */ #include "getopt.h" #include "regex.h" - #include "fnmatch.h" /* * The following causes "tar.h" to produce definitions of all the * global variables, rather than just "extern" declarations of them. */ ! #define TAR_EXTERN /**/ #include "tar.h" #include "port.h" ! ! #if defined(_POSIX_VERSION) || defined(DIRENT) ! #include ! #ifdef direct ! #undef direct ! #endif /* direct */ ! #define direct dirent ! #define DP_NAMELEN(x) strlen((x)->d_name) ! #endif /* _POSIX_VERSION or DIRENT */ ! #if !defined(_POSIX_VERSION) && !defined(DIRENT) && defined(BSD42) ! #include ! #define DP_NAMELEN(x) (x)->d_namlen ! #endif /* not _POSIX_VERSION and BSD42 */ ! #ifdef __MSDOS__ ! #include "msd_dir.h" ! #define DP_NAMELEN(x) (x)->d_namlen ! #define direct dirent ! #endif ! #if defined(USG) && !defined(_POSIX_VERSION) && !defined(DIRENT) ! #include ! #define DP_NAMELEN(x) strlen((x)->d_name) ! #endif /* USG and not _POSIX_VERSION and not DIRENT */ /* * We should use a conversion routine that does reasonable error --- 27,42 ---- #include /* Needed for typedefs in tar.h */ #include "getopt.h" #include "regex.h" /* * The following causes "tar.h" to produce definitions of all the * global variables, rather than just "extern" declarations of them. */ ! #define TAR_EXTERN /**/ #include "tar.h" #include "port.h" ! #include "fnmatch.h" /* * We should use a conversion routine that does reasonable error *************** *** 65,109 **** * checking -- atoi doesn't. For now, punt. FIXME. */ #define intconv atoi ! PTR ck_malloc(); ! PTR ck_realloc(); ! extern int getoldopt(); ! extern void read_and(); ! extern void list_archive(); ! extern void extract_archive(); ! extern void diff_archive(); ! extern void create_archive(); ! extern void update_archive(); ! extern void junk_archive(); /* JF */ ! extern time_t get_date(); time_t new_time; ! static FILE *namef; /* File to read names from */ ! static char **n_argv; /* Argv used by name routines */ ! static int n_argc; /* Argc used by name routines */ ! static char **n_ind; /* Store an array of names */ ! static int n_indalloc; /* How big is the array? */ ! static int n_indused; /* How many entries does it have? */ ! static int n_indscan; /* How many of the entries have we scanned? */ extern FILE *msg_file; ! int check_exclude(); ! void add_exclude(); ! void add_exclude_file(); ! void addname(); ! void describe(); ! void diff_init(); ! void extr_init(); ! int is_regex(); ! void name_add(); ! void name_init(); ! void options(); ! char *un_quote_string(); #ifndef S_ISLNK #define lstat stat --- 43,89 ---- * checking -- atoi doesn't. For now, punt. FIXME. */ #define intconv atoi ! PTR ck_malloc (); ! PTR ck_realloc (); ! extern int getoldopt (); ! extern void read_and (); ! extern void list_archive (); ! extern void extract_archive (); ! extern void diff_archive (); ! extern void create_archive (); ! extern void update_archive (); ! extern void junk_archive (); ! extern void init_volume_number (); ! extern void closeout_volume_number (); /* JF */ ! extern time_t get_date (); time_t new_time; ! static FILE *namef; /* File to read names from */ ! static char **n_argv; /* Argv used by name routines */ ! static int n_argc; /* Argc used by name routines */ ! static char **n_ind; /* Store an array of names */ ! static int n_indalloc; /* How big is the array? */ ! static int n_indused; /* How many entries does it have? */ ! static int n_indscan; /* How many of the entries have we scanned? */ extern FILE *msg_file; ! int check_exclude (); ! void add_exclude (); ! void add_exclude_file (); ! void addname (); ! void describe (); ! void diff_init (); ! void extr_init (); ! int is_regex (); ! void name_add (); ! void name_init (); ! void options (); ! char *un_quote_string (); #ifndef S_ISLNK #define lstat stat *************** *** 126,200 **** struct option long_options[] = { ! {"create", 0, 0, 'c'}, ! {"append", 0, 0, 'r'}, ! {"extract", 0, 0, 'x'}, ! {"get", 0, 0, 'x'}, ! {"list", 0, 0, 't'}, ! {"update", 0, 0, 'u'}, ! {"catenate", 0, 0, 'A'}, ! {"concatenate", 0, 0, 'A'}, ! {"compare", 0, 0, 'd'}, ! {"diff", 0, 0, 'd'}, ! {"delete", 0, 0, 14}, ! {"help", 0, 0, 12}, ! ! {"null", 0, 0, 16}, ! {"directory", 1, 0, 'C'}, ! {"record-number", 0, &f_sayblock, 1}, ! {"files-from", 1, 0, 'T'}, ! {"label", 1, 0, 'V'}, ! {"exclude-from", 1, 0, 'X'}, ! {"exclude", 1, 0, 15}, ! {"file", 1, 0, 'f'}, ! {"block-size", 1, 0, 'b'}, ! {"version", 0, 0, 11}, ! {"verbose", 0, 0, 'v'}, ! {"totals", 0, &f_totals, 1}, ! ! {"read-full-blocks", 0, &f_reblock, 1}, ! {"starting-file", 1, 0, 'K'}, ! {"to-stdout", 0, &f_exstdout, 1}, ! {"ignore-zeros", 0, &f_ignorez, 1}, ! {"keep-old-files", 0, 0, 'k'}, ! {"uncompress", 0, &f_compress, 1}, ! {"same-permissions", 0, &f_use_protection, 1}, ! {"preserve-permissions",0, &f_use_protection, 1}, ! {"modification-time", 0, &f_modified, 1}, ! {"preserve", 0, 0, 10}, ! {"same-order", 0, &f_sorted_names, 1}, ! {"same-owner", 0, &f_do_chown, 1}, ! {"preserve-order", 0, &f_sorted_names, 1}, ! ! {"newer", 1, 0, 'N'}, ! {"after-date", 1, 0, 'N'}, ! {"newer-mtime", 1, 0, 13}, ! {"incremental", 0, 0, 'G'}, ! {"listed-incremental", 1, 0, 'g'}, ! {"multi-volume", 0, &f_multivol, 1}, ! {"info-script", 1, 0, 'F'}, ! {"absolute-paths", 0, &f_absolute_paths, 1}, ! {"interactive", 0, &f_confirm, 1}, ! {"confirmation", 0, &f_confirm, 1}, ! ! {"verify", 0, &f_verify, 1}, ! {"dereference", 0, &f_follow_links, 1}, ! {"one-file-system", 0, &f_local_filesys, 1}, ! {"old-archive", 0, 0, 'o'}, ! {"portability", 0, 0, 'o'}, ! {"compress", 0, &f_compress, 1}, ! {"compress-block", 0, &f_compress, 2}, ! {"sparse", 0, &f_sparse_files, 1}, ! {"tape-length", 1, 0, 'L'}, ! {"remove-files", 0, &f_remove_files, 1}, ! {"ignore-failed-read", 0, &f_ignore_failed_read, 1}, ! {"checkpoint", 0, &f_checkpoint, 1}, ! {"show-omitted-dirs", 0, &f_show_omitted_dirs, 1}, ! {"volno-file", 1, 0, 17}, ! {"force-local", 0, &f_force_local, 1}, ! {"atime-preserve", 0, &f_atime_preserve, 1}, ! {0, 0, 0, 0} }; /* --- 106,187 ---- struct option long_options[] = { ! {"create", 0, 0, 'c'}, ! {"append", 0, 0, 'r'}, ! {"extract", 0, 0, 'x'}, ! {"get", 0, 0, 'x'}, ! {"list", 0, 0, 't'}, ! {"update", 0, 0, 'u'}, ! {"catenate", 0, 0, 'A'}, ! {"concatenate", 0, 0, 'A'}, ! {"compare", 0, 0, 'd'}, ! {"diff", 0, 0, 'd'}, ! {"delete", 0, 0, 14}, ! {"help", 0, 0, 12}, ! ! {"null", 0, 0, 16}, ! {"directory", 1, 0, 'C'}, ! {"record-number", 0, &f_sayblock, 1}, ! {"files-from", 1, 0, 'T'}, ! {"label", 1, 0, 'V'}, ! {"exclude-from", 1, 0, 'X'}, ! {"exclude", 1, 0, 15}, ! {"file", 1, 0, 'f'}, ! {"block-size", 1, 0, 'b'}, ! {"version", 0, 0, 11}, ! {"verbose", 0, 0, 'v'}, ! {"totals", 0, &f_totals, 1}, ! ! {"read-full-blocks", 0, &f_reblock, 1}, ! {"starting-file", 1, 0, 'K'}, ! {"to-stdout", 0, &f_exstdout, 1}, ! {"ignore-zeros", 0, &f_ignorez, 1}, ! {"keep-old-files", 0, 0, 'k'}, ! {"same-permissions", 0, &f_use_protection, 1}, ! {"preserve-permissions", 0, &f_use_protection, 1}, ! {"modification-time", 0, &f_modified, 1}, ! {"preserve", 0, 0, 10}, ! {"same-order", 0, &f_sorted_names, 1}, ! {"same-owner", 0, &f_do_chown, 1}, ! {"preserve-order", 0, &f_sorted_names, 1}, ! ! {"newer", 1, 0, 'N'}, ! {"after-date", 1, 0, 'N'}, ! {"newer-mtime", 1, 0, 13}, ! {"incremental", 0, 0, 'G'}, ! {"listed-incremental", 1, 0, 'g'}, ! {"multi-volume", 0, &f_multivol, 1}, ! {"info-script", 1, 0, 'F'}, ! {"new-volume-script", 1, 0, 'F'}, ! {"absolute-paths", 0, &f_absolute_paths, 1}, ! {"interactive", 0, &f_confirm, 1}, ! {"confirmation", 0, &f_confirm, 1}, ! ! {"verify", 0, &f_verify, 1}, ! {"dereference", 0, &f_follow_links, 1}, ! {"one-file-system", 0, &f_local_filesys, 1}, ! {"old-archive", 0, 0, 'o'}, ! {"portability", 0, 0, 'o'}, ! {"compress", 0, 0, 'Z'}, ! {"uncompress", 0, 0, 'Z'}, ! {"block-compress", 0, &f_compress_block, 1}, ! {"gzip", 0, 0, 'z'}, ! {"ungzip", 0, 0, 'z'}, ! {"use-compress-program", 1, 0, 18}, ! ! ! {"same-permissions", 0, &f_use_protection, 1}, ! {"sparse", 0, &f_sparse_files, 1}, ! {"tape-length", 1, 0, 'L'}, ! {"remove-files", 0, &f_remove_files, 1}, ! {"ignore-failed-read", 0, &f_ignore_failed_read, 1}, ! {"checkpoint", 0, &f_checkpoint, 1}, ! {"show-omitted-dirs", 0, &f_show_omitted_dirs, 1}, ! {"volno-file", 1, 0, 17}, ! {"force-local", 0, &f_force_local, 1}, ! {"atime-preserve", 0, &f_atime_preserve, 1}, ! {0, 0, 0, 0} }; /* *************** *** 201,292 **** * Main routine for tar. */ void ! main(argc, argv) ! int argc; ! char **argv; ! { ! extern char version_string[]; ! ! tar = argv[0]; /* JF: was "tar" Set program name */ ! filename_terminator = '\n'; ! errors = 0; ! ! options(argc, argv); ! ! if(!n_argv) ! name_init(argc, argv); ! ! if (f_volno_file) ! init_volume_number (); ! ! switch(cmd_mode) { ! case CMD_CAT: ! case CMD_UPDATE: ! case CMD_APPEND: ! update_archive(); ! break; ! case CMD_DELETE: ! junk_archive(); ! break; ! case CMD_CREATE: ! create_archive(); ! if (f_totals) ! fprintf (stderr, "Total bytes written: %d\n", tot_written); ! break; ! case CMD_EXTRACT: ! if (f_volhdr) { ! const char *err; ! label_pattern = (struct re_pattern_buffer *) ! ck_malloc (sizeof *label_pattern); ! err = re_compile_pattern (f_volhdr, strlen (f_volhdr), ! label_pattern); ! if (err) { ! fprintf (stderr,"Bad regular expression: %s\n", ! err); ! errors++; ! break; ! } ! ! } ! extr_init(); ! read_and(extract_archive); ! break; ! case CMD_LIST: ! if (f_volhdr) { ! const char *err; ! label_pattern = (struct re_pattern_buffer *) ! ck_malloc (sizeof *label_pattern); ! err = re_compile_pattern (f_volhdr, strlen (f_volhdr), ! label_pattern); ! if (err) { ! fprintf (stderr,"Bad regular expression: %s\n", ! err); ! errors++; ! break; ! } ! } ! read_and(list_archive); #if 0 ! if (!errors) ! errors = different; #endif ! break; ! case CMD_DIFF: ! diff_init(); ! read_and(diff_archive); ! break; ! case CMD_VERSION: ! fprintf(stderr,"%s\n",version_string); ! break; ! case CMD_NONE: ! msg("you must specify exactly one of the r, c, t, x, or d options\n"); ! fprintf(stderr,"For more information, type ``%s --help''.\n",tar); ! exit(EX_ARGSBAD); ! } ! if (f_volno_file) ! closeout_volume_number (); ! exit(errors); ! /* NOTREACHED */ } --- 188,284 ---- * Main routine for tar. */ void ! main (argc, argv) ! int argc; ! char **argv; ! { ! extern char version_string[]; ! ! tar = argv[0]; /* JF: was "tar" Set program name */ ! filename_terminator = '\n'; ! errors = 0; ! ! options (argc, argv); ! ! if (!n_argv) ! name_init (argc, argv); ! ! if (f_volno_file) ! init_volume_number (); ! ! switch (cmd_mode) ! { ! case CMD_CAT: ! case CMD_UPDATE: ! case CMD_APPEND: ! update_archive (); ! break; ! case CMD_DELETE: ! junk_archive (); ! break; ! case CMD_CREATE: ! create_archive (); ! if (f_totals) ! fprintf (stderr, "Total bytes written: %d\n", tot_written); ! break; ! case CMD_EXTRACT: ! if (f_volhdr) ! { ! const char *err; ! label_pattern = (struct re_pattern_buffer *) ! ck_malloc (sizeof *label_pattern); ! err = re_compile_pattern (f_volhdr, strlen (f_volhdr), ! label_pattern); ! if (err) ! { ! fprintf (stderr, "Bad regular expression: %s\n", ! err); ! errors++; ! break; ! } ! ! } ! extr_init (); ! read_and (extract_archive); ! break; ! case CMD_LIST: ! if (f_volhdr) ! { ! const char *err; ! label_pattern = (struct re_pattern_buffer *) ! ck_malloc (sizeof *label_pattern); ! err = re_compile_pattern (f_volhdr, strlen (f_volhdr), ! label_pattern); ! if (err) ! { ! fprintf (stderr, "Bad regular expression: %s\n", ! err); ! errors++; ! break; ! } ! } ! read_and (list_archive); #if 0 ! if (!errors) ! errors = different; #endif ! break; ! case CMD_DIFF: ! diff_init (); ! read_and (diff_archive); ! break; ! case CMD_VERSION: ! fprintf (stderr, "%s\n", version_string); ! break; ! case CMD_NONE: ! msg ("you must specify exactly one of the r, c, t, x, or d options\n"); ! fprintf (stderr, "For more information, type ``%s --help''.\n", tar); ! exit (EX_ARGSBAD); ! } ! if (f_volno_file) ! closeout_volume_number (); ! exit (errors); ! /* NOTREACHED */ } *************** *** 294,391 **** * Parse the options for tar. */ void ! options(argc, argv) ! int argc; ! char **argv; ! { ! register int c; /* Option letter */ ! int ind = -1; ! ! /* Set default option values */ ! blocking = DEFBLOCKING; /* From Makefile */ ! ar_files = (char **) malloc (sizeof (char *) * 10); ! ar_files_len = 10; ! n_ar_files = 0; ! cur_ar_file = 0; ! ! /* Parse options */ ! while ((c = getoldopt(argc, argv, ! "-01234567Ab:BcC:df:F:g:GhikK:lL:mMN:oOpPrRsStT:uvV:wWxX:zZ", ! long_options, &ind)) != EOF) { ! switch (c) { ! case 0: /* long options that set a single flag */ ! break; ! case 1: ! /* File name or non-parsed option */ ! name_add(optarg); ! break; ! case 'C': ! name_add("-C"); ! name_add(optarg); ! break; ! case 10: /* preserve */ ! f_use_protection = f_sorted_names = 1; ! break; ! case 11: ! if(cmd_mode!=CMD_NONE) ! goto badopt; ! cmd_mode=CMD_VERSION; ! break; ! case 12: /* help */ ! printf("This is GNU tar, the tape archiving program.\n"); ! describe(); ! exit(1); ! case 13: ! f_new_files++; ! goto get_newer; ! ! case 14: /* Delete in the archive */ ! if(cmd_mode!=CMD_NONE) ! goto badopt; ! cmd_mode=CMD_DELETE; ! break; ! ! case 15: ! f_exclude++; ! add_exclude(optarg); ! break; ! ! case 16: /* -T reads null terminated filenames. */ ! filename_terminator = '\0'; ! break; ! ! case 17: ! f_volno_file = optarg; ! break; ! ! case 'g': /* We are making a GNU dump; save directories at the beginning of the archive, and include in each directory its contents */ ! if(f_oldarch) ! goto badopt; ! f_gnudump++; ! gnu_dumpfile=optarg; ! break; ! ! ! case '0': ! case '1': ! case '2': ! case '3': ! case '4': ! case '5': ! case '6': ! case '7': ! { ! /* JF this'll have to be modified for other systems, of course! */ ! int d,add; ! static char buf[50]; ! d=getoldopt(argc,argv,"lmh"); #ifdef MAYBEDEF ! sprintf(buf,"/dev/rmt/%d%c",c,d); #else #ifndef LOW_NUM #define LOW_NUM 0 --- 286,394 ---- * Parse the options for tar. */ void ! options (argc, argv) ! int argc; ! char **argv; ! { ! register int c; /* Option letter */ ! int ind = -1; ! ! /* Set default option values */ ! blocking = DEFBLOCKING; /* From Makefile */ ! ar_files = (char **) ck_malloc (sizeof (char *) * 10); ! ar_files_len = 10; ! n_ar_files = 0; ! cur_ar_file = 0; ! ! /* Parse options */ ! while ((c = getoldopt (argc, argv, ! "-01234567Ab:BcC:df:F:g:GhikK:lL:mMN:oOpPrRsStT:uvV:wWxX:zZ", ! long_options, &ind)) != EOF) ! { ! switch (c) ! { ! case 0: /* long options that set a single flag */ ! break; ! case 1: ! /* File name or non-parsed option */ ! name_add (optarg); ! break; ! case 'C': ! name_add ("-C"); ! name_add (optarg); ! break; ! case 10: /* preserve */ ! f_use_protection = f_sorted_names = 1; ! break; ! case 11: ! if (cmd_mode != CMD_NONE) ! goto badopt; ! cmd_mode = CMD_VERSION; ! break; ! case 12: /* help */ ! printf ("This is GNU tar, the tape archiving program.\n"); ! describe (); ! exit (1); ! case 13: ! f_new_files++; ! goto get_newer; ! ! case 14: /* Delete in the archive */ ! if (cmd_mode != CMD_NONE) ! goto badopt; ! cmd_mode = CMD_DELETE; ! break; ! ! case 15: ! f_exclude++; ! add_exclude (optarg); ! break; ! ! case 16: /* -T reads null terminated filenames. */ ! filename_terminator = '\0'; ! break; ! ! case 17: ! f_volno_file = optarg; ! break; ! ! case 18: ! if (f_compressprog) ! { ! msg ("Only one compression option permitted\n"); ! exit (EX_ARGSBAD); ! } ! f_compressprog = optarg; ! break; ! ! case 'g': /* We are making a GNU dump; save directories at the beginning of the archive, and include in each directory its contents */ ! if (f_oldarch) ! goto badopt; ! f_gnudump++; ! gnu_dumpfile = optarg; ! break; ! ! ! case '0': ! case '1': ! case '2': ! case '3': ! case '4': ! case '5': ! case '6': ! case '7': ! { ! /* JF this'll have to be modified for other systems, of course! */ ! int d, add; ! static char buf[50]; ! d = getoldopt (argc, argv, "lmh"); #ifdef MAYBEDEF ! sprintf (buf, "/dev/rmt/%d%c", c, d); #else #ifndef LOW_NUM #define LOW_NUM 0 *************** *** 392,640 **** #define MID_NUM 8 #define HGH_NUM 16 #endif ! if(d=='l') add=LOW_NUM; ! else if(d=='m') add=MID_NUM; ! else if(d=='h') add=HGH_NUM; ! else goto badopt; ! sprintf(buf,"/dev/rmt%d",add+c-'0'); #endif ! if (n_ar_files == ar_files_len) ! ar_files ! = (char **) ! ck_malloc (sizeof (char *) ! * (ar_files_len *= 2)); ! ar_files[n_ar_files++]=buf; ! } ! break; ! case 'A': /* Arguments are tar files, just cat them onto the end of the archive. */ ! if(cmd_mode!=CMD_NONE) ! goto badopt; ! cmd_mode=CMD_CAT; ! break; ! ! case 'b': /* Set blocking factor */ ! blocking = intconv(optarg); ! break; ! ! case 'B': /* Try to reblock input */ ! f_reblock++; /* For reading 4.2BSD pipes */ ! break; ! ! case 'c': /* Create an archive */ ! if(cmd_mode!=CMD_NONE) ! goto badopt; ! cmd_mode=CMD_CREATE; ! break; #if 0 ! case 'C': ! if(chdir(optarg)<0) ! msg_perror("Can't change directory to %d",optarg); ! break; #endif ! case 'd': /* Find difference tape/disk */ ! if(cmd_mode!=CMD_NONE) ! goto badopt; ! cmd_mode=CMD_DIFF; ! break; ! ! case 'f': /* Use ar_file for the archive */ ! if (n_ar_files == ar_files_len) ! ar_files ! = (char **) ck_malloc (sizeof (char *) ! * (ar_files_len *= 2)); ! ! ar_files[n_ar_files++] = optarg; ! break; ! ! case 'F': ! /* Since -F is only useful with -M , make it implied */ ! f_run_script_at_end++; /* run this script at the end */ ! info_script = optarg; /* of each tape */ ! f_multivol++; ! break; ! case 'G': /* We are making a GNU dump; save directories at the beginning of the archive, and include in each directory its contents */ ! if(f_oldarch) ! goto badopt; ! f_gnudump++; ! gnu_dumpfile=0; ! break; ! ! case 'h': ! f_follow_links++; /* follow symbolic links */ ! break; ! ! case 'i': ! f_ignorez++; /* Ignore zero records (eofs) */ ! /* * This can't be the default, because Unix tar * writes two records of zeros, then pads out the * block with garbage. */ ! break; ! case 'k': /* Don't overwrite files */ #ifdef NO_OPEN3 ! msg("can't keep old files on this system"); ! exit(EX_ARGSBAD); #else ! f_keep++; #endif ! break; ! case 'K': ! f_startfile++; ! addname(optarg); ! break; ! case 'l': /* When dumping directories, don't dump files/subdirectories that are on other filesystems. */ ! f_local_filesys++; ! break; ! case 'L': ! tape_length = intconv (optarg); ! f_multivol++; ! break; ! case 'm': ! f_modified++; ! break; ! case 'M': /* Make Multivolume archive: When we can't write any more into the archive, re-open it, and continue writing */ ! f_multivol++; ! break; ! case 'N': /* Only write files newer than X */ ! get_newer: ! f_new_files++; ! new_time=get_date(optarg, (PTR) 0); ! if (new_time == (time_t) -1) { ! msg("invalid date format `%s'", optarg); ! exit(EX_ARGSBAD); ! } ! break; ! ! case 'o': /* Generate old archive */ ! if(f_gnudump /* || f_dironly */) ! goto badopt; ! f_oldarch++; ! break; ! ! case 'O': ! f_exstdout++; ! break; ! ! case 'p': ! f_use_protection++; ! break; ! ! case 'P': ! f_absolute_paths++; ! break; ! ! case 'r': /* Append files to the archive */ ! if(cmd_mode!=CMD_NONE) ! goto badopt; ! cmd_mode=CMD_APPEND; ! break; ! ! case 'R': ! f_sayblock++; /* Print block #s for debug */ ! break; /* of bad tar archives */ ! ! case 's': ! f_sorted_names++; /* Names to extr are sorted */ ! break; ! ! case 'S': /* deal with sparse files */ ! f_sparse_files++; ! break; ! case 't': ! if(cmd_mode!=CMD_NONE) ! goto badopt; ! cmd_mode=CMD_LIST; ! f_verbose++; /* "t" output == "cv" or "xv" */ ! break; ! ! case 'T': ! name_file = optarg; ! f_namefile++; ! break; ! case 'u': /* Append files to the archive that aren't there, or are newer than the copy in the archive */ ! if(cmd_mode!=CMD_NONE) ! goto badopt; ! cmd_mode=CMD_UPDATE; ! break; ! ! case 'v': ! f_verbose++; ! break; ! ! case 'V': ! f_volhdr=optarg; ! break; ! ! case 'w': ! f_confirm++; ! break; ! ! case 'W': ! f_verify++; ! break; ! ! case 'x': /* Extract files from the archive */ ! if(cmd_mode!=CMD_NONE) ! goto badopt; ! cmd_mode=CMD_EXTRACT; ! break; ! ! case 'X': ! f_exclude++; ! add_exclude_file(optarg); ! break; ! ! case 'z': /* Easy to type */ ! case 'Z': /* Like the filename extension .Z */ ! f_compress++; ! break; ! ! case '?': ! badopt: ! msg("Unknown option. Use '%s --help' for a complete list of options.", tar); ! exit(EX_ARGSBAD); ! } } ! blocksize = blocking * RECORDSIZE; ! if (n_ar_files == 0) ! { ! n_ar_files = 1; ! ar_files[0] = getenv("TAPE"); /* From environment, or */ ! if (ar_files[0] == 0) ! ar_files[0] = DEF_AR_FILE; /* From Makefile */ ! } ! if (n_ar_files > 1 && !f_multivol) ! { ! msg ("Multiple archive files requires --multi-volume\n"); ! exit (EX_ARGSBAD); ! } } --- 395,667 ---- #define MID_NUM 8 #define HGH_NUM 16 #endif ! if (d == 'l') ! add = LOW_NUM; ! else if (d == 'm') ! add = MID_NUM; ! else if (d == 'h') ! add = HGH_NUM; ! else ! goto badopt; ! sprintf (buf, "/dev/rmt%d", add + c - '0'); #endif ! if (n_ar_files == ar_files_len) ! ar_files ! = (char **) ! ck_malloc (sizeof (char *) ! * (ar_files_len *= 2)); ! ar_files[n_ar_files++] = buf; ! } ! break; ! case 'A': /* Arguments are tar files, just cat them onto the end of the archive. */ ! if (cmd_mode != CMD_NONE) ! goto badopt; ! cmd_mode = CMD_CAT; ! break; ! ! case 'b': /* Set blocking factor */ ! blocking = intconv (optarg); ! break; ! ! case 'B': /* Try to reblock input */ ! f_reblock++; /* For reading 4.2BSD pipes */ ! break; ! ! case 'c': /* Create an archive */ ! if (cmd_mode != CMD_NONE) ! goto badopt; ! cmd_mode = CMD_CREATE; ! break; #if 0 ! case 'C': ! if (chdir (optarg) < 0) ! msg_perror ("Can't change directory to %d", optarg); ! break; #endif ! case 'd': /* Find difference tape/disk */ ! if (cmd_mode != CMD_NONE) ! goto badopt; ! cmd_mode = CMD_DIFF; ! break; ! ! case 'f': /* Use ar_file for the archive */ ! if (n_ar_files == ar_files_len) ! ar_files ! = (char **) ck_malloc (sizeof (char *) ! * (ar_files_len *= 2)); ! ! ar_files[n_ar_files++] = optarg; ! break; ! ! case 'F': ! /* Since -F is only useful with -M , make it implied */ ! f_run_script_at_end++;/* run this script at the end */ ! info_script = optarg; /* of each tape */ ! f_multivol++; ! break; ! case 'G': /* We are making a GNU dump; save directories at the beginning of the archive, and include in each directory its contents */ ! if (f_oldarch) ! goto badopt; ! f_gnudump++; ! gnu_dumpfile = 0; ! break; ! ! case 'h': ! f_follow_links++; /* follow symbolic links */ ! break; ! ! case 'i': ! f_ignorez++; /* Ignore zero records (eofs) */ ! /* * This can't be the default, because Unix tar * writes two records of zeros, then pads out the * block with garbage. */ ! break; ! case 'k': /* Don't overwrite files */ #ifdef NO_OPEN3 ! msg ("can't keep old files on this system"); ! exit (EX_ARGSBAD); #else ! f_keep++; #endif ! break; ! case 'K': ! f_startfile++; ! addname (optarg); ! break; ! case 'l': /* When dumping directories, don't dump files/subdirectories that are on other filesystems. */ ! f_local_filesys++; ! break; ! case 'L': ! tape_length = intconv (optarg); ! f_multivol++; ! break; ! case 'm': ! f_modified++; ! break; ! case 'M': /* Make Multivolume archive: When we can't write any more into the archive, re-open it, and continue writing */ ! f_multivol++; ! break; ! ! case 'N': /* Only write files newer than X */ ! get_newer: ! f_new_files++; ! new_time = get_date (optarg, (PTR) 0); ! if (new_time == (time_t) - 1) ! { ! msg ("invalid date format `%s'", optarg); ! exit (EX_ARGSBAD); ! } ! break; ! case 'o': /* Generate old archive */ ! if (f_gnudump /* || f_dironly */ ) ! goto badopt; ! f_oldarch++; ! break; ! ! case 'O': ! f_exstdout++; ! break; ! ! case 'p': ! f_use_protection++; ! break; ! ! case 'P': ! f_absolute_paths++; ! break; ! ! case 'r': /* Append files to the archive */ ! if (cmd_mode != CMD_NONE) ! goto badopt; ! cmd_mode = CMD_APPEND; ! break; ! ! case 'R': ! f_sayblock++; /* Print block #s for debug */ ! break; /* of bad tar archives */ ! ! case 's': ! f_sorted_names++; /* Names to extr are sorted */ ! break; ! ! case 'S': /* deal with sparse files */ ! f_sparse_files++; ! break; ! case 't': ! if (cmd_mode != CMD_NONE) ! goto badopt; ! cmd_mode = CMD_LIST; ! f_verbose++; /* "t" output == "cv" or "xv" */ ! break; ! ! case 'T': ! name_file = optarg; ! f_namefile++; ! break; ! case 'u': /* Append files to the archive that aren't there, or are newer than the copy in the archive */ ! if (cmd_mode != CMD_NONE) ! goto badopt; ! cmd_mode = CMD_UPDATE; ! break; ! ! case 'v': ! f_verbose++; ! break; ! ! case 'V': ! f_volhdr = optarg; ! break; ! ! case 'w': ! f_confirm++; ! break; ! ! case 'W': ! f_verify++; ! break; ! ! case 'x': /* Extract files from the archive */ ! if (cmd_mode != CMD_NONE) ! goto badopt; ! cmd_mode = CMD_EXTRACT; ! break; ! ! case 'X': ! f_exclude++; ! add_exclude_file (optarg); ! break; ! ! case 'z': ! if (f_compressprog) ! { ! msg ("Only one compression option permitted\n"); ! exit (EX_ARGSBAD); ! } ! f_compressprog = "gzip"; ! break; ! case 'Z': ! if (f_compressprog) ! { ! msg ("Only one compression option permitted\n"); ! exit (EX_ARGSBAD); ! } ! f_compressprog = "compress"; ! break; ! ! case '?': ! badopt: ! msg ("Unknown option. Use '%s --help' for a complete list of options.", tar); ! exit (EX_ARGSBAD); ! } + } ! blocksize = blocking * RECORDSIZE; ! if (n_ar_files == 0) ! { ! n_ar_files = 1; ! ar_files[0] = getenv ("TAPE"); /* From environment, or */ ! if (ar_files[0] == 0) ! ar_files[0] = DEF_AR_FILE; /* From Makefile */ ! } ! if (n_ar_files > 1 && !f_multivol) ! { ! msg ("Multiple archive files requires --multi-volume\n"); ! exit (EX_ARGSBAD); ! } ! if (f_compress_block && !f_compressprog) ! { ! msg ("You must use a compression option (--gzip, --compress\n\ ! or --use-compress-program) with --block-compress.\n"); ! exit (EX_ARGSBAD); ! } } *************** *** 647,681 **** * problem. */ void ! describe() { ! puts("choose one of the following:"); ! fputs("\ -A, --catenate,\n\ --concatenate append tar files to an archive\n\ -c, --create create a new archive\n\ -d, --diff,\n\ --compare find differences between archive and file system\n\ ! --delete delete from the archive (not for use on mag tapes!)\n\ -r, --append append files to the end of an archive\n\ -t, --list list the contents of an archive\n\ -u, --update only append files that are newer than copy in archive\n\ -x, --extract,\n\ ! --get extract files from an archive\n",stdout); ! fprintf(stdout, "\ Other options:\n\ --atime-preserve don't change access times on dumped files\n\ -b, --block-size N block size of Nx512 bytes (default N=%d)\n", DEFBLOCKING); ! fputs ("\ -B, --read-full-blocks reblock as we read (for reading 4.2BSD pipes)\n\ -C, --directory DIR change to directory DIR\n\ --checkpoint print directory names while reading the archive\n\ ! ", stdout); /* KLUDGE */ fprintf(stdout, "\ -f, --file [HOSTNAME:]F use archive file or device F (default %s)\n", ! DEF_AR_FILE); fputs("\ --force-local archive file is local even if has a colon\n\ ! -F, --info-script F run script at end of each tape (implies -M)\n\ -G, --incremental create/list/extract old GNU-format incremental backup\n\ -g, --listed-incremental F create/list/extract new GNU-format incremental backup\n\ -h, --dereference don't dump symlinks; dump the files they point to\n\ --- 674,711 ---- * problem. */ void ! describe () { ! puts ("choose one of the following:"); ! fputs ("\ -A, --catenate,\n\ --concatenate append tar files to an archive\n\ -c, --create create a new archive\n\ -d, --diff,\n\ --compare find differences between archive and file system\n\ ! --delete delete from the archive (not for use on mag tapes!)\n\ -r, --append append files to the end of an archive\n\ -t, --list list the contents of an archive\n\ -u, --update only append files that are newer than copy in archive\n\ -x, --extract,\n\ ! --get extract files from an archive\n", stdout); ! fprintf (stdout, "\ Other options:\n\ --atime-preserve don't change access times on dumped files\n\ -b, --block-size N block size of Nx512 bytes (default N=%d)\n", DEFBLOCKING); ! fputs ("\ -B, --read-full-blocks reblock as we read (for reading 4.2BSD pipes)\n\ -C, --directory DIR change to directory DIR\n\ --checkpoint print directory names while reading the archive\n\ ! ", stdout); /* KLUDGE */ ! fprintf (stdout, "\ -f, --file [HOSTNAME:]F use archive file or device F (default %s)\n", ! DEF_AR_FILE); ! fputs ("\ --force-local archive file is local even if has a colon\n\ ! -F, --info-script F\n\ ! --new-volume-script F run script at end of each tape (implies -M)\n\ -G, --incremental create/list/extract old GNU-format incremental backup\n\ -g, --listed-incremental F create/list/extract new GNU-format incremental backup\n\ -h, --dereference don't dump symlinks; dump the files they point to\n\ *************** *** 682,695 **** -i, --ignore-zeros ignore blocks of zeros in archive (normally mean EOF)\n\ --ignore-failed-read don't exit with non-zero status on unreadable files\n\ -k, --keep-old-files keep existing files; don't overwrite them from archive\n\ ! -K, --starting-file FILE begin at FILE in the archive\n\ -l, --one-file-system stay in local file system when creating an archive\n\ ! -L, --tape-length LENGTH change tapes after writing LENGTH\n\ ! ", stdout); /* KLUDGE */ fputs("\ -m, --modification-time don't extract file modified time\n\ -M, --multi-volume create/list/extract multi-volume archive\n\ -N, --after-date DATE,\n\ ! --newer DATE only store files newer than DATE\n\ -o, --old-archive,\n\ --portability write a V7 format archive, rather than ANSI format\n\ -O, --to-stdout extract files to standard output\n\ --- 712,726 ---- -i, --ignore-zeros ignore blocks of zeros in archive (normally mean EOF)\n\ --ignore-failed-read don't exit with non-zero status on unreadable files\n\ -k, --keep-old-files keep existing files; don't overwrite them from archive\n\ ! -K, --starting-file F begin at file F in the archive\n\ -l, --one-file-system stay in local file system when creating an archive\n\ ! -L, --tape-length N change tapes after writing N*1024 bytes\n\ ! ", stdout); /* KLUDGE */ ! fputs ("\ -m, --modification-time don't extract file modified time\n\ -M, --multi-volume create/list/extract multi-volume archive\n\ -N, --after-date DATE,\n\ ! --newer DATE only store files newer than DATE\n\ -o, --old-archive,\n\ --portability write a V7 format archive, rather than ANSI format\n\ -O, --to-stdout extract files to standard output\n\ *************** *** 697,703 **** --preserve-permissions extract all protection information\n\ -P, --absolute-paths don't strip leading `/'s from file names\n\ --preserve like -p -s\n\ ! ", stdout); /* KLUDGE */ fputs("\ -R, --record-number show record number within archive with each message\n\ --remove-files remove files after adding them to the archive\n\ -s, --same-order,\n\ --- 728,735 ---- --preserve-permissions extract all protection information\n\ -P, --absolute-paths don't strip leading `/'s from file names\n\ --preserve like -p -s\n\ ! ", stdout); /* KLUDGE */ ! fputs ("\ -R, --record-number show record number within archive with each message\n\ --remove-files remove files after adding them to the archive\n\ -s, --same-order,\n\ *************** *** 706,738 **** -S, --sparse handle sparse files efficiently\n\ -T, --files-from F get names to extract or create from file F\n\ --null -T reads null-terminated names, disable -C\n\ ! --totals print total bytes written with --create\n\ -v, --verbose verbosely list files processed\n\ ! -V, --label NAME create archive with volume name NAME\n\ --version print tar program version number\n\ -w, --interactive,\n\ --confirmation ask for confirmation for every action\n\ ! ", stdout); /* KLUDGE */ fputs("\ -W, --verify attempt to verify the archive after writing it\n\ --exclude FILE exclude file FILE\n\ -X, --exclude-from FILE exclude files listed in FILE\n\ ! -z, -Z, --compress,\n\ --uncompress filter the archive through compress\n\ -[0-7][lmh] specify drive and density\n\ ", stdout); } void ! name_add(name) ! char *name; { ! if(n_indalloc==n_indused) { ! n_indalloc+=10; ! n_ind=(char **)(n_indused ? ck_realloc(n_ind,n_indalloc*sizeof(char *)) : ck_malloc(n_indalloc*sizeof(char *))); ! } ! n_ind[n_indused++]=name; } ! /* * Set up to gather file names for tar. * --- 738,777 ---- -S, --sparse handle sparse files efficiently\n\ -T, --files-from F get names to extract or create from file F\n\ --null -T reads null-terminated names, disable -C\n\ ! --totals print total bytes written with --create\n\ -v, --verbose verbosely list files processed\n\ ! -V, --label NAME create archive with volume name NAME\n\ --version print tar program version number\n\ -w, --interactive,\n\ --confirmation ask for confirmation for every action\n\ ! ", stdout); /* KLUDGE */ ! fputs ("\ -W, --verify attempt to verify the archive after writing it\n\ --exclude FILE exclude file FILE\n\ -X, --exclude-from FILE exclude files listed in FILE\n\ ! -Z, --compress,\n\ --uncompress filter the archive through compress\n\ + -z, --gzip,\n\ + --ungzip filter the archive through gzip\n\ + --use-compress-program PROG\n\ + filter the archive through PROG (which must accept -d)\n\ + --block-compress block the output of compression program for tapes\n\ -[0-7][lmh] specify drive and density\n\ ", stdout); } void ! name_add (name) ! char *name; { ! if (n_indalloc == n_indused) ! { ! n_indalloc += 10; ! n_ind = (char **) (n_indused ? ck_realloc (n_ind, n_indalloc * sizeof (char *)): ck_malloc (n_indalloc * sizeof (char *))); ! } ! n_ind[n_indused++] = name; } ! /* * Set up to gather file names for tar. * *************** *** 739,768 **** * They can either come from stdin or from argv. */ void ! name_init(argc, argv) ! int argc; ! char **argv; { ! if (f_namefile) { ! if (optind < argc) { ! msg("too many args with -T option"); ! exit(EX_ARGSBAD); ! } ! if (!strcmp(name_file, "-")) { ! namef = stdin; ! } else { ! namef = fopen(name_file, "r"); ! if (namef == NULL) { ! msg_perror("can't open file %s",name_file); ! exit(EX_BADFILE); ! } ! } ! } else { ! /* Get file names from argv, after options. */ ! n_argc = argc; ! n_argv = argv; } } /* Read the next filename read from STREAM and null-terminate it. --- 778,815 ---- * They can either come from stdin or from argv. */ void ! name_init (argc, argv) ! int argc; ! char **argv; { ! if (f_namefile) ! { ! if (optind < argc) ! { ! msg ("too many args with -T option"); ! exit (EX_ARGSBAD); ! } ! if (!strcmp (name_file, "-")) ! { ! namef = stdin; } + else + { + namef = fopen (name_file, "r"); + if (namef == NULL) + { + msg_perror ("can't open file %s", name_file); + exit (EX_BADFILE); + } + } + } + else + { + /* Get file names from argv, after options. */ + n_argc = argc; + n_argv = argv; + } } /* Read the next filename read from STREAM and null-terminate it. *************** *** 811,887 **** */ char * ! name_next(change_dirs) int change_dirs; { ! static char *buffer; /* Holding pattern */ ! static int buffer_siz; ! register char *p; ! register char *q = 0; ! register int next_name_is_dir = 0; ! extern char *un_quote_string(); ! ! if(buffer_siz==0) { ! buffer=ck_malloc(NAMSIZ+2); ! buffer_siz=NAMSIZ; ! } ! if (filename_terminator == '\0') ! change_dirs = 0; ! tryagain: ! if (namef == NULL) { ! if(n_indscan p && *q == '/') /* Zap trailing "/"s. */ ! *q-- = '\0'; ! if (change_dirs && next_name_is_dir == 0 ! && p[0] == '-' && p[1] == 'C' && p[2] == '\0') { ! next_name_is_dir = 1; ! goto tryagain; ! } ! if (next_name_is_dir) { ! if (chdir (p) < 0) ! msg_perror ("Can't change to directory %s", p); ! next_name_is_dir = 0; ! goto tryagain; ! } ! if(f_exclude && check_exclude(p)) ! goto tryagain; ! return un_quote_string(p); } ! return NULL; } --- 858,946 ---- */ char * ! name_next (change_dirs) int change_dirs; { ! static char *buffer; /* Holding pattern */ ! static int buffer_siz; ! register char *p; ! register char *q = 0; ! register int next_name_is_dir = 0; ! extern char *un_quote_string (); ! ! if (buffer_siz == 0) ! { ! buffer = ck_malloc (NAMSIZ + 2); ! buffer_siz = NAMSIZ; ! } ! if (filename_terminator == '\0') ! change_dirs = 0; ! tryagain: ! if (namef == NULL) ! { ! if (n_indscan < n_indused) ! p = n_ind[n_indscan++]; ! else if (optind < n_argc) ! /* Names come from argv, after options */ ! p = n_argv[optind++]; ! else ! { ! if (q) ! msg ("Missing filename after -C"); ! return NULL; ! } ! /* JF trivial support for -C option. I don't know if chdir'ing at this point is dangerous or not. It seems to work, which is all I ask. */ ! if (change_dirs && !q && p[0] == '-' && p[1] == 'C' && p[2] == '\0') ! { ! q = p; ! goto tryagain; ! } ! if (q) ! { ! if (chdir (p) < 0) ! msg_perror ("Can't chdir to %s", p); ! q = 0; ! goto tryagain; ! } ! /* End of JF quick -C hack */ ! #if 0 ! if (f_exclude && check_exclude (p)) ! goto tryagain; ! #endif ! return un_quote_string (p); ! } ! while (p = read_name_from_file (buffer, &buffer_siz, namef)) ! { ! buffer = p; ! if (*p == '\0') ! continue; /* Ignore empty lines. */ ! q = p + strlen (p) - 1; ! while (q > p && *q == '/')/* Zap trailing "/"s. */ ! *q-- = '\0'; ! if (change_dirs && next_name_is_dir == 0 ! && p[0] == '-' && p[1] == 'C' && p[2] == '\0') ! { ! next_name_is_dir = 1; ! goto tryagain; ! } ! if (next_name_is_dir) ! { ! if (chdir (p) < 0) ! msg_perror ("Can't change to directory %s", p); ! next_name_is_dir = 0; ! goto tryagain; } ! #if 0 ! if (f_exclude && check_exclude (p)) ! goto tryagain; ! #endif ! return un_quote_string (p); ! } ! return NULL; } *************** *** 889,898 **** * Close the name file, if any. */ void ! name_close() { ! if (namef != NULL && namef != stdin) fclose(namef); } --- 948,958 ---- * Close the name file, if any. */ void ! name_close () { ! if (namef != NULL && namef != stdin) ! fclose (namef); } *************** *** 908,954 **** * number of files by doing "tar t" and editing down the list of files. */ void ! name_gather() { ! register char *p; ! static struct name *namebuf; /* One-name buffer */ ! static namelen; ! static char *chdir_name; ! ! if (f_sorted_names) { ! if(!namelen) { ! namelen=NAMSIZ; ! namebuf=(struct name *)ck_malloc(sizeof(struct name)+NAMSIZ); ! } ! p = name_next(0); ! if (p) { ! if(*p=='-' && p[1]=='C' && p[2]=='\0') { ! chdir_name=name_next(0); ! p=name_next(0); ! if(!p) { ! msg("Missing file name after -C"); ! exit(EX_ARGSBAD); ! } ! namebuf->change_dir=chdir_name; ! } ! namebuf->length = strlen(p); ! if (namebuf->length >= namelen) { ! namebuf=(struct name *)ck_realloc(namebuf,sizeof(struct name)+namebuf->length); ! namelen=namebuf->length; ! } ! strncpy(namebuf->name, p, namebuf->length); ! namebuf->name[ namebuf->length ] = 0; ! namebuf->next = (struct name *)NULL; ! namebuf->found = 0; ! namelist = namebuf; ! namelast = namelist; } ! return; } ! /* Non sorted names -- read them all in */ ! while (p = name_next(0)) ! addname(p); } /* --- 968,1020 ---- * number of files by doing "tar t" and editing down the list of files. */ void ! name_gather () { ! register char *p; ! static struct name *namebuf; /* One-name buffer */ ! static namelen; ! static char *chdir_name; ! ! if (f_sorted_names) ! { ! if (!namelen) ! { ! namelen = NAMSIZ; ! namebuf = (struct name *) ck_malloc (sizeof (struct name) + NAMSIZ); ! } ! p = name_next (0); ! if (p) ! { ! if (*p == '-' && p[1] == 'C' && p[2] == '\0') ! { ! chdir_name = name_next (0); ! p = name_next (0); ! if (!p) ! { ! msg ("Missing file name after -C"); ! exit (EX_ARGSBAD); } ! namebuf->change_dir = chdir_name; ! } ! namebuf->length = strlen (p); ! if (namebuf->length >= namelen) ! { ! namebuf = (struct name *) ck_realloc (namebuf, sizeof (struct name) + namebuf->length); ! namelen = namebuf->length; ! } ! strncpy (namebuf->name, p, namebuf->length); ! namebuf->name[namebuf->length] = 0; ! namebuf->next = (struct name *) NULL; ! namebuf->found = 0; ! namelist = namebuf; ! namelast = namelist; } + return; + } ! /* Non sorted names -- read them all in */ ! while (p = name_next (0)) ! addname (p); } /* *************** *** 955,1037 **** * Add a name to the namelist. */ void ! addname(name) ! char *name; /* pointer to name */ { ! register int i; /* Length of string */ ! register struct name *p; /* Current struct pointer */ ! static char *chdir_name; ! char *new_name(); ! ! if(name[0]=='-' && name[1]=='C' && name[2]=='\0') { ! chdir_name=name_next(0); ! name=name_next(0); ! if(!chdir_name) { ! msg("Missing file name after -C"); ! exit(EX_ARGSBAD); ! } ! if(chdir_name[0]!='/') { ! char *path = ck_malloc(PATH_MAX); ! #if defined(__MSDOS__) || defined(USG) || defined(_POSIX_VERSION) ! if(!getcwd(path,PATH_MAX)) { ! msg("Couldn't get current directory."); ! exit(EX_SYSTEM); ! } #else ! char *getwd(); ! if(!getwd(path)) { ! msg("Couldn't get current directory: %s",path); ! exit(EX_SYSTEM); ! } #endif ! chdir_name=new_name(path,chdir_name); ! free(path); ! } } ! if (name) ! { ! i = strlen(name); ! /*NOSTRICT*/ ! p = (struct name *)malloc((unsigned)(sizeof(struct name) + i)); ! } ! else ! p = (struct name *)malloc ((unsigned)(sizeof (struct name))); ! if (!p) { ! if (name) ! msg("cannot allocate mem for name '%s'.",name); ! else ! msg("cannot allocate mem for chdir record."); ! exit(EX_SYSTEM); } ! p->next = (struct name *)NULL; ! if (name) ! { ! p->fake = 0; ! p->length = i; ! strncpy(p->name, name, i); ! p->name[i] = '\0'; /* Null term */ ! } ! else ! p->fake = 1; ! p->found = 0; ! p->regexp = 0; /* Assume not a regular expression */ ! p->firstch = 1; /* Assume first char is literal */ ! p->change_dir=chdir_name; ! p->dir_contents = 0; /* JF */ ! if (name) ! { ! if (index(name, '*') || index(name, '[') || index(name, '?')) { ! p->regexp = 1; /* No, it's a regexp */ ! if (name[0] == '*' || name[0] == '[' || name[0] == '?') ! p->firstch = 0; /* Not even 1st char literal */ ! } ! } ! if (namelast) namelast->next = p; ! namelast = p; ! if (!namelist) namelist = p; } /* --- 1021,1112 ---- * Add a name to the namelist. */ void ! addname (name) ! char *name; /* pointer to name */ { ! register int i; /* Length of string */ ! register struct name *p; /* Current struct pointer */ ! static char *chdir_name; ! char *new_name (); ! ! if (name[0] == '-' && name[1] == 'C' && name[2] == '\0') ! { ! chdir_name = name_next (0); ! name = name_next (0); ! if (!chdir_name) ! { ! msg ("Missing file name after -C"); ! exit (EX_ARGSBAD); ! } ! if (chdir_name[0] != '/') ! { ! char *path = ck_malloc (PATH_MAX); ! #if defined(__MSDOS__) || defined(HAVE_GETCWD) || defined(_POSIX_VERSION) ! if (!getcwd (path, PATH_MAX)) ! { ! msg ("Couldn't get current directory."); ! exit (EX_SYSTEM); ! } #else ! char *getwd (); ! if (!getwd (path)) ! { ! msg ("Couldn't get current directory: %s", path); ! exit (EX_SYSTEM); ! } #endif ! chdir_name = new_name (path, chdir_name); ! free (path); } + } ! if (name) ! { ! i = strlen (name); ! /*NOSTRICT*/ ! p = (struct name *) malloc ((unsigned) (sizeof (struct name) + i)); ! } ! else ! p = (struct name *) malloc ((unsigned) (sizeof (struct name))); ! if (!p) ! { ! if (name) ! msg ("cannot allocate mem for name '%s'.", name); ! else ! msg ("cannot allocate mem for chdir record."); ! exit (EX_SYSTEM); ! } ! p->next = (struct name *) NULL; ! if (name) ! { ! p->fake = 0; ! p->length = i; ! strncpy (p->name, name, i); ! p->name[i] = '\0'; /* Null term */ ! } ! else ! p->fake = 1; ! p->found = 0; ! p->regexp = 0; /* Assume not a regular expression */ ! p->firstch = 1; /* Assume first char is literal */ ! p->change_dir = chdir_name; ! p->dir_contents = 0; /* JF */ ! if (name) ! { ! if (index (name, '*') || index (name, '[') || index (name, '?')) ! { ! p->regexp = 1; /* No, it's a regexp */ ! if (name[0] == '*' || name[0] == '[' || name[0] == '?') ! p->firstch = 0; /* Not even 1st char literal */ } ! } ! if (namelast) ! namelast->next = p; ! namelast = p; ! if (!namelist) ! namelist = p; } /* *************** *** 1039,1099 **** * the namelist, zero if not. */ int ! name_match(p) ! register char *p; { ! register struct name *nlp; ! register int len; again: ! if (0 == (nlp = namelist)) /* Empty namelist is easy */ ! return 1; ! if (nlp->fake) ! { ! if (nlp->change_dir && chdir (nlp->change_dir)) ! msg_perror ("Can't change to directory %d", nlp->change_dir); ! namelist = 0; ! return 1; ! } ! len = strlen(p); ! for (; nlp != 0; nlp = nlp->next) { ! /* If first chars don't match, quick skip */ ! if (nlp->firstch && nlp->name[0] != p[0]) ! continue; ! ! /* Regular expressions (shell globbing, actually). */ ! if (nlp->regexp) { ! if (fnmatch(nlp->name, p, FNM_TARPATH) == 0) { ! nlp->found = 1; /* Remember it matched */ ! if(f_startfile) { ! free((void *)namelist); ! namelist=0; ! } ! if(nlp->change_dir && chdir(nlp->change_dir)) ! msg_perror("Can't change to directory %s",nlp->change_dir); ! return 1; /* We got a match */ ! } ! continue; ! } ! /* Plain Old Strings */ ! if (nlp->length <= len /* Archive len >= specified */ ! && (p[nlp->length] == '\0' || p[nlp->length] == '/') ! /* Full match on file/dirname */ ! && strncmp(p, nlp->name, nlp->length) == 0) /* Name compare */ { ! nlp->found = 1; /* Remember it matched */ ! if(f_startfile) { ! free((void *)namelist); ! namelist = 0; ! } ! if(nlp->change_dir && chdir(nlp->change_dir)) ! msg_perror("Can't change to directory %s",nlp->change_dir); ! return 1; /* We got a match */ } } ! /* * Filename from archive not found in namelist. * If we have the whole namelist here, just return 0. * Otherwise, read the next name in and compare it. --- 1114,1179 ---- * the namelist, zero if not. */ int ! name_match (p) ! register char *p; { ! register struct name *nlp; ! register int len; again: ! if (0 == (nlp = namelist)) /* Empty namelist is easy */ ! return 1; ! if (nlp->fake) ! { ! if (nlp->change_dir && chdir (nlp->change_dir)) ! msg_perror ("Can't change to directory %d", nlp->change_dir); ! namelist = 0; ! return 1; ! } ! len = strlen (p); ! for (; nlp != 0; nlp = nlp->next) ! { ! /* If first chars don't match, quick skip */ ! if (nlp->firstch && nlp->name[0] != p[0]) ! continue; ! /* Regular expressions (shell globbing, actually). */ ! if (nlp->regexp) ! { ! if (fnmatch (nlp->name, p, FNM_LEADING_DIR) == 0) ! { ! nlp->found = 1; /* Remember it matched */ ! if (f_startfile) { ! free ((void *) namelist); ! namelist = 0; } + if (nlp->change_dir && chdir (nlp->change_dir)) + msg_perror ("Can't change to directory %s", nlp->change_dir); + return 1; /* We got a match */ + } + continue; + } + + /* Plain Old Strings */ + if (nlp->length <= len /* Archive len >= specified */ + && (p[nlp->length] == '\0' || p[nlp->length] == '/') + /* Full match on file/dirname */ + && strncmp (p, nlp->name, nlp->length) == 0) /* Name compare */ + { + nlp->found = 1; /* Remember it matched */ + if (f_startfile) + { + free ((void *) namelist); + namelist = 0; + } + if (nlp->change_dir && chdir (nlp->change_dir)) + msg_perror ("Can't change to directory %s", nlp->change_dir); + return 1; /* We got a match */ } + } ! /* * Filename from archive not found in namelist. * If we have the whole namelist here, just return 0. * Otherwise, read the next name in and compare it. *************** *** 1100,1110 **** * If this was the last name, namelist->found will remain on. * If not, we loop to compare the newly read name. */ ! if (f_sorted_names && namelist->found) { ! name_gather(); /* Read one more */ ! if (!namelist->found) goto again; ! } ! return 0; } --- 1180,1192 ---- * If this was the last name, namelist->found will remain on. * If not, we loop to compare the newly read name. */ ! if (f_sorted_names && namelist->found) ! { ! name_gather (); /* Read one more */ ! if (!namelist->found) ! goto again; ! } ! return 0; } *************** *** 1112,1128 **** * Print the names of things in the namelist that were not matched. */ void ! names_notfound() { ! register struct name *nlp,*next; ! register char *p; ! for (nlp = namelist; nlp != 0; nlp = next) { ! next=nlp->next; ! if (!nlp->found) ! msg("%s not found in archive",nlp->name); ! /* * We could free() the list, but the process is about * to die anyway, so save some CPU time. Amigas and * other similarly broken software will need to waste --- 1194,1211 ---- * Print the names of things in the namelist that were not matched. */ void ! names_notfound () { ! register struct name *nlp, *next; ! register char *p; ! for (nlp = namelist; nlp != 0; nlp = next) ! { ! next = nlp->next; ! if (!nlp->found) ! msg ("%s not found in archive", nlp->name); ! /* * We could free() the list, but the process is about * to die anyway, so save some CPU time. Amigas and * other similarly broken software will need to waste *************** *** 1129,1153 **** * the time, though. */ #ifdef amiga ! if (!f_sorted_names) ! free(nlp); #endif ! } ! namelist = (struct name *)NULL; ! namelast = (struct name *)NULL; ! if (f_sorted_names) { ! while (0 != (p = name_next(1))) ! msg("%s not found in archive", p); ! } } /* These next routines were created by JF */ void ! name_expand() { ! ; } /* This is like name_match(), except that it returns a pointer to the name --- 1212,1237 ---- * the time, though. */ #ifdef amiga ! if (!f_sorted_names) ! free (nlp); #endif ! } ! namelist = (struct name *) NULL; ! namelast = (struct name *) NULL; ! if (f_sorted_names) ! { ! while (0 != (p = name_next (1))) ! msg ("%s not found in archive", p); ! } } /* These next routines were created by JF */ void ! name_expand () { ! ; } /* This is like name_match(), except that it returns a pointer to the name *************** *** 1156,1192 **** name_match(), which returns TRUE */ struct name * ! name_scan(p) ! register char *p; { ! register struct name *nlp; ! register int len; again: ! if (0 == (nlp = namelist)) /* Empty namelist is easy */ ! return 0; ! len = strlen(p); ! for (; nlp != 0; nlp = nlp->next) { ! /* If first chars don't match, quick skip */ ! if (nlp->firstch && nlp->name[0] != p[0]) ! continue; ! ! /* Regular expressions */ ! if (nlp->regexp) { ! if (fnmatch(nlp->name, p, FNM_TARPATH) == 0) ! return nlp; /* We got a match */ ! continue; ! } ! /* Plain Old Strings */ ! if (nlp->length <= len /* Archive len >= specified */ ! && (p[nlp->length] == '\0' || p[nlp->length] == '/') ! /* Full match on file/dirname */ ! && strncmp(p, nlp->name, nlp->length) == 0) /* Name compare */ ! return nlp; /* We got a match */ } ! /* * Filename from archive not found in namelist. * If we have the whole namelist here, just return 0. * Otherwise, read the next name in and compare it. --- 1240,1278 ---- name_match(), which returns TRUE */ struct name * ! name_scan (p) ! register char *p; { ! register struct name *nlp; ! register int len; again: ! if (0 == (nlp = namelist)) /* Empty namelist is easy */ ! return 0; ! len = strlen (p); ! for (; nlp != 0; nlp = nlp->next) ! { ! /* If first chars don't match, quick skip */ ! if (nlp->firstch && nlp->name[0] != p[0]) ! continue; ! /* Regular expressions */ ! if (nlp->regexp) ! { ! if (fnmatch (nlp->name, p, FNM_LEADING_DIR) == 0) ! return nlp; /* We got a match */ ! continue; } ! /* Plain Old Strings */ ! if (nlp->length <= len /* Archive len >= specified */ ! && (p[nlp->length] == '\0' || p[nlp->length] == '/') ! /* Full match on file/dirname */ ! && strncmp (p, nlp->name, nlp->length) == 0) /* Name compare */ ! return nlp; /* We got a match */ ! } ! ! /* * Filename from archive not found in namelist. * If we have the whole namelist here, just return 0. * Otherwise, read the next name in and compare it. *************** *** 1193,1203 **** * If this was the last name, namelist->found will remain on. * If not, we loop to compare the newly read name. */ ! if (f_sorted_names && namelist->found) { ! name_gather(); /* Read one more */ ! if (!namelist->found) goto again; ! } ! return (struct name *) 0; } /* This returns a name from the namelist which doesn't have ->found set. --- 1279,1291 ---- * If this was the last name, namelist->found will remain on. * If not, we loop to compare the newly read name. */ ! if (f_sorted_names && namelist->found) ! { ! name_gather (); /* Read one more */ ! if (!namelist->found) ! goto again; ! } ! return (struct name *) 0; } /* This returns a name from the namelist which doesn't have ->found set. *************** *** 1207,1277 **** struct name *gnu_list_name; char * ! name_from_list() { ! if(!gnu_list_name) ! gnu_list_name = namelist; ! while(gnu_list_name && gnu_list_name->found) ! gnu_list_name=gnu_list_name->next; ! if(gnu_list_name) { ! gnu_list_name->found++; ! if(gnu_list_name->change_dir) ! if(chdir(gnu_list_name->change_dir)<0) ! msg_perror("can't chdir to %s",gnu_list_name->change_dir); ! return gnu_list_name->name; ! } ! return (char *)0; } void ! blank_name_list() { ! struct name *n; ! gnu_list_name = 0; ! for(n=namelist;n;n=n->next) ! n->found = 0; } char * ! new_name(path,name) ! char *path,*name; { ! char *path_buf; ! path_buf=(char *)malloc(strlen(path)+strlen(name)+2); ! if(path_buf==0) { ! msg("Can't allocate memory for name '%s/%s",path,name); ! exit(EX_SYSTEM); ! } ! (void) sprintf(path_buf,"%s/%s",path,name); ! return path_buf; } /* returns non-zero if the luser typed 'y' or 'Y', zero otherwise. */ int ! confirm(action,file) ! char *action, *file; { ! int c,nl; ! static FILE *confirm_file = 0; ! extern FILE *msg_file; ! extern char TTY_NAME[]; ! ! fprintf(msg_file,"%s %s?", action, file); ! fflush(msg_file); ! if(!confirm_file) { ! confirm_file = (archive == 0) ? fopen(TTY_NAME, "r") : stdin; ! if(!confirm_file) { ! msg("Can't read confirmation from user"); ! exit(EX_SYSTEM); ! } } ! c=getc(confirm_file); ! for(nl = c; nl != '\n' && nl != EOF; nl = getc(confirm_file)) ! ; ! return (c=='y' || c=='Y'); } char *x_buffer = 0; --- 1295,1369 ---- struct name *gnu_list_name; char * ! name_from_list () { ! if (!gnu_list_name) ! gnu_list_name = namelist; ! while (gnu_list_name && gnu_list_name->found) ! gnu_list_name = gnu_list_name->next; ! if (gnu_list_name) ! { ! gnu_list_name->found++; ! if (gnu_list_name->change_dir) ! if (chdir (gnu_list_name->change_dir) < 0) ! msg_perror ("can't chdir to %s", gnu_list_name->change_dir); ! return gnu_list_name->name; ! } ! return (char *) 0; } void ! blank_name_list () { ! struct name *n; ! gnu_list_name = 0; ! for (n = namelist; n; n = n->next) ! n->found = 0; } char * ! new_name (path, name) ! char *path, *name; { ! char *path_buf; ! path_buf = (char *) malloc (strlen (path) + strlen (name) + 2); ! if (path_buf == 0) ! { ! msg ("Can't allocate memory for name '%s/%s", path, name); ! exit (EX_SYSTEM); ! } ! (void) sprintf (path_buf, "%s/%s", path, name); ! return path_buf; } /* returns non-zero if the luser typed 'y' or 'Y', zero otherwise. */ int ! confirm (action, file) ! char *action, *file; { ! int c, nl; ! static FILE *confirm_file = 0; ! extern FILE *msg_file; ! extern char TTY_NAME[]; ! ! fprintf (msg_file, "%s %s?", action, file); ! fflush (msg_file); ! if (!confirm_file) ! { ! confirm_file = (archive == 0) ? fopen (TTY_NAME, "r") : stdin; ! if (!confirm_file) ! { ! msg ("Can't read confirmation from user"); ! exit (EX_SYSTEM); } ! } ! c = getc (confirm_file); ! for (nl = c; nl != '\n' && nl != EOF; nl = getc (confirm_file)) ! ; ! return (c == 'y' || c == 'Y'); } char *x_buffer = 0; *************** *** 1287,1400 **** int free_re_exclude = 0; void ! add_exclude(name) ! char *name; { ! /* char *rname;*/ ! /* char **tmp_ptr;*/ ! int size_buf; ! ! un_quote_string(name); ! size_buf = strlen(name); ! ! if(x_buffer==0) { ! x_buffer = (char *)ck_malloc(size_buf+1024); ! free_x_buffer=1024; ! } else if(free_x_buffer<=size_buf) { ! char *old_x_buffer; ! char **tmp_ptr; ! ! old_x_buffer = x_buffer; ! x_buffer = (char *)ck_realloc(x_buffer,size_x_buffer+1024); ! free_x_buffer = 1024; ! for(tmp_ptr=exclude;tmp_ptr #include --- 38,44 ---- posted to comp.sys.ibm.pc in November, 1988. Major performance enhancements and bug fixes, and source cleanup, ! by David MacKenzie, djm@gnu.ai.mit.edu. */ #include #include *************** *** 46,55 **** #include #include ! /* Number of new arguments to allocate space for at a time. */ #define ARGS_INCREMENT 10 ! /* The name this program was run with, for error messages. */ static char *program_name; static char **grow_argv (char **new_argv, int new_argc); --- 46,55 ---- #include #include ! /* Number of new arguments to allocate space for at a time. */ #define ARGS_INCREMENT 10 ! /* The name this program was run with, for error messages. */ static char *program_name; static char **grow_argv (char **new_argv, int new_argc); *************** *** 106,112 **** strlwr (path); do { ! /* Only match "." and ".." explicitly. */ if (*block.ff_name == '.' && *arg_base != '.') continue; path_length = stpcpy (path_base, block.ff_name) - path + 1; --- 106,112 ---- strlwr (path); do { ! /* Only match "." and ".." explicitly. */ if (*block.ff_name == '.' && *arg_base != '.') continue; path_length = stpcpy (path_base, block.ff_name) - path + 1; *************** *** 176,203 **** /* Shell-style pattern matching for ?, \, [], and * characters. I'm putting this replacement in the public domain. ! Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986. */ ! /* The character that inverts a character class; '!' or '^'. */ #define INVERT '!' static int star (char *string, char *pattern); /* Return nonzero if `string' matches Unix-style wildcard pattern ! `pattern'; zero if not. */ int wild_match (char *string, char *pattern) { ! int prev; /* Previous character in character class. */ ! int matched; /* If 1, character class has been matched. */ ! int reverse; /* If 1, character class is inverted. */ for (; *pattern; string++, pattern++) switch (*pattern) { case '\\': ! /* Literal match with following character; fall through. */ pattern++; default: if (*string != *pattern) --- 176,203 ---- /* Shell-style pattern matching for ?, \, [], and * characters. I'm putting this replacement in the public domain. ! Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986. */ ! /* The character that inverts a character class; '!' or '^'. */ #define INVERT '!' static int star (char *string, char *pattern); /* Return nonzero if `string' matches Unix-style wildcard pattern ! `pattern'; zero if not. */ int wild_match (char *string, char *pattern) { ! int prev; /* Previous character in character class. */ ! int matched; /* If 1, character class has been matched. */ ! int reverse; /* If 1, character class is inverted. */ for (; *pattern; string++, pattern++) switch (*pattern) { case '\\': ! /* Literal match with following character; fall through. */ pattern++; default: if (*string != *pattern) *************** *** 204,218 **** return 0; continue; case '?': ! /* Match anything. */ if (*string == '\0') return 0; continue; case '*': ! /* Trailing star matches everything. */ return *++pattern ? star (string, pattern) : 1; case '[': ! /* Check for inverse character class. */ reverse = pattern[1] == INVERT; if (reverse) pattern++; --- 204,218 ---- return 0; continue; case '?': ! /* Match anything. */ if (*string == '\0') return 0; continue; case '*': ! /* Trailing star matches everything. */ return *++pattern ? star (string, pattern) : 1; case '[': ! /* Check for inverse character class. */ reverse = pattern[1] == INVERT; if (reverse) pattern++; diff -c3 tar-1.11.1/testpad.c tar-1.11.2/testpad.c *** tar-1.11.1/testpad.c Fri Dec 20 13:50:22 1991 --- tar-1.11.2/testpad.c Fri Sep 18 14:45:58 1992 *************** *** 43,49 **** struct test1 t1; struct test2 t2; int t1diff, t2diff; ! FILE *fp = fopen("testpad.h", "w"); if (fp == 0) { --- 43,49 ---- struct test1 t1; struct test2 t2; int t1diff, t2diff; ! FILE *fp = fopen ("testpad.h", "w"); if (fp == 0) { *************** *** 53,61 **** exit (1); } ! t1diff = (char *)&t1.in[0] - (char *)&t1; ! t2diff = (char *)&t2.in[0] - (char *)&t2; ! if (t2diff == t1diff + 1) fprintf (fp, "#define NEEDPAD\n"); else if (t1diff != t2diff) --- 53,61 ---- exit (1); } ! t1diff = (char *) &t1.in[0] - (char *) &t1; ! t2diff = (char *) &t2.in[0] - (char *) &t2; ! if (t2diff == t1diff + 1) fprintf (fp, "#define NEEDPAD\n"); else if (t1diff != t2diff) diff -c3 tar-1.11.1/update.c tar-1.11.2/update.c *** tar-1.11.1/update.c Tue Sep 8 16:12:17 1992 --- tar-1.11.2/update.c Fri Sep 18 14:46:05 1992 *************** *** 66,184 **** if we can't backspace the output and have to null out the first part of the block */ ! extern void skip_file(); ! extern void skip_extended_headers(); extern union record *head; extern struct stat hstat; ! void append_file(); ! void close_archive(); ! int confirm(); ! void decode_header(); ! void fl_read(); ! void fl_write(); ! void flush_archive(); ! int move_arch(); ! struct name *name_scan(); ! char *name_from_list(); ! void name_expand(); ! void name_gather(); ! void names_notfound(); ! void open_archive(); ! int read_header(); ! void reset_eof(); ! void write_block(); ! void write_eot(); /* Implement the 'r' (add files to end of archive), and 'u' (add files to end of archive if they arent there, or are more up to date than the version in the archive.) commands.*/ void ! update_archive() { ! int found_end = 0; ! int status = 3; ! int prev_status; ! char *p; ! struct name *name; ! extern void dump_file(); ! ! name_gather(); ! if(cmd_mode==CMD_UPDATE) ! name_expand(); ! open_archive(2); /* Open for updating */ ! ! do { ! prev_status=status; ! status=read_header(); ! switch(status) { ! case EOF: ! found_end=1; ! break; ! ! case 0: /* A bad record */ ! userec(head); ! switch(prev_status) { ! case 3: ! msg("This doesn't look like a tar archive."); ! /* FALL THROUGH */ ! case 2: ! case 1: ! msg("Skipping to next header"); ! case 0: ! break; ! } ! break; ! ! /* A good record */ ! case 1: ! /* printf("File %s\n",head->header.name); */ ! /* head->header.name[NAMSIZ-1]='\0'; */ ! if(cmd_mode==CMD_UPDATE && (name=name_scan(current_file_name))) ! { ! ! /* struct stat hstat; */ ! struct stat nstat; ! int head_standard; ! ! decode_header(head,&hstat,&head_standard,0); ! if(stat(current_file_name,&nstat)<0) { ! msg_perror("can't stat %s:",current_file_name); ! } else { ! if(hstat.st_mtime>=nstat.st_mtime) ! name->found++; ! } ! } ! userec(head); ! if (head->header.isextended) ! skip_extended_headers(); ! skip_file((long)hstat.st_size); ! break; ! ! case 2: ! ar_record=head; ! found_end = 1; ! break; ! } ! } while(!found_end); ! ! reset_eof(); ! time_to_start_writing = 1; ! output_start=ar_record->charptr; ! ! while(p=name_from_list()) { ! if(f_confirm && !confirm("add", p)) ! continue; ! if(cmd_mode==CMD_CAT) ! append_file(p); ! else ! dump_file(p,-1, 1); ! } ! ! write_eot(); ! close_archive(); ! names_notfound(); } /* Catenate file p to the archive without creating a header for it. It had --- 66,192 ---- if we can't backspace the output and have to null out the first part of the block */ ! extern void skip_file (); ! extern void skip_extended_headers (); extern union record *head; extern struct stat hstat; ! void append_file (); ! void close_archive (); ! int confirm (); ! void decode_header (); ! void fl_read (); ! void fl_write (); ! void flush_archive (); ! int move_arch (); ! struct name *name_scan (); ! char *name_from_list (); ! void name_expand (); ! void name_gather (); ! void names_notfound (); ! void open_archive (); ! int read_header (); ! void reset_eof (); ! void write_block (); ! void write_eot (); /* Implement the 'r' (add files to end of archive), and 'u' (add files to end of archive if they arent there, or are more up to date than the version in the archive.) commands.*/ void ! update_archive () { ! int found_end = 0; ! int status = 3; ! int prev_status; ! char *p; ! struct name *name; ! extern void dump_file (); ! ! name_gather (); ! if (cmd_mode == CMD_UPDATE) ! name_expand (); ! open_archive (2); /* Open for updating */ ! ! do ! { ! prev_status = status; ! status = read_header (); ! switch (status) ! { ! case EOF: ! found_end = 1; ! break; ! ! case 0: /* A bad record */ ! userec (head); ! switch (prev_status) ! { ! case 3: ! msg ("This doesn't look like a tar archive."); ! /* FALL THROUGH */ ! case 2: ! case 1: ! msg ("Skipping to next header"); ! case 0: ! break; ! } ! break; ! ! /* A good record */ ! case 1: ! /* printf("File %s\n",head->header.name); */ ! /* head->header.name[NAMSIZ-1]='\0'; */ ! if (cmd_mode == CMD_UPDATE && (name = name_scan (current_file_name))) ! { ! ! /* struct stat hstat; */ ! struct stat nstat; ! int head_standard; ! ! decode_header (head, &hstat, &head_standard, 0); ! if (stat (current_file_name, &nstat) < 0) ! { ! msg_perror ("can't stat %s:", current_file_name); ! } ! else ! { ! if (hstat.st_mtime >= nstat.st_mtime) ! name->found++; ! } ! } ! userec (head); ! if (head->header.isextended) ! skip_extended_headers (); ! skip_file ((long) hstat.st_size); ! break; ! ! case 2: ! ar_record = head; ! found_end = 1; ! break; ! } ! } ! while (!found_end); ! ! reset_eof (); ! time_to_start_writing = 1; ! output_start = ar_record->charptr; ! ! while (p = name_from_list ()) ! { ! if (f_confirm && !confirm ("add", p)) ! continue; ! if (cmd_mode == CMD_CAT) ! append_file (p); ! else ! dump_file (p, -1, 1); ! } ! ! write_eot (); ! close_archive (); ! names_notfound (); } /* Catenate file p to the archive without creating a header for it. It had *************** *** 185,266 **** better be a tar file or the archive is screwed */ void ! append_file(p) ! char *p; { ! int fd; ! struct stat statbuf; ! long bytes_left; ! union record *start; ! long bufsiz,count; ! ! if(0 != stat(p,&statbuf) || (fd=open(p,O_RDONLY|O_BINARY))<0) { ! msg_perror("can't open file %s",p); ! errors++; ! return; ! } ! ! bytes_left = statbuf.st_size; ! ! while(bytes_left>0) { ! start=findrec(); ! bufsiz=endofrecs()->charptr - start->charptr; ! if(bytes_left < bufsiz) { ! bufsiz = bytes_left; ! count = bufsiz % RECORDSIZE; ! if(count) ! bzero(start->charptr + bytes_left,(int)(RECORDSIZE-count)); ! } ! count=read(fd,start->charptr,bufsiz); ! if(count<0) { ! msg_perror("read error at byte %ld reading %d bytes in file %s",statbuf.st_size-bytes_left,bufsiz,p); ! exit(EX_ARGSBAD); /* FOO */ ! } ! bytes_left-=count; ! userec(start+(count-1)/RECORDSIZE); ! if(count!=bufsiz) { ! msg("%s: file shrunk by %d bytes, yark!",p,bytes_left); ! abort(); ! } } ! (void)close(fd); } #ifdef DONTDEF ! bprint(fp,buf,num) ! FILE *fp; ! char *buf; { ! int c; ! if(num==0 || num==-1) ! return; ! fputs(" '",fp); ! while(num--) { ! c= *buf++; ! if(c=='\\') fputs("\\\\",fp); ! else if(c>=' ' && c<='~') ! putc(c,fp); ! else switch(c) { ! case '\n': ! fputs("\\n",fp); ! break; ! case '\r': ! fputs("\\r",fp); ! break; ! case '\b': ! fputs("\\b",fp); ! break; ! case '\0': ! /* fputs("\\-",fp); */ ! break; ! default: ! fprintf(fp,"\\%03o",c); ! break; ! } ! } ! fputs("'\n",fp); } #endif int number_of_blocks_read = 0; --- 193,284 ---- better be a tar file or the archive is screwed */ void ! append_file (p) ! char *p; { ! int fd; ! struct stat statbuf; ! long bytes_left; ! union record *start; ! long bufsiz, count; ! ! if (0 != stat (p, &statbuf) || (fd = open (p, O_RDONLY | O_BINARY)) < 0) ! { ! msg_perror ("can't open file %s", p); ! errors++; ! return; ! } ! ! bytes_left = statbuf.st_size; ! ! while (bytes_left > 0) ! { ! start = findrec (); ! bufsiz = endofrecs ()->charptr - start->charptr; ! if (bytes_left < bufsiz) ! { ! bufsiz = bytes_left; ! count = bufsiz % RECORDSIZE; ! if (count) ! bzero (start->charptr + bytes_left, (int) (RECORDSIZE - count)); ! } ! count = read (fd, start->charptr, bufsiz); ! if (count < 0) ! { ! msg_perror ("read error at byte %ld reading %d bytes in file %s", statbuf.st_size - bytes_left, bufsiz, p); ! exit (EX_ARGSBAD); /* FOO */ ! } ! bytes_left -= count; ! userec (start + (count - 1) / RECORDSIZE); ! if (count != bufsiz) ! { ! msg ("%s: file shrunk by %d bytes, yark!", p, bytes_left); ! abort (); } ! } ! (void) close (fd); } #ifdef DONTDEF ! bprint (fp, buf, num) ! FILE *fp; ! char *buf; { ! int c; ! if (num == 0 || num == -1) ! return; ! fputs (" '", fp); ! while (num--) ! { ! c = *buf++; ! if (c == '\\') ! fputs ("\\\\", fp); ! else if (c >= ' ' && c <= '~') ! putc (c, fp); ! else ! switch (c) ! { ! case '\n': ! fputs ("\\n", fp); ! break; ! case '\r': ! fputs ("\\r", fp); ! break; ! case '\b': ! fputs ("\\b", fp); ! break; ! case '\0': ! /* fputs("\\-",fp); */ ! break; ! default: ! fprintf (fp, "\\%03o", c); ! break; ! } ! } ! fputs ("'\n", fp); } + #endif int number_of_blocks_read = 0; *************** *** 272,509 **** union record *save_block = 0; void ! junk_archive() { ! int found_stuff = 0; ! int status = 3; ! int prev_status; ! struct name *name; ! ! /* int dummy_head; */ ! int number_of_records_to_skip = 0; ! int number_of_records_to_keep = 0; ! int number_of_kept_records_in_block; ! int sub_status; ! extern int write_archive_to_stdout; ! ! /* fprintf(stderr,"Junk files\n"); */ ! name_gather(); ! open_archive(2); ! ! while(!found_stuff) { ! prev_status=status; ! status=read_header(); ! switch(status) { ! case EOF: ! found_stuff = 1; ! break; ! ! case 0: ! userec(head); ! switch(prev_status) { ! case 3: ! msg("This doesn't look like a tar archive."); ! /* FALL THROUGH */ ! case 2: ! case 1: ! msg("Skipping to next header"); ! /* FALL THROUGH */ ! case 0: ! break; ! } ! break; ! ! case 1: ! /* head->header.name[NAMSIZ-1] = '\0'; */ ! /* fprintf(stderr,"file %s\n",head->header.name); */ ! if((name=name_scan(current_file_name))==(struct name *)0) { ! userec(head); ! /* fprintf(stderr,"Skip %ld\n",(long)(hstat.st_size)); */ ! if (head->header.isextended) ! skip_extended_headers(); ! skip_file((long)(hstat.st_size)); ! break; ! } ! name->found = 1; ! found_stuff = 2; ! break; ! ! case 2: ! found_stuff = 1; ! break; ! } ! } ! /* fprintf(stderr,"Out of first loop\n"); */ ! ! if(found_stuff!=2) { ! write_eot(); ! close_archive(); ! names_notfound(); ! return; ! } ! ! if(write_archive_to_stdout) ! write_archive_to_stdout = 0; ! new_block = (union record *)malloc(blocksize); ! if(new_block==0) { ! msg("Can't allocate secondary block of %d bytes",blocksize); ! exit(EX_SYSTEM); ! } ! ! /* Save away records before this one in this block */ ! number_of_new_records=ar_record-ar_block; ! number_of_records_needed = blocking - number_of_new_records; ! if(number_of_new_records) ! bcopy((void *)ar_block,(void *)new_block,(number_of_new_records)*RECORDSIZE); ! ! /* fprintf(stderr,"Saved %d recs, need %d more\n",number_of_new_records,number_of_records_needed); */ ! userec(head); ! if (head->header.isextended) ! skip_extended_headers(); ! skip_file((long)(hstat.st_size)); ! found_stuff=0; ! /* goto flush_file; */ ! ! for(;;) { ! /* Fill in a block */ ! /* another_file: */ ! if(ar_record==ar_last) { ! /* fprintf(stderr,"New block\n"); */ ! flush_archive(); ! number_of_blocks_read++; ! } ! sub_status = read_header(); ! /* fprintf(stderr,"Header type %d\n",sub_status); */ ! ! if(sub_status==2 && f_ignorez) { ! userec(head); ! continue; ! } ! if(sub_status==EOF || sub_status==2) { ! found_stuff = 1; ! bzero(new_block[number_of_new_records].charptr,RECORDSIZE*number_of_records_needed); ! number_of_new_records+=number_of_records_needed; ! number_of_records_needed = 0; ! write_block(0); ! break; ! } ! ! if(sub_status==0) { ! msg("Deleting non-header from archive."); ! userec(head); ! continue; ! } ! ! /* Found another header. Yipee! */ ! /* head->header.name[NAMSIZ-1] = '\0'; */ ! /* fprintf(stderr,"File %s ",head->header.name); */ ! if(name=name_scan(current_file_name)) { ! name->found = 1; ! /* fprintf(stderr,"Flush it\n"); */ ! /* flush_file: */ ! /* decode_header(head,&hstat,&dummy_head,0); */ ! userec(head); ! number_of_records_to_skip=(hstat.st_size+RECORDSIZE-1)/RECORDSIZE; ! /* fprintf(stderr,"Flushing %d recs from %s\n",number_of_records_to_skip,head->header.name); */ ! ! while(ar_last-ar_record<=number_of_records_to_skip) { ! ! /* fprintf(stderr,"Block: %d <= %d ",ar_last-ar_record,number_of_records_to_skip); */ ! number_of_records_to_skip -= (ar_last - ar_record); ! flush_archive(); ! number_of_blocks_read++; ! /* fprintf(stderr,"Block %d left\n",number_of_records_to_skip); */ ! } ! ar_record+=number_of_records_to_skip; ! /* fprintf(stderr,"Final %d\n",number_of_records_to_skip); */ ! number_of_records_to_skip = 0; ! continue; ! } ! ! /* copy_header: */ ! new_block[number_of_new_records]= *head; ! number_of_new_records++; ! number_of_records_needed--; ! number_of_records_to_keep=(hstat.st_size+RECORDSIZE-1)/RECORDSIZE; ! userec(head); ! if(number_of_records_needed==0) ! write_block(1); ! /* copy_data: */ ! number_of_kept_records_in_block = ar_last - ar_record; ! if(number_of_kept_records_in_block > number_of_records_to_keep) ! number_of_kept_records_in_block = number_of_records_to_keep; ! ! /* fprintf(stderr,"Need %d kept_in %d keep %d\n",blocking,number_of_kept_records_in_block,number_of_records_to_keep); */ ! ! while(number_of_records_to_keep) { ! int n; ! ! if(ar_record==ar_last) { ! /* fprintf(stderr,"Flush. . .\n"); */ ! fl_read(); ! number_of_blocks_read++; ! ar_record=ar_block; ! number_of_kept_records_in_block = blocking; ! if(number_of_kept_records_in_block > number_of_records_to_keep) ! number_of_kept_records_in_block = number_of_records_to_keep; ! } ! n = number_of_kept_records_in_block; ! if(n>number_of_records_needed) ! n = number_of_records_needed; ! ! /* fprintf(stderr,"Copying %d\n",n); */ ! bcopy((void *)ar_record, (void *)(new_block+number_of_new_records), n*RECORDSIZE); ! number_of_new_records += n; ! number_of_records_needed -= n; ! ar_record += n; ! number_of_records_to_keep -= n; ! number_of_kept_records_in_block -= n; ! /* fprintf(stderr,"Now new %d need %d keep %d keep_in %d rec %d/%d\n", number_of_new_records,number_of_records_needed,number_of_records_to_keep, number_of_kept_records_in_block,ar_record-ar_block,ar_last-ar_block); */ - - if(number_of_records_needed == 0) { - write_block(1); - } - } - } ! write_eot(); ! close_archive(); ! names_notfound(); } void ! write_block(f) int f; { ! /* fprintf(stderr,"Write block\n"); */ ! /* We've filled out a block. Write it out. */ ! /* Backspace back to where we started. . . */ ! if(archive!=STDIN) ! (void)move_arch(-(number_of_blocks_read+1)); ! save_block = ar_block; ! ar_block = new_block; ! ! if(archive==STDIN) ! archive=STDOUT; ! fl_write(); ! ! if(archive==STDOUT) ! archive=STDIN; ! ar_block = save_block; ! ! if(f) { ! /* Move the tape head back to where we were */ ! if(archive!=STDIN) ! (void)move_arch(number_of_blocks_read); ! number_of_blocks_read--; ! } ! ! number_of_records_needed = blocking; ! number_of_new_records = 0; } /* Move archive descriptor by n blocks worth. If n is positive we move --- 290,544 ---- union record *save_block = 0; void ! junk_archive () { ! int found_stuff = 0; ! int status = 3; ! int prev_status; ! struct name *name; ! ! /* int dummy_head; */ ! int number_of_records_to_skip = 0; ! int number_of_records_to_keep = 0; ! int number_of_kept_records_in_block; ! int sub_status; ! extern int write_archive_to_stdout; ! ! /* fprintf(stderr,"Junk files\n"); */ ! name_gather (); ! open_archive (2); ! ! while (!found_stuff) ! { ! prev_status = status; ! status = read_header (); ! switch (status) ! { ! case EOF: ! found_stuff = 1; ! break; ! ! case 0: ! userec (head); ! switch (prev_status) ! { ! case 3: ! msg ("This doesn't look like a tar archive."); ! /* FALL THROUGH */ ! case 2: ! case 1: ! msg ("Skipping to next header"); ! /* FALL THROUGH */ ! case 0: ! break; ! } ! break; ! ! case 1: ! /* head->header.name[NAMSIZ-1] = '\0'; */ ! /* fprintf(stderr,"file %s\n",head->header.name); */ ! if ((name = name_scan (current_file_name)) == (struct name *) 0) ! { ! userec (head); ! /* fprintf(stderr,"Skip %ld\n",(long)(hstat.st_size)); */ ! if (head->header.isextended) ! skip_extended_headers (); ! skip_file ((long) (hstat.st_size)); ! break; ! } ! name->found = 1; ! found_stuff = 2; ! break; ! ! case 2: ! found_stuff = 1; ! break; ! } ! } ! /* fprintf(stderr,"Out of first loop\n"); */ ! ! if (found_stuff != 2) ! { ! write_eot (); ! close_archive (); ! names_notfound (); ! return; ! } ! ! if (write_archive_to_stdout) ! write_archive_to_stdout = 0; ! new_block = (union record *) malloc (blocksize); ! if (new_block == 0) ! { ! msg ("Can't allocate secondary block of %d bytes", blocksize); ! exit (EX_SYSTEM); ! } ! ! /* Save away records before this one in this block */ ! number_of_new_records = ar_record - ar_block; ! number_of_records_needed = blocking - number_of_new_records; ! if (number_of_new_records) ! bcopy ((void *) ar_block, (void *) new_block, (number_of_new_records) * RECORDSIZE); ! ! /* fprintf(stderr,"Saved %d recs, need %d more\n",number_of_new_records,number_of_records_needed); */ ! userec (head); ! if (head->header.isextended) ! skip_extended_headers (); ! skip_file ((long) (hstat.st_size)); ! found_stuff = 0; ! /* goto flush_file; */ ! ! for (;;) ! { ! /* Fill in a block */ ! /* another_file: */ ! if (ar_record == ar_last) ! { ! /* fprintf(stderr,"New block\n"); */ ! flush_archive (); ! number_of_blocks_read++; ! } ! sub_status = read_header (); ! /* fprintf(stderr,"Header type %d\n",sub_status); */ ! ! if (sub_status == 2 && f_ignorez) ! { ! userec (head); ! continue; ! } ! if (sub_status == EOF || sub_status == 2) ! { ! found_stuff = 1; ! bzero (new_block[number_of_new_records].charptr, RECORDSIZE * number_of_records_needed); ! number_of_new_records += number_of_records_needed; ! number_of_records_needed = 0; ! write_block (0); ! break; ! } ! ! if (sub_status == 0) ! { ! msg ("Deleting non-header from archive."); ! userec (head); ! continue; ! } ! ! /* Found another header. Yipee! */ ! /* head->header.name[NAMSIZ-1] = '\0'; */ ! /* fprintf(stderr,"File %s ",head->header.name); */ ! if (name = name_scan (current_file_name)) ! { ! name->found = 1; ! /* fprintf(stderr,"Flush it\n"); */ ! /* flush_file: */ ! /* decode_header(head,&hstat,&dummy_head,0); */ ! userec (head); ! number_of_records_to_skip = (hstat.st_size + RECORDSIZE - 1) / RECORDSIZE; ! /* fprintf(stderr,"Flushing %d recs from %s\n",number_of_records_to_skip,head->header.name); */ ! ! while (ar_last - ar_record <= number_of_records_to_skip) ! { ! ! /* fprintf(stderr,"Block: %d <= %d ",ar_last-ar_record,number_of_records_to_skip); */ ! number_of_records_to_skip -= (ar_last - ar_record); ! flush_archive (); ! number_of_blocks_read++; ! /* fprintf(stderr,"Block %d left\n",number_of_records_to_skip); */ ! } ! ar_record += number_of_records_to_skip; ! /* fprintf(stderr,"Final %d\n",number_of_records_to_skip); */ ! number_of_records_to_skip = 0; ! continue; ! } ! ! /* copy_header: */ ! new_block[number_of_new_records] = *head; ! number_of_new_records++; ! number_of_records_needed--; ! number_of_records_to_keep = (hstat.st_size + RECORDSIZE - 1) / RECORDSIZE; ! userec (head); ! if (number_of_records_needed == 0) ! write_block (1); ! /* copy_data: */ ! number_of_kept_records_in_block = ar_last - ar_record; ! if (number_of_kept_records_in_block > number_of_records_to_keep) ! number_of_kept_records_in_block = number_of_records_to_keep; ! ! /* fprintf(stderr,"Need %d kept_in %d keep %d\n",blocking,number_of_kept_records_in_block,number_of_records_to_keep); */ ! ! while (number_of_records_to_keep) ! { ! int n; ! ! if (ar_record == ar_last) ! { ! /* fprintf(stderr,"Flush. . .\n"); */ ! fl_read (); ! number_of_blocks_read++; ! ar_record = ar_block; ! number_of_kept_records_in_block = blocking; ! if (number_of_kept_records_in_block > number_of_records_to_keep) ! number_of_kept_records_in_block = number_of_records_to_keep; ! } ! n = number_of_kept_records_in_block; ! if (n > number_of_records_needed) ! n = number_of_records_needed; ! ! /* fprintf(stderr,"Copying %d\n",n); */ ! bcopy ((void *) ar_record, (void *) (new_block + number_of_new_records), n * RECORDSIZE); ! number_of_new_records += n; ! number_of_records_needed -= n; ! ar_record += n; ! number_of_records_to_keep -= n; ! number_of_kept_records_in_block -= n; ! /* fprintf(stderr,"Now new %d need %d keep %d keep_in %d rec %d/%d\n", number_of_new_records,number_of_records_needed,number_of_records_to_keep, number_of_kept_records_in_block,ar_record-ar_block,ar_last-ar_block); */ ! if (number_of_records_needed == 0) ! { ! write_block (1); ! } ! } ! } ! ! write_eot (); ! close_archive (); ! names_notfound (); } void ! write_block (f) int f; { ! /* fprintf(stderr,"Write block\n"); */ ! /* We've filled out a block. Write it out. */ ! /* Backspace back to where we started. . . */ ! if (archive != STDIN) ! (void) move_arch (-(number_of_blocks_read + 1)); ! ! save_block = ar_block; ! ar_block = new_block; ! ! if (archive == STDIN) ! archive = STDOUT; ! fl_write (); ! ! if (archive == STDOUT) ! archive = STDIN; ! ar_block = save_block; ! ! if (f) ! { ! /* Move the tape head back to where we were */ ! if (archive != STDIN) ! (void) move_arch (number_of_blocks_read); ! number_of_blocks_read--; ! } ! number_of_records_needed = blocking; ! number_of_new_records = 0; } /* Move archive descriptor by n blocks worth. If n is positive we move *************** *** 511,547 **** work. If its something else, we try to seek on it. If we can't seek, we lose! */ int ! move_arch(n) int n; { ! long cur; #ifdef MTIOCTOP ! struct mtop t; ! int er; ! if(n>0) { ! t.mt_op = MTFSR; ! t.mt_count = n; ! } else { ! t.mt_op = MTBSR; ! t.mt_count = -n; ! } ! if((er=rmtioctl(archive,MTIOCTOP,&t))>=0) ! return 1; ! if(errno==EIO && (er=rmtioctl(archive,MTIOCTOP,&t))>=0) ! return 1; #endif ! cur=rmtlseek(archive,0L,1); ! cur+=blocksize*n; ! /* fprintf(stderr,"Fore to %x\n",cur); */ ! if(rmtlseek(archive,cur,0)!=cur) { ! /* Lseek failed. Try a different method */ ! msg("Couldn't re-position archive file."); ! exit(EX_BADARCH); ! } ! return 3; } - --- 546,585 ---- work. If its something else, we try to seek on it. If we can't seek, we lose! */ int ! move_arch (n) int n; { ! long cur; #ifdef MTIOCTOP ! struct mtop t; ! int er; ! if (n > 0) ! { ! t.mt_op = MTFSR; ! t.mt_count = n; ! } ! else ! { ! t.mt_op = MTBSR; ! t.mt_count = -n; ! } ! if ((er = rmtioctl (archive, MTIOCTOP, &t)) >= 0) ! return 1; ! if (errno == EIO && (er = rmtioctl (archive, MTIOCTOP, &t)) >= 0) ! return 1; #endif ! cur = rmtlseek (archive, 0L, 1); ! cur += blocksize * n; ! /* fprintf(stderr,"Fore to %x\n",cur); */ ! if (rmtlseek (archive, cur, 0) != cur) ! { ! /* Lseek failed. Try a different method */ ! msg ("Couldn't re-position archive file."); ! exit (EX_BADARCH); ! } ! return 3; } diff -c3 tar-1.11.1/version.c tar-1.11.2/version.c *** tar-1.11.1/version.c Fri Sep 11 00:38:53 1992 --- tar-1.11.2/version.c Thu Mar 25 13:35:25 1993 *************** *** 1 **** ! char version_string[] = "GNU tar version 1.11.1"; --- 1 ---- ! char version_string[] = "GNU tar version 1.11.2";