diff options
Diffstat (limited to 'libtar')
39 files changed, 7404 insertions, 0 deletions
diff --git a/libtar/Android.mk b/libtar/Android.mk new file mode 100644 index 000000000..838b44175 --- /dev/null +++ b/libtar/Android.mk @@ -0,0 +1,39 @@ +LOCAL_PATH := $(call my-dir) + +# Build shared library +include $(CLEAR_VARS) + +LOCAL_MODULE := libtar +LOCAL_MODULE_TAGS := eng optional +LOCAL_CFLAGS := +LOCAL_SRC_FILES = append.c block.c decode.c encode.c extract.c handle.c output.c util.c wrapper.c basename.c strmode.c libtar_hash.c libtar_list.c dirname.c +LOCAL_C_INCLUDES += $(LOCAL_PATH) \ + external/zlib +LOCAL_SHARED_LIBRARIES += libz libc + +ifeq ($(TWHAVE_SELINUX), true) + LOCAL_C_INCLUDES += external/libselinux/include + LOCAL_SHARED_LIBRARIES += libselinux + LOCAL_CFLAGS += -DHAVE_SELINUX +endif + +include $(BUILD_SHARED_LIBRARY) + +# Build static library +include $(CLEAR_VARS) + +LOCAL_MODULE := libtar_static +LOCAL_MODULE_TAGS := eng optional +LOCAL_CFLAGS = +LOCAL_SRC_FILES = append.c block.c decode.c encode.c extract.c handle.c output.c util.c wrapper.c basename.c strmode.c libtar_hash.c libtar_list.c dirname.c +LOCAL_C_INCLUDES += $(LOCAL_PATH) \ + external/zlib +LOCAL_STATIC_LIBRARIES += libz libc + +ifeq ($(TWHAVE_SELINUX), true) + LOCAL_C_INCLUDES += external/libselinux/include + LOCAL_STATIC_LIBRARIES += libselinux + LOCAL_CFLAGS += -DHAVE_SELINUX +endif + +include $(BUILD_STATIC_LIBRARY) diff --git a/libtar/COPYRIGHT b/libtar/COPYRIGHT new file mode 100644 index 000000000..2471ec01b --- /dev/null +++ b/libtar/COPYRIGHT @@ -0,0 +1,35 @@ +Copyright (c) 1998-2003 University of Illinois Board of Trustees +Copyright (c) 1998-2003 Mark D. Roth +All rights reserved. + +Developed by: Campus Information Technologies and Educational Services, + University of Illinois at Urbana-Champaign + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +``Software''), to deal with the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimers. + +* Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + +* Neither the names of Campus Information Technologies and Educational + Services, University of Illinois at Urbana-Champaign, nor the names + of its contributors may be used to endorse or promote products derived + from this Software without specific prior written permission. + +THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. + diff --git a/libtar/ChangeLog b/libtar/ChangeLog new file mode 100644 index 000000000..cde7675e2 --- /dev/null +++ b/libtar/ChangeLog @@ -0,0 +1,15 @@ +2002-12-09 added list_empty() and hash_empty() functions + +2002-09-12 fixed list_iterate function to return -1 if it gets + an invalid argument + + include <config.h> and <compat.h> from source files, not + from header file, since header file is sometimes + installed as part of a user-visible API + (those APIs should eventually be redesigned without the + listhash code being publicly visible, but for now we + need to accomodate this) + +2002-07-07 modified list iterate function to return int + (returns -1 if plugin function returns -1) + diff --git a/libtar/ChangeLog-1.0.x b/libtar/ChangeLog-1.0.x new file mode 100644 index 000000000..23b06b3ac --- /dev/null +++ b/libtar/ChangeLog-1.0.x @@ -0,0 +1,141 @@ +libtar 1.0.2 - 6/21/00 +------------ + +- tar_set_file_perms() now calls chown() only if the effective user ID is 0 + (workaround for IRIX and HP-UX, which allow file giveaways) + +- tar_set_file_perms() now calls chmod() or lchmod() after chown() + (this fixes a problem with extracting setuid files under Linux) + +- removed calls to fchown() and fchmod() from tar_extract_regfile() + +- fixed bugs in th_read() which didn't set errno properly + +- removed various unused variables + +---------------------------------------------------------------------- + +libtar 1.0.1 - 4/1/00 +------------ + +- removed libgen.h include from dirname and basename compat code + +- added lib/fnmatch.c compatability module from OpenBSD + +- fixed several objdirs bugs in libtar/Makefile.in + +- misc Makefile changes (added $CPPFLAGS support, added -o flag to compile + commands, use $CFLAGS on link line, etc) + +- removed "inline" keyword from all source files to prevent portability + problems + +- updated README + +---------------------------------------------------------------------- + +libtar 1.0 - 1/2/00 +---------- + +- various portability fixes + +- "make install" now runs mkencap and epkg if they're available + +- libmisc is now integrated into libtar + +---------------------------------------------------------------------- + +libtar 0.5.6 beta - 12/16/99 +----------------- + +- changed API to allow better error reporting via errno + +- added manpages to document libtar API + +- replaced symbolic_mode() call with strmode() compatibility code + +---------------------------------------------------------------------- + +libtar 0.5.5 beta - 11/16/99 +----------------- + +- fixed conditional expression in extract.c to check if we're overwriting + a pre-existing file + +- many improvements to libtar.c driver program (better error checking, + added -C and -v options, etc) + +- changed API to include list of canned file types, instead of passing + function pointers to tar_open() + +- fixed tar_set_file_perms() to not complain about chown() if not root + and not to call utime() on a symlink + +- added hash code for extracting hard links in other directory paths + +- fixed tar_extract_glob() to only print filenames if TAR_VERBOSE option + is set + +- replaced GNU basename(), dirname(), and strdup() compatibility code + with OpenBSD versions + +- configure performs super-anal checking of basename() and dirname() + +---------------------------------------------------------------------- + +libtar 0.5.4 beta - 11/13/99 +----------------- + +- portability fix: use ranlib instead of ar -s + +- misc fixes in append.c, extract.c, and wrapper.c to do error checking + +- fixed a bug in tar_append_file() in append.c which added some garbage + characters to encoded symlink names (wasn't NULL-terminating the result + of readlink()) + +- fixed a bug in symbolic_mode() in output.c concerning setuid and setgid + bit displaying + +- fixed tar_extract_all() in wrapper.c to only call print_long_ls() if + the TAR_VERBOSE option is set + +- added libtar_version constant string to handle.c for external configure + scripts to detect what version of libtar is installed + +---------------------------------------------------------------------- + +libtar 0.5.3 beta - 09/27/99 +----------------- + +- fixed mk_dirs_for_file() to avoid broken dirname() implementations + +- misc portability fixes + +- merged old "compat" and "libds" directories into new "misc" directory + and cleaned up Makefiles + +---------------------------------------------------------------------- + +libtar 0.5.2 beta - 09/10/99 +----------------- + +- use calloc() instead of malloc() in tar_open() to fix a bounds-checking + bug in tar_extract_all() + +- fix tar_extract_all() to properly honor the prefix argument + +---------------------------------------------------------------------- + +libtar 0.5.1 beta - 08/27/99 +----------------- + +- misc portability fixes + +---------------------------------------------------------------------- + +libtar 0.5 beta - 07/05/99 +--------------- + +- first public release + diff --git a/libtar/INSTALL b/libtar/INSTALL new file mode 100644 index 000000000..50dbe439d --- /dev/null +++ b/libtar/INSTALL @@ -0,0 +1,183 @@ +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, 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 +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + 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. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. + diff --git a/libtar/README b/libtar/README new file mode 100644 index 000000000..91f466cbe --- /dev/null +++ b/libtar/README @@ -0,0 +1,121 @@ +libtar - C library for manipulating tar files +====== + +libtar is a library for manipulating tar files from within C programs. +Here are some of its features: + + * Handles both POSIX tar file format and the GNU extensions. + * API provides functions for easy use, such as tar_extract_all(). + * Also provides functions for more granular use, such as + tar_append_regfile(). + + +Installation +------------ + +To build libtar, you should be able to simply run these commands: + + ./configure + make + make install + + +Encap Package Support +--------------------- + +To build this software as an Encap package, you can pass the +--enable-encap option to configure. This will be automatically +enabled if the epkg or mkencap programs are detected on the system, +but can be overridden by the --disable-encap option. + +When building an Encap package, the configure script will automatically +adjust the installation prefix to use an appropriate Encap package +directory. It does this using a heuristic algorithm which examines the +values of the ${ENCAP_SOURCE} and ${ENCAP_TARGET} environment variables +and the argument to configure's --prefix option. + +If mkencap was detected on the system, it will be automatically run during +"make install". By default, epkg will also be run, but this can be +inhibited with the --disable-epkg-install configure option. + +For information on the Encap package management system, see the WSG +Encap Archive: + + http://www.encap.org/ + + +zlib Support +------------ + +The configure script will attempt to find the zlib library on your system +for use with the libtar driver program. The zlib package is available from: + + http://www.gzip.org/zlib/ + +If zlib is installed on your system, but you do not wish to use it, +specify the --without-zlib option when you invoke configure. + + +More Information +---------------- + +For documentation of the libtar API, see the enclosed manpages. For more +information on the libtar package, see: + + http://www-dev.cites.uiuc.edu/libtar/ + +Source code for the latest version of libtar will be available there, as +well as Encap binary distributions for many common platforms. + + +Supported Platforms +------------------- + +I develop and test libtar on the following platforms: + + AIX 4.3.3 and 5.1 + HP-UX 11.00 + IRIX 6.5 + RedHat Linux 7.2 + Solaris 8 and 9 + +It should also build on the following platforms, but I do not actively +support them: + + AIX 3.2.5 + AIX 4.2.1 + Cygwin + FreeBSD + HP-UX 10.20 + Linux/libc5 + OpenBSD + Solaris 2.5 + Solaris 2.6 + Solaris 7 + +If you successfully build libtar on another platform, please email me a +patch and/or configuration information. + + +Compatibility Code +------------------ + +libtar depends on some library calls which are not available or not +usable on some platforms. To accomodate these systems, I've included +a version of these calls in the compat subdirectory. + +I've slightly modified these functions for integration into this source +tree, but the functionality has not been modified from the original +source. Please note that while this code should work for you, I didn't +write it, so please don't send me bug reports on it. + + +Author +------ + +Feedback and bug reports are welcome. + +Mark D. Roth <roth@uiuc.edu> +Campus Information Technologies and Educational Services +University of Illinois at Urbana-Champaign + diff --git a/libtar/TODO b/libtar/TODO new file mode 100644 index 000000000..f2f859f54 --- /dev/null +++ b/libtar/TODO @@ -0,0 +1,21 @@ +Functionality: +-------------- + +* add list mode to allow nodes to be inserted in any arbitrary location +* add "*_hash_iterate()" function +* add flags argument to *_list_del() that allows the listptr to be set + to the previous or next element +* add a generic pointer type to replace *_listptr_t and *_hashptr_t ??? + + +Code Cleanup: +------------- + +* rename functions: + *_list_next => *_listptr_next() + *_list_prev => *_listptr_prev() + *_hash_next => *_hashptr_next() +* start using "*_list_t" and "*_hash_t" instead of "*_list_t *" and + "*_hash_t *" ? +* add prefixes to structure member field names + diff --git a/libtar/append.c b/libtar/append.c new file mode 100644 index 000000000..1831990be --- /dev/null +++ b/libtar/append.c @@ -0,0 +1,277 @@ +/* +** Copyright 1998-2003 University of Illinois Board of Trustees +** Copyright 1998-2003 Mark D. Roth +** All rights reserved. +** +** append.c - libtar code to append files to a tar archive +** +** Mark D. Roth <roth@uiuc.edu> +** Campus Information Technologies and Educational Services +** University of Illinois at Urbana-Champaign +*/ + +#include <internal.h> + +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/param.h> +#include <sys/types.h> + +#ifdef STDC_HEADERS +# include <stdlib.h> +# include <string.h> +#endif + +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#ifdef HAVE_SELINUX +#include "selinux/selinux.h" +#endif + +struct tar_dev +{ + dev_t td_dev; + libtar_hash_t *td_h; +}; +typedef struct tar_dev tar_dev_t; + +struct tar_ino +{ + ino_t ti_ino; + char ti_name[MAXPATHLEN]; +}; +typedef struct tar_ino tar_ino_t; + + +/* free memory associated with a tar_dev_t */ +void +tar_dev_free(tar_dev_t *tdp) +{ + libtar_hash_free(tdp->td_h, free); + free(tdp); +} + + +/* appends a file to the tar archive */ +int +tar_append_file(TAR *t, char *realname, char *savename) +{ + struct stat s; + int i; + libtar_hashptr_t hp; + tar_dev_t *td = NULL; + tar_ino_t *ti = NULL; + char path[MAXPATHLEN]; + +#ifdef DEBUG + printf("==> tar_append_file(TAR=0x%lx (\"%s\"), realname=\"%s\", " + "savename=\"%s\")\n", t, t->pathname, realname, + (savename ? savename : "[NULL]")); +#endif + + if (lstat(realname, &s) != 0) + { +#ifdef DEBUG + perror("lstat()"); +#endif + return -1; + } + + /* set header block */ +#ifdef DEBUG + puts(" tar_append_file(): setting header block..."); +#endif + memset(&(t->th_buf), 0, sizeof(struct tar_header)); + th_set_from_stat(t, &s); + + /* set the header path */ +#ifdef DEBUG + puts(" tar_append_file(): setting header path..."); +#endif + th_set_path(t, (savename ? savename : realname)); + +#ifdef HAVE_SELINUX + /* get selinux context */ + if(t->options & TAR_STORE_SELINUX) { + if(t->th_buf.selinux_context != NULL) { + free(t->th_buf.selinux_context); + t->th_buf.selinux_context = NULL; + } + + security_context_t selinux_context = NULL; + if (lgetfilecon(realname, &selinux_context) >= 0) { + t->th_buf.selinux_context = strdup(selinux_context); + printf("setting selinux context: %s\n", selinux_context); + freecon(selinux_context); + } + else + perror("Failed to get selinux context"); + } +#endif + /* check if it's a hardlink */ +#ifdef DEBUG + puts(" tar_append_file(): checking inode cache for hardlink..."); +#endif + libtar_hashptr_reset(&hp); + if (libtar_hash_getkey(t->h, &hp, &(s.st_dev), + (libtar_matchfunc_t)dev_match) != 0) + td = (tar_dev_t *)libtar_hashptr_data(&hp); + else + { +#ifdef DEBUG + printf("+++ adding hash for device (0x%lx, 0x%lx)...\n", + major(s.st_dev), minor(s.st_dev)); +#endif + td = (tar_dev_t *)calloc(1, sizeof(tar_dev_t)); + td->td_dev = s.st_dev; + td->td_h = libtar_hash_new(256, (libtar_hashfunc_t)ino_hash); + if (td->td_h == NULL) + return -1; + if (libtar_hash_add(t->h, td) == -1) + return -1; + } + libtar_hashptr_reset(&hp); + if (libtar_hash_getkey(td->td_h, &hp, &(s.st_ino), + (libtar_matchfunc_t)ino_match) != 0) + { + ti = (tar_ino_t *)libtar_hashptr_data(&hp); +#ifdef DEBUG + printf(" tar_append_file(): encoding hard link \"%s\" " + "to \"%s\"...\n", realname, ti->ti_name); +#endif + t->th_buf.typeflag = LNKTYPE; + th_set_link(t, ti->ti_name); + } + else + { +#ifdef DEBUG + printf("+++ adding entry: device (0x%lx,0x%lx), inode %ld " + "(\"%s\")...\n", major(s.st_dev), minor(s.st_dev), + s.st_ino, realname); +#endif + ti = (tar_ino_t *)calloc(1, sizeof(tar_ino_t)); + if (ti == NULL) + return -1; + ti->ti_ino = s.st_ino; + snprintf(ti->ti_name, sizeof(ti->ti_name), "%s", + savename ? savename : realname); + libtar_hash_add(td->td_h, ti); + } + + /* check if it's a symlink */ + if (TH_ISSYM(t)) + { + i = readlink(realname, path, sizeof(path)); + if (i == -1) + return -1; + if (i >= MAXPATHLEN) + i = MAXPATHLEN - 1; + path[i] = '\0'; +#ifdef DEBUG + printf(" tar_append_file(): encoding symlink \"%s\" -> " + "\"%s\"...\n", realname, path); +#endif + th_set_link(t, path); + } + + /* print file info */ + if (t->options & TAR_VERBOSE) + th_print_long_ls(t); + +#ifdef DEBUG + puts(" tar_append_file(): writing header"); +#endif + /* write header */ + if (th_write(t) != 0) + { +#ifdef DEBUG + printf("t->fd = %d\n", t->fd); +#endif + return -1; + } +#ifdef DEBUG + puts(" tar_append_file(): back from th_write()"); +#endif + + /* if it's a regular file, write the contents as well */ + if (TH_ISREG(t) && tar_append_regfile(t, realname) != 0) + return -1; + + return 0; +} + + +/* write EOF indicator */ +int +tar_append_eof(TAR *t) +{ + int i, j; + char block[T_BLOCKSIZE]; + + memset(&block, 0, T_BLOCKSIZE); + for (j = 0; j < 2; j++) + { + i = tar_block_write(t, &block); + if (i != T_BLOCKSIZE) + { + if (i != -1) + errno = EINVAL; + return -1; + } + } + + return 0; +} + + +/* add file contents to a tarchive */ +int +tar_append_regfile(TAR *t, char *realname) +{ + char block[T_BLOCKSIZE]; + int filefd; + int j; + size_t size, i; + + filefd = open(realname, O_RDONLY); + if (filefd == -1) + { +#ifdef DEBUG + perror("open()"); +#endif + return -1; + } + + size = th_get_size(t); + for (i = size; i > T_BLOCKSIZE; i -= T_BLOCKSIZE) + { + j = read(filefd, &block, T_BLOCKSIZE); + if (j != T_BLOCKSIZE) + { + if (j != -1) + errno = EINVAL; + return -1; + } + if (tar_block_write(t, &block) == -1) + return -1; + } + + if (i > 0) + { + j = read(filefd, &block, i); + if (j == -1) + return -1; + memset(&(block[i]), 0, T_BLOCKSIZE - i); + if (tar_block_write(t, &block) == -1) + return -1; + } + + close(filefd); + + return 0; +} + + diff --git a/libtar/basename.c b/libtar/basename.c new file mode 100644 index 000000000..2ac1e139e --- /dev/null +++ b/libtar/basename.c @@ -0,0 +1,74 @@ +/* $OpenBSD: basename.c,v 1.4 1999/05/30 17:10:30 espie Exp $ */ + +/* + * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef lint +static char rcsid[] = "$OpenBSD: basename.c,v 1.4 1999/05/30 17:10:30 espie Exp $"; +#endif /* not lint */ + +#include <errno.h> +#include <string.h> +#include <sys/param.h> + +char * +openbsd_basename(path) + const char *path; +{ + static char bname[MAXPATHLEN]; + register const char *endp, *startp; + + /* Empty or NULL string gets treated as "." */ + if (path == NULL || *path == '\0') { + (void)strcpy(bname, "."); + return(bname); + } + + /* Strip trailing slashes */ + endp = path + strlen(path) - 1; + while (endp > path && *endp == '/') + endp--; + + /* All slashes becomes "/" */ + if (endp == path && *endp == '/') { + (void)strcpy(bname, "/"); + return(bname); + } + + /* Find the start of the base */ + startp = endp; + while (startp > path && *(startp - 1) != '/') + startp--; + + if (endp - startp + 1 > sizeof(bname)) { + errno = ENAMETOOLONG; + return(NULL); + } + (void)strncpy(bname, startp, endp - startp + 1); + bname[endp - startp + 1] = '\0'; + return(bname); +} diff --git a/libtar/block.c b/libtar/block.c new file mode 100644 index 000000000..6ed9e6000 --- /dev/null +++ b/libtar/block.c @@ -0,0 +1,496 @@ +/* +** Copyright 1998-2003 University of Illinois Board of Trustees +** Copyright 1998-2003 Mark D. Roth +** All rights reserved. +** +** block.c - libtar code to handle tar archive header blocks +** +** Mark D. Roth <roth@uiuc.edu> +** Campus Information Technologies and Educational Services +** University of Illinois at Urbana-Champaign +*/ + +#include <internal.h> +#include <stdio.h> +#include <errno.h> + +#ifdef STDC_HEADERS +# include <string.h> +# include <stdlib.h> +#endif + +#define BIT_ISSET(bitmask, bit) ((bitmask) & (bit)) + +// Used to identify selinux_context in extended ('x') +// metadata. From RedHat implementation. +#define SELINUX_TAG "RHT.security.selinux=" +#define SELINUX_TAG_LEN 21 + +/* read a header block */ +int +th_read_internal(TAR *t) +{ + int i; + int num_zero_blocks = 0; + +#ifdef DEBUG + printf("==> th_read_internal(TAR=\"%s\")\n", t->pathname); +#endif + + while ((i = tar_block_read(t, &(t->th_buf))) == T_BLOCKSIZE) + { + /* two all-zero blocks mark EOF */ + if (t->th_buf.name[0] == '\0') + { + num_zero_blocks++; + if (!BIT_ISSET(t->options, TAR_IGNORE_EOT) + && num_zero_blocks >= 2) + return 0; /* EOF */ + else + continue; + } + + /* verify magic and version */ + if (BIT_ISSET(t->options, TAR_CHECK_MAGIC) + && strncmp(t->th_buf.magic, TMAGIC, TMAGLEN - 1) != 0) + { +#ifdef DEBUG + puts("!!! unknown magic value in tar header"); +#endif + return -2; + } + + if (BIT_ISSET(t->options, TAR_CHECK_VERSION) + && strncmp(t->th_buf.version, TVERSION, TVERSLEN) != 0) + { +#ifdef DEBUG + puts("!!! unknown version value in tar header"); +#endif + return -2; + } + + /* check chksum */ + if (!BIT_ISSET(t->options, TAR_IGNORE_CRC) + && !th_crc_ok(t)) + { +#ifdef DEBUG + puts("!!! tar header checksum error"); +#endif + return -2; + } + + break; + } + +#ifdef DEBUG + printf("<== th_read_internal(): returning %d\n", i); +#endif + return i; +} + + +/* wrapper function for th_read_internal() to handle GNU extensions */ +int +th_read(TAR *t) +{ + int i, j; + size_t sz; + char *ptr; + +#ifdef DEBUG + printf("==> th_read(t=0x%lx)\n", t); +#endif + + if (t->th_buf.gnu_longname != NULL) + free(t->th_buf.gnu_longname); + if (t->th_buf.gnu_longlink != NULL) + free(t->th_buf.gnu_longlink); +#ifdef HAVE_SELINUX + if (t->th_buf.selinux_context != NULL) + free(t->th_buf.selinux_context); +#endif + + memset(&(t->th_buf), 0, sizeof(struct tar_header)); + + i = th_read_internal(t); + if (i == 0) + return 1; + else if (i != T_BLOCKSIZE) + { + if (i != -1) + errno = EINVAL; + return -1; + } + + /* check for GNU long link extention */ + if (TH_ISLONGLINK(t)) + { + sz = th_get_size(t); + j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0); +#ifdef DEBUG + printf(" th_read(): GNU long linkname detected " + "(%ld bytes, %d blocks)\n", sz, j); +#endif + t->th_buf.gnu_longlink = (char *)malloc(j * T_BLOCKSIZE); + if (t->th_buf.gnu_longlink == NULL) + return -1; + + for (ptr = t->th_buf.gnu_longlink; j > 0; + j--, ptr += T_BLOCKSIZE) + { +#ifdef DEBUG + printf(" th_read(): reading long linkname " + "(%d blocks left, ptr == %ld)\n", j, ptr); +#endif + i = tar_block_read(t, ptr); + if (i != T_BLOCKSIZE) + { + if (i != -1) + errno = EINVAL; + return -1; + } +#ifdef DEBUG + printf(" th_read(): read block == \"%s\"\n", ptr); +#endif + } +#ifdef DEBUG + printf(" th_read(): t->th_buf.gnu_longlink == \"%s\"\n", + t->th_buf.gnu_longlink); +#endif + + i = th_read_internal(t); + if (i != T_BLOCKSIZE) + { + if (i != -1) + errno = EINVAL; + return -1; + } + } + + /* check for GNU long name extention */ + if (TH_ISLONGNAME(t)) + { + sz = th_get_size(t); + j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0); +#ifdef DEBUG + printf(" th_read(): GNU long filename detected " + "(%ld bytes, %d blocks)\n", sz, j); +#endif + t->th_buf.gnu_longname = (char *)malloc(j * T_BLOCKSIZE); + if (t->th_buf.gnu_longname == NULL) + return -1; + + for (ptr = t->th_buf.gnu_longname; j > 0; + j--, ptr += T_BLOCKSIZE) + { +#ifdef DEBUG + printf(" th_read(): reading long filename " + "(%d blocks left, ptr == %ld)\n", j, ptr); +#endif + i = tar_block_read(t, ptr); + if (i != T_BLOCKSIZE) + { + if (i != -1) + errno = EINVAL; + return -1; + } +#ifdef DEBUG + printf(" th_read(): read block == \"%s\"\n", ptr); +#endif + } +#ifdef DEBUG + printf(" th_read(): t->th_buf.gnu_longname == \"%s\"\n", + t->th_buf.gnu_longname); +#endif + + i = th_read_internal(t); + if (i != T_BLOCKSIZE) + { + if (i != -1) + errno = EINVAL; + return -1; + } + } + +#ifdef HAVE_SELINUX + if(TH_ISEXTHEADER(t)) + { + sz = th_get_size(t); + + if(sz >= T_BLOCKSIZE) // Not supported + { +#ifdef DEBUG + printf(" th_read(): Extended header is too long!\n"); +#endif + } + else + { + char buf[T_BLOCKSIZE]; + i = tar_block_read(t, buf); + if (i != T_BLOCKSIZE) + { + if (i != -1) + errno = EINVAL; + return -1; + } + + // To be sure + buf[T_BLOCKSIZE-1] = 0; + + int len = strlen(buf); + char *start = strstr(buf, SELINUX_TAG); + if(start && start+SELINUX_TAG_LEN < buf+len) + { + start += SELINUX_TAG_LEN; + char *end = strchr(start, '\n'); + if(end) + { + t->th_buf.selinux_context = strndup(start, end-start); +#ifdef DEBUG + printf(" th_read(): SELinux context xattr detected: %s\n", t->th_buf.selinux_context); +#endif + } + } + } + + i = th_read_internal(t); + if (i != T_BLOCKSIZE) + { + if (i != -1) + errno = EINVAL; + return -1; + } + } +#endif + +#if 0 + /* + ** work-around for old archive files with broken typeflag fields + ** NOTE: I fixed this in the TH_IS*() macros instead + */ + + /* + ** (directories are signified with a trailing '/') + */ + if (t->th_buf.typeflag == AREGTYPE + && t->th_buf.name[strlen(t->th_buf.name) - 1] == '/') + t->th_buf.typeflag = DIRTYPE; + + /* + ** fallback to using mode bits + */ + if (t->th_buf.typeflag == AREGTYPE) + { + mode = (mode_t)oct_to_int(t->th_buf.mode); + + if (S_ISREG(mode)) + t->th_buf.typeflag = REGTYPE; + else if (S_ISDIR(mode)) + t->th_buf.typeflag = DIRTYPE; + else if (S_ISFIFO(mode)) + t->th_buf.typeflag = FIFOTYPE; + else if (S_ISCHR(mode)) + t->th_buf.typeflag = CHRTYPE; + else if (S_ISBLK(mode)) + t->th_buf.typeflag = BLKTYPE; + else if (S_ISLNK(mode)) + t->th_buf.typeflag = SYMTYPE; + } +#endif + + return 0; +} + + +/* write a header block */ +int +th_write(TAR *t) +{ + int i, j; + char type2; + size_t sz, sz2; + char *ptr; + char buf[T_BLOCKSIZE]; + +#ifdef DEBUG + printf("==> th_write(TAR=\"%s\")\n", t->pathname); + th_print(t); +#endif + + if ((t->options & TAR_GNU) && t->th_buf.gnu_longlink != NULL) + { +#ifdef DEBUG + printf("th_write(): using gnu_longlink (\"%s\")\n", + t->th_buf.gnu_longlink); +#endif + /* save old size and type */ + type2 = t->th_buf.typeflag; + sz2 = th_get_size(t); + + /* write out initial header block with fake size and type */ + t->th_buf.typeflag = GNU_LONGLINK_TYPE; + sz = strlen(t->th_buf.gnu_longlink); + th_set_size(t, sz); + th_finish(t); + i = tar_block_write(t, &(t->th_buf)); + if (i != T_BLOCKSIZE) + { + if (i != -1) + errno = EINVAL; + return -1; + } + + /* write out extra blocks containing long name */ + for (j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0), + ptr = t->th_buf.gnu_longlink; j > 1; + j--, ptr += T_BLOCKSIZE) + { + i = tar_block_write(t, ptr); + if (i != T_BLOCKSIZE) + { + if (i != -1) + errno = EINVAL; + return -1; + } + } + memset(buf, 0, T_BLOCKSIZE); + strncpy(buf, ptr, T_BLOCKSIZE); + i = tar_block_write(t, &buf); + if (i != T_BLOCKSIZE) + { + if (i != -1) + errno = EINVAL; + return -1; + } + + /* reset type and size to original values */ + t->th_buf.typeflag = type2; + th_set_size(t, sz2); + } + + if ((t->options & TAR_GNU) && t->th_buf.gnu_longname != NULL) + { +#ifdef DEBUG + printf("th_write(): using gnu_longname (\"%s\")\n", + t->th_buf.gnu_longname); +#endif + /* save old size and type */ + type2 = t->th_buf.typeflag; + sz2 = th_get_size(t); + + /* write out initial header block with fake size and type */ + t->th_buf.typeflag = GNU_LONGNAME_TYPE; + sz = strlen(t->th_buf.gnu_longname); + th_set_size(t, sz); + th_finish(t); + i = tar_block_write(t, &(t->th_buf)); + if (i != T_BLOCKSIZE) + { + if (i != -1) + errno = EINVAL; + return -1; + } + + /* write out extra blocks containing long name */ + for (j = (sz / T_BLOCKSIZE) + (sz % T_BLOCKSIZE ? 1 : 0), + ptr = t->th_buf.gnu_longname; j > 1; + j--, ptr += T_BLOCKSIZE) + { + i = tar_block_write(t, ptr); + if (i != T_BLOCKSIZE) + { + if (i != -1) + errno = EINVAL; + return -1; + } + } + memset(buf, 0, T_BLOCKSIZE); + strncpy(buf, ptr, T_BLOCKSIZE); + i = tar_block_write(t, &buf); + if (i != T_BLOCKSIZE) + { + if (i != -1) + errno = EINVAL; + return -1; + } + + /* reset type and size to original values */ + t->th_buf.typeflag = type2; + th_set_size(t, sz2); + } + +#ifdef HAVE_SELINUX + if((t->options & TAR_STORE_SELINUX) && t->th_buf.selinux_context != NULL) + { +#ifdef DEBUG + printf("th_write(): using selinux_context (\"%s\")\n", + t->th_buf.selinux_context); +#endif + /* save old size and type */ + type2 = t->th_buf.typeflag; + sz2 = th_get_size(t); + + /* write out initial header block with fake size and type */ + t->th_buf.typeflag = TH_EXT_TYPE; + + /* setup size - EXT header has format "*size of this whole tag as ascii numbers* *space* *content* *newline* */ + // size newline + sz = SELINUX_TAG_LEN + strlen(t->th_buf.selinux_context) + 3 + 1; + + if(sz >= 100) // another ascci digit for size + ++sz; + + if(sz >= T_BLOCKSIZE) // impossible + { + errno = EINVAL; + return -1; + } + + th_set_size(t, sz); + th_finish(t); + i = tar_block_write(t, &(t->th_buf)); + if (i != T_BLOCKSIZE) + { + if (i != -1) + errno = EINVAL; + return -1; + } + + memset(buf, 0, T_BLOCKSIZE); + snprintf(buf, T_BLOCKSIZE, "%d "SELINUX_TAG"%s\n", sz, t->th_buf.selinux_context); + i = tar_block_write(t, &buf); + if (i != T_BLOCKSIZE) + { + if (i != -1) + errno = EINVAL; + return -1; + } + + /* reset type and size to original values */ + t->th_buf.typeflag = type2; + th_set_size(t, sz2); + } +#endif + + th_finish(t); + +#ifdef DEBUG + /* print tar header */ + th_print(t); +#endif + + i = tar_block_write(t, &(t->th_buf)); + if (i != T_BLOCKSIZE) + { + if (i != -1) + errno = EINVAL; + return -1; + } + +#ifdef DEBUG + puts("th_write(): returning 0"); +#endif + return 0; +} + + diff --git a/libtar/compat.h b/libtar/compat.h new file mode 100644 index 000000000..d0862943b --- /dev/null +++ b/libtar/compat.h @@ -0,0 +1,260 @@ +/* prototypes for borrowed "compatibility" code */ + +#include <config.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#include <stdarg.h> +#include <stddef.h> + +#ifdef HAVE_LIBGEN_H +# include <libgen.h> +#endif + +#ifdef HAVE_SELINUX +#include "selinux/selinux.h" +#endif + + +#if defined(NEED_BASENAME) && !defined(HAVE_BASENAME) + +# ifdef basename +# undef basename /* fix glibc brokenness */ +# endif + +char *openbsd_basename(const char *); +# define basename openbsd_basename + +#endif /* NEED_BASENAME && ! HAVE_BASENAME */ + + +#if defined(NEED_DIRNAME) && !defined(HAVE_DIRNAME) + +char *openbsd_dirname(const char *); +# define dirname openbsd_dirname + +#endif /* NEED_DIRNAME && ! HAVE_DIRNAME */ + + +#ifdef NEED_FNMATCH +# ifndef HAVE_FNMATCH + +# define FNM_NOMATCH 1 /* Match failed. */ + +# define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */ +# define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */ +# define FNM_PERIOD 0x04 /* Period must be matched by period. */ + +# define FNM_LEADING_DIR 0x08 /* Ignore /<tail> after Imatch. */ +# define FNM_CASEFOLD 0x10 /* Case insensitive search. */ +# define FNM_IGNORECASE FNM_CASEFOLD +# define FNM_FILE_NAME FNM_PATHNAME + +int openbsd_fnmatch(const char *, const char *, int); +# define fnmatch openbsd_fnmatch + +# else /* HAVE_FNMATCH */ + +# ifdef HAVE_FNMATCH_H +# include <fnmatch.h> +# endif + +# endif /* ! HAVE_FNMATCH */ +#endif /* NEED_FNMATCH */ + + +#ifdef NEED_GETHOSTBYNAME_R + +# include <netdb.h> + +# if GETHOSTBYNAME_R_NUM_ARGS != 6 + +int compat_gethostbyname_r(const char *, struct hostent *, + char *, size_t, struct hostent **, int *); + +# define gethostbyname_r compat_gethostbyname_r + +# endif /* GETHOSTBYNAME_R_NUM_ARGS != 6 */ + +#endif /* NEED_GETHOSTBYNAME_R */ + + +#if defined(NEED_GETHOSTNAME) && !defined(HAVE_GETHOSTNAME) + +int gethostname(char *, size_t); + +#endif /* NEED_GETHOSTNAME && ! HAVE_GETHOSTNAME */ + + +#ifdef NEED_GETSERVBYNAME_R + +# include <netdb.h> + +# if GETSERVBYNAME_R_NUM_ARGS != 6 + +int compat_getservbyname_r(const char *, const char *, struct servent *, + char *, size_t, struct servent **); + +# define getservbyname_r compat_getservbyname_r + +# endif /* GETSERVBYNAME_R_NUM_ARGS != 6 */ + +#endif /* NEED_GETSERVBYNAME_R */ + + + +#ifdef NEED_GLOB +# ifndef HAVE_GLOB + +typedef struct { + int gl_pathc; /* Count of total paths so far. */ + int gl_matchc; /* Count of paths matching pattern. */ + int gl_offs; /* Reserved at beginning of gl_pathv. */ + int gl_flags; /* Copy of flags parameter to glob. */ + char **gl_pathv; /* List of paths matching pattern. */ + /* Copy of errfunc parameter to glob. */ + int (*gl_errfunc)(const char *, int); + + /* + * Alternate filesystem access methods for glob; replacement + * versions of closedir(3), readdir(3), opendir(3), stat(2) + * and lstat(2). + */ + void (*gl_closedir)(void *); + struct dirent *(*gl_readdir)(void *); + void *(*gl_opendir)(const char *); + int (*gl_lstat)(const char *, struct stat *); + int (*gl_stat)(const char *, struct stat *); +} glob_t; + +/* Flags */ +# define GLOB_APPEND 0x0001 /* Append to output from previous call. */ +# define GLOB_DOOFFS 0x0002 /* Use gl_offs. */ +# define GLOB_ERR 0x0004 /* Return on error. */ +# define GLOB_MARK 0x0008 /* Append / to matching directories. */ +# define GLOB_NOCHECK 0x0010 /* Return pattern itself if nothing matches. */ +# define GLOB_NOSORT 0x0020 /* Don't sort. */ + +# define GLOB_ALTDIRFUNC 0x0040 /* Use alternately specified directory funcs. */ +# define GLOB_BRACE 0x0080 /* Expand braces ala csh. */ +# define GLOB_MAGCHAR 0x0100 /* Pattern had globbing characters. */ +# define GLOB_NOMAGIC 0x0200 /* GLOB_NOCHECK without magic chars (csh). */ +# define GLOB_QUOTE 0x0400 /* Quote special chars with \. */ +# define GLOB_TILDE 0x0800 /* Expand tilde names from the passwd file. */ +# define GLOB_NOESCAPE 0x1000 /* Disable backslash escaping. */ + +/* Error values returned by glob(3) */ +# define GLOB_NOSPACE (-1) /* Malloc call failed. */ +# define GLOB_ABORTED (-2) /* Unignored error. */ +# define GLOB_NOMATCH (-3) /* No match and GLOB_NOCHECK not set. */ +# define GLOB_NOSYS (-4) /* Function not supported. */ +# define GLOB_ABEND GLOB_ABORTED + +int openbsd_glob(const char *, int, int (*)(const char *, int), glob_t *); +void openbsd_globfree(glob_t *); +# define glob openbsd_glob +# define globfree openbsd_globfree + +# else /* HAVE_GLOB */ + +# ifdef HAVE_GLOB_H +# include <glob.h> +# endif + +# endif /* ! HAVE_GLOB */ +#endif /* NEED_GLOB */ + + +#if defined(NEED_INET_ATON) && !defined(HAVE_INET_ATON) + +int inet_aton(const char *, struct in_addr *); + +#endif /* NEED_INET_ATON && ! HAVE_INET_ATON */ + + +#ifdef NEED_MAKEDEV + +# ifdef MAJOR_IN_MKDEV +# include <sys/mkdev.h> +# else +# ifdef MAJOR_IN_SYSMACROS +# include <sys/sysmacros.h> +# endif +# endif + +/* +** On most systems makedev() has two args. +** Some weird systems, like QNX6, have makedev() functions that expect +** an extra first argument for "node", which can be 0 for a local +** machine. +*/ + +# ifdef MAKEDEV_THREE_ARGS +# define compat_makedev(maj, min) makedev(0, maj, min) +# else +# define compat_makedev makedev +# endif + +#endif /* NEED_MAKEDEV */ + + +#if defined(NEED_SNPRINTF) && !defined(HAVE_SNPRINTF) + +int mutt_snprintf(char *, size_t, const char *, ...); +int mutt_vsnprintf(char *, size_t, const char *, va_list); +#define snprintf mutt_snprintf +#define vsnprintf mutt_vsnprintf + +#endif /* NEED_SNPRINTF && ! HAVE_SNPRINTF */ + + +#if defined(NEED_STRLCAT) && !defined(HAVE_STRLCAT) + +size_t strlcat(char *, const char *, size_t); + +#endif /* NEED_STRLCAT && ! HAVE_STRLCAT */ + + +#if defined(NEED_STRLCPY) && !defined(HAVE_STRLCPY) + +size_t strlcpy(char *, const char *, size_t); + +#endif /* NEED_STRLCPY && ! HAVE_STRLCPY */ + + +#if defined(NEED_STRDUP) && !defined(HAVE_STRDUP) + +char *openbsd_strdup(const char *); +# define strdup openbsd_strdup + +#endif /* NEED_STRDUP && ! HAVE_STRDUP */ + + +#if defined(NEED_STRMODE) && !defined(HAVE_STRMODE) + +void strmode(register mode_t, register char *); + +#endif /* NEED_STRMODE && ! HAVE_STRMODE */ + + +#if defined(NEED_STRRSTR) && !defined(HAVE_STRRSTR) + +char *strrstr(char *, char *); + +#endif /* NEED_STRRSTR && ! HAVE_STRRSTR */ + + +#ifdef NEED_STRSEP + +# ifdef HAVE_STRSEP +# define _LINUX_SOURCE_COMPAT /* needed on AIX 4.3.3 */ +# else + +char *strsep(register char **, register const char *); + +# endif + +#endif /* NEED_STRSEP */ + + diff --git a/libtar/config.h b/libtar/config.h new file mode 100644 index 000000000..c658020ea --- /dev/null +++ b/libtar/config.h @@ -0,0 +1,188 @@ +/* config.h. Generated by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define if your system has a working basename */ +/* #undef HAVE_BASENAME */ + +/* Define to 1 if you have the <ctype.h> header file. */ +/* #undef HAVE_CTYPE_H */ + +/* Define to 1 if the system has the type `dev_t'. */ +#define HAVE_DEV_T 1 + +/* Define if your system has a working dirname */ +/* #undef HAVE_DIRNAME */ + +/* Define to 1 if your system has a working POSIX `fnmatch' function. */ +#define HAVE_FNMATCH 1 + +/* Define to 1 if you have the <fnmatch.h> header file. */ +#define HAVE_FNMATCH_H 1 + +/* Define to 1 if you have the <inttypes.h> header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `lchown' function. */ +#define HAVE_LCHOWN 1 + +/* Define to 1 if you have the <libgen.h> header file. */ +#define HAVE_LIBGEN_H 1 + +/* Define to 1 if you have the `z' library (-lz). */ +#define HAVE_LIBZ 1 + +/* Define to 1 if the system has the type `major_t'. */ +/* #undef HAVE_MAJOR_T */ + +/* Define to 1 if you have the <memory.h> header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if the system has the type `minor_t'. */ +/* #undef HAVE_MINOR_T */ + +/* Define to 1 if the system has the type `nlink_t'. */ +#define HAVE_NLINK_T 1 + +/* Define if your system has a working snprintf */ +#define HAVE_SNPRINTF 1 + +/* Define to 1 if the system has the type `socklen_t'. */ +#define HAVE_SOCKLEN_T 1 + +/* Define to 1 if you have the <stdint.h> header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the <stdlib.h> header file. */ +#define HAVE_STDLIB_H 1 + +/* Define if you have the strdup function */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strftime' function. */ +#define HAVE_STRFTIME 1 + +/* Define to 1 if you have the <strings.h> header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* Define if you have the strlcpy function */ +/* #undef HAVE_STRLCPY */ + +/* Define if you have the strmode function */ +/* #undef HAVE_STRMODE */ + +/* Define if you have the strsep function */ +#define HAVE_STRSEP 1 + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the <sys/types.h> header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if the system has the type `uint64_t'. */ +#define HAVE_UINT64_T 1 + +/* Define to 1 if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>. + */ +/* #undef MAJOR_IN_MKDEV */ + +/* Define to 1 if `major', `minor', and `makedev' are declared in + <sysmacros.h>. */ +/* #undef MAJOR_IN_SYSMACROS */ + +/* Define as 1 if makedev expects three arguments */ +/* #undef MAKEDEV_THREE_ARGS */ + +/* Define if you want to use the basename function */ +#define NEED_BASENAME 1 + +/* Define if you want to use the dirname function */ +#define NEED_DIRNAME 1 + +/* Define if you want to use the fnmatch function */ +#define NEED_FNMATCH 1 + +/* Define if you want to use the makedev function */ +#define NEED_MAKEDEV 1 + +/* Define if you want to use the snprintf function */ +#define NEED_SNPRINTF 1 + +/* Define if you want to use the strdup function */ +#define NEED_STRDUP 1 + +/* Define if you want to use the strlcpy function */ +#define NEED_STRLCPY 1 + +/* Define if you want to use the strmode function */ +#define NEED_STRMODE 1 + +/* Define if you want to use the strsep function */ +#define NEED_STRSEP 1 + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libtar" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libtar 1.2.11" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libtar" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.2.11" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if on AIX 3. + System headers sometimes define this. + We just want to avoid a redefinition error message. */ +#ifndef _ALL_SOURCE +/* # undef _ALL_SOURCE */ +#endif + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `unsigned long' if not defined in system header files. */ +/* #undef dev_t */ + +/* Define to `int' if <sys/types.h> doesn't define. */ +/* #undef gid_t */ + +/* Define to `unsigned int' if not defined in system header files. */ +#define major_t unsigned int + +/* Define to `unsigned int' if not defined in system header files. */ +#define minor_t unsigned int + +/* Define to `int' if <sys/types.h> does not define. */ +/* #undef mode_t */ + +/* Define to `unsigned short' if not defined in system header files. */ +/* #undef nlink_t */ + +/* Define to `long' if <sys/types.h> does not define. */ +/* #undef off_t */ + +/* Define to `unsigned' if <sys/types.h> does not define. */ +/* #undef size_t */ + +/* Define to `unsigned long' if not defined in system header files. */ +/* #undef socklen_t */ + +/* Define to `int' if <sys/types.h> doesn't define. */ +/* #undef uid_t */ + +/* Define to `long long' if not defined in system header files. */ +/* #undef uint64_t */ diff --git a/libtar/decode.c b/libtar/decode.c new file mode 100644 index 000000000..383306d64 --- /dev/null +++ b/libtar/decode.c @@ -0,0 +1,122 @@ +/* +** Copyright 1998-2003 University of Illinois Board of Trustees +** Copyright 1998-2003 Mark D. Roth +** All rights reserved. +** +** decode.c - libtar code to decode tar header blocks +** +** Mark D. Roth <roth@uiuc.edu> +** Campus Information Technologies and Educational Services +** University of Illinois at Urbana-Champaign +*/ + +#include <internal.h> + +#include <stdio.h> +#include <sys/param.h> +#include <pwd.h> +#include <grp.h> + +#ifdef STDC_HEADERS +# include <string.h> +#endif + + +/* determine full path name */ +char * +th_get_pathname(TAR *t) +{ + char filename[MAXPATHLEN]; + + if (t->th_buf.gnu_longname) { + printf("returning gnu longname\n"); + return t->th_buf.gnu_longname; + } + + if (t->th_buf.prefix[0] != '\0') + { + snprintf(filename, sizeof(filename), "%.155s/%.100s", + t->th_buf.prefix, t->th_buf.name); + return strdup(filename); + } + + snprintf(filename, sizeof(filename), "%.100s", t->th_buf.name); + return strdup(filename); +} + + +uid_t +th_get_uid(TAR *t) +{ + int uid; + struct passwd *pw; + + pw = getpwnam(t->th_buf.uname); + if (pw != NULL) + return pw->pw_uid; + + /* if the password entry doesn't exist */ + sscanf(t->th_buf.uid, "%o", &uid); + return uid; +} + + +gid_t +th_get_gid(TAR *t) +{ + int gid; + struct group *gr; + + gr = getgrnam(t->th_buf.gname); + if (gr != NULL) + return gr->gr_gid; + + /* if the group entry doesn't exist */ + sscanf(t->th_buf.gid, "%o", &gid); + return gid; +} + + +mode_t +th_get_mode(TAR *t) +{ + mode_t mode; + + mode = (mode_t)oct_to_int(t->th_buf.mode); + if (! (mode & S_IFMT)) + { + switch (t->th_buf.typeflag) + { + case SYMTYPE: + mode |= S_IFLNK; + break; + case CHRTYPE: + mode |= S_IFCHR; + break; + case BLKTYPE: + mode |= S_IFBLK; + break; + case DIRTYPE: + mode |= S_IFDIR; + break; + case FIFOTYPE: + mode |= S_IFIFO; + break; + case AREGTYPE: + if (t->th_buf.name[strlen(t->th_buf.name) - 1] == '/') + { + mode |= S_IFDIR; + break; + } + /* FALLTHROUGH */ + case LNKTYPE: + case REGTYPE: + default: + mode |= S_IFREG; + } + } + + return mode; +} + + diff --git a/libtar/dirname.c b/libtar/dirname.c new file mode 100644 index 000000000..986db4aa1 --- /dev/null +++ b/libtar/dirname.c @@ -0,0 +1,77 @@ +/* $OpenBSD: dirname.c,v 1.4 1999/05/30 17:10:30 espie Exp $ */ + +/* + * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef lint +static char rcsid[] = "$OpenBSD: dirname.c,v 1.4 1999/05/30 17:10:30 espie Exp $"; +#endif /* not lint */ + +#include <errno.h> +#include <string.h> +#include <sys/param.h> + +char * +openbsd_dirname(path) + const char *path; +{ + static char bname[MAXPATHLEN]; + register const char *endp; + + /* Empty or NULL string gets treated as "." */ + if (path == NULL || *path == '\0') { + (void)strcpy(bname, "."); + return(bname); + } + + /* Strip trailing slashes */ + endp = path + strlen(path) - 1; + while (endp > path && *endp == '/') + endp--; + + /* Find the start of the dir */ + while (endp > path && *endp != '/') + endp--; + + /* Either the dir is "/" or there are no slashes */ + if (endp == path) { + (void)strcpy(bname, *endp == '/' ? "/" : "."); + return(bname); + } else { + do { + endp--; + } while (endp > path && *endp == '/'); + } + + if (endp - path + 1 > sizeof(bname)) { + errno = ENAMETOOLONG; + return(NULL); + } + (void)strncpy(bname, path, endp - path + 1); + bname[endp - path + 1] = '\0'; + return(bname); +} diff --git a/libtar/encode.c b/libtar/encode.c new file mode 100644 index 000000000..662eff584 --- /dev/null +++ b/libtar/encode.c @@ -0,0 +1,213 @@ +/* +** Copyright 1998-2003 University of Illinois Board of Trustees +** Copyright 1998-2003 Mark D. Roth +** All rights reserved. +** +** encode.c - libtar code to encode tar header blocks +** +** Mark D. Roth <roth@uiuc.edu> +** Campus Information Technologies and Educational Services +** University of Illinois at Urbana-Champaign +*/ + +#include <internal.h> + +#include <stdio.h> +#include <pwd.h> +#include <grp.h> +#include <sys/types.h> + +#ifdef STDC_HEADERS +# include <string.h> +# include <stdlib.h> +#endif + + +/* magic, version, and checksum */ +void +th_finish(TAR *t) +{ + if (t->options & TAR_GNU) + { + /* we're aiming for this result, but must do it in + * two calls to avoid FORTIFY segfaults on some Linux + * systems: + * strncpy(t->th_buf.magic, "ustar ", 8); + */ + strncpy(t->th_buf.magic, "ustar ", 6); + strncpy(t->th_buf.version, " ", 2); + } + else + { + strncpy(t->th_buf.version, TVERSION, TVERSLEN); + strncpy(t->th_buf.magic, TMAGIC, TMAGLEN); + } + + int_to_oct(th_crc_calc(t), t->th_buf.chksum, 8); +} + + +/* map a file mode to a typeflag */ +void +th_set_type(TAR *t, mode_t mode) +{ + if (S_ISLNK(mode)) + t->th_buf.typeflag = SYMTYPE; + if (S_ISREG(mode)) + t->th_buf.typeflag = REGTYPE; + if (S_ISDIR(mode)) + t->th_buf.typeflag = DIRTYPE; + if (S_ISCHR(mode)) + t->th_buf.typeflag = CHRTYPE; + if (S_ISBLK(mode)) + t->th_buf.typeflag = BLKTYPE; + if (S_ISFIFO(mode) || S_ISSOCK(mode)) + t->th_buf.typeflag = FIFOTYPE; +} + + +/* encode file path */ +void +th_set_path(TAR *t, char *pathname) +{ + char suffix[2] = ""; + char *tmp; + +#ifdef DEBUG + printf("in th_set_path(th, pathname=\"%s\")\n", pathname); +#endif + + if (t->th_buf.gnu_longname != NULL) + free(t->th_buf.gnu_longname); + t->th_buf.gnu_longname = NULL; + + if (pathname[strlen(pathname) - 1] != '/' && TH_ISDIR(t)) + strcpy(suffix, "/"); + + if (strlen(pathname) > T_NAMELEN-1 && (t->options & TAR_GNU)) + { + /* GNU-style long name */ + t->th_buf.gnu_longname = strdup(pathname); + strncpy(t->th_buf.name, t->th_buf.gnu_longname, T_NAMELEN); + } + else if (strlen(pathname) > T_NAMELEN) + { + /* POSIX-style prefix field */ + tmp = strchr(&(pathname[strlen(pathname) - T_NAMELEN - 1]), '/'); + if (tmp == NULL) + { + printf("!!! '/' not found in \"%s\"\n", pathname); + return; + } + snprintf(t->th_buf.name, 100, "%s%s", &(tmp[1]), suffix); + snprintf(t->th_buf.prefix, + ((tmp - pathname + 1) < + 155 ? (tmp - pathname + 1) : 155), "%s", pathname); + } + else + /* classic tar format */ + snprintf(t->th_buf.name, 100, "%s%s", pathname, suffix); + +#ifdef DEBUG + puts("returning from th_set_path()..."); +#endif +} + + +/* encode link path */ +void +th_set_link(TAR *t, char *linkname) +{ +#ifdef DEBUG + printf("==> th_set_link(th, linkname=\"%s\")\n", linkname); +#endif + + if (strlen(linkname) > T_NAMELEN-1 && (t->options & TAR_GNU)) + { + /* GNU longlink format */ + t->th_buf.gnu_longlink = strdup(linkname); + strcpy(t->th_buf.linkname, "././@LongLink"); + } + else + { + /* classic tar format */ + strlcpy(t->th_buf.linkname, linkname, + sizeof(t->th_buf.linkname)); + if (t->th_buf.gnu_longlink != NULL) + free(t->th_buf.gnu_longlink); + t->th_buf.gnu_longlink = NULL; + } +} + + +/* encode device info */ +void +th_set_device(TAR *t, dev_t device) +{ +#ifdef DEBUG + printf("th_set_device(): major = %d, minor = %d\n", + major(device), minor(device)); +#endif + int_to_oct(major(device), t->th_buf.devmajor, 8); + int_to_oct(minor(device), t->th_buf.devminor, 8); +} + + +/* encode user info */ +void +th_set_user(TAR *t, uid_t uid) +{ + struct passwd *pw; + + pw = getpwuid(uid); + if (pw != NULL) + strlcpy(t->th_buf.uname, pw->pw_name, sizeof(t->th_buf.uname)); + + int_to_oct(uid, t->th_buf.uid, 8); +} + + +/* encode group info */ +void +th_set_group(TAR *t, gid_t gid) +{ + struct group *gr; + + gr = getgrgid(gid); + if (gr != NULL) + strlcpy(t->th_buf.gname, gr->gr_name, sizeof(t->th_buf.gname)); + + int_to_oct(gid, t->th_buf.gid, 8); +} + + +/* encode file mode */ +void +th_set_mode(TAR *t, mode_t fmode) +{ + if (S_ISSOCK(fmode)) + { + fmode &= ~S_IFSOCK; + fmode |= S_IFIFO; + } + int_to_oct(fmode, (t)->th_buf.mode, 8); +} + + +void +th_set_from_stat(TAR *t, struct stat *s) +{ + th_set_type(t, s->st_mode); + if (S_ISCHR(s->st_mode) || S_ISBLK(s->st_mode)) + th_set_device(t, s->st_rdev); + th_set_user(t, s->st_uid); + th_set_group(t, s->st_gid); + th_set_mode(t, s->st_mode); + th_set_mtime(t, s->st_mtime); + if (S_ISREG(s->st_mode)) + th_set_size(t, s->st_size); + else + th_set_size(t, 0); +} + + diff --git a/libtar/extract.c b/libtar/extract.c new file mode 100644 index 000000000..69e08bd54 --- /dev/null +++ b/libtar/extract.c @@ -0,0 +1,570 @@ +/* +** Copyright 1998-2003 University of Illinois Board of Trustees +** Copyright 1998-2003 Mark D. Roth +** All rights reserved. +** +** extract.c - libtar code to extract a file from a tar archive +** +** Mark D. Roth <roth@uiuc.edu> +** Campus Information Technologies and Educational Services +** University of Illinois at Urbana-Champaign +*/ + +#include <internal.h> + +#include <stdio.h> +#include <sys/param.h> +#include <sys/types.h> +#include <fcntl.h> +#include <errno.h> +#include <utime.h> +#include <string.h> + +#define DEBUG +#ifdef STDC_HEADERS +# include <stdlib.h> +#endif + +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#define DEBUG + +static int +tar_set_file_perms(TAR *t, char *realname) +{ + mode_t mode; + uid_t uid; + gid_t gid; + struct utimbuf ut; + char *filename; + + filename = (realname ? realname : th_get_pathname(t)); + mode = th_get_mode(t); + uid = th_get_uid(t); + gid = th_get_gid(t); + ut.modtime = ut.actime = th_get_mtime(t); + +#ifdef DEBUG + printf(" ==> setting perms: %s (mode %04o, uid %d, gid %d)\n", + filename, mode, uid, gid); +#endif + + /* change owner/group */ + if (geteuid() == 0) +#ifdef HAVE_LCHOWN + if (lchown(filename, uid, gid) == -1) + { +# ifdef DEBUG + fprintf(stderr, "lchown(\"%s\", %d, %d): %s\n", + filename, uid, gid, strerror(errno)); +# endif +#else /* ! HAVE_LCHOWN */ + if (!TH_ISSYM(t) && chown(filename, uid, gid) == -1) + { +# ifdef DEBUG + fprintf(stderr, "chown(\"%s\", %d, %d): %s\n", + filename, uid, gid, strerror(errno)); +# endif +#endif /* HAVE_LCHOWN */ + return -1; + } + + /* change access/modification time */ + if (!TH_ISSYM(t) && utime(filename, &ut) == -1) + { +#ifdef DEBUG + perror("utime()"); +#endif + return -1; + } + + /* change permissions */ + if (!TH_ISSYM(t) && chmod(filename, mode) == -1) + { +#ifdef DEBUG + perror("chmod()"); +#endif + return -1; + } + + return 0; +} + + +/* switchboard */ +int +tar_extract_file(TAR *t, char *realname, char *prefix, const int *progress_fd) +{ + int i; + char *lnp; + int pathname_len; + int realname_len; + + if (t->options & TAR_NOOVERWRITE) + { + struct stat s; + + if (lstat(realname, &s) == 0 || errno != ENOENT) + { + errno = EEXIST; + return -1; + } + } + + if (TH_ISDIR(t)) + { + printf("dir\n"); + i = tar_extract_dir(t, realname); + if (i == 1) + i = 0; + } + else if (TH_ISLNK(t)) { + printf("link\n"); + i = tar_extract_hardlink(t, realname, prefix); + } + else if (TH_ISSYM(t)) { + printf("sym\n"); + i = tar_extract_symlink(t, realname); + } + else if (TH_ISCHR(t)) { + printf("chr\n"); + i = tar_extract_chardev(t, realname); + } + else if (TH_ISBLK(t)) { + printf("blk\n"); + i = tar_extract_blockdev(t, realname); + } + else if (TH_ISFIFO(t)) { + printf("fifo\n"); + i = tar_extract_fifo(t, realname); + } + else /* if (TH_ISREG(t)) */ { + printf("reg\n"); + i = tar_extract_regfile(t, realname, progress_fd); + } + + if (i != 0) { + printf("FAILED RESTORE OF FILE i: %s\n", realname); + return i; + } + + i = tar_set_file_perms(t, realname); + if (i != 0) { + printf("FAILED SETTING PERMS: %d\n", i); + return i; + } + +#ifdef HAVE_SELINUX + if((t->options & TAR_STORE_SELINUX) && t->th_buf.selinux_context != NULL) + { +#ifdef DEBUG + printf(" Restoring SELinux context %s to file %s\n", t->th_buf.selinux_context, realname); +#endif + if (lsetfilecon(realname, t->th_buf.selinux_context) < 0) { + fprintf(stderr, "Failed to restore SELinux context %s!\n", strerror(errno)); + } + } +#endif + +/* + pathname_len = strlen(th_get_pathname(t)) + 1; + realname_len = strlen(realname) + 1; + lnp = (char *)calloc(1, pathname_len + realname_len); + if (lnp == NULL) + return -1; + strcpy(&lnp[0], th_get_pathname(t)); + strcpy(&lnp[pathname_len], realname); +#ifdef DEBUG + printf("tar_extract_file(): calling libtar_hash_add(): key=\"%s\", " + "value=\"%s\"\n", th_get_pathname(t), realname); +#endif + if (libtar_hash_add(t->h, lnp) != 0) + return -1; + free(lnp); +*/ + return 0; +} + + +/* extract regular file */ +int +tar_extract_regfile(TAR *t, char *realname, const int *progress_fd) +{ + //mode_t mode; + size_t size, i; + //uid_t uid; + //gid_t gid; + int fdout; + int k; + char buf[T_BLOCKSIZE]; + char *filename; + + fflush(NULL); +#ifdef DEBUG + printf("==> tar_extract_regfile(t=0x%lx, realname=\"%s\")\n", t, + realname); +#endif + + if (!TH_ISREG(t)) + { + errno = EINVAL; + return -1; + } + + filename = (realname ? realname : th_get_pathname(t)); + //mode = th_get_mode(t); + size = th_get_size(t); + //uid = th_get_uid(t); + //gid = th_get_gid(t); + + if (mkdirhier(dirname(filename)) == -1) + return -1; + +#ifdef DEBUG + //printf(" ==> extracting: %s (mode %04o, uid %d, gid %d, %d bytes)\n", + // filename, mode, uid, gid, size); + printf(" ==> extracting: %s (file size %d bytes)\n", + filename, size); +#endif + fdout = open(filename, O_WRONLY | O_CREAT | O_TRUNC +#ifdef O_BINARY + | O_BINARY +#endif + , 0666); + if (fdout == -1) + { +#ifdef DEBUG + perror("open()"); +#endif + return -1; + } + +#if 0 + /* change the owner. (will only work if run as root) */ + if (fchown(fdout, uid, gid) == -1 && errno != EPERM) + { +#ifdef DEBUG + perror("fchown()"); +#endif + return -1; + } + + /* make sure the mode isn't inheritted from a file we're overwriting */ + if (fchmod(fdout, mode & 07777) == -1) + { +#ifdef DEBUG + perror("fchmod()"); +#endif + return -1; + } +#endif + + /* extract the file */ + for (i = size; i > 0; i -= tar_min(i, T_BLOCKSIZE)) + { + k = tar_block_read(t, buf); + if (k != T_BLOCKSIZE) + { + if (k != -1) + errno = EINVAL; + return -1; + } + + /* write block to output file */ + if (write(fdout, buf, + ((i > T_BLOCKSIZE) ? T_BLOCKSIZE : i)) == -1) + return -1; + } + + /* close output file */ + if (close(fdout) == -1) + return -1; + +#ifdef DEBUG + printf("### done extracting %s\n", filename); +#endif + + if (*progress_fd != 0) { + unsigned long long file_size = (unsigned long long)(size); + write(*progress_fd, &file_size, sizeof(file_size)); + } + + return 0; +} + + +/* skip regfile */ +int +tar_skip_regfile(TAR *t) +{ + int k; + size_t size, i; + char buf[T_BLOCKSIZE]; + + if (!TH_ISREG(t)) + { + errno = EINVAL; + return -1; + } + + size = th_get_size(t); + for (i = size; i > 0; i -= tar_min(i, T_BLOCKSIZE)) + { + k = tar_block_read(t, buf); + if (k != T_BLOCKSIZE) + { + if (k != -1) + errno = EINVAL; + return -1; + } + } + + return 0; +} + + +/* hardlink */ +int +tar_extract_hardlink(TAR * t, char *realname, char *prefix) +{ + char *filename; + char *linktgt = NULL; + char *lnp; + libtar_hashptr_t hp; + + if (!TH_ISLNK(t)) + { + errno = EINVAL; + return -1; + } + + filename = (realname ? realname : th_get_pathname(t)); + if (mkdirhier(dirname(filename)) == -1) + return -1; + libtar_hashptr_reset(&hp); + if (libtar_hash_getkey(t->h, &hp, th_get_linkname(t), + (libtar_matchfunc_t)libtar_str_match) != 0) + { + lnp = (char *)libtar_hashptr_data(&hp); + linktgt = &lnp[strlen(lnp) + 1]; + } + else + linktgt = th_get_linkname(t); + char *newtgt = strdup(linktgt); + sprintf(linktgt, "%s/%s", prefix, newtgt); +#ifdef DEBUG + printf(" ==> extracting: %s (link to %s)\n", filename, linktgt); +#endif + if (link(linktgt, filename) == -1) + { +#ifdef DEBUG + perror("link()"); +#endif + printf("Failed restore of hardlink '%s' but returning as if nothing bad happened anyway\n", filename); + return 0; // Used to be -1 + } + + return 0; +} + + +/* symlink */ +int +tar_extract_symlink(TAR *t, char *realname) +{ + char *filename; + + if (!TH_ISSYM(t)) + { + printf("not a sym\n"); + errno = EINVAL; + return -1; + } + + filename = (realname ? realname : th_get_pathname(t)); + printf("file: %s\n", filename); + if (mkdirhier(dirname(filename)) == -1) { + printf("mkdirhier\n"); + return -1; + } + + if (unlink(filename) == -1 && errno != ENOENT) { + printf("unlink\n"); + return -1; + } + +#ifdef DEBUG + printf(" ==> extracting: %s (symlink to %s)\n", + filename, th_get_linkname(t)); +#endif + if (symlink(th_get_linkname(t), filename) == -1) + { +#ifdef DEBUG + perror("symlink()"); +#endif + return -1; + } + + return 0; +} + + +/* character device */ +int +tar_extract_chardev(TAR *t, char *realname) +{ + mode_t mode; + unsigned long devmaj, devmin; + char *filename; + + if (!TH_ISCHR(t)) + { + errno = EINVAL; + return -1; + } + + filename = (realname ? realname : th_get_pathname(t)); + mode = th_get_mode(t); + devmaj = th_get_devmajor(t); + devmin = th_get_devminor(t); + + if (mkdirhier(dirname(filename)) == -1) + return -1; + +#ifdef DEBUG + printf(" ==> extracting: %s (character device %ld,%ld)\n", + filename, devmaj, devmin); +#endif + if (mknod(filename, mode | S_IFCHR, + compat_makedev(devmaj, devmin)) == -1) + { +#ifdef DEBUG + printf("mknod() failed, returning good anyway"); +#endif + return 0; + } + + return 0; +} + + +/* block device */ +int +tar_extract_blockdev(TAR *t, char *realname) +{ + mode_t mode; + unsigned long devmaj, devmin; + char *filename; + + if (!TH_ISBLK(t)) + { + errno = EINVAL; + return -1; + } + + filename = (realname ? realname : th_get_pathname(t)); + mode = th_get_mode(t); + devmaj = th_get_devmajor(t); + devmin = th_get_devminor(t); + + if (mkdirhier(dirname(filename)) == -1) + return -1; + +#ifdef DEBUG + printf(" ==> extracting: %s (block device %ld,%ld)\n", + filename, devmaj, devmin); +#endif + if (mknod(filename, mode | S_IFBLK, + compat_makedev(devmaj, devmin)) == -1) + { +#ifdef DEBUG + printf("mknod() failed but returning anyway"); +#endif + return 0; + } + + return 0; +} + + +/* directory */ +int +tar_extract_dir(TAR *t, char *realname) +{ + mode_t mode; + char *filename; + if (!TH_ISDIR(t)) + { + errno = EINVAL; + return -1; + } + + filename = (realname ? realname : th_get_pathname(t)); + mode = th_get_mode(t); + + if (mkdirhier(dirname(filename)) == -1) { + printf("tar_extract_dir mkdirhier failed\n"); + return -1; + } + +#ifdef DEBUG + printf(" ==> extracting: %s (mode %04o, directory)\n", filename, + mode); +#endif + if (mkdir(filename, mode) == -1) + { + if (errno == EEXIST) + { +#ifdef DEBUG + printf(" *** using existing directory"); +#endif + } + else + { +#ifdef DEBUG + perror("mkdir()"); +#endif + return -1; + } + } + + return 0; +} + + +/* FIFO */ +int +tar_extract_fifo(TAR *t, char *realname) +{ + mode_t mode; + char *filename; + + if (!TH_ISFIFO(t)) + { + errno = EINVAL; + return -1; + } + + filename = (realname ? realname : th_get_pathname(t)); + mode = th_get_mode(t); + + if (mkdirhier(dirname(filename)) == -1) + return -1; + +#ifdef DEBUG + printf(" ==> extracting: %s (fifo)\n", filename); +#endif + if (mkfifo(filename, mode) == -1) + { +#ifdef DEBUG + perror("mkfifo()"); +#endif + return -1; + } + + return 0; +} + + diff --git a/libtar/fnmatch.c b/libtar/fnmatch.c new file mode 100644 index 000000000..fe75f0eeb --- /dev/null +++ b/libtar/fnmatch.c @@ -0,0 +1,237 @@ +/* $OpenBSD: fnmatch.c,v 1.6 1998/03/19 00:29:59 millert Exp $ */ + +/* + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Guido van Rossum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94"; +#else +static char rcsid[] = "$OpenBSD: fnmatch.c,v 1.6 1998/03/19 00:29:59 millert Exp $"; +#endif +#endif /* LIBC_SCCS and not lint */ + +/* + * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6. + * Compares a filename or pathname to a pattern. + */ + +#include <config.h> + +#include <stdio.h> + +#ifdef STDC_HEADERS +# include <string.h> +#endif + +#ifdef HAVE_CTYPE_H +# include <ctype.h> +#endif + +#include <compat.h> + + +#define EOS '\0' + +#define RANGE_MATCH 1 +#define RANGE_NOMATCH 0 +#define RANGE_ERROR (-1) + +#ifdef NO_IBM_COMPILER_HORKAGE +static int rangematch (const char *, char, int, char **); +#else +static int rangematch (); +#endif + +int +fnmatch(pattern, string, flags) + const char *pattern, *string; + int flags; +{ + const char *stringstart; + char *newp; + char c, test; + + for (stringstart = string;;) + switch (c = *pattern++) { + case EOS: + if ((flags & FNM_LEADING_DIR) && *string == '/') + return (0); + return (*string == EOS ? 0 : FNM_NOMATCH); + case '?': + if (*string == EOS) + return (FNM_NOMATCH); + if (*string == '/' && (flags & FNM_PATHNAME)) + return (FNM_NOMATCH); + if (*string == '.' && (flags & FNM_PERIOD) && + (string == stringstart || + ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) + return (FNM_NOMATCH); + ++string; + break; + case '*': + c = *pattern; + /* Collapse multiple stars. */ + while (c == '*') + c = *++pattern; + + if (*string == '.' && (flags & FNM_PERIOD) && + (string == stringstart || + ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) + return (FNM_NOMATCH); + + /* Optimize for pattern with * at end or before /. */ + if (c == EOS) { + if (flags & FNM_PATHNAME) + return ((flags & FNM_LEADING_DIR) || + strchr(string, '/') == NULL ? + 0 : FNM_NOMATCH); + else + return (0); + } else if (c == '/' && (flags & FNM_PATHNAME)) { + if ((string = strchr(string, '/')) == NULL) + return (FNM_NOMATCH); + break; + } + + /* General case, use recursion. */ + while ((test = *string) != EOS) { + if (!fnmatch(pattern, string, flags & ~FNM_PERIOD)) + return (0); + if (test == '/' && (flags & FNM_PATHNAME)) + break; + ++string; + } + return (FNM_NOMATCH); + case '[': + if (*string == EOS) + return (FNM_NOMATCH); + if (*string == '/' && (flags & FNM_PATHNAME)) + return (FNM_NOMATCH); + if (*string == '.' && (flags & FNM_PERIOD) && + (string == stringstart || + ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) + return (FNM_NOMATCH); + + switch (rangematch(pattern, *string, flags, &newp)) { + case RANGE_ERROR: + /* not a good range, treat as normal text */ + goto normal; + case RANGE_MATCH: + pattern = newp; + break; + case RANGE_NOMATCH: + return (FNM_NOMATCH); + } + ++string; + break; + case '\\': + if (!(flags & FNM_NOESCAPE)) { + if ((c = *pattern++) == EOS) { + c = '\\'; + --pattern; + } + } + /* FALLTHROUGH */ + default: + normal: + if (c != *string && !((flags & FNM_CASEFOLD) && + (tolower((unsigned char)c) == + tolower((unsigned char)*string)))) + return (FNM_NOMATCH); + ++string; + break; + } + /* NOTREACHED */ +} + +static int +rangematch(pattern, test, flags, newp) + const char *pattern; + char test; + int flags; + char **newp; +{ + int negate, ok; + char c, c2; + + /* + * A bracket expression starting with an unquoted circumflex + * character produces unspecified results (IEEE 1003.2-1992, + * 3.13.2). This implementation treats it like '!', for + * consistency with the regular expression syntax. + * J.T. Conklin (conklin@ngai.kaleida.com) + */ + if ((negate = (*pattern == '!' || *pattern == '^'))) + ++pattern; + + if (flags & FNM_CASEFOLD) + test = tolower((unsigned char)test); + + /* + * A right bracket shall lose its special meaning and represent + * itself in a bracket expression if it occurs first in the list. + * -- POSIX.2 2.8.3.2 + */ + ok = 0; + c = *pattern++; + do { + if (c == '\\' && !(flags & FNM_NOESCAPE)) + c = *pattern++; + if (c == EOS) + return (RANGE_ERROR); + if (c == '/' && (flags & FNM_PATHNAME)) + return (RANGE_NOMATCH); + if ((flags & FNM_CASEFOLD)) + c = tolower((unsigned char)c); + if (*pattern == '-' + && (c2 = *(pattern+1)) != EOS && c2 != ']') { + pattern += 2; + if (c2 == '\\' && !(flags & FNM_NOESCAPE)) + c2 = *pattern++; + if (c2 == EOS) + return (RANGE_ERROR); + if (flags & FNM_CASEFOLD) + c2 = tolower((unsigned char)c2); + if (c <= test && test <= c2) + ok = 1; + } else if (c == test) + ok = 1; + } while ((c = *pattern++) != ']'); + + *newp = (char *)pattern; + return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH); +} diff --git a/libtar/gethostbyname_r.c b/libtar/gethostbyname_r.c new file mode 100644 index 000000000..5264b8444 --- /dev/null +++ b/libtar/gethostbyname_r.c @@ -0,0 +1,41 @@ +/* +** Copyright 2002 University of Illinois Board of Trustees +** Copyright 2002 Mark D. Roth +** All rights reserved. +** +** gethostbyname_r.c - gethostbyname_r() function for compatibility library +** +** Mark D. Roth <roth@uiuc.edu> +** Campus Information Technologies and Educational Services +** University of Illinois at Urbana-Champaign +*/ + +#include <config.h> + +#include <stdio.h> +#include <sys/types.h> +#include <netdb.h> + + +int +compat_gethostbyname_r(const char *name, struct hostent *hp, + char *buf, size_t buflen, + struct hostent **hpp, int *herr) +{ +#if GETHOSTBYNAME_R_NUM_ARGS == 5 + *hpp = gethostbyname_r(name, hp, buf, buflen, herr); + + if (*hpp == NULL) + return -1; + return 0; +#elif GETHOSTBYNAME_R_NUM_ARGS == 3 + struct hostent_data hdata; + + if (gethostbyname_r(name, hp, &hdata) == -1) + return -1; + *hpp = hp; + return 0; +#endif /* GETHOSTBYNAME_R_NUM_ARGS == 5 */ +} + + diff --git a/libtar/gethostname.c b/libtar/gethostname.c new file mode 100644 index 000000000..1abaae124 --- /dev/null +++ b/libtar/gethostname.c @@ -0,0 +1,36 @@ +/* gethostname.c: minimal substitute for missing gethostname() function + * created 2000-Mar-02 jmk + * requires SVR4 uname() and -lc + * + * by Jim Knoble <jmknoble@pobox.com> + * Copyright ? 2000 Jim Knoble + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear in + * supporting documentation. + * + * This software is provided "as is", without warranty of any kind, + * express or implied, including but not limited to the warranties of + * merchantability, fitness for a particular purpose and + * noninfringement. In no event shall the author(s) be liable for any + * claim, damages or other liability, whether in an action of contract, + * tort or otherwise, arising from, out of or in connection with the + * software or the use or other dealings in the software. + */ + +#include <string.h> +#include <sys/utsname.h> + +int gethostname(char *name, size_t len) +{ + struct utsname u; + int status = uname(&u); + if (-1 != status) { + strncpy(name, u.nodename, len); + name[len - 1] = '\0'; + } + return(status); +} + diff --git a/libtar/getservbyname_r.c b/libtar/getservbyname_r.c new file mode 100644 index 000000000..e386bc9f6 --- /dev/null +++ b/libtar/getservbyname_r.c @@ -0,0 +1,41 @@ +/* +** Copyright 2002 University of Illinois Board of Trustees +** Copyright 2002 Mark D. Roth +** All rights reserved. +** +** getservbyname_r.c - getservbyname_r() function for compatibility library +** +** Mark D. Roth <roth@uiuc.edu> +** Campus Information Technologies and Educational Services +** University of Illinois at Urbana-Champaign +*/ + +#include <config.h> + +#include <stdio.h> +#include <sys/types.h> +#include <netdb.h> + + +int +compat_getservbyname_r(const char *name, const char *proto, + struct servent *sp, char *buf, size_t buflen, + struct servent **spp) +{ +#if GETSERVBYNAME_R_NUM_ARGS == 5 + *spp = getservbyname_r(name, proto, sp, buf, buflen); + + if (*spp == NULL) + return -1; + return 0; +#elif GETSERVBYNAME_R_NUM_ARGS == 4 + struct servent_data sdata; + + if (getservbyname_r(name, proto, sp, &sdata) == -1) + return -1; + *spp = sp; + return 0; +#endif /* GETSERVBYNAME_R_NUM_ARGS == 5 */ +} + + diff --git a/libtar/glob.c b/libtar/glob.c new file mode 100644 index 000000000..9ee235a35 --- /dev/null +++ b/libtar/glob.c @@ -0,0 +1,873 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Guido van Rossum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93"; +#else +static char rcsid[] = "$OpenBSD: glob.c,v 1.8 1998/08/14 21:39:30 deraadt Exp $"; +#endif +#endif /* LIBC_SCCS and not lint */ + +/* + * glob(3) -- a superset of the one defined in POSIX 1003.2. + * + * The [!...] convention to negate a range is supported (SysV, Posix, ksh). + * + * Optional extra services, controlled by flags not defined by POSIX: + * + * GLOB_QUOTE: + * Escaping convention: \ inhibits any special meaning the following + * character might have (except \ at end of string is retained). + * GLOB_MAGCHAR: + * Set in gl_flags if pattern contained a globbing character. + * GLOB_NOMAGIC: + * Same as GLOB_NOCHECK, but it will only append pattern if it did + * not contain any magic characters. [Used in csh style globbing] + * GLOB_ALTDIRFUNC: + * Use alternately specified directory access functions. + * GLOB_TILDE: + * expand ~user/foo to the /home/dir/of/user/foo + * GLOB_BRACE: + * expand {1,2}{a,b} to 1a 1b 2a 2b + * gl_matchc: + * Number of matches in the current invocation of glob. + */ + +#include <config.h> + +#include <sys/param.h> +#include <sys/stat.h> + +#include <dirent.h> +#include <errno.h> +#include <pwd.h> +#include <stdio.h> + +#ifdef STDC_HEADERS +# include <stdlib.h> +# include <string.h> +#endif + +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#include <compat.h> + + +#define DOLLAR '$' +#define DOT '.' +#define EOS '\0' +#define LBRACKET '[' +#define NOT '!' +#define QUESTION '?' +#define QUOTE '\\' +#define RANGE '-' +#define RBRACKET ']' +#define SEP '/' +#define STAR '*' +#define TILDE '~' +#define UNDERSCORE '_' +#define LBRACE '{' +#define RBRACE '}' +#define SLASH '/' +#define COMMA ',' + +#ifndef DEBUG + +#define M_QUOTE 0x8000 +#define M_PROTECT 0x4000 +#define M_MASK 0xffff +#define M_ASCII 0x00ff + +typedef u_short Char; + +#else + +#define M_QUOTE 0x80 +#define M_PROTECT 0x40 +#define M_MASK 0xff +#define M_ASCII 0x7f + +typedef char Char; + +#endif + + +#define CHAR(c) ((Char)((c)&M_ASCII)) +#define META(c) ((Char)((c)|M_QUOTE)) +#define M_ALL META('*') +#define M_END META(']') +#define M_NOT META('!') +#define M_ONE META('?') +#define M_RNG META('-') +#define M_SET META('[') +#define ismeta(c) (((c)&M_QUOTE) != 0) + + +static int compare (const void *, const void *); +static void g_Ctoc (const Char *, char *); +static int g_lstat (Char *, struct stat *, glob_t *); +static DIR *g_opendir (Char *, glob_t *); +static Char *g_strchr (Char *, int); +#ifdef notdef +static Char *g_strcat (Char *, const Char *); +#endif +static int g_stat (Char *, struct stat *, glob_t *); +static int glob0 (const Char *, glob_t *); +static int glob1 (Char *, glob_t *); +static int glob2 (Char *, Char *, Char *, glob_t *); +static int glob3 (Char *, Char *, Char *, Char *, glob_t *); +static int globextend (const Char *, glob_t *); +static const Char * globtilde (const Char *, Char *, size_t, glob_t *); +static int globexp1 (const Char *, glob_t *); +static int globexp2 (const Char *, const Char *, glob_t *, int *); +static int match (Char *, Char *, Char *); +#ifdef DEBUG +static void qprintf (const char *, Char *); +#endif + +int +openbsd_glob(pattern, flags, errfunc, pglob) + const char *pattern; + int flags, (*errfunc) __P((const char *, int)); + glob_t *pglob; +{ + const u_char *patnext; + int c; + Char *bufnext, *bufend, patbuf[MAXPATHLEN+1]; + + patnext = (u_char *) pattern; + if (!(flags & GLOB_APPEND)) { + pglob->gl_pathc = 0; + pglob->gl_pathv = NULL; + if (!(flags & GLOB_DOOFFS)) + pglob->gl_offs = 0; + } + pglob->gl_flags = flags & ~GLOB_MAGCHAR; + pglob->gl_errfunc = errfunc; + pglob->gl_matchc = 0; + + bufnext = patbuf; + bufend = bufnext + MAXPATHLEN; + if (flags & GLOB_NOESCAPE) + while (bufnext < bufend && (c = *patnext++) != EOS) + *bufnext++ = c; + else { + /* Protect the quoted characters. */ + while (bufnext < bufend && (c = *patnext++) != EOS) + if (c == QUOTE) { + if ((c = *patnext++) == EOS) { + c = QUOTE; + --patnext; + } + *bufnext++ = c | M_PROTECT; + } + else + *bufnext++ = c; + } + *bufnext = EOS; + + if (flags & GLOB_BRACE) + return globexp1(patbuf, pglob); + else + return glob0(patbuf, pglob); +} + +/* + * Expand recursively a glob {} pattern. When there is no more expansion + * invoke the standard globbing routine to glob the rest of the magic + * characters + */ +static int globexp1(pattern, pglob) + const Char *pattern; + glob_t *pglob; +{ + const Char* ptr = pattern; + int rv; + + /* Protect a single {}, for find(1), like csh */ + if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) + return glob0(pattern, pglob); + + while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL) + if (!globexp2(ptr, pattern, pglob, &rv)) + return rv; + + return glob0(pattern, pglob); +} + + +/* + * Recursive brace globbing helper. Tries to expand a single brace. + * If it succeeds then it invokes globexp1 with the new pattern. + * If it fails then it tries to glob the rest of the pattern and returns. + */ +static int globexp2(ptr, pattern, pglob, rv) + const Char *ptr, *pattern; + glob_t *pglob; + int *rv; +{ + int i; + Char *lm, *ls; + const Char *pe, *pm, *pl; + Char patbuf[MAXPATHLEN + 1]; + + /* copy part up to the brace */ + for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++) + continue; + ls = lm; + + /* Find the balanced brace */ + for (i = 0, pe = ++ptr; *pe; pe++) + if (*pe == LBRACKET) { + /* Ignore everything between [] */ + for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++) + continue; + if (*pe == EOS) { + /* + * We could not find a matching RBRACKET. + * Ignore and just look for RBRACE + */ + pe = pm; + } + } + else if (*pe == LBRACE) + i++; + else if (*pe == RBRACE) { + if (i == 0) + break; + i--; + } + + /* Non matching braces; just glob the pattern */ + if (i != 0 || *pe == EOS) { + *rv = glob0(patbuf, pglob); + return 0; + } + + for (i = 0, pl = pm = ptr; pm <= pe; pm++) + switch (*pm) { + case LBRACKET: + /* Ignore everything between [] */ + for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++) + continue; + if (*pm == EOS) { + /* + * We could not find a matching RBRACKET. + * Ignore and just look for RBRACE + */ + pm = pl; + } + break; + + case LBRACE: + i++; + break; + + case RBRACE: + if (i) { + i--; + break; + } + /* FALLTHROUGH */ + case COMMA: + if (i && *pm == COMMA) + break; + else { + /* Append the current string */ + for (lm = ls; (pl < pm); *lm++ = *pl++) + continue; + /* + * Append the rest of the pattern after the + * closing brace + */ + for (pl = pe + 1; (*lm++ = *pl++) != EOS;) + continue; + + /* Expand the current pattern */ +#ifdef DEBUG + qprintf("globexp2:", patbuf); +#endif + *rv = globexp1(patbuf, pglob); + + /* move after the comma, to the next string */ + pl = pm + 1; + } + break; + + default: + break; + } + *rv = 0; + return 0; +} + + + +/* + * expand tilde from the passwd file. + */ +static const Char * +globtilde(pattern, patbuf, patbuf_len, pglob) + const Char *pattern; + Char *patbuf; + size_t patbuf_len; + glob_t *pglob; +{ + struct passwd *pwd; + char *h; + const Char *p; + Char *b, *eb; + + if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE)) + return pattern; + + /* Copy up to the end of the string or / */ + eb = &patbuf[patbuf_len - 1]; + for (p = pattern + 1, h = (char *) patbuf; + h < (char *)eb && *p && *p != SLASH; *h++ = *p++) + continue; + + *h = EOS; + + if (((char *) patbuf)[0] == EOS) { + /* + * handle a plain ~ or ~/ by expanding $HOME + * first and then trying the password file + */ +#ifdef HAVE_ISSETUGID + if (issetugid() != 0 || (h = getenv("HOME")) == NULL) { +#endif + if ((pwd = getpwuid(getuid())) == NULL) + return pattern; + else + h = pwd->pw_dir; +#ifdef HAVE_ISSETUGID + } +#endif + } + else { + /* + * Expand a ~user + */ + if ((pwd = getpwnam((char*) patbuf)) == NULL) + return pattern; + else + h = pwd->pw_dir; + } + + /* Copy the home directory */ + for (b = patbuf; b < eb && *h; *b++ = *h++) + continue; + + /* Append the rest of the pattern */ + while (b < eb && (*b++ = *p++) != EOS) + continue; + *b = EOS; + + return patbuf; +} + + +/* + * The main glob() routine: compiles the pattern (optionally processing + * quotes), calls glob1() to do the real pattern matching, and finally + * sorts the list (unless unsorted operation is requested). Returns 0 + * if things went well, nonzero if errors occurred. It is not an error + * to find no matches. + */ +static int +glob0(pattern, pglob) + const Char *pattern; + glob_t *pglob; +{ + const Char *qpatnext; + int c, err, oldpathc; + Char *bufnext, patbuf[MAXPATHLEN+1]; + + qpatnext = globtilde(pattern, patbuf, sizeof(patbuf) / sizeof(Char), + pglob); + oldpathc = pglob->gl_pathc; + bufnext = patbuf; + + /* We don't need to check for buffer overflow any more. */ + while ((c = *qpatnext++) != EOS) { + switch (c) { + case LBRACKET: + c = *qpatnext; + if (c == NOT) + ++qpatnext; + if (*qpatnext == EOS || + g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) { + *bufnext++ = LBRACKET; + if (c == NOT) + --qpatnext; + break; + } + *bufnext++ = M_SET; + if (c == NOT) + *bufnext++ = M_NOT; + c = *qpatnext++; + do { + *bufnext++ = CHAR(c); + if (*qpatnext == RANGE && + (c = qpatnext[1]) != RBRACKET) { + *bufnext++ = M_RNG; + *bufnext++ = CHAR(c); + qpatnext += 2; + } + } while ((c = *qpatnext++) != RBRACKET); + pglob->gl_flags |= GLOB_MAGCHAR; + *bufnext++ = M_END; + break; + case QUESTION: + pglob->gl_flags |= GLOB_MAGCHAR; + *bufnext++ = M_ONE; + break; + case STAR: + pglob->gl_flags |= GLOB_MAGCHAR; + /* collapse adjacent stars to one, + * to avoid exponential behavior + */ + if (bufnext == patbuf || bufnext[-1] != M_ALL) + *bufnext++ = M_ALL; + break; + default: + *bufnext++ = CHAR(c); + break; + } + } + *bufnext = EOS; +#ifdef DEBUG + qprintf("glob0:", patbuf); +#endif + + if ((err = glob1(patbuf, pglob)) != 0) + return(err); + + /* + * If there was no match we are going to append the pattern + * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified + * and the pattern did not contain any magic characters + * GLOB_NOMAGIC is there just for compatibility with csh. + */ + if (pglob->gl_pathc == oldpathc) { + if ((pglob->gl_flags & GLOB_NOCHECK) || + ((pglob->gl_flags & GLOB_NOMAGIC) && + !(pglob->gl_flags & GLOB_MAGCHAR))) + return(globextend(pattern, pglob)); + else + return(GLOB_NOMATCH); + } + if (!(pglob->gl_flags & GLOB_NOSORT)) + qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, + pglob->gl_pathc - oldpathc, sizeof(char *), compare); + return(0); +} + +static int +compare(p, q) + const void *p, *q; +{ + return(strcmp(*(char **)p, *(char **)q)); +} + +static int +glob1(pattern, pglob) + Char *pattern; + glob_t *pglob; +{ + Char pathbuf[MAXPATHLEN+1]; + + /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ + if (*pattern == EOS) + return(0); + return(glob2(pathbuf, pathbuf, pattern, pglob)); +} + +/* + * The functions glob2 and glob3 are mutually recursive; there is one level + * of recursion for each segment in the pattern that contains one or more + * meta characters. + */ +static int +glob2(pathbuf, pathend, pattern, pglob) + Char *pathbuf, *pathend, *pattern; + glob_t *pglob; +{ + struct stat sb; + Char *p, *q; + int anymeta; + + /* + * Loop over pattern segments until end of pattern or until + * segment with meta character found. + */ + for (anymeta = 0;;) { + if (*pattern == EOS) { /* End of pattern? */ + *pathend = EOS; + if (g_lstat(pathbuf, &sb, pglob)) + return(0); + + if (((pglob->gl_flags & GLOB_MARK) && + pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) + || (S_ISLNK(sb.st_mode) && + (g_stat(pathbuf, &sb, pglob) == 0) && + S_ISDIR(sb.st_mode)))) { + *pathend++ = SEP; + *pathend = EOS; + } + ++pglob->gl_matchc; + return(globextend(pathbuf, pglob)); + } + + /* Find end of next segment, copy tentatively to pathend. */ + q = pathend; + p = pattern; + while (*p != EOS && *p != SEP) { + if (ismeta(*p)) + anymeta = 1; + *q++ = *p++; + } + + if (!anymeta) { /* No expansion, do next segment. */ + pathend = q; + pattern = p; + while (*pattern == SEP) + *pathend++ = *pattern++; + } else /* Need expansion, recurse. */ + return(glob3(pathbuf, pathend, pattern, p, pglob)); + } + /* NOTREACHED */ +} + +static int +glob3(pathbuf, pathend, pattern, restpattern, pglob) + Char *pathbuf, *pathend, *pattern, *restpattern; + glob_t *pglob; +{ + register struct dirent *dp; + DIR *dirp; + int err; + char buf[MAXPATHLEN]; + + /* + * The readdirfunc declaration can't be prototyped, because it is + * assigned, below, to two functions which are prototyped in glob.h + * and dirent.h as taking pointers to differently typed opaque + * structures. + */ + struct dirent *(*readdirfunc)(); + + *pathend = EOS; + errno = 0; + + if ((dirp = g_opendir(pathbuf, pglob)) == NULL) { + /* TODO: don't call for ENOENT or ENOTDIR? */ + if (pglob->gl_errfunc) { + g_Ctoc(pathbuf, buf); + if (pglob->gl_errfunc(buf, errno) || + pglob->gl_flags & GLOB_ERR) + return (GLOB_ABORTED); + } + return(0); + } + + err = 0; + + /* Search directory for matching names. */ + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + readdirfunc = pglob->gl_readdir; + else + readdirfunc = readdir; + while ((dp = (*readdirfunc)(dirp))) { + register u_char *sc; + register Char *dc; + + /* Initial DOT must be matched literally. */ + if (dp->d_name[0] == DOT && *pattern != DOT) + continue; + for (sc = (u_char *) dp->d_name, dc = pathend; + (*dc++ = *sc++) != EOS;) + continue; + if (!match(pathend, pattern, restpattern)) { + *pathend = EOS; + continue; + } + err = glob2(pathbuf, --dc, restpattern, pglob); + if (err) + break; + } + + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + (*pglob->gl_closedir)(dirp); + else + closedir(dirp); + return(err); +} + + +/* + * Extend the gl_pathv member of a glob_t structure to accomodate a new item, + * add the new item, and update gl_pathc. + * + * This assumes the BSD realloc, which only copies the block when its size + * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic + * behavior. + * + * Return 0 if new item added, error code if memory couldn't be allocated. + * + * Invariant of the glob_t structure: + * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and + * gl_pathv points to (gl_offs + gl_pathc + 1) items. + */ +static int +globextend(path, pglob) + const Char *path; + glob_t *pglob; +{ + register char **pathv; + register int i; + u_int newsize; + char *copy; + const Char *p; + + newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); + pathv = pglob->gl_pathv ? + realloc((char *)pglob->gl_pathv, newsize) : + malloc(newsize); + if (pathv == NULL) { + if (pglob->gl_pathv) + free(pglob->gl_pathv); + return(GLOB_NOSPACE); + } + + if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { + /* first time around -- clear initial gl_offs items */ + pathv += pglob->gl_offs; + for (i = pglob->gl_offs; --i >= 0; ) + *--pathv = NULL; + } + pglob->gl_pathv = pathv; + + for (p = path; *p++;) + continue; + if ((copy = malloc(p - path)) != NULL) { + g_Ctoc(path, copy); + pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; + } + pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; + return(copy == NULL ? GLOB_NOSPACE : 0); +} + + +/* + * pattern matching function for filenames. Each occurrence of the * + * pattern causes a recursion level. + */ +static int +match(name, pat, patend) + register Char *name, *pat, *patend; +{ + int ok, negate_range; + Char c, k; + + while (pat < patend) { + c = *pat++; + switch (c & M_MASK) { + case M_ALL: + if (pat == patend) + return(1); + do + if (match(name, pat, patend)) + return(1); + while (*name++ != EOS); + return(0); + case M_ONE: + if (*name++ == EOS) + return(0); + break; + case M_SET: + ok = 0; + if ((k = *name++) == EOS) + return(0); + if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS) + ++pat; + while (((c = *pat++) & M_MASK) != M_END) + if ((*pat & M_MASK) == M_RNG) { + if (c <= k && k <= pat[1]) + ok = 1; + pat += 2; + } else if (c == k) + ok = 1; + if (ok == negate_range) + return(0); + break; + default: + if (*name++ != c) + return(0); + break; + } + } + return(*name == EOS); +} + +/* Free allocated data belonging to a glob_t structure. */ +void +openbsd_globfree(pglob) + glob_t *pglob; +{ + register int i; + register char **pp; + + if (pglob->gl_pathv != NULL) { + pp = pglob->gl_pathv + pglob->gl_offs; + for (i = pglob->gl_pathc; i--; ++pp) + if (*pp) + free(*pp); + free(pglob->gl_pathv); + } +} + +static DIR * +g_opendir(str, pglob) + register Char *str; + glob_t *pglob; +{ + char buf[MAXPATHLEN]; + + if (!*str) + strcpy(buf, "."); + else + g_Ctoc(str, buf); + + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + return((*pglob->gl_opendir)(buf)); + + return(opendir(buf)); +} + +static int +g_lstat(fn, sb, pglob) + register Char *fn; + struct stat *sb; + glob_t *pglob; +{ + char buf[MAXPATHLEN]; + + g_Ctoc(fn, buf); + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + return((*pglob->gl_lstat)(buf, sb)); + return(lstat(buf, sb)); +} + +static int +g_stat(fn, sb, pglob) + register Char *fn; + struct stat *sb; + glob_t *pglob; +{ + char buf[MAXPATHLEN]; + + g_Ctoc(fn, buf); + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + return((*pglob->gl_stat)(buf, sb)); + return(stat(buf, sb)); +} + +static Char * +g_strchr(str, ch) + Char *str; + int ch; +{ + do { + if (*str == ch) + return (str); + } while (*str++); + return (NULL); +} + +#ifdef notdef +static Char * +g_strcat(dst, src) + Char *dst; + const Char* src; +{ + Char *sdst = dst; + + while (*dst++) + continue; + --dst; + while((*dst++ = *src++) != EOS) + continue; + + return (sdst); +} +#endif + +static void +g_Ctoc(str, buf) + register const Char *str; + char *buf; +{ + register char *dc; + + for (dc = buf; (*dc++ = *str++) != EOS;) + continue; +} + +#ifdef DEBUG +static void +qprintf(str, s) + const char *str; + register Char *s; +{ + register Char *p; + + (void)printf("%s:\n", str); + for (p = s; *p; p++) + (void)printf("%c", CHAR(*p)); + (void)printf("\n"); + for (p = s; *p; p++) + (void)printf("%c", *p & M_PROTECT ? '"' : ' '); + (void)printf("\n"); + for (p = s; *p; p++) + (void)printf("%c", ismeta(*p) ? '_' : ' '); + (void)printf("\n"); +} +#endif diff --git a/libtar/handle.c b/libtar/handle.c new file mode 100644 index 000000000..ae974b9f0 --- /dev/null +++ b/libtar/handle.c @@ -0,0 +1,129 @@ +/* +** Copyright 1998-2003 University of Illinois Board of Trustees +** Copyright 1998-2003 Mark D. Roth +** All rights reserved. +** +** handle.c - libtar code for initializing a TAR handle +** +** Mark D. Roth <roth@uiuc.edu> +** Campus Information Technologies and Educational Services +** University of Illinois at Urbana-Champaign +*/ + +#include <internal.h> + +#include <stdio.h> +#include <fcntl.h> +#include <errno.h> + +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#ifdef STDC_HEADERS +# include <stdlib.h> +#endif + + +const char libtar_version[] = PACKAGE_VERSION; + +static tartype_t default_type = { open, close, read, write }; + + +static int +tar_init(TAR **t, char *pathname, tartype_t *type, + int oflags, int mode, int options) +{ + if ((oflags & O_ACCMODE) == O_RDWR) + { + errno = EINVAL; + return -1; + } + + *t = (TAR *)calloc(1, sizeof(TAR)); + if (*t == NULL) + return -1; + + (*t)->pathname = pathname; + (*t)->options = options; + (*t)->type = (type ? type : &default_type); + (*t)->oflags = oflags; + + if ((oflags & O_ACCMODE) == O_RDONLY) + (*t)->h = libtar_hash_new(256, + (libtar_hashfunc_t)path_hashfunc); + else + (*t)->h = libtar_hash_new(16, (libtar_hashfunc_t)dev_hash); + if ((*t)->h == NULL) + { + free(*t); + return -1; + } + + return 0; +} + + +/* open a new tarfile handle */ +int +tar_open(TAR **t, char *pathname, tartype_t *type, + int oflags, int mode, int options) +{ + if (tar_init(t, pathname, type, oflags, mode, options) == -1) + return -1; + + if ((options & TAR_NOOVERWRITE) && (oflags & O_CREAT)) + oflags |= O_EXCL; + +#ifdef O_BINARY + oflags |= O_BINARY; +#endif + + (*t)->fd = (*((*t)->type->openfunc))(pathname, oflags, mode); + if ((*t)->fd == -1) + { + free(*t); + return -1; + } + + return 0; +} + + +int +tar_fdopen(TAR **t, int fd, char *pathname, tartype_t *type, + int oflags, int mode, int options) +{ + if (tar_init(t, pathname, type, oflags, mode, options) == -1) + return -1; + + (*t)->fd = fd; + return 0; +} + + +int +tar_fd(TAR *t) +{ + return t->fd; +} + + +/* close tarfile handle */ +int +tar_close(TAR *t) +{ + int i; + + i = (*(t->type->closefunc))(t->fd); + + if (t->h != NULL) + libtar_hash_free(t->h, ((t->oflags & O_ACCMODE) == O_RDONLY + ? free + : (libtar_freefunc_t)tar_dev_free)); + free(t); + + return i; +} + + diff --git a/libtar/inet_aton.c b/libtar/inet_aton.c new file mode 100644 index 000000000..a935d5a6b --- /dev/null +++ b/libtar/inet_aton.c @@ -0,0 +1,27 @@ +/* +** Copyright 2002 University of Illinois Board of Trustees +** Copyright 2002 Mark D. Roth +** All rights reserved. +** +** inet_aton.c - inet_aton() function for compatibility library +** +** Mark D. Roth <roth@uiuc.edu> +** Campus Information Technologies and Educational Services +** University of Illinois at Urbana-Champaign +*/ + +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + + +int +inet_aton(const char *cp, struct in_addr *inp) +{ + inp->s_addr = inet_addr(cp); + if (inp->s_addr == -1) + return 0; + return 1; +} + + diff --git a/libtar/internal.h b/libtar/internal.h new file mode 100644 index 000000000..23243d296 --- /dev/null +++ b/libtar/internal.h @@ -0,0 +1,17 @@ +/* +** Copyright 2002-2003 University of Illinois Board of Trustees +** Copyright 2002-2003 Mark D. Roth +** All rights reserved. +** +** internal.h - internal header file for libtar +** +** Mark D. Roth <roth@uiuc.edu> +** Campus Information Technologies and Educational Services +** University of Illinois at Urbana-Champaign +*/ + +#include <config.h> +#include <compat.h> + +#include <libtar.h> + diff --git a/libtar/libtar.h b/libtar/libtar.h new file mode 100644 index 000000000..d2c4d003c --- /dev/null +++ b/libtar/libtar.h @@ -0,0 +1,311 @@ +/* +** Copyright 1998-2003 University of Illinois Board of Trustees +** Copyright 1998-2003 Mark D. Roth +** All rights reserved. +** +** libtar.h - header file for libtar library +** +** Mark D. Roth <roth@uiuc.edu> +** Campus Information Technologies and Educational Services +** University of Illinois at Urbana-Champaign +*/ + +#ifndef LIBTAR_H +#define LIBTAR_H + +#include <sys/types.h> +#include <sys/stat.h> +#include "tar.h" + +#include "libtar_listhash.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/* useful constants */ +#define T_BLOCKSIZE 512 +#define T_NAMELEN 100 +#define T_PREFIXLEN 155 +#define T_MAXPATHLEN (T_NAMELEN + T_PREFIXLEN) + +/* GNU extensions for typeflag */ +#define GNU_LONGNAME_TYPE 'L' +#define GNU_LONGLINK_TYPE 'K' + +/* extended metadata for next file - used to store selinux_context */ +#define TH_EXT_TYPE 'x' + +/* our version of the tar header structure */ +struct tar_header +{ + char name[100]; + char mode[8]; + char uid[8]; + char gid[8]; + char size[12]; + char mtime[12]; + char chksum[8]; + char typeflag; + char linkname[100]; + char magic[6]; + char version[2]; + char uname[32]; + char gname[32]; + char devmajor[8]; + char devminor[8]; + char prefix[155]; + char padding[12]; + char *gnu_longname; + char *gnu_longlink; +#ifdef HAVE_SELINUX + char *selinux_context; +#endif +}; + + +/***** handle.c ************************************************************/ + +typedef int (*openfunc_t)(const char *, int, ...); +typedef int (*closefunc_t)(int); +typedef ssize_t (*readfunc_t)(int, void *, size_t); +typedef ssize_t (*writefunc_t)(int, const void *, size_t); + +typedef struct +{ + openfunc_t openfunc; + closefunc_t closefunc; + readfunc_t readfunc; + writefunc_t writefunc; +} +tartype_t; + +typedef struct +{ + tartype_t *type; + char *pathname; + long fd; + int oflags; + int options; + struct tar_header th_buf; + libtar_hash_t *h; +} +TAR; + +/* constant values for the TAR options field */ +#define TAR_GNU 1 /* use GNU extensions */ +#define TAR_VERBOSE 2 /* output file info to stdout */ +#define TAR_NOOVERWRITE 4 /* don't overwrite existing files */ +#define TAR_IGNORE_EOT 8 /* ignore double zero blocks as EOF */ +#define TAR_CHECK_MAGIC 16 /* check magic in file header */ +#define TAR_CHECK_VERSION 32 /* check version in file header */ +#define TAR_IGNORE_CRC 64 /* ignore CRC in file header */ +#define TAR_STORE_SELINUX 128 /* store selinux context */ + +/* this is obsolete - it's here for backwards-compatibility only */ +#define TAR_IGNORE_MAGIC 0 + +extern const char libtar_version[]; + + +/* open a new tarfile handle */ +int tar_open(TAR **t, char *pathname, tartype_t *type, + int oflags, int mode, int options); + +/* make a tarfile handle out of a previously-opened descriptor */ +int tar_fdopen(TAR **t, int fd, char *pathname, tartype_t *type, + int oflags, int mode, int options); + +/* returns the descriptor associated with t */ +int tar_fd(TAR *t); + +/* close tarfile handle */ +int tar_close(TAR *t); + + +/***** append.c ************************************************************/ + +/* forward declaration to appease the compiler */ +struct tar_dev; + +/* cleanup function */ +void tar_dev_free(struct tar_dev *tdp); + +/* Appends a file to the tar archive. + * Arguments: + * t = TAR handle to append to + * realname = path of file to append + * savename = name to save the file under in the archive + */ +int tar_append_file(TAR *t, char *realname, char *savename); + +/* write EOF indicator */ +int tar_append_eof(TAR *t); + +/* add file contents to a tarchive */ +int tar_append_regfile(TAR *t, char *realname); + + +/***** block.c *************************************************************/ + +/* macros for reading/writing tarchive blocks */ +#define tar_block_read(t, buf) \ + (*((t)->type->readfunc))((t)->fd, (char *)(buf), T_BLOCKSIZE) +#define tar_block_write(t, buf) \ + (*((t)->type->writefunc))((t)->fd, (char *)(buf), T_BLOCKSIZE) + +/* read/write a header block */ +int th_read(TAR *t); +int th_write(TAR *t); + + +/***** decode.c ************************************************************/ + +/* determine file type */ +#define TH_ISREG(t) ((t)->th_buf.typeflag == REGTYPE \ + || (t)->th_buf.typeflag == AREGTYPE \ + || (t)->th_buf.typeflag == CONTTYPE \ + || (S_ISREG((mode_t)oct_to_int((t)->th_buf.mode)) \ + && (t)->th_buf.typeflag != LNKTYPE)) +#define TH_ISLNK(t) ((t)->th_buf.typeflag == LNKTYPE) +#define TH_ISSYM(t) ((t)->th_buf.typeflag == SYMTYPE \ + || S_ISLNK((mode_t)oct_to_int((t)->th_buf.mode))) +#define TH_ISCHR(t) ((t)->th_buf.typeflag == CHRTYPE \ + || S_ISCHR((mode_t)oct_to_int((t)->th_buf.mode))) +#define TH_ISBLK(t) ((t)->th_buf.typeflag == BLKTYPE \ + || S_ISBLK((mode_t)oct_to_int((t)->th_buf.mode))) +#define TH_ISDIR(t) ((t)->th_buf.typeflag == DIRTYPE \ + || S_ISDIR((mode_t)oct_to_int((t)->th_buf.mode)) \ + || ((t)->th_buf.typeflag == AREGTYPE \ + && ((t)->th_buf.name[strlen((t)->th_buf.name) - 1] == '/'))) +#define TH_ISFIFO(t) ((t)->th_buf.typeflag == FIFOTYPE \ + || S_ISFIFO((mode_t)oct_to_int((t)->th_buf.mode))) +#define TH_ISLONGNAME(t) ((t)->th_buf.typeflag == GNU_LONGNAME_TYPE) +#define TH_ISLONGLINK(t) ((t)->th_buf.typeflag == GNU_LONGLINK_TYPE) +#define TH_ISEXTHEADER(t) ((t)->th_buf.typeflag == TH_EXT_TYPE) + +/* decode tar header info */ +#define th_get_crc(t) oct_to_int((t)->th_buf.chksum) +#define th_get_size(t) oct_to_int((t)->th_buf.size) +#define th_get_mtime(t) oct_to_int((t)->th_buf.mtime) +#define th_get_devmajor(t) oct_to_int((t)->th_buf.devmajor) +#define th_get_devminor(t) oct_to_int((t)->th_buf.devminor) +#define th_get_linkname(t) ((t)->th_buf.gnu_longlink \ + ? (t)->th_buf.gnu_longlink \ + : (t)->th_buf.linkname) +char *th_get_pathname(TAR *t); +mode_t th_get_mode(TAR *t); +uid_t th_get_uid(TAR *t); +gid_t th_get_gid(TAR *t); + + +/***** encode.c ************************************************************/ + +/* encode file info in th_header */ +void th_set_type(TAR *t, mode_t mode); +void th_set_path(TAR *t, char *pathname); +void th_set_link(TAR *t, char *linkname); +void th_set_device(TAR *t, dev_t device); +void th_set_user(TAR *t, uid_t uid); +void th_set_group(TAR *t, gid_t gid); +void th_set_mode(TAR *t, mode_t fmode); +#define th_set_mtime(t, fmtime) \ + int_to_oct_nonull((fmtime), (t)->th_buf.mtime, 12) +#define th_set_size(t, fsize) \ + int_to_oct_nonull((fsize), (t)->th_buf.size, 12) + +/* encode everything at once (except the pathname and linkname) */ +void th_set_from_stat(TAR *t, struct stat *s); + +/* encode magic, version, and crc - must be done after everything else is set */ +void th_finish(TAR *t); + + +/***** extract.c ***********************************************************/ + +/* sequentially extract next file from t */ +int tar_extract_file(TAR *t, char *realname, char *prefix, const int *progress_fd); + +/* extract different file types */ +int tar_extract_dir(TAR *t, char *realname); +int tar_extract_hardlink(TAR *t, char *realname, char *prefix); +int tar_extract_symlink(TAR *t, char *realname); +int tar_extract_chardev(TAR *t, char *realname); +int tar_extract_blockdev(TAR *t, char *realname); +int tar_extract_fifo(TAR *t, char *realname); + +/* for regfiles, we need to extract the content blocks as well */ +int tar_extract_regfile(TAR *t, char *realname, const int *progress_fd); +int tar_skip_regfile(TAR *t); + + +/***** output.c ************************************************************/ + +/* print the tar header */ +void th_print(TAR *t); + +/* print "ls -l"-like output for the file described by th */ +void th_print_long_ls(TAR *t); + + +/***** util.c *************************************************************/ + +/* hashing function for pathnames */ +int path_hashfunc(char *key, int numbuckets); + +/* matching function for dev_t's */ +int dev_match(dev_t *dev1, dev_t *dev2); + +/* matching function for ino_t's */ +int ino_match(ino_t *ino1, ino_t *ino2); + +/* hashing function for dev_t's */ +int dev_hash(dev_t *dev); + +/* hashing function for ino_t's */ +int ino_hash(ino_t *inode); + +/* create any necessary dirs */ +int mkdirhier(char *path); + +/* calculate header checksum */ +int th_crc_calc(TAR *t); + +/* calculate a signed header checksum */ +int th_signed_crc_calc(TAR *t); + +/* compare checksums in a forgiving way */ +#define th_crc_ok(t) (th_get_crc(t) == th_crc_calc(t) || th_get_crc(t) == th_signed_crc_calc(t)) + +/* string-octal to integer conversion */ +int oct_to_int(char *oct); + +/* integer to NULL-terminated string-octal conversion */ +#define int_to_oct(num, oct, octlen) \ + snprintf((oct), (octlen), "%*lo ", (octlen) - 2, (unsigned long)(num)) + +/* integer to string-octal conversion, no NULL */ +void int_to_oct_nonull(int num, char *oct, size_t octlen); + +#define tar_min(x, y) (x < y ? x : y) + +/***** wrapper.c **********************************************************/ + +/* extract groups of files */ +int tar_extract_glob(TAR *t, char *globname, char *prefix); +int tar_extract_all(TAR *t, char *prefix, const int *progress_fd); + +/* add a whole tree of files */ +int tar_append_tree(TAR *t, char *realdir, char *savedir, char *exclude); + +/* find an entry */ +int tar_find(TAR *t, char *searchstr); + +#ifdef __cplusplus +} +#endif + +#endif /* ! LIBTAR_H */ + diff --git a/libtar/libtar_hash.c b/libtar/libtar_hash.c new file mode 100644 index 000000000..796ebbee6 --- /dev/null +++ b/libtar/libtar_hash.c @@ -0,0 +1,344 @@ +/* listhash/libtar_hash.c. Generated from hash.c.in by configure. */ + +/* +** Copyright 1998-2002 University of Illinois Board of Trustees +** Copyright 1998-2002 Mark D. Roth +** All rights reserved. +** +** libtar_hash.c - hash table routines +** +** Mark D. Roth <roth@uiuc.edu> +** Campus Information Technologies and Educational Services +** University of Illinois at Urbana-Champaign +*/ + +#include <config.h> +#include <compat.h> + +#include <libtar_listhash.h> + +#include <stdio.h> +#include <errno.h> + +#ifdef STDC_HEADERS +# include <stdlib.h> +#endif + + +/* +** libtar_hashptr_reset() - reset a hash pointer +*/ +void +libtar_hashptr_reset(libtar_hashptr_t *hp) +{ + libtar_listptr_reset(&(hp->node)); + hp->bucket = -1; +} + + +/* +** libtar_hashptr_data() - retrieve the data being pointed to +*/ +void * +libtar_hashptr_data(libtar_hashptr_t *hp) +{ + return libtar_listptr_data(&(hp->node)); +} + + +/* +** libtar_str_hashfunc() - default hash function, optimized for +** 7-bit strings +*/ +unsigned int +libtar_str_hashfunc(char *key, unsigned int num_buckets) +{ +#if 0 + register unsigned result = 0; + register int i; + + if (key == NULL) + return 0; + + for (i = 0; *key != '\0' && i < 32; i++) + result = result * 33U + *key++; + + return (result % num_buckets); +#else + if (key == NULL) + return 0; + + return (key[0] % num_buckets); +#endif +} + + +/* +** libtar_hash_nents() - return number of elements from hash +*/ +unsigned int +libtar_hash_nents(libtar_hash_t *h) +{ + return h->nents; +} + + +/* +** libtar_hash_new() - create a new hash +*/ +libtar_hash_t * +libtar_hash_new(int num, libtar_hashfunc_t hashfunc) +{ + libtar_hash_t *hash; + + hash = (libtar_hash_t *)calloc(1, sizeof(libtar_hash_t)); + if (hash == NULL) + return NULL; + hash->numbuckets = num; + if (hashfunc != NULL) + hash->hashfunc = hashfunc; + else + hash->hashfunc = (libtar_hashfunc_t)libtar_str_hashfunc; + + hash->table = (libtar_list_t **)calloc(num, sizeof(libtar_list_t *)); + if (hash->table == NULL) + { + free(hash); + return NULL; + } + + return hash; +} + + +/* +** libtar_hash_next() - get next element in hash +** returns: +** 1 data found +** 0 end of list +*/ +int +libtar_hash_next(libtar_hash_t *h, + libtar_hashptr_t *hp) +{ +#ifdef DS_DEBUG + printf("==> libtar_hash_next(h=0x%lx, hp={%d,0x%lx})\n", + h, hp->bucket, hp->node); +#endif + + if (hp->bucket >= 0 && hp->node != NULL && + libtar_list_next(h->table[hp->bucket], &(hp->node)) != 0) + { +#ifdef DS_DEBUG + printf(" libtar_hash_next(): found additional " + "data in current bucket (%d), returing 1\n", + hp->bucket); +#endif + return 1; + } + +#ifdef DS_DEBUG + printf(" libtar_hash_next(): done with bucket %d\n", + hp->bucket); +#endif + + for (hp->bucket++; hp->bucket < h->numbuckets; hp->bucket++) + { +#ifdef DS_DEBUG + printf(" libtar_hash_next(): " + "checking bucket %d\n", hp->bucket); +#endif + hp->node = NULL; + if (h->table[hp->bucket] != NULL && + libtar_list_next(h->table[hp->bucket], + &(hp->node)) != 0) + { +#ifdef DS_DEBUG + printf(" libtar_hash_next(): " + "found data in bucket %d, returing 1\n", + hp->bucket); +#endif + return 1; + } + } + + if (hp->bucket == h->numbuckets) + { +#ifdef DS_DEBUG + printf(" libtar_hash_next(): hash pointer " + "wrapped to 0\n"); +#endif + hp->bucket = -1; + hp->node = NULL; + } + +#ifdef DS_DEBUG + printf("<== libtar_hash_next(): no more data, " + "returning 0\n"); +#endif + return 0; +} + + +/* +** libtar_hash_del() - delete an entry from the hash +** returns: +** 0 success +** -1 (and sets errno) failure +*/ +int +libtar_hash_del(libtar_hash_t *h, + libtar_hashptr_t *hp) +{ + if (hp->bucket < 0 + || hp->bucket >= h->numbuckets + || h->table[hp->bucket] == NULL + || hp->node == NULL) + { + errno = EINVAL; + return -1; + } + + libtar_list_del(h->table[hp->bucket], &(hp->node)); + h->nents--; + return 0; +} + + +/* +** libtar_hash_empty() - empty the hash +*/ +void +libtar_hash_empty(libtar_hash_t *h, libtar_freefunc_t freefunc) +{ + int i; + + for (i = 0; i < h->numbuckets; i++) + if (h->table[i] != NULL) + libtar_list_empty(h->table[i], freefunc); + + h->nents = 0; +} + + +/* +** libtar_hash_free() - delete all of the nodes in the hash +*/ +void +libtar_hash_free(libtar_hash_t *h, libtar_freefunc_t freefunc) +{ + int i; + + for (i = 0; i < h->numbuckets; i++) + if (h->table[i] != NULL) + libtar_list_free(h->table[i], freefunc); + + free(h->table); + free(h); +} + + +/* +** libtar_hash_search() - iterative search for an element in a hash +** returns: +** 1 match found +** 0 no match +*/ +int +libtar_hash_search(libtar_hash_t *h, + libtar_hashptr_t *hp, void *data, + libtar_matchfunc_t matchfunc) +{ + while (libtar_hash_next(h, hp) != 0) + if ((*matchfunc)(data, libtar_listptr_data(&(hp->node))) != 0) + return 1; + + return 0; +} + + +/* +** libtar_hash_getkey() - hash-based search for an element in a hash +** returns: +** 1 match found +** 0 no match +*/ +int +libtar_hash_getkey(libtar_hash_t *h, + libtar_hashptr_t *hp, void *key, + libtar_matchfunc_t matchfunc) +{ +#ifdef DS_DEBUG + printf("==> libtar_hash_getkey(h=0x%lx, hp={%d,0x%lx}, " + "key=0x%lx, matchfunc=0x%lx)\n", + h, hp->bucket, hp->node, key, matchfunc); +#endif + + if (hp->bucket == -1) + { + hp->bucket = (*(h->hashfunc))(key, h->numbuckets); +#ifdef DS_DEBUG + printf(" libtar_hash_getkey(): hp->bucket " + "set to %d\n", hp->bucket); +#endif + } + + if (h->table[hp->bucket] == NULL) + { +#ifdef DS_DEBUG + printf(" libtar_hash_getkey(): no list " + "for bucket %d, returning 0\n", hp->bucket); +#endif + hp->bucket = -1; + return 0; + } + +#ifdef DS_DEBUG + printf("<== libtar_hash_getkey(): " + "returning libtar_list_search()\n"); +#endif + return libtar_list_search(h->table[hp->bucket], &(hp->node), + key, matchfunc); +} + + +/* +** libtar_hash_add() - add an element to the hash +** returns: +** 0 success +** -1 (and sets errno) failure +*/ +int +libtar_hash_add(libtar_hash_t *h, void *data) +{ + int bucket, i; + +#ifdef DS_DEBUG + printf("==> libtar_hash_add(h=0x%lx, data=0x%lx)\n", + h, data); +#endif + + bucket = (*(h->hashfunc))(data, h->numbuckets); +#ifdef DS_DEBUG + printf(" libtar_hash_add(): inserting in bucket %d\n", + bucket); +#endif + if (h->table[bucket] == NULL) + { +#ifdef DS_DEBUG + printf(" libtar_hash_add(): creating new list\n"); +#endif + h->table[bucket] = libtar_list_new(LIST_QUEUE, NULL); + } + +#ifdef DS_DEBUG + printf("<== libtar_hash_add(): " + "returning libtar_list_add()\n"); +#endif + i = libtar_list_add(h->table[bucket], data); + if (i == 0) + h->nents++; + return i; +} + + diff --git a/libtar/libtar_list.c b/libtar/libtar_list.c new file mode 100644 index 000000000..2c5febb01 --- /dev/null +++ b/libtar/libtar_list.c @@ -0,0 +1,458 @@ +/* listhash/libtar_list.c. Generated from list.c.in by configure. */ + +/* +** Copyright 1998-2002 University of Illinois Board of Trustees +** Copyright 1998-2002 Mark D. Roth +** All rights reserved. +** +** libtar_list.c - linked list routines +** +** Mark D. Roth <roth@uiuc.edu> +** Campus Information Technologies and Educational Services +** University of Illinois at Urbana-Champaign +*/ + +#include <config.h> +#include <compat.h> + +#include <libtar_listhash.h> + +#include <stdio.h> +#include <errno.h> +#include <sys/param.h> + +#ifdef STDC_HEADERS +# include <string.h> +# include <stdlib.h> +#endif + + +/* +** libtar_listptr_reset() - reset a list pointer +*/ +void +libtar_listptr_reset(libtar_listptr_t *lp) +{ + *lp = NULL; +} + + +/* +** libtar_listptr_data() - retrieve the data pointed to by lp +*/ +void * +libtar_listptr_data(libtar_listptr_t *lp) +{ + return (*lp)->data; +} + + +/* +** libtar_list_new() - create a new, empty list +*/ +libtar_list_t * +libtar_list_new(int flags, libtar_cmpfunc_t cmpfunc) +{ + libtar_list_t *newlist; + +#ifdef DS_DEBUG + printf("in libtar_list_new(%d, 0x%lx)\n", flags, cmpfunc); +#endif + + if (flags != LIST_USERFUNC + && flags != LIST_STACK + && flags != LIST_QUEUE) + { + errno = EINVAL; + return NULL; + } + + newlist = (libtar_list_t *)calloc(1, sizeof(libtar_list_t)); + if (cmpfunc != NULL) + newlist->cmpfunc = cmpfunc; + else + newlist->cmpfunc = (libtar_cmpfunc_t)strcmp; + newlist->flags = flags; + + return newlist; +} + + +/* +** libtar_list_iterate() - call a function for every element +** in a list +*/ +int +libtar_list_iterate(libtar_list_t *l, + libtar_iterate_func_t plugin, + void *state) +{ + libtar_listptr_t n; + + if (l == NULL) + return -1; + + for (n = l->first; n != NULL; n = n->next) + { + if ((*plugin)(n->data, state) == -1) + return -1; + } + + return 0; +} + + +/* +** libtar_list_empty() - empty the list +*/ +void +libtar_list_empty(libtar_list_t *l, libtar_freefunc_t freefunc) +{ + libtar_listptr_t n; + + for (n = l->first; n != NULL; n = l->first) + { + l->first = n->next; + if (freefunc != NULL) + (*freefunc)(n->data); + free(n); + } + + l->nents = 0; +} + + +/* +** libtar_list_free() - remove and free() the whole list +*/ +void +libtar_list_free(libtar_list_t *l, libtar_freefunc_t freefunc) +{ + libtar_list_empty(l, freefunc); + free(l); +} + + +/* +** libtar_list_nents() - return number of elements in the list +*/ +unsigned int +libtar_list_nents(libtar_list_t *l) +{ + return l->nents; +} + + +/* +** libtar_list_add() - adds an element to the list +** returns: +** 0 success +** -1 (and sets errno) failure +*/ +int +libtar_list_add(libtar_list_t *l, void *data) +{ + libtar_listptr_t n, m; + +#ifdef DS_DEBUG + printf("==> libtar_list_add(\"%s\")\n", (char *)data); +#endif + + n = (libtar_listptr_t)malloc(sizeof(struct libtar_node)); + if (n == NULL) + return -1; + n->data = data; + l->nents++; + +#ifdef DS_DEBUG + printf(" libtar_list_add(): allocated data\n"); +#endif + + /* if the list is empty */ + if (l->first == NULL) + { + l->last = l->first = n; + n->next = n->prev = NULL; +#ifdef DS_DEBUG + printf("<== libtar_list_add(): list was empty; " + "added first element and returning 0\n"); +#endif + return 0; + } + +#ifdef DS_DEBUG + printf(" libtar_list_add(): list not empty\n"); +#endif + + if (l->flags == LIST_STACK) + { + n->prev = NULL; + n->next = l->first; + if (l->first != NULL) + l->first->prev = n; + l->first = n; +#ifdef DS_DEBUG + printf("<== libtar_list_add(): LIST_STACK set; " + "added in front\n"); +#endif + return 0; + } + + if (l->flags == LIST_QUEUE) + { + n->prev = l->last; + n->next = NULL; + if (l->last != NULL) + l->last->next = n; + l->last = n; +#ifdef DS_DEBUG + printf("<== libtar_list_add(): LIST_QUEUE set; " + "added at end\n"); +#endif + return 0; + } + + for (m = l->first; m != NULL; m = m->next) + if ((*(l->cmpfunc))(data, m->data) < 0) + { + /* + ** if we find one that's bigger, + ** insert data before it + */ +#ifdef DS_DEBUG + printf(" libtar_list_add(): gotcha..." + "inserting data\n"); +#endif + if (m == l->first) + { + l->first = n; + n->prev = NULL; + m->prev = n; + n->next = m; +#ifdef DS_DEBUG + printf("<== libtar_list_add(): " + "added first, returning 0\n"); +#endif + return 0; + } + m->prev->next = n; + n->prev = m->prev; + m->prev = n; + n->next = m; +#ifdef DS_DEBUG + printf("<== libtar_list_add(): added middle," + " returning 0\n"); +#endif + return 0; + } + +#ifdef DS_DEBUG + printf(" libtar_list_add(): new data larger than current " + "list elements\n"); +#endif + + /* if we get here, data is bigger than everything in the list */ + l->last->next = n; + n->prev = l->last; + l->last = n; + n->next = NULL; +#ifdef DS_DEBUG + printf("<== libtar_list_add(): added end, returning 0\n"); +#endif + return 0; +} + + +/* +** libtar_list_del() - remove the element pointed to by n +** from the list l +*/ +void +libtar_list_del(libtar_list_t *l, libtar_listptr_t *n) +{ + libtar_listptr_t m; + +#ifdef DS_DEBUG + printf("==> libtar_list_del()\n"); +#endif + + l->nents--; + + m = (*n)->next; + + if ((*n)->prev) + (*n)->prev->next = (*n)->next; + else + l->first = (*n)->next; + if ((*n)->next) + (*n)->next->prev = (*n)->prev; + else + l->last = (*n)->prev; + + free(*n); + *n = m; +} + + +/* +** libtar_list_next() - get the next element in the list +** returns: +** 1 success +** 0 end of list +*/ +int +libtar_list_next(libtar_list_t *l, + libtar_listptr_t *n) +{ + if (*n == NULL) + *n = l->first; + else + *n = (*n)->next; + + return (*n != NULL ? 1 : 0); +} + + +/* +** libtar_list_prev() - get the previous element in the list +** returns: +** 1 success +** 0 end of list +*/ +int +libtar_list_prev(libtar_list_t *l, + libtar_listptr_t *n) +{ + if (*n == NULL) + *n = l->last; + else + *n = (*n)->prev; + + return (*n != NULL ? 1 : 0); +} + + +/* +** libtar_str_match() - string matching function +** returns: +** 1 match +** 0 no match +*/ +int +libtar_str_match(char *check, char *data) +{ + return !strcmp(check, data); +} + + +/* +** libtar_list_add_str() - splits string str into delim-delimited +** elements and adds them to list l +** returns: +** 0 success +** -1 (and sets errno) failure +*/ +int +libtar_list_add_str(libtar_list_t *l, + char *str, char *delim) +{ + char tmp[10240]; + char *tokp, *nextp = tmp; + + strlcpy(tmp, str, sizeof(tmp)); + while ((tokp = strsep(&nextp, delim)) != NULL) + { + if (*tokp == '\0') + continue; + if (libtar_list_add(l, strdup(tokp))) + return -1; + } + + return 0; +} + + +/* +** libtar_list_search() - find an entry in a list +** returns: +** 1 match found +** 0 no match +*/ +int +libtar_list_search(libtar_list_t *l, + libtar_listptr_t *n, void *data, + libtar_matchfunc_t matchfunc) +{ +#ifdef DS_DEBUG + printf("==> libtar_list_search(l=0x%lx, n=0x%lx, \"%s\")\n", + l, n, (char *)data); +#endif + + if (matchfunc == NULL) + matchfunc = (libtar_matchfunc_t)libtar_str_match; + + if (*n == NULL) + *n = l->first; + else + *n = (*n)->next; + + for (; *n != NULL; *n = (*n)->next) + { +#ifdef DS_DEBUG + printf("checking against \"%s\"\n", (char *)(*n)->data); +#endif + if ((*(matchfunc))(data, (*n)->data) != 0) + return 1; + } + +#ifdef DS_DEBUG + printf("no matches found\n"); +#endif + return 0; +} + + +/* +** libtar_list_dup() - copy an existing list +*/ +libtar_list_t * +libtar_list_dup(libtar_list_t *l) +{ + libtar_list_t *newlist; + libtar_listptr_t n; + + newlist = libtar_list_new(l->flags, l->cmpfunc); + for (n = l->first; n != NULL; n = n->next) + libtar_list_add(newlist, n->data); + +#ifdef DS_DEBUG + printf("returning from libtar_list_dup()\n"); +#endif + return newlist; +} + + +/* +** libtar_list_merge() - merge two lists into a new list +*/ +libtar_list_t * +libtar_list_merge(libtar_cmpfunc_t cmpfunc, int flags, + libtar_list_t *list1, + libtar_list_t *list2) +{ + libtar_list_t *newlist; + libtar_listptr_t n; + + newlist = libtar_list_new(flags, cmpfunc); + + n = NULL; + while (libtar_list_next(list1, &n) != 0) + libtar_list_add(newlist, n->data); + n = NULL; + while (libtar_list_next(list2, &n) != 0) + libtar_list_add(newlist, n->data); + + return newlist; +} + + diff --git a/libtar/libtar_listhash.h b/libtar/libtar_listhash.h new file mode 100644 index 000000000..fa33cfd25 --- /dev/null +++ b/libtar/libtar_listhash.h @@ -0,0 +1,196 @@ +/* listhash/libtar_listhash.h. Generated from listhash.h.in by configure. */ + +/* +** Copyright 1998-2002 University of Illinois Board of Trustees +** Copyright 1998-2002 Mark D. Roth +** All rights reserved. +** +** libtar_listhash.h - header file for listhash module +** +** Mark D. Roth <roth@uiuc.edu> +** Campus Information Technologies and Educational Services +** University of Illinois at Urbana-Champaign +*/ + +#ifndef libtar_LISTHASH_H +#define libtar_LISTHASH_H + + +/***** list.c **********************************************************/ + +/* +** Comparison function (used to determine order of elements in a list) +** returns less than, equal to, or greater than 0 +** if data1 is less than, equal to, or greater than data2 +*/ +typedef int (*libtar_cmpfunc_t)(void *, void *); + +/* +** Free function (for freeing allocated memory in each element) +*/ +typedef void (*libtar_freefunc_t)(void *); + +/* +** Plugin function for libtar_list_iterate() +*/ +typedef int (*libtar_iterate_func_t)(void *, void *); + +/* +** Matching function (used to find elements in a list) +** first argument is the data to search for +** second argument is the list element it's being compared to +** returns 0 if no match is found, non-zero otherwise +*/ +typedef int (*libtar_matchfunc_t)(void *, void *); + + +struct libtar_node +{ + void *data; + struct libtar_node *next; + struct libtar_node *prev; +}; +typedef struct libtar_node *libtar_listptr_t; + +struct libtar_list +{ + libtar_listptr_t first; + libtar_listptr_t last; + libtar_cmpfunc_t cmpfunc; + int flags; + unsigned int nents; +}; +typedef struct libtar_list libtar_list_t; + + +/* values for flags */ +#define LIST_USERFUNC 0 /* use cmpfunc() to order */ +#define LIST_STACK 1 /* new elements go in front */ +#define LIST_QUEUE 2 /* new elements go at the end */ + + +/* reset a list pointer */ +void libtar_listptr_reset(libtar_listptr_t *); + +/* retrieve the data being pointed to */ +void *libtar_listptr_data(libtar_listptr_t *); + +/* creates a new, empty list */ +libtar_list_t *libtar_list_new(int, libtar_cmpfunc_t); + +/* call a function for every element in a list */ +int libtar_list_iterate(libtar_list_t *, + libtar_iterate_func_t, void *); + +/* empty the list */ +void libtar_list_empty(libtar_list_t *, + libtar_freefunc_t); + +/* remove and free() the entire list */ +void libtar_list_free(libtar_list_t *, + libtar_freefunc_t); + +/* add elements */ +int libtar_list_add(libtar_list_t *, void *); + +/* removes an element from the list - returns -1 on error */ +void libtar_list_del(libtar_list_t *, + libtar_listptr_t *); + +/* returns 1 when valid data is returned, or 0 at end of list */ +int libtar_list_next(libtar_list_t *, + libtar_listptr_t *); + +/* returns 1 when valid data is returned, or 0 at end of list */ +int libtar_list_prev(libtar_list_t *, + libtar_listptr_t *); + +/* return 1 if the data matches a list entry, 0 otherwise */ +int libtar_list_search(libtar_list_t *, + libtar_listptr_t *, void *, + libtar_matchfunc_t); + +/* return number of elements from list */ +unsigned int libtar_list_nents(libtar_list_t *); + +/* adds elements from a string delimited by delim */ +int libtar_list_add_str(libtar_list_t *, char *, char *); + +/* string matching function */ +int libtar_str_match(char *, char *); + + +/***** hash.c **********************************************************/ + +/* +** Hashing function (determines which bucket the given key hashes into) +** first argument is the key to hash +** second argument is the total number of buckets +** returns the bucket number +*/ +typedef unsigned int (*libtar_hashfunc_t)(void *, unsigned int); + + +struct libtar_hashptr +{ + int bucket; + libtar_listptr_t node; +}; +typedef struct libtar_hashptr libtar_hashptr_t; + +struct libtar_hash +{ + int numbuckets; + libtar_list_t **table; + libtar_hashfunc_t hashfunc; + unsigned int nents; +}; +typedef struct libtar_hash libtar_hash_t; + + +/* reset a hash pointer */ +void libtar_hashptr_reset(libtar_hashptr_t *); + +/* retrieve the data being pointed to */ +void *libtar_hashptr_data(libtar_hashptr_t *); + +/* default hash function, optimized for 7-bit strings */ +unsigned int libtar_str_hashfunc(char *, unsigned int); + +/* return number of elements from hash */ +unsigned int libtar_hash_nents(libtar_hash_t *); + +/* create a new hash */ +libtar_hash_t *libtar_hash_new(int, libtar_hashfunc_t); + +/* empty the hash */ +void libtar_hash_empty(libtar_hash_t *, + libtar_freefunc_t); + +/* delete all the libtar_nodes of the hash and clean up */ +void libtar_hash_free(libtar_hash_t *, + libtar_freefunc_t); + +/* returns 1 when valid data is returned, or 0 at end of list */ +int libtar_hash_next(libtar_hash_t *, + libtar_hashptr_t *); + +/* return 1 if the data matches a list entry, 0 otherwise */ +int libtar_hash_search(libtar_hash_t *, + libtar_hashptr_t *, void *, + libtar_matchfunc_t); + +/* return 1 if the key matches a list entry, 0 otherwise */ +int libtar_hash_getkey(libtar_hash_t *, + libtar_hashptr_t *, void *, + libtar_matchfunc_t); + +/* inserting data */ +int libtar_hash_add(libtar_hash_t *, void *); + +/* delete an entry */ +int libtar_hash_del(libtar_hash_t *, + libtar_hashptr_t *); + +#endif /* ! libtar_LISTHASH_H */ + diff --git a/libtar/output.c b/libtar/output.c new file mode 100644 index 000000000..a2db9293c --- /dev/null +++ b/libtar/output.c @@ -0,0 +1,134 @@ +/* +** Copyright 1998-2003 University of Illinois Board of Trustees +** Copyright 1998-2003 Mark D. Roth +** All rights reserved. +** +** output.c - libtar code to print out tar header blocks +** +** Mark D. Roth <roth@uiuc.edu> +** Campus Information Technologies and Educational Services +** University of Illinois at Urbana-Champaign +*/ + +#include <internal.h> + +#include <stdio.h> +#include <pwd.h> +#include <grp.h> +#include <time.h> +#include <limits.h> +#include <sys/param.h> + +#ifdef STDC_HEADERS +# include <string.h> +#endif + + +#ifndef _POSIX_LOGIN_NAME_MAX +# define _POSIX_LOGIN_NAME_MAX 9 +#endif + + +void +th_print(TAR *t) +{ + puts("\nPrinting tar header:"); + printf(" name = \"%.100s\"\n", t->th_buf.name); + printf(" mode = \"%.8s\"\n", t->th_buf.mode); + printf(" uid = \"%.8s\"\n", t->th_buf.uid); + printf(" gid = \"%.8s\"\n", t->th_buf.gid); + printf(" size = \"%.12s\"\n", t->th_buf.size); + printf(" mtime = \"%.12s\"\n", t->th_buf.mtime); + printf(" chksum = \"%.8s\"\n", t->th_buf.chksum); + printf(" typeflag = \'%c\'\n", t->th_buf.typeflag); + printf(" linkname = \"%.100s\"\n", t->th_buf.linkname); + printf(" magic = \"%.6s\"\n", t->th_buf.magic); + /*printf(" version = \"%.2s\"\n", t->th_buf.version); */ + printf(" version[0] = \'%c\',version[1] = \'%c\'\n", + t->th_buf.version[0], t->th_buf.version[1]); + printf(" uname = \"%.32s\"\n", t->th_buf.uname); + printf(" gname = \"%.32s\"\n", t->th_buf.gname); + printf(" devmajor = \"%.8s\"\n", t->th_buf.devmajor); + printf(" devminor = \"%.8s\"\n", t->th_buf.devminor); + printf(" prefix = \"%.155s\"\n", t->th_buf.prefix); + printf(" padding = \"%.12s\"\n", t->th_buf.padding); + printf(" gnu_longname = \"%s\"\n", + (t->th_buf.gnu_longname ? t->th_buf.gnu_longname : "[NULL]")); + printf(" gnu_longlink = \"%s\"\n", + (t->th_buf.gnu_longlink ? t->th_buf.gnu_longlink : "[NULL]")); +} + + +void +th_print_long_ls(TAR *t) +{ + char modestring[12]; + struct passwd *pw; + struct group *gr; + uid_t uid; + gid_t gid; + char username[_POSIX_LOGIN_NAME_MAX]; + char groupname[_POSIX_LOGIN_NAME_MAX]; + time_t mtime; + struct tm *mtm; + +#ifdef HAVE_STRFTIME + char timebuf[18]; +#else + const char *months[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; +#endif + + uid = th_get_uid(t); + pw = getpwuid(uid); + if (pw == NULL) + snprintf(username, sizeof(username), "%d", uid); + else + strlcpy(username, pw->pw_name, sizeof(username)); + + gid = th_get_gid(t); + gr = getgrgid(gid); + if (gr == NULL) + snprintf(groupname, sizeof(groupname), "%d", gid); + else + strlcpy(groupname, gr->gr_name, sizeof(groupname)); + + strmode(th_get_mode(t), modestring); + printf("%.10s %-8.8s %-8.8s ", modestring, username, groupname); + + if (TH_ISCHR(t) || TH_ISBLK(t)) + printf(" %3d, %3d ", th_get_devmajor(t), th_get_devminor(t)); + else + printf("%9ld ", (long)th_get_size(t)); + + mtime = th_get_mtime(t); + mtm = localtime(&mtime); +#ifdef HAVE_STRFTIME + strftime(timebuf, sizeof(timebuf), "%h %e %H:%M %Y", mtm); + printf("%s", timebuf); +#else + printf("%.3s %2d %2d:%02d %4d", + months[mtm->tm_mon], + mtm->tm_mday, mtm->tm_hour, mtm->tm_min, mtm->tm_year + 1900); +#endif + + printf(" %s", th_get_pathname(t)); + + if (TH_ISSYM(t) || TH_ISLNK(t)) + { + if (TH_ISSYM(t)) + printf(" -> "); + else + printf(" link to "); + if ((t->options & TAR_GNU) && t->th_buf.gnu_longlink != NULL) + printf("%s", t->th_buf.gnu_longlink); + else + printf("%.100s", t->th_buf.linkname); + } + + putchar('\n'); +} + + diff --git a/libtar/snprintf.c b/libtar/snprintf.c new file mode 100644 index 000000000..8c228d447 --- /dev/null +++ b/libtar/snprintf.c @@ -0,0 +1,761 @@ +/************************************************************** + * Original: + * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 + * A bombproof version of doprnt (dopr) included. + * Sigh. This sort of thing is always nasty do deal with. Note that + * the version here does not include floating point... + * + * snprintf() is used instead of sprintf() as it does limit checks + * for string length. This covers a nasty loophole. + * + * The other functions are there to prevent NULL pointers from + * causing nast effects. + * + * More Recently: + * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43 + * This was ugly. It is still ugly. I opted out of floating point + * numbers, but the formatter understands just about everything + * from the normal C string format, at least as far as I can tell from + * the Solaris 2.5 printf(3S) man page. + * + * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1 + * Ok, added some minimal floating point support, which means this + * probably requires libm on most operating systems. Don't yet + * support the exponent (e,E) and sigfig (g,G). Also, fmtint() + * was pretty badly broken, it just wasn't being exercised in ways + * which showed it, so that's been fixed. Also, formated the code + * to mutt conventions, and removed dead code left over from the + * original. Also, there is now a builtin-test, just compile with: + * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm + * and run snprintf for results. + * + * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i + * The PGP code was using unsigned hexadecimal formats. + * Unfortunately, unsigned formats simply didn't work. + * + * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8 + * The original code assumed that both snprintf() and vsnprintf() were + * missing. Some systems only have snprintf() but not vsnprintf(), so + * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. + * + * Chris Frey <cdfrey@foursquare.net> 2012/09/05 + * Removed varargs.h and all dependency on it. + * + **************************************************************/ + +#include <config.h> + +#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) + +#include <string.h> +# include <ctype.h> +#include <sys/types.h> + +#include <stdarg.h> +#define VA_LOCAL_DECL va_list ap +#define VA_START(f) va_start(ap, f) +#define VA_SHIFT(v,t) ; /* no-op for ANSI */ +#define VA_END va_end(ap) + +/*int snprintf (char *str, size_t count, const char *fmt, ...);*/ +/*int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);*/ + +static void dopr (char *buffer, size_t maxlen, const char *format, + va_list args); +static void fmtstr (char *buffer, size_t *currlen, size_t maxlen, + char *value, int flags, int min, int max); +static void fmtint (char *buffer, size_t *currlen, size_t maxlen, + long value, int base, int min, int max, int flags); +static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, + long double fvalue, int min, int max, int flags); +static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c ); + +/* + * dopr(): poor man's version of doprintf + */ + +/* format read states */ +#define DP_S_DEFAULT 0 +#define DP_S_FLAGS 1 +#define DP_S_MIN 2 +#define DP_S_DOT 3 +#define DP_S_MAX 4 +#define DP_S_MOD 5 +#define DP_S_CONV 6 +#define DP_S_DONE 7 + +/* format flags - Bits */ +#define DP_F_MINUS (1 << 0) +#define DP_F_PLUS (1 << 1) +#define DP_F_SPACE (1 << 2) +#define DP_F_NUM (1 << 3) +#define DP_F_ZERO (1 << 4) +#define DP_F_UP (1 << 5) +#define DP_F_UNSIGNED (1 << 6) + +/* Conversion Flags */ +#define DP_C_SHORT 1 +#define DP_C_LONG 2 +#define DP_C_LDOUBLE 3 + +#define char_to_int(p) (p - '0') +#define MAX(p,q) ((p >= q) ? p : q) + +static void dopr (char *buffer, size_t maxlen, const char *format, va_list args) +{ + char ch; + long value; + long double fvalue; + char *strvalue; + int min; + int max; + int state; + int flags; + int cflags; + size_t currlen; + + state = DP_S_DEFAULT; + currlen = flags = cflags = min = 0; + max = -1; + ch = *format++; + + while (state != DP_S_DONE) + { + if ((ch == '\0') || (currlen >= maxlen)) + state = DP_S_DONE; + + switch(state) + { + case DP_S_DEFAULT: + if (ch == '%') + state = DP_S_FLAGS; + else + dopr_outch (buffer, &currlen, maxlen, ch); + ch = *format++; + break; + case DP_S_FLAGS: + switch (ch) + { + case '-': + flags |= DP_F_MINUS; + ch = *format++; + break; + case '+': + flags |= DP_F_PLUS; + ch = *format++; + break; + case ' ': + flags |= DP_F_SPACE; + ch = *format++; + break; + case '#': + flags |= DP_F_NUM; + ch = *format++; + break; + case '0': + flags |= DP_F_ZERO; + ch = *format++; + break; + default: + state = DP_S_MIN; + break; + } + break; + case DP_S_MIN: + if (isdigit((unsigned char)ch)) + { + min = 10*min + char_to_int (ch); + ch = *format++; + } + else if (ch == '*') + { + min = va_arg (args, int); + ch = *format++; + state = DP_S_DOT; + } + else + state = DP_S_DOT; + break; + case DP_S_DOT: + if (ch == '.') + { + state = DP_S_MAX; + ch = *format++; + } + else + state = DP_S_MOD; + break; + case DP_S_MAX: + if (isdigit((unsigned char)ch)) + { + if (max < 0) + max = 0; + max = 10*max + char_to_int (ch); + ch = *format++; + } + else if (ch == '*') + { + max = va_arg (args, int); + ch = *format++; + state = DP_S_MOD; + } + else + state = DP_S_MOD; + break; + case DP_S_MOD: + /* Currently, we don't support Long Long, bummer */ + switch (ch) + { + case 'h': + cflags = DP_C_SHORT; + ch = *format++; + break; + case 'l': + cflags = DP_C_LONG; + ch = *format++; + break; + case 'L': + cflags = DP_C_LDOUBLE; + ch = *format++; + break; + default: + break; + } + state = DP_S_CONV; + break; + case DP_S_CONV: + switch (ch) + { + case 'd': + case 'i': + if (cflags == DP_C_SHORT) + value = va_arg (args, int); + else if (cflags == DP_C_LONG) + value = va_arg (args, long int); + else + value = va_arg (args, int); + fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); + break; + case 'o': + flags |= DP_F_UNSIGNED; + if (cflags == DP_C_SHORT) + value = va_arg (args, unsigned int); + else if (cflags == DP_C_LONG) + value = va_arg (args, unsigned long int); + else + value = va_arg (args, unsigned int); + fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags); + break; + case 'u': + flags |= DP_F_UNSIGNED; + if (cflags == DP_C_SHORT) + value = va_arg (args, unsigned int); + else if (cflags == DP_C_LONG) + value = va_arg (args, unsigned long int); + else + value = va_arg (args, unsigned int); + fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); + break; + case 'X': + flags |= DP_F_UP; + case 'x': + flags |= DP_F_UNSIGNED; + if (cflags == DP_C_SHORT) + value = va_arg (args, unsigned int); + else if (cflags == DP_C_LONG) + value = va_arg (args, unsigned long int); + else + value = va_arg (args, unsigned int); + fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags); + break; + case 'f': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg (args, long double); + else + fvalue = va_arg (args, double); + /* um, floating point? */ + fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags); + break; + case 'E': + flags |= DP_F_UP; + case 'e': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg (args, long double); + else + fvalue = va_arg (args, double); + break; + case 'G': + flags |= DP_F_UP; + case 'g': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg (args, long double); + else + fvalue = va_arg (args, double); + break; + case 'c': + dopr_outch (buffer, &currlen, maxlen, va_arg (args, int)); + break; + case 's': + strvalue = va_arg (args, char *); + if (max < 0) + max = maxlen; /* ie, no max */ + fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max); + break; + case 'p': + strvalue = va_arg (args, void *); + fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags); + break; + case 'n': + if (cflags == DP_C_SHORT) + { + short int *num; + num = va_arg (args, short int *); + *num = currlen; + } + else if (cflags == DP_C_LONG) + { + long int *num; + num = va_arg (args, long int *); + *num = currlen; + } + else + { + int *num; + num = va_arg (args, int *); + *num = currlen; + } + break; + case '%': + dopr_outch (buffer, &currlen, maxlen, ch); + break; + case 'w': + /* not supported yet, treat as next char */ + ch = *format++; + break; + default: + /* Unknown, skip */ + break; + } + ch = *format++; + state = DP_S_DEFAULT; + flags = cflags = min = 0; + max = -1; + break; + case DP_S_DONE: + break; + default: + /* hmm? */ + break; /* some picky compilers need this */ + } + } + if (currlen < maxlen - 1) + buffer[currlen] = '\0'; + else + buffer[maxlen - 1] = '\0'; +} + +static void fmtstr (char *buffer, size_t *currlen, size_t maxlen, + char *value, int flags, int min, int max) +{ + int padlen, strln; /* amount to pad */ + int cnt = 0; + + if (value == 0) + { + value = "<NULL>"; + } + + for (strln = 0; value[strln]; ++strln); /* strlen */ + padlen = min - strln; + if (padlen < 0) + padlen = 0; + if (flags & DP_F_MINUS) + padlen = -padlen; /* Left Justify */ + + while ((padlen > 0) && (cnt < max)) + { + dopr_outch (buffer, currlen, maxlen, ' '); + --padlen; + ++cnt; + } + while (*value && (cnt < max)) + { + dopr_outch (buffer, currlen, maxlen, *value++); + ++cnt; + } + while ((padlen < 0) && (cnt < max)) + { + dopr_outch (buffer, currlen, maxlen, ' '); + ++padlen; + ++cnt; + } +} + +/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ + +static void fmtint (char *buffer, size_t *currlen, size_t maxlen, + long value, int base, int min, int max, int flags) +{ + int signvalue = 0; + unsigned long uvalue; + char convert[20]; + int place = 0; + int spadlen = 0; /* amount to space pad */ + int zpadlen = 0; /* amount to zero pad */ + int caps = 0; + + if (max < 0) + max = 0; + + uvalue = value; + + if(!(flags & DP_F_UNSIGNED)) + { + if( value < 0 ) { + signvalue = '-'; + uvalue = -value; + } + else + if (flags & DP_F_PLUS) /* Do a sign (+/i) */ + signvalue = '+'; + else + if (flags & DP_F_SPACE) + signvalue = ' '; + } + + if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ + + do { + convert[place++] = + (caps? "0123456789ABCDEF":"0123456789abcdef") + [uvalue % (unsigned)base ]; + uvalue = (uvalue / (unsigned)base ); + } while(uvalue && (place < 20)); + if (place == 20) place--; + convert[place] = 0; + + zpadlen = max - place; + spadlen = min - MAX (max, place) - (signvalue ? 1 : 0); + if (zpadlen < 0) zpadlen = 0; + if (spadlen < 0) spadlen = 0; + if (flags & DP_F_ZERO) + { + zpadlen = MAX(zpadlen, spadlen); + spadlen = 0; + } + if (flags & DP_F_MINUS) + spadlen = -spadlen; /* Left Justifty */ + +#ifdef DEBUG_SNPRINTF + dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n", + zpadlen, spadlen, min, max, place)); +#endif + + /* Spaces */ + while (spadlen > 0) + { + dopr_outch (buffer, currlen, maxlen, ' '); + --spadlen; + } + + /* Sign */ + if (signvalue) + dopr_outch (buffer, currlen, maxlen, signvalue); + + /* Zeros */ + if (zpadlen > 0) + { + while (zpadlen > 0) + { + dopr_outch (buffer, currlen, maxlen, '0'); + --zpadlen; + } + } + + /* Digits */ + while (place > 0) + dopr_outch (buffer, currlen, maxlen, convert[--place]); + + /* Left Justified spaces */ + while (spadlen < 0) { + dopr_outch (buffer, currlen, maxlen, ' '); + ++spadlen; + } +} + +static long double abs_val (long double value) +{ + long double result = value; + + if (value < 0) + result = -value; + + return result; +} + +static long double pow10_ (int exp) +{ + long double result = 1; + + while (exp) + { + result *= 10; + exp--; + } + + return result; +} + +static long round_ (long double value) +{ + long intpart; + + intpart = value; + value = value - intpart; + if (value >= 0.5) + intpart++; + + return intpart; +} + +static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, + long double fvalue, int min, int max, int flags) +{ + int signvalue = 0; + long double ufvalue; + char iconvert[20]; + char fconvert[20]; + int iplace = 0; + int fplace = 0; + int padlen = 0; /* amount to pad */ + int zpadlen = 0; + int caps = 0; + long intpart; + long fracpart; + + /* + * AIX manpage says the default is 0, but Solaris says the default + * is 6, and sprintf on AIX defaults to 6 + */ + if (max < 0) + max = 6; + + ufvalue = abs_val (fvalue); + + if (fvalue < 0) + signvalue = '-'; + else + if (flags & DP_F_PLUS) /* Do a sign (+/i) */ + signvalue = '+'; + else + if (flags & DP_F_SPACE) + signvalue = ' '; + +#if 0 + if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ +#endif + + intpart = ufvalue; + + /* + * Sorry, we only support 9 digits past the decimal because of our + * conversion method + */ + if (max > 9) + max = 9; + + /* We "cheat" by converting the fractional part to integer by + * multiplying by a factor of 10 + */ + fracpart = round_ ((pow10_ (max)) * (ufvalue - intpart)); + + if (fracpart >= pow10_ (max)) + { + intpart++; + fracpart -= pow10_ (max); + } + +#ifdef DEBUG_SNPRINTF + dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart)); +#endif + + /* Convert integer part */ + do { + iconvert[iplace++] = + (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10]; + intpart = (intpart / 10); + } while(intpart && (iplace < 20)); + if (iplace == 20) iplace--; + iconvert[iplace] = 0; + + /* Convert fractional part */ + do { + fconvert[fplace++] = + (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10]; + fracpart = (fracpart / 10); + } while(fracpart && (fplace < 20)); + if (fplace == 20) fplace--; + fconvert[fplace] = 0; + + /* -1 for decimal point, another -1 if we are printing a sign */ + padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); + zpadlen = max - fplace; + if (zpadlen < 0) + zpadlen = 0; + if (padlen < 0) + padlen = 0; + if (flags & DP_F_MINUS) + padlen = -padlen; /* Left Justifty */ + + if ((flags & DP_F_ZERO) && (padlen > 0)) + { + if (signvalue) + { + dopr_outch (buffer, currlen, maxlen, signvalue); + --padlen; + signvalue = 0; + } + while (padlen > 0) + { + dopr_outch (buffer, currlen, maxlen, '0'); + --padlen; + } + } + while (padlen > 0) + { + dopr_outch (buffer, currlen, maxlen, ' '); + --padlen; + } + if (signvalue) + dopr_outch (buffer, currlen, maxlen, signvalue); + + while (iplace > 0) + dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]); + + /* + * Decimal point. This should probably use locale to find the correct + * char to print out. + */ + dopr_outch (buffer, currlen, maxlen, '.'); + + while (fplace > 0) + dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]); + + while (zpadlen > 0) + { + dopr_outch (buffer, currlen, maxlen, '0'); + --zpadlen; + } + + while (padlen < 0) + { + dopr_outch (buffer, currlen, maxlen, ' '); + ++padlen; + } +} + +static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c) +{ + if (*currlen < maxlen) + buffer[(*currlen)++] = c; +} +#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */ + +#ifndef HAVE_VSNPRINTF +int mutt_vsnprintf (char *str, size_t count, const char *fmt, va_list args) +{ + str[0] = 0; + dopr(str, count, fmt, args); + return(strlen(str)); +} +#endif /* !HAVE_VSNPRINTF */ + +#ifndef HAVE_SNPRINTF +int mutt_snprintf (char *str,size_t count,const char *fmt,...) +{ + VA_LOCAL_DECL; + + VA_START (fmt); + VA_SHIFT (str, char *); + VA_SHIFT (count, size_t ); + VA_SHIFT (fmt, char *); + (void) mutt_vsnprintf(str, count, fmt, ap); + VA_END; + return(strlen(str)); +} + +#ifdef TEST_SNPRINTF +#ifndef LONG_STRING +#define LONG_STRING 1024 +#endif +int main (void) +{ + char buf1[LONG_STRING]; + char buf2[LONG_STRING]; + char *fp_fmt[] = { + "%-1.5f", + "%1.5f", + "%123.9f", + "%10.5f", + "% 10.5f", + "%+22.9f", + "%+4.9f", + "%01.3f", + "%4f", + "%3.1f", + "%3.2f", + NULL + }; + double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996, + 0.9996, 1.996, 4.136, 0}; + char *int_fmt[] = { + "%-1.5d", + "%1.5d", + "%123.9d", + "%5.5d", + "%10.5d", + "% 10.5d", + "%+22.33d", + "%01.3d", + "%4d", + NULL + }; + long int_nums[] = { -1, 134, 91340, 341, 0203, 0}; + int x, y; + int fail = 0; + int num = 0; + + printf ("Testing snprintf format codes against system sprintf...\n"); + + for (x = 0; fp_fmt[x] != NULL ; x++) + for (y = 0; fp_nums[y] != 0 ; y++) + { + mutt_snprintf (buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]); + sprintf (buf2, fp_fmt[x], fp_nums[y]); + if (strcmp (buf1, buf2)) + { + printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n", + fp_fmt[x], buf1, buf2); + fail++; + } + num++; + } + + for (x = 0; int_fmt[x] != NULL ; x++) + for (y = 0; int_nums[y] != 0 ; y++) + { + mutt_snprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]); + sprintf (buf2, int_fmt[x], int_nums[y]); + if (strcmp (buf1, buf2)) + { + printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n", + int_fmt[x], buf1, buf2); + fail++; + } + num++; + } + printf ("%d tests failed out of %d.\n", fail, num); +} +#endif /* SNPRINTF_TEST */ + +#endif /* !HAVE_SNPRINTF */ diff --git a/libtar/strdup.c b/libtar/strdup.c new file mode 100644 index 000000000..75e9af505 --- /dev/null +++ b/libtar/strdup.c @@ -0,0 +1,62 @@ +/* $OpenBSD: strdup.c,v 1.3 1997/08/20 04:18:52 millert Exp $ */ + +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)strdup.c 8.1 (Berkeley) 6/4/93"; +#else +static char *rcsid = "$OpenBSD: strdup.c,v 1.3 1997/08/20 04:18:52 millert Exp $"; +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> + +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +char * +openbsd_strdup(str) + const char *str; +{ + size_t siz; + char *copy; + + siz = strlen(str) + 1; + if ((copy = malloc(siz)) == NULL) + return(NULL); + (void)memcpy(copy, str, siz); + return(copy); +} diff --git a/libtar/strlcat.c b/libtar/strlcat.c new file mode 100644 index 000000000..39125393c --- /dev/null +++ b/libtar/strlcat.c @@ -0,0 +1,72 @@ +/* $OpenBSD: strlcat.c,v 1.5 2001/01/13 16:17:24 millert Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: strlcat.c,v 1.5 2001/01/13 16:17:24 millert Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <string.h> + +/* + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz <= strlen(dst)). + * Returns strlen(initial dst) + strlen(src); if retval >= siz, + * truncation occurred. + */ +size_t strlcat(dst, src, siz) + char *dst; + const char *src; + size_t siz; +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return(dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} diff --git a/libtar/strlcpy.c b/libtar/strlcpy.c new file mode 100644 index 000000000..300a28bc3 --- /dev/null +++ b/libtar/strlcpy.c @@ -0,0 +1,68 @@ +/* $OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <string.h> + +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t strlcpy(dst, src, siz) + char *dst; + const char *src; + size_t siz; +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} diff --git a/libtar/strmode.c b/libtar/strmode.c new file mode 100644 index 000000000..5e7f15e85 --- /dev/null +++ b/libtar/strmode.c @@ -0,0 +1,152 @@ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: strmode.c,v 1.3 1997/06/13 13:57:20 deraadt Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <string.h> + +void +strmode(mode, p) + register mode_t mode; + register char *p; +{ + /* print type */ + switch (mode & S_IFMT) { + case S_IFDIR: /* directory */ + *p++ = 'd'; + break; + case S_IFCHR: /* character special */ + *p++ = 'c'; + break; + case S_IFBLK: /* block special */ + *p++ = 'b'; + break; + case S_IFREG: /* regular */ + *p++ = '-'; + break; + case S_IFLNK: /* symbolic link */ + *p++ = 'l'; + break; + case S_IFSOCK: /* socket */ + *p++ = 's'; + break; +#ifdef S_IFIFO + case S_IFIFO: /* fifo */ + *p++ = 'p'; + break; +#endif +#ifdef S_IFWHT + case S_IFWHT: /* whiteout */ + *p++ = 'w'; + break; +#endif + default: /* unknown */ + *p++ = '?'; + break; + } + /* usr */ + if (mode & S_IRUSR) + *p++ = 'r'; + else + *p++ = '-'; + if (mode & S_IWUSR) + *p++ = 'w'; + else + *p++ = '-'; + switch (mode & (S_IXUSR | S_ISUID)) { + case 0: + *p++ = '-'; + break; + case S_IXUSR: + *p++ = 'x'; + break; + case S_ISUID: + *p++ = 'S'; + break; + case S_IXUSR | S_ISUID: + *p++ = 's'; + break; + } + /* group */ + if (mode & S_IRGRP) + *p++ = 'r'; + else + *p++ = '-'; + if (mode & S_IWGRP) + *p++ = 'w'; + else + *p++ = '-'; + switch (mode & (S_IXGRP | S_ISGID)) { + case 0: + *p++ = '-'; + break; + case S_IXGRP: + *p++ = 'x'; + break; + case S_ISGID: + *p++ = 'S'; + break; + case S_IXGRP | S_ISGID: + *p++ = 's'; + break; + } + /* other */ + if (mode & S_IROTH) + *p++ = 'r'; + else + *p++ = '-'; + if (mode & S_IWOTH) + *p++ = 'w'; + else + *p++ = '-'; + switch (mode & (S_IXOTH | S_ISVTX)) { + case 0: + *p++ = '-'; + break; + case S_IXOTH: + *p++ = 'x'; + break; + case S_ISVTX: + *p++ = 'T'; + break; + case S_IXOTH | S_ISVTX: + *p++ = 't'; + break; + } + *p++ = ' '; /* will be a '+' if ACL's implemented */ + *p = '\0'; +} diff --git a/libtar/strrstr.c b/libtar/strrstr.c new file mode 100644 index 000000000..097ef9182 --- /dev/null +++ b/libtar/strrstr.c @@ -0,0 +1,40 @@ +/* +** Copyright 1998-2002 University of Illinois Board of Trustees +** Copyright 1998-2002 Mark D. Roth +** All rights reserved. +** +** strrstr.c - strrstr() function for compatibility library +** +** Mark D. Roth <roth@uiuc.edu> +** Campus Information Technologies and Educational Services +** University of Illinois at Urbana-Champaign +*/ + +#include <stdio.h> +#include <sys/types.h> + +#include <string.h> + + +/* +** find the last occurrance of find in string +*/ +char * +strrstr(char *string, char *find) +{ + size_t stringlen, findlen; + char *cp; + + findlen = strlen(find); + stringlen = strlen(string); + if (findlen > stringlen) + return NULL; + + for (cp = string + stringlen - findlen; cp >= string; cp--) + if (strncmp(cp, find, findlen) == 0) + return cp; + + return NULL; +} + + diff --git a/libtar/strsep.c b/libtar/strsep.c new file mode 100644 index 000000000..3132962c9 --- /dev/null +++ b/libtar/strsep.c @@ -0,0 +1,87 @@ +/* $OpenBSD: strsep.c,v 1.3 1997/08/20 04:28:14 millert Exp $ */ + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <string.h> +#include <stdio.h> + +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)strsep.c 8.1 (Berkeley) 6/4/93"; +#else +static char *rcsid = "$OpenBSD: strsep.c,v 1.3 1997/08/20 04:28:14 millert Exp $"; +#endif +#endif /* LIBC_SCCS and not lint */ + +#ifndef HAVE_STRSEP +/* + * Get next token from string *stringp, where tokens are possibly-empty + * strings separated by characters from delim. + * + * Writes NULs into the string at *stringp to end tokens. + * delim need not remain constant from call to call. + * On return, *stringp points past the last NUL written (if there might + * be further tokens), or is NULL (if there are definitely no more tokens). + * + * If *stringp is NULL, strsep returns NULL. + */ +char * +strsep(stringp, delim) + register char **stringp; + register const char *delim; +{ + register char *s; + register const char *spanp; + register int c, sc; + char *tok; + + if ((s = *stringp) == NULL) + return (NULL); + for (tok = s;;) { + c = *s++; + spanp = delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + *stringp = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} +#endif /* ! HAVE_STRSEP */ diff --git a/libtar/tar.h b/libtar/tar.h new file mode 100644 index 000000000..ddfef755d --- /dev/null +++ b/libtar/tar.h @@ -0,0 +1,108 @@ +/* Extended tar format from POSIX.1. + Copyright (C) 1992, 1996 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by David J. MacKenzie. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef _TAR_H +#define _TAR_H 1 + +/* A tar archive consists of 512-byte blocks. + Each file in the archive has a header block followed by 0+ data blocks. + Two blocks of NUL bytes indicate the end of the archive. */ + +/* The fields of header blocks: + All strings are stored as ISO 646 (approximately ASCII) strings. + + Fields are numeric unless otherwise noted below; numbers are ISO 646 + representations of octal numbers, with leading zeros as needed. + + linkname is only valid when typeflag==LNKTYPE. It doesn't use prefix; + files that are links to pathnames >100 chars long can not be stored + in a tar archive. + + If typeflag=={LNKTYPE,SYMTYPE,DIRTYPE} then size must be 0. + + devmajor and devminor are only valid for typeflag=={BLKTYPE,CHRTYPE}. + + chksum contains the sum of all 512 bytes in the header block, + treating each byte as an 8-bit unsigned value and treating the + 8 bytes of chksum as blank characters. + + uname and gname are used in preference to uid and gid, if those + names exist locally. + + Field Name Byte Offset Length in Bytes Field Type + name 0 100 NUL-terminated if NUL fits + mode 100 8 + uid 108 8 + gid 116 8 + size 124 12 + mtime 136 12 + chksum 148 8 + typeflag 156 1 see below + linkname 157 100 NUL-terminated if NUL fits + magic 257 6 must be TMAGIC (NUL term.) + version 263 2 must be TVERSION + uname 265 32 NUL-terminated + gname 297 32 NUL-terminated + devmajor 329 8 + devminor 337 8 + prefix 345 155 NUL-terminated if NUL fits + + If the first character of prefix is '\0', the file name is name; + otherwise, it is prefix/name. Files whose pathnames don't fit in that + length can not be stored in a tar archive. */ + +/* The bits in mode: */ +#define TSUID 04000 +#define TSGID 02000 +#define TSVTX 01000 +#define TUREAD 00400 +#define TUWRITE 00200 +#define TUEXEC 00100 +#define TGREAD 00040 +#define TGWRITE 00020 +#define TGEXEC 00010 +#define TOREAD 00004 +#define TOWRITE 00002 +#define TOEXEC 00001 + +/* The values for typeflag: + Values 'A'-'Z' are reserved for custom implementations. + All other values are reserved for future POSIX.1 revisions. */ + +#define REGTYPE '0' /* Regular file (preferred code). */ +#define AREGTYPE '\0' /* Regular file (alternate code). */ +#define LNKTYPE '1' /* Hard link. */ +#define SYMTYPE '2' /* Symbolic link (hard if not supported). */ +#define CHRTYPE '3' /* Character special. */ +#define BLKTYPE '4' /* Block special. */ +#define DIRTYPE '5' /* Directory. */ +#define FIFOTYPE '6' /* Named pipe. */ +#define CONTTYPE '7' /* Contiguous file */ + /* (regular file if not supported). */ + +/* Contents of magic field and its length. */ +#define TMAGIC "ustar" +#define TMAGLEN 6 + +/* Contents of the version field and its length. */ +#define TVERSION "00" +#define TVERSLEN 2 + +#endif /* tar.h */ diff --git a/libtar/util.c b/libtar/util.c new file mode 100644 index 000000000..31e831507 --- /dev/null +++ b/libtar/util.c @@ -0,0 +1,165 @@ +/* +** Copyright 1998-2003 University of Illinois Board of Trustees +** Copyright 1998-2003 Mark D. Roth +** All rights reserved. +** +** util.c - miscellaneous utility code for libtar +** +** Mark D. Roth <roth@uiuc.edu> +** Campus Information Technologies and Educational Services +** University of Illinois at Urbana-Champaign +*/ + +#include <internal.h> + +#include <stdio.h> +#include <sys/param.h> +#include <errno.h> + +#ifdef STDC_HEADERS +# include <string.h> +#endif + + +/* hashing function for pathnames */ +int +path_hashfunc(char *key, int numbuckets) +{ + char buf[MAXPATHLEN]; + char *p; + + strcpy(buf, key); + p = basename(buf); + + return (((unsigned int)p[0]) % numbuckets); +} + + +/* matching function for dev_t's */ +int +dev_match(dev_t *dev1, dev_t *dev2) +{ + return !memcmp(dev1, dev2, sizeof(dev_t)); +} + + +/* matching function for ino_t's */ +int +ino_match(ino_t *ino1, ino_t *ino2) +{ + return !memcmp(ino1, ino2, sizeof(ino_t)); +} + + +/* hashing function for dev_t's */ +int +dev_hash(dev_t *dev) +{ + return *dev % 16; +} + + +/* hashing function for ino_t's */ +int +ino_hash(ino_t *inode) +{ + return *inode % 256; +} + + +/* +** mkdirhier() - create all directories in a given path +** returns: +** 0 success +** 1 all directories already exist +** -1 (and sets errno) error +*/ +int +mkdirhier(char *path) +{ + char src[MAXPATHLEN], dst[MAXPATHLEN] = ""; + char *dirp, *nextp = src; + int retval = 1; + + if (strlcpy(src, path, sizeof(src)) > sizeof(src)) + { + errno = ENAMETOOLONG; + return -1; + } + + if (path[0] == '/') + strcpy(dst, "/"); + + while ((dirp = strsep(&nextp, "/")) != NULL) + { + if (*dirp == '\0') + continue; + + if (dst[0] != '\0') + strcat(dst, "/"); + strcat(dst, dirp); + + if (mkdir(dst, 0777) == -1) + { + if (errno != EEXIST) + return -1; + } + else + retval = 0; + } + + return retval; +} + + +/* calculate header checksum */ +int +th_crc_calc(TAR *t) +{ + int i, sum = 0; + + for (i = 0; i < T_BLOCKSIZE; i++) + sum += ((unsigned char *)(&(t->th_buf)))[i]; + for (i = 0; i < 8; i++) + sum += (' ' - (unsigned char)t->th_buf.chksum[i]); + + return sum; +} + + +/* calculate a signed header checksum */ +int +th_signed_crc_calc(TAR *t) +{ + int i, sum = 0; + + for (i = 0; i < T_BLOCKSIZE; i++) + sum += ((signed char *)(&(t->th_buf)))[i]; + for (i = 0; i < 8; i++) + sum += (' ' - (signed char)t->th_buf.chksum[i]); + + return sum; +} + + +/* string-octal to integer conversion */ +int +oct_to_int(char *oct) +{ + int i; + + sscanf(oct, "%o", &i); + + return i; +} + + +/* integer to string-octal conversion, no NULL */ +void +int_to_oct_nonull(int num, char *oct, size_t octlen) +{ + snprintf(oct, octlen, "%*lo", octlen - 1, (unsigned long)num); + oct[octlen - 1] = ' '; +} + + diff --git a/libtar/wrapper.c b/libtar/wrapper.c new file mode 100644 index 000000000..82f045f7d --- /dev/null +++ b/libtar/wrapper.c @@ -0,0 +1,213 @@ +/* +** Copyright 1998-2003 University of Illinois Board of Trustees +** Copyright 1998-2003 Mark D. Roth +** All rights reserved. +** +** wrapper.c - libtar high-level wrapper code +** +** Mark D. Roth <roth@uiuc.edu> +** Campus Information Technologies and Educational Services +** University of Illinois at Urbana-Champaign +*/ + +#define DEBUG +#include <internal.h> + +#include <stdio.h> +#include <sys/param.h> +#include <dirent.h> +#include <errno.h> +#include <stdlib.h> +#ifdef STDC_HEADERS +# include <string.h> +#endif + +int +tar_extract_glob(TAR *t, char *globname, char *prefix) +{ + char *filename; + char buf[MAXPATHLEN]; + int i, fd = 0; + + while ((i = th_read(t)) == 0) + { + filename = th_get_pathname(t); + if (fnmatch(globname, filename, FNM_PATHNAME | FNM_PERIOD)) + { + if (TH_ISREG(t) && tar_skip_regfile(t)) + return -1; + continue; + } + if (t->options & TAR_VERBOSE) + th_print_long_ls(t); + if (prefix != NULL) + snprintf(buf, sizeof(buf), "%s/%s", prefix, filename); + else + strlcpy(buf, filename, sizeof(buf)); + if (tar_extract_file(t, filename, prefix, &fd) != 0) + return -1; + } + + return (i == 1 ? 0 : -1); +} + + +int +tar_extract_all(TAR *t, char *prefix, const int *progress_fd) +{ + char *filename; + char buf[MAXPATHLEN]; + int i; + printf("prefix: %s\n", prefix); +#ifdef DEBUG + printf("==> tar_extract_all(TAR *t, \"%s\")\n", + (prefix ? prefix : "(null)")); +#endif + while ((i = th_read(t)) == 0) + { +#ifdef DEBUG + puts(" tar_extract_all(): calling th_get_pathname()"); +#endif + filename = th_get_pathname(t); + if (t->options & TAR_VERBOSE) + th_print_long_ls(t); + if (prefix != NULL) + snprintf(buf, sizeof(buf), "%s/%s", prefix, filename); + else + strlcpy(buf, filename, sizeof(buf)); +#ifdef DEBUG + printf(" tar_extract_all(): calling tar_extract_file(t, " + "\"%s\")\n", buf); +#endif + printf("item name: '%s'\n", filename); + if (tar_extract_file(t, buf, prefix, progress_fd) != 0) + return -1; + } + return (i == 1 ? 0 : -1); +} + + +int +tar_append_tree(TAR *t, char *realdir, char *savedir, char *exclude) +{ +#ifdef DEBUG + printf("==> tar_append_tree(0x%lx, \"%s\", \"%s\")\n", + (long unsigned int)t, realdir, (savedir ? savedir : "[NULL]")); +#endif + + char temp[1024]; + int skip = 0, i, n_spaces = 0; + char ** excluded = NULL; + char * p = NULL; + if (exclude) { + strcpy(temp, exclude); + p = strtok(exclude, " "); + if (p == NULL) { + excluded = realloc(excluded, sizeof(char*) * (++n_spaces)); + excluded[0] = temp; + } else { + while (p) { + excluded = realloc(excluded, sizeof(char*) * (++n_spaces)); + excluded[n_spaces-1] = p; + p = strtok(NULL, " "); + } + } + excluded = realloc(excluded, sizeof(char*) * (n_spaces+1)); + excluded[n_spaces] = 0; + for (i = 0; i < (n_spaces+1); i++) { + if (realdir == excluded[i]) { + printf(" excluding '%s'\n", excluded[i]); + skip = 1; + break; + } + } + } + if (skip == 0) { + if (tar_append_file(t, realdir, savedir) != 0) + return -1; + } + + char realpath[MAXPATHLEN]; + char savepath[MAXPATHLEN]; + struct dirent *dent; + DIR *dp; + struct stat s; + + dp = opendir(realdir); + if (dp == NULL) { + if (errno == ENOTDIR) + return 0; + return -1; + } + while ((dent = readdir(dp)) != NULL) { + if(strcmp(dent->d_name, ".") == 0 + || strcmp(dent->d_name, "..") == 0) + continue; + + if (exclude) { + int omit = 0; + for (i = 0; i < (n_spaces+1); i++) { + if (excluded[i] != NULL) { + if (strcmp(dent->d_name, excluded[i]) == 0 || strcmp(excluded[i], realdir) == 0) { + printf(" excluding '%s'\n", excluded[i]); + omit = 1; + break; + } + } + } + if (omit) + continue; + } + + snprintf(realpath, MAXPATHLEN, "%s/%s", realdir, dent->d_name); + if (savedir) + snprintf(savepath, MAXPATHLEN, "%s/%s", savedir, dent->d_name); + + if (lstat(realpath, &s) != 0) + return -1; + + if (S_ISDIR(s.st_mode)) { + if (tar_append_tree(t, realpath, (savedir ? savepath : NULL), (exclude ? exclude : NULL)) != 0) + return -1; + continue; + } else { + if (tar_append_file(t, realpath, (savedir ? savepath : NULL)) != 0) + return -1; + continue; + } + } + closedir(dp); + free(excluded); + + return 0; +} + + +int +tar_find(TAR *t, char *searchstr) +{ + if (!searchstr) + return 0; + + char *filename; + int i, entryfound = 0; +#ifdef DEBUG + printf("==> tar_find(0x%lx, %s)\n", (long unsigned int)t, searchstr); +#endif + while ((i = th_read(t)) == 0) { + filename = th_get_pathname(t); + if (fnmatch(searchstr, filename, FNM_FILE_NAME | FNM_PERIOD) == 0) { + entryfound++; +#ifdef DEBUG + printf("Found matching entry: %s\n", filename); +#endif + break; + } + } +#ifdef DEBUG + if (!entryfound) + printf("No matching entry found.\n"); +#endif + + return entryfound; +} |