summaryrefslogtreecommitdiffstats
path: root/Utilities/cmtar
diff options
context:
space:
mode:
authorAndy Cedilnik <andy.cedilnik@kitware.com>2005-12-28 15:18:37 (GMT)
committerAndy Cedilnik <andy.cedilnik@kitware.com>2005-12-28 15:18:37 (GMT)
commitbc1548b236515514c138da8b59f61af2efbfc4a5 (patch)
treeab8ab5b2bceca941f363ca7064248ece6779b617 /Utilities/cmtar
parent552842d11f845ad53e4f34be549aa4007737564b (diff)
downloadCMake-bc1548b236515514c138da8b59f61af2efbfc4a5.zip
CMake-bc1548b236515514c138da8b59f61af2efbfc4a5.tar.gz
CMake-bc1548b236515514c138da8b59f61af2efbfc4a5.tar.bz2
ENH: Initial import
Diffstat (limited to 'Utilities/cmtar')
-rw-r--r--Utilities/cmtar/CMakeLists.txt360
-rw-r--r--Utilities/cmtar/COPYRIGHT35
-rw-r--r--Utilities/cmtar/append.c272
-rw-r--r--Utilities/cmtar/block.c384
-rw-r--r--Utilities/cmtar/compat/README12
-rw-r--r--Utilities/cmtar/compat/basename.c75
-rw-r--r--Utilities/cmtar/compat/compat.h314
-rw-r--r--Utilities/cmtar/compat/dirname.c78
-rw-r--r--Utilities/cmtar/compat/fnmatch.c237
-rw-r--r--Utilities/cmtar/compat/gethostbyname_r.c41
-rw-r--r--Utilities/cmtar/compat/gethostname.c36
-rw-r--r--Utilities/cmtar/compat/getservbyname_r.c41
-rw-r--r--Utilities/cmtar/compat/glob.c874
-rw-r--r--Utilities/cmtar/compat/inet_aton.c27
-rw-r--r--Utilities/cmtar/compat/snprintf.c788
-rw-r--r--Utilities/cmtar/compat/strdup.c62
-rw-r--r--Utilities/cmtar/compat/strlcat.c72
-rw-r--r--Utilities/cmtar/compat/strlcpy.c68
-rw-r--r--Utilities/cmtar/compat/strmode.c185
-rw-r--r--Utilities/cmtar/compat/strrstr.c40
-rw-r--r--Utilities/cmtar/compat/strsep.c87
-rw-r--r--Utilities/cmtar/config.h.in190
-rw-r--r--Utilities/cmtar/decode.c136
-rw-r--r--Utilities/cmtar/encode.c234
-rw-r--r--Utilities/cmtar/extract.c561
-rw-r--r--Utilities/cmtar/filesystem.c82
-rw-r--r--Utilities/cmtar/filesystem.h35
-rw-r--r--Utilities/cmtar/handle.c136
-rw-r--r--Utilities/cmtar/internal.h17
-rw-r--r--Utilities/cmtar/libtar.c377
-rw-r--r--Utilities/cmtar/libtar.h295
-rw-r--r--Utilities/cmtar/listhash/hash.c.in344
-rw-r--r--Utilities/cmtar/listhash/list.c.in457
-rw-r--r--Utilities/cmtar/listhash/listhash.h.in196
-rw-r--r--Utilities/cmtar/output.c145
-rw-r--r--Utilities/cmtar/tar.h71
-rw-r--r--Utilities/cmtar/util.c158
-rw-r--r--Utilities/cmtar/wrapper.c183
38 files changed, 7705 insertions, 0 deletions
diff --git a/Utilities/cmtar/CMakeLists.txt b/Utilities/cmtar/CMakeLists.txt
new file mode 100644
index 0000000..dd50316
--- /dev/null
+++ b/Utilities/cmtar/CMakeLists.txt
@@ -0,0 +1,360 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.0)
+PROJECT(LIBTAR C)
+INCLUDE_REGULAR_EXPRESSION("^.*\\.h$")
+
+# We need ansi c-flags, especially on HP
+SET(CMAKE_C_FLAGS "${CMAKE_ANSI_CFLAGS} ${CMAKE_C_FLAGS}")
+SET(CMAKE_REQUIRED_FLAGS ${CMAKE_ANSI_CFLAGS})
+
+# If we are on AIX, do the _ALL_SOURCE magic
+IF(${CMAKE_SYSTEM_NAME} MATCHES AIX)
+ SET(_ALL_SOURCE 1)
+ENDIF(${CMAKE_SYSTEM_NAME} MATCHES AIX)
+
+# Include all the necessary files for macros
+#SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake")
+# Include all the necessary files for macros
+INCLUDE (CheckIncludeFiles)
+INCLUDE (CheckFunctionExists)
+INCLUDE (CheckTypeSize)
+INCLUDE (CheckSymbolExists)
+INCLUDE (TestBigEndian)
+
+MACRO(MANGLE_VARIABLE_NAME str var prefix)
+ STRING(TOUPPER "${str}" mangle_variable_name_var)
+ STRING(REGEX REPLACE "[/. ]" "_" mangle_variable_name_var "${mangle_variable_name_var}")
+ SET(${var} "${prefix}${mangle_variable_name_var}")
+ENDMACRO(MANGLE_VARIABLE_NAME str var)
+
+# Check if header file exists and add it to the list.
+MACRO(CHECK_INCLUDE_FILE_CONCAT FILE)
+ MANGLE_VARIABLE_NAME("${FILE}" "CHECK_INCLUDE_FILE_CONCAT_VAR" "HAVE_")
+ CHECK_INCLUDE_FILES("${HEADER_INCLUDES};${FILE}" ${CHECK_INCLUDE_FILE_CONCAT_VAR})
+ IF(${CHECK_INCLUDE_FILE_CONCAT_VAR})
+ SET(HEADER_INCLUDES ${HEADER_INCLUDES} ${FILE})
+ ENDIF(${CHECK_INCLUDE_FILE_CONCAT_VAR})
+ENDMACRO(CHECK_INCLUDE_FILE_CONCAT)
+
+MACRO(CHECK_FUNCTION_EXISTS_EX FUNC)
+ MANGLE_VARIABLE_NAME("${FUNC}" "CHECK_FUNCTION_EXISTS_EX_VAR" "HAVE_")
+ CHECK_FUNCTION_EXISTS("${FUNC}" "${CHECK_FUNCTION_EXISTS_EX_VAR}")
+ENDMACRO(CHECK_FUNCTION_EXISTS_EX)
+
+MACRO(CHECK_SYMBOL_EXISTS_EX SYM)
+ MANGLE_VARIABLE_NAME("${SYM}" "CHECK_SYMBOL_EXISTS_EX_VAR" "HAVE_")
+ CHECK_SYMBOL_EXISTS("${SYM}" "${HEADER_INCLUDES}" "${CHECK_SYMBOL_EXISTS_EX_VAR}")
+ENDMACRO(CHECK_SYMBOL_EXISTS_EX)
+
+#MACRO(CHECK_TYPE_SIZE_EX type defualt_size)
+# MANGLE_VARIABLE_NAME("${type}" "check_type_size_var" "")
+# CHECK_TYPE_SIZE("${type}" "SIZEOF_${check_type_size_var}")
+# IF(HAVE_${check_type_size_var})
+# SET("HAVE_${check_type_size_var}" 1)
+# ELSE(HAVE_${check_type_size_var})
+# ENDIF(HAVE_${check_type_size_var})
+#ENDMACRO(CHECK_TYPE_SIZE_EX)
+
+
+
+INCLUDE_DIRECTORIES("${CMAKE_CURRENT_BINARY_DIR}")
+INCLUDE_DIRECTORIES(${CURL_SPECIAL_LIBZ_INCLUDES})
+
+#check for stdc headers
+CHECK_INCLUDE_FILES("stdlib.h;stdarg.h;string.h;float.h" STDC_HEADERS)
+
+#check for other headers used by the program
+FOREACH(file
+ "ctype.h"
+ "fnmatch.h"
+ "inttypes.h"
+ "libgen.h"
+ "memory.h"
+ "stdint.h"
+ "stdlib.h"
+ "stdio.h"
+ "string.h"
+ "strings.h"
+ "sys/types.h"
+ "sys/stat.h"
+ "unistd.h"
+ "glob.h"
+ )
+ CHECK_INCLUDE_FILE_CONCAT("${file}")
+ENDFOREACH(file)
+
+#check for the functions used by the program
+FOREACH(func
+ basename
+ dirname
+ fnmatch
+ lchown
+ snprintf
+ strlcpy
+ strmode
+ strsep
+ strdup
+ strftime
+ glob
+ )
+ CHECK_SYMBOL_EXISTS_EX("${func}")
+ENDFOREACH(func)
+
+CHECK_TYPE_SIZE("dev_t" SIZEOF_DEV_T)
+IF(HAVE_SIZEOF_DEV_T)
+ SET (HAVE_DEV_T 1)
+ELSE(HAVE_SIZEOF_DEV_T)
+ SET (HAVE_DEV_T 0)
+ SET (dev_t "unsigned long")
+ENDIF(HAVE_SIZEOF_DEV_T)
+
+CHECK_TYPE_SIZE("major_t" SIZEOF_MAJOR_T)
+IF(HAVE_SIZEOF_MAJOR_T)
+ SET (HAVE_MAJOR_T 1)
+ELSE(HAVE_SIZEOF_MAJOR_T)
+ SET (HAVE_MAJOR_T 0)
+ SET (major_t "unsigned int")
+ENDIF(HAVE_SIZEOF_MAJOR_T)
+
+CHECK_TYPE_SIZE("minor_t" SIZEOF_MINOR_T)
+IF(HAVE_SIZEOF_MINOR_T)
+ SET (HAVE_MINOR_T 1)
+ELSE(HAVE_SIZEOF_MINOR_T)
+ SET (HAVE_MINOR_T 0)
+ SET (minor_t "unsigned int")
+ENDIF(HAVE_SIZEOF_MINOR_T)
+
+CHECK_TYPE_SIZE("nlink_t" SIZEOF_NLINK_T)
+IF(HAVE_SIZEOF_NLINK_T)
+ SET (HAVE_NLINK_T 1)
+ELSE(HAVE_SIZEOF_NLINK_T)
+ SET (HAVE_NLINK_T 0)
+ SET (nlink_t "unsigned short")
+ENDIF(HAVE_SIZEOF_NLINK_T)
+
+CHECK_TYPE_SIZE("uint64_t" SIZEOF_UINT64_T)
+IF(HAVE_SIZEOF_UINT64_T)
+ SET (HAVE_UINT64_T 1)
+ELSE(HAVE_SIZEOF_UINT64_T)
+ SET (HAVE_UINT64_T 0)
+ SET (uint64_t "long long")
+ENDIF(HAVE_SIZEOF_UINT64_T)
+
+CHECK_TYPE_SIZE("socklen_t" SIZEOF_SOCKLEN_T)
+IF(HAVE_SIZEOF_SOCKLEN_T)
+ SET (HAVE_SOCKLEN_T 1)
+ELSE(HAVE_SIZEOF_SOCKLEN_T)
+ SET (HAVE_SOCKLEN_T 0)
+ SET (socklen_t "unsigned long")
+ENDIF(HAVE_SIZEOF_SOCKLEN_T)
+
+CHECK_TYPE_SIZE("gid_t" SIZEOF_GID_T)
+IF(HAVE_SIZEOF_GID_T)
+ SET (HAVE_GID_T 1)
+ELSE(HAVE_SIZEOF_GID_T)
+ SET (HAVE_GID_T 0)
+ SET (gid_t "int")
+ENDIF(HAVE_SIZEOF_GID_T)
+
+CHECK_TYPE_SIZE("mode_t" SIZEOF_MODE_T)
+IF(HAVE_SIZEOF_MODE_T)
+ SET (HAVE_MODE_T 1)
+ELSE(HAVE_SIZEOF_MODE_T)
+ SET (HAVE_MODE_T 0)
+ SET (mode_t "int")
+ENDIF(HAVE_SIZEOF_MODE_T)
+
+CHECK_TYPE_SIZE("off_t" SIZEOF_OFF_T)
+IF(HAVE_SIZEOF_OFF_T)
+ SET (HAVE_OFF_T 1)
+ELSE(HAVE_SIZEOF_OFF_T)
+ SET (HAVE_OFF_T 0)
+ SET (off_t "long")
+ENDIF(HAVE_SIZEOF_OFF_T)
+
+CHECK_TYPE_SIZE("size_t" SIZEOF_SIZE_T)
+IF(HAVE_SIZEOF_SIZE_T)
+ SET (HAVE_SIZE_T 1)
+ELSE(HAVE_SIZEOF_SIZE_T)
+ SET (HAVE_SIZE_T 0)
+ SET (size_t "unsigned")
+ENDIF(HAVE_SIZEOF_SIZE_T)
+
+CHECK_TYPE_SIZE("ssize_t" SIZEOF_SSIZE_T)
+IF(HAVE_SIZEOF_SSIZE_T)
+ SET (HAVE_SSIZE_T 1)
+ELSE(HAVE_SIZEOF_SSIZE_T)
+ SET (HAVE_SSIZE_T 0)
+ SET (ssize_t "int")
+ENDIF(HAVE_SIZEOF_SSIZE_T)
+
+CHECK_TYPE_SIZE("uid_t" SIZEOF_UID_T)
+IF(HAVE_SIZEOF_UID_T)
+ SET (HAVE_UID_T 1)
+ELSE(HAVE_SIZEOF_UID_T)
+ SET (HAVE_UID_T 0)
+ SET (uid_t "int")
+ENDIF(HAVE_SIZEOF_UID_T)
+
+#SET (HAVE_BASENAME 0)
+#SET (HAVE_CTYPE_H 0)
+#SET (HAVE_DEV_T 1)
+#SET (HAVE_DIRNAME 0)
+#SET (HAVE_FNMATCH 1)
+#SET (HAVE_FNMATCH_H 1)
+#SET (HAVE_INTTYPES_H 1)
+#SET (HAVE_LCHOWN 1)
+#SET (HAVE_LIBGEN_H 1)
+SET (HAVE_LIBZ 1)
+#SET (HAVE_MAJOR_T 0)
+#SET (HAVE_MEMORY_H 1)
+#SET (HAVE_MINOR_T 0)
+#SET (HAVE_NLINK_T 1)
+#SET (HAVE_SNPRINTF 1)
+#SET (HAVE_SOCKLEN_T 1)
+#SET (HAVE_STDINT_H 1)
+#SET (HAVE_STDLIB_H 1)
+#SET (HAVE_STRDUP 1)
+#SET (HAVE_STRFTIME 1)
+#SET (HAVE_STRINGS_H 1)
+#SET (HAVE_STRING_H 1)
+#SET (HAVE_STRLCPY 0)
+#SET (HAVE_STRMODE 0)
+#SET (HAVE_STRSEP 1)
+#SET (HAVE_SYS_STAT_H 1)
+#SET (HAVE_SYS_TYPES_H 1)
+#SET (HAVE_UINT64_T 1)
+#SET (HAVE_UNISTD_H 1)
+SET (MAJOR_IN_MKDEV 0)
+SET (MAJOR_IN_SYSMACROS 0)
+SET (MAKEDEV_THREE_ARGS 0)
+#SET (NEED_BASENAME 0)
+#SET (NEED_DIRNAME 0)
+#SET (NEED_FNMATCH 1)
+#SET (NEED_MAKEDEV 1)
+#SET (NEED_SNPRINTF 0)
+#SET (NEED_STRDUP 0)
+#SET (NEED_STRLCPY 0)
+#SET (NEED_STRMODE 1)
+#SET (NEED_STRSEP 0)
+SET (PACKAGE_BUGREPORT "")
+SET (PACKAGE_NAME "\"libtar\"")
+SET (PACKAGE_STRING "\"libtar 1.2.11\"")
+SET (PACKAGE_TARNAME "\"libtar\"")
+SET (PACKAGE_VERSION "\"1.2.11\"")
+#SET (STDC_HEADERS 1)
+SET (const 0)
+#SET (dev_t 0)
+#SET (gid_t 0)
+#SET (major_t "unsigned int")
+#SET (minor_t "unsigned int")
+#SET (mode_t 0)
+#SET (nlink_t 0)
+#SET (off_t 0)
+#SET (size_t 0)
+#SET (socklen_t 0)
+#SET (uid_t 0)
+#SET (uint64_t 0)
+SET (LISTHASH_PREFIX "libtar")
+
+CONFIGURE_FILE(${LIBTAR_SOURCE_DIR}/listhash/listhash.h.in
+ ${LIBTAR_BINARY_DIR}/libtar/libtar_listhash.h @ONLY IMMEDIATE)
+CONFIGURE_FILE(${LIBTAR_SOURCE_DIR}/listhash/list.c.in
+ ${LIBTAR_BINARY_DIR}/listhash/libtar_list.c @ONLY IMMEDIATE)
+CONFIGURE_FILE(${LIBTAR_SOURCE_DIR}/listhash/hash.c.in
+ ${LIBTAR_BINARY_DIR}/listhash/libtar_hash.c @ONLY IMMEDIATE)
+
+FOREACH(hfile libtar.h tar.h compat/compat.h)
+ GET_FILENAME_COMPONENT(outname "${hfile}" NAME)
+ CONFIGURE_FILE(${LIBTAR_SOURCE_DIR}/${hfile}
+ ${LIBTAR_BINARY_DIR}/libtar/${outname} @ONLY IMMEDIATE)
+ENDFOREACH(hfile)
+
+CONFIGURE_FILE(${LIBTAR_SOURCE_DIR}/internal.h
+ ${LIBTAR_BINARY_DIR}/libtarint/internal.h @ONLY IMMEDIATE)
+
+SET(libtar_SRC
+ append.c
+ block.c
+ decode.c
+ encode.c
+ extract.c
+ handle.c
+ ${LIBTAR_BINARY_DIR}/listhash/libtar_hash.c
+ ${LIBTAR_BINARY_DIR}/listhash/libtar_list.c
+ output.c
+ util.c
+ wrapper.c
+ filesystem.c filesystem.h
+ internal.h
+ ${LIBTAR_BINARY_DIR}/libtar/config.h
+ config.h.in
+ tar.h
+ libtar.h
+ compat/compat.h
+
+# compat/strlcpy.c
+# compat/basename.c
+# compat/dirname.c
+# compat/strmode.c
+# compat/strsep.c
+)
+
+IF(NOT HAVE_STRLCPY)
+SET(libtar_SRC ${libtar_SRC} compat/strlcpy.c)
+SET(NEED_STRLCPY 1)
+ENDIF(NOT HAVE_STRLCPY)
+
+IF(NOT HAVE_STRMODE)
+SET(libtar_SRC ${libtar_SRC} compat/strmode.c)
+SET(NEED_STRMODE 1)
+ENDIF(NOT HAVE_STRMODE)
+
+IF(WIN32)
+IF(NOT HAVE_SNPRINTF)
+SET(libtar_SRC ${libtar_SRC} compat/snprintf.c)
+SET(NEED_SNPRINTF 1)
+ENDIF(NOT HAVE_SNPRINTF)
+ENDIF(WIN32)
+
+IF(NOT HAVE_DIRNAME)
+SET(libtar_SRC ${libtar_SRC} compat/dirname.c)
+SET(NEED_DIRNAME 1)
+ENDIF(NOT HAVE_DIRNAME)
+
+
+IF(NOT HAVE_STRSEP)
+SET(libtar_SRC ${libtar_SRC} compat/strsep.c)
+SET(NEED_STRSEP 1)
+ENDIF(NOT HAVE_STRSEP)
+
+
+IF(NOT HAVE_BASENAME)
+SET(libtar_SRC ${libtar_SRC} compat/basename.c)
+SET(NEED_BASENAME 1)
+ENDIF(NOT HAVE_BASENAME)
+
+IF(NOT HAVE_FNMATCH)
+SET(libtar_SRC ${libtar_SRC} compat/fnmatch.c)
+SET(NEED_FNMATCH 1)
+ENDIF(NOT HAVE_FNMATCH)
+
+#IF(NOT HAVE_GLOB)
+#SET(libtar_SRC ${libtar_SRC} compat/glob.c)
+#SET(NEED_GLOB 1)
+#ENDIF(NOT HAVE_GLOB)
+
+
+IF(WIN32)
+SET(NEED_MAKEDEV 0)
+ELSE(WIN32)
+SET(NEED_MAKEDEV 1)
+ENDIF(WIN32)
+
+
+CONFIGURE_FILE(${LIBTAR_SOURCE_DIR}/config.h.in
+ ${LIBTAR_BINARY_DIR}/libtar/config.h)
+
+ADD_LIBRARY(tar STATIC ${libtar_SRC})
+ADD_EXECUTABLE(tartest libtar.c)
+TARGET_LINK_LIBRARIES(tartest tar ${CMAKE_ZLIB_LIBRARIES})
+
diff --git a/Utilities/cmtar/COPYRIGHT b/Utilities/cmtar/COPYRIGHT
new file mode 100644
index 0000000..2471ec0
--- /dev/null
+++ b/Utilities/cmtar/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/Utilities/cmtar/append.c b/Utilities/cmtar/append.c
new file mode 100644
index 0000000..4350745
--- /dev/null
+++ b/Utilities/cmtar/append.c
@@ -0,0 +1,272 @@
+/*
+** 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 <libtarint/internal.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef _MSC_VER
+# include <libtar/compat.h>
+#else
+# include <sys/param.h>
+#endif
+#include <libtar/compat.h>
+#include <sys/types.h>
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <string.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifdef _MSC_VER
+#include <io.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
+
+#ifdef WIN32
+ if (stat(realname, &s) != 0)
+#else
+ if (lstat(realname, &s) != 0)
+#endif
+ {
+#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));
+
+ /* 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);
+ }
+
+#ifndef WIN32
+ /* check if it's a symlink */
+ if (TH_ISSYM(t))
+ {
+#ifdef WIN32
+ i = -1;
+#else
+ i = readlink(realname, path, sizeof(path));
+#endif
+ 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);
+ }
+#endif
+ /* 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 i, j;
+ size_t size;
+
+ 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/Utilities/cmtar/block.c b/Utilities/cmtar/block.c
new file mode 100644
index 0000000..f47f7ba
--- /dev/null
+++ b/Utilities/cmtar/block.c
@@ -0,0 +1,384 @@
+/*
+** 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 <libtarint/internal.h>
+
+#include <errno.h>
+
+#ifdef STDC_HEADERS
+# include <string.h>
+# include <stdlib.h>
+#endif
+
+
+#define BIT_ISSET(bitmask, bit) ((bitmask) & (bit))
+
+
+/* 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);
+ 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;
+ }
+ }
+
+#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);
+ }
+
+ 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/Utilities/cmtar/compat/README b/Utilities/cmtar/compat/README
new file mode 100644
index 0000000..fd23ced
--- /dev/null
+++ b/Utilities/cmtar/compat/README
@@ -0,0 +1,12 @@
+Compatibility Suite
+-------------------
+
+This directory contains a compatibility suite that provides alternate
+implementations of various library functions which are not available or
+not usable on some platforms.
+
+The original copyright information for each function is included in
+the source files. I've modified the files slightly for integration
+into this suite, but the functionality has not been modified from
+the original source.
+
diff --git a/Utilities/cmtar/compat/basename.c b/Utilities/cmtar/compat/basename.c
new file mode 100644
index 0000000..21cc13d
--- /dev/null
+++ b/Utilities/cmtar/compat/basename.c
@@ -0,0 +1,75 @@
+/* $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>
+#include <compat.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/Utilities/cmtar/compat/compat.h b/Utilities/cmtar/compat/compat.h
new file mode 100644
index 0000000..880f54b
--- /dev/null
+++ b/Utilities/cmtar/compat/compat.h
@@ -0,0 +1,314 @@
+/* prototypes for borrowed "compatibility" code */
+
+#include <libtar/config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef STDC_HEADERS
+# include <stdarg.h>
+# include <stddef.h>
+#else
+# include <varargs.h>
+#endif
+
+#ifdef HAVE_LIBGEN_H
+# include <libgen.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 */
+
+#ifdef _MSC_VER //compile snprintf only onwin32
+//#if defined(NEED_SNPRINTF) && !defined(HAVE_SNPRINTF)
+#if !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 */
+#endif
+
+#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 */
+
+#ifdef _MSC_VER
+#include <stdlib.h>
+#define MAXPATHLEN _MAX_PATH
+#ifndef O_ACCMODE
+# define O_ACCMODE 0x0003
+#endif
+#endif
+
+
+
+
+#ifndef S_ISREG
+#ifndef S_IFREG
+#ifndef _S_IFREG
+#define S_IFREG (-1)
+#else
+#define S_IFREG _S_IFREG
+#endif
+#endif
+#define S_ISREG(m) (((m)&S_IFREG)==S_IFREG)
+#endif
+
+
+#ifndef S_ISDIR
+#ifndef S_IFDIR
+#ifndef _S_IFDIR
+#define S_IFDIR (-1)
+#else
+#define S_IFDIR _S_IFDIR
+#endif
+#endif
+#define S_ISDIR(m) (((m)&S_IFDIR)==S_IFDIR)
+#endif
+
+#ifndef S_ISBLK
+#ifndef S_IFBLK
+#ifndef _S_IFBLK
+#define S_IFBLK (-1)
+#else
+#define S_IFBLK _S_IFBLK
+#endif
+#endif
+#define S_ISBLK(m) (((m)&S_IFBLK)==S_IFBLK)
+#endif
+
+#ifndef S_ISFIFO
+#ifndef S_IFFIFO
+#ifndef _S_IFFIFO
+#define S_IFFIFO (-1)
+#else
+#define S_IFFIFO _S_IFFIFO
+#endif
+#endif
+#define S_ISFIFO(m) (((m)&S_IFFIFO)==S_IFFIFO)
+#endif
diff --git a/Utilities/cmtar/compat/dirname.c b/Utilities/cmtar/compat/dirname.c
new file mode 100644
index 0000000..63455a9
--- /dev/null
+++ b/Utilities/cmtar/compat/dirname.c
@@ -0,0 +1,78 @@
+/* $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>
+#include <compat.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/Utilities/cmtar/compat/fnmatch.c b/Utilities/cmtar/compat/fnmatch.c
new file mode 100644
index 0000000..f1c5da1
--- /dev/null
+++ b/Utilities/cmtar/compat/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/Utilities/cmtar/compat/gethostbyname_r.c b/Utilities/cmtar/compat/gethostbyname_r.c
new file mode 100644
index 0000000..1b88bad
--- /dev/null
+++ b/Utilities/cmtar/compat/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/Utilities/cmtar/compat/gethostname.c b/Utilities/cmtar/compat/gethostname.c
new file mode 100644
index 0000000..1abaae1
--- /dev/null
+++ b/Utilities/cmtar/compat/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/Utilities/cmtar/compat/getservbyname_r.c b/Utilities/cmtar/compat/getservbyname_r.c
new file mode 100644
index 0000000..3afedf0
--- /dev/null
+++ b/Utilities/cmtar/compat/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/Utilities/cmtar/compat/glob.c b/Utilities/cmtar/compat/glob.c
new file mode 100644
index 0000000..939d76f
--- /dev/null
+++ b/Utilities/cmtar/compat/glob.c
@@ -0,0 +1,874 @@
+/*
+ * 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 <compat.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/Utilities/cmtar/compat/inet_aton.c b/Utilities/cmtar/compat/inet_aton.c
new file mode 100644
index 0000000..cc1e507
--- /dev/null
+++ b/Utilities/cmtar/compat/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/Utilities/cmtar/compat/snprintf.c b/Utilities/cmtar/compat/snprintf.c
new file mode 100644
index 0000000..a6d8c05
--- /dev/null
+++ b/Utilities/cmtar/compat/snprintf.c
@@ -0,0 +1,788 @@
+/**************************************************************
+ * 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.
+ *
+ **************************************************************/
+
+#include <config.h>
+
+#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)
+
+#include <string.h>
+# include <ctype.h>
+#include <sys/types.h>
+
+/* Define this as a fall through, HAVE_STDARG_H is probably already set */
+
+#define HAVE_VARARGS_H
+
+/* varargs declarations: */
+
+#if defined(HAVE_STDARG_H)
+# include <stdarg.h>
+# define HAVE_STDARGS /* let's hope that works everywhere (mj) */
+# 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)
+#else
+# if defined(HAVE_VARARGS_H)
+# include <varargs.h>
+# undef HAVE_STDARGS
+# define VA_LOCAL_DECL va_list ap
+# define VA_START(f) va_start(ap) /* f is ignored! */
+# define VA_SHIFT(v,t) v = va_arg(ap,t)
+# define VA_END va_end(ap)
+# else
+/*XX ** NO VARARGS ** XX*/
+# endif
+#endif
+
+/*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, short 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 short 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 short 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 short 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
+/* VARARGS3 */
+#ifdef HAVE_STDARGS
+int mutt_snprintf (char *str,size_t count,const char *fmt,...)
+#else
+int mutt_snprintf (va_alist) va_dcl
+#endif
+{
+#ifndef HAVE_STDARGS
+ char *str;
+ size_t count;
+ char *fmt;
+#endif
+ 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/Utilities/cmtar/compat/strdup.c b/Utilities/cmtar/compat/strdup.c
new file mode 100644
index 0000000..9dabf37
--- /dev/null
+++ b/Utilities/cmtar/compat/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/Utilities/cmtar/compat/strlcat.c b/Utilities/cmtar/compat/strlcat.c
new file mode 100644
index 0000000..e8945c1
--- /dev/null
+++ b/Utilities/cmtar/compat/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/Utilities/cmtar/compat/strlcpy.c b/Utilities/cmtar/compat/strlcpy.c
new file mode 100644
index 0000000..f85c71b
--- /dev/null
+++ b/Utilities/cmtar/compat/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/Utilities/cmtar/compat/strmode.c b/Utilities/cmtar/compat/strmode.c
new file mode 100644
index 0000000..832b0e7
--- /dev/null
+++ b/Utilities/cmtar/compat/strmode.c
@@ -0,0 +1,185 @@
+/*-
+ * 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>
+#include <libtar/compat.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;
+#ifdef S_IFLNK
+ case S_IFLNK: /* symbolic link */
+ *p++ = 'l';
+ break;
+#endif
+#ifdef S_IFSOCK
+ case S_IFSOCK: /* socket */
+ *p++ = 's';
+ break;
+#endif
+#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 */
+#ifdef S_IRUSR
+ if (mode & S_IRUSR)
+ *p++ = 'r';
+ else
+#endif
+ *p++ = '-';
+
+#ifdef S_IWUSR
+ if (mode & S_IWUSR)
+ *p++ = 'w';
+ else
+#endif
+ *p++ = '-';
+
+#ifndef _MSC_VER
+#ifdef S_ISUID
+ switch (mode & (S_IXUSR | S_ISUID)) {
+#else
+ switch (mode & (S_IXUSR)) {
+#endif
+ case 0:
+ *p++ = '-';
+ break;
+ case S_IXUSR:
+ *p++ = 'x';
+ break;
+#ifdef S_ISUID
+ case S_ISUID:
+ *p++ = 'S';
+ break;
+ case S_IXUSR | S_ISUID:
+ *p++ = 's';
+ break;
+#endif
+ }
+#endif
+ /* group */
+#ifdef S_IRGRP
+ if (mode & S_IRGRP)
+ *p++ = 'r';
+ else
+#endif
+ *p++ = '-';
+#ifdef S_IWGRP
+ if (mode & S_IWGRP)
+ *p++ = 'w';
+ else
+#endif
+ *p++ = '-';
+#if defined(S_IXGRP) && defined(S_ISGID)
+ 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;
+ }
+#else
+ *p++ = '-';
+#endif
+#ifndef WIN32
+ /* 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;
+ }
+#else
+ *p++ = '-';
+ *p++ = '-';
+ *p++ = '-';
+#endif
+ *p++ = ' '; /* will be a '+' if ACL's implemented */
+ *p = '\0';
+}
diff --git a/Utilities/cmtar/compat/strrstr.c b/Utilities/cmtar/compat/strrstr.c
new file mode 100644
index 0000000..8b7f299
--- /dev/null
+++ b/Utilities/cmtar/compat/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/Utilities/cmtar/compat/strsep.c b/Utilities/cmtar/compat/strsep.c
new file mode 100644
index 0000000..9d036a9
--- /dev/null
+++ b/Utilities/cmtar/compat/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/Utilities/cmtar/config.h.in b/Utilities/cmtar/config.h.in
new file mode 100644
index 0000000..eba0ed3
--- /dev/null
+++ b/Utilities/cmtar/config.h.in
@@ -0,0 +1,190 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define if your system has a working basename */
+#cmakedefine HAVE_BASENAME @HAVE_BASENAME@
+
+/* Define to 1 if you have the <ctype.h> header file. */
+#cmakedefine HAVE_CTYPE_H @HAVE_CTYPE_H@
+
+/* Define to 1 if the system has the type `dev_t'. */
+#cmakedefine HAVE_DEV_T @HAVE_DEV_T@
+
+/* Define if your system has a working dirname */
+#cmakedefine HAVE_DIRNAME @HAVE_DIRNAME@
+
+/* Define to 1 if your system has a working POSIX `fnmatch' function. */
+#cmakedefine HAVE_FNMATCH @HAVE_FNMATCH@
+
+/* Define to 1 if you have the <fnmatch.h> header file. */
+#cmakedefine HAVE_FNMATCH_H @HAVE_FNMATCH_H@
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#cmakedefine HAVE_INTTYPES_H @HAVE_INTTYPES_H@
+
+/* Define to 1 if you have the `lchown' function. */
+#cmakedefine HAVE_LCHOWN @HAVE_LCHOWN@
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#cmakedefine HAVE_LIBGEN_H @HAVE_LIBGEN_H@
+
+/* Define to 1 if you have the `z' library (-lz). */
+#cmakedefine HAVE_LIBZ @HAVE_LIBZ@
+
+/* Define to 1 if the system has the type `major_t'. */
+#cmakedefine HAVE_MAJOR_T @HAVE_MAJOR_T@
+
+/* Define to 1 if you have the <memory.h> header file. */
+#cmakedefine HAVE_MEMORY_H @HAVE_MEMORY_H@
+
+/* Define to 1 if the system has the type `minor_t'. */
+#cmakedefine HAVE_MINOR_T @HAVE_MINOR_T@
+
+/* Define to 1 if the system has the type `nlink_t'. */
+#cmakedefine HAVE_NLINK_T @HAVE_NLINK_T@
+
+/* Define if your system has a working snprintf */
+#cmakedefine HAVE_SNPRINTF @HAVE_SNPRINTF@
+
+/* Define to 1 if the system has the type `socklen_t'. */
+#cmakedefine HAVE_SOCKLEN_T @HAVE_SOCKLEN_T@
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#cmakedefine HAVE_STDINT_H @HAVE_STDINT_H@
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#cmakedefine HAVE_STDLIB_H @HAVE_STDLIB_H@
+
+/* Define if you have the strdup function */
+#cmakedefine HAVE_STRDUP @HAVE_STRDUP@
+
+/* Define to 1 if you have the `strftime' function. */
+#cmakedefine HAVE_STRFTIME @HAVE_STRFTIME@
+
+/* Define to 1 if you have the <strings.h> header file. */
+#cmakedefine HAVE_STRINGS_H @HAVE_STRINGS_H@
+
+/* Define to 1 if you have the <string.h> header file. */
+#cmakedefine HAVE_STRING_H @HAVE_STRING_H@
+
+/* Define if you have the strlcpy function */
+#cmakedefine HAVE_STRLCPY @HAVE_STRLCPY@
+
+/* Define if you have the strmode function */
+#cmakedefine HAVE_STRMODE @HAVE_STRMODE@
+
+/* Define if you have the strsep function */
+#cmakedefine HAVE_STRSEP @HAVE_STRSEP@
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#cmakedefine HAVE_SYS_STAT_H @HAVE_SYS_STAT_H@
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#cmakedefine HAVE_SYS_TYPES_H @HAVE_SYS_TYPES_H@
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#cmakedefine HAVE_UINT64_T @HAVE_UINT64_T@
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#cmakedefine HAVE_UNISTD_H @HAVE_UNISTD_H@
+
+/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>.
+ */
+#cmakedefine MAJOR_IN_MKDEV @MAJOR_IN_MKDEV@
+
+/* Define to 1 if `major', `minor', and `makedev' are declared in
+ <sysmacros.h>. */
+#cmakedefine MAJOR_IN_SYSMACROS @MAJOR_IN_SYSMACROS@
+
+/* Define as 1 if makedev expects three arguments */
+#cmakedefine MAKEDEV_THREE_ARGS @MAKEDEV_THREE_ARGS@
+
+/* Define if you want to use the basename function */
+#cmakedefine NEED_BASENAME @NEED_BASENAME@
+
+/* Define if you want to use the dirname function */
+#cmakedefine NEED_DIRNAME @NEED_DIRNAME@
+
+/* Define if you want to use the fnmatch function */
+#cmakedefine NEED_FNMATCH @NEED_FNMATCH@
+
+/* Define if you want to use the makedev function */
+#cmakedefine NEED_MAKEDEV @NEED_MAKEDEV@
+
+/* Define if you want to use the snprintf function */
+#cmakedefine NEED_SNPRINTF @NEED_SNPRINTF@
+
+/* Define if you want to use the strdup function */
+#cmakedefine NEED_STRDUP @NEED_STRDUP@
+
+/* Define if you want to use the strlcpy function */
+#cmakedefine NEED_STRLCPY @NEED_STRLCPY@
+
+/* Define if you want to use the strmode function */
+#cmakedefine NEED_STRMODE @NEED_STRMODE@
+
+/* Define if you want to use the strsep function */
+#cmakedefine NEED_STRSEP @NEED_STRSEP@
+
+/* Define to the address where bug reports for this package should be sent. */
+#cmakedefine PACKAGE_BUGREPORT @PACKAGE_BUGREPORT@
+
+/* Define to the full name of this package. */
+#cmakedefine PACKAGE_NAME @PACKAGE_NAME@
+
+/* Define to the full name and version of this package. */
+#cmakedefine PACKAGE_STRING @PACKAGE_STRING@
+
+/* Define to the one symbol short name of this package. */
+#cmakedefine PACKAGE_TARNAME @PACKAGE_TARNAME@
+
+/* Define to the version of this package. */
+#cmakedefine PACKAGE_VERSION @PACKAGE_VERSION@
+
+/* Define to 1 if you have the ANSI C header files. */
+#cmakedefine STDC_HEADERS @STDC_HEADERS@
+
+/* Define to 1 if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+#ifndef _ALL_SOURCE
+#cmakedefine _ALL_SOURCE @_ALL_SOURCE@
+#endif
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#cmakedefine const @const@
+
+/* Define to `unsigned long' if not defined in system header files. */
+#cmakedefine dev_t @dev_t@
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#cmakedefine gid_t @gid_t@
+
+/* Define to `unsigned int' if not defined in system header files. */
+#cmakedefine major_t @major_t@
+
+/* Define to `unsigned int' if not defined in system header files. */
+#cmakedefine minor_t @minor_t@
+
+/* Define to `int' if <sys/types.h> does not define. */
+#cmakedefine mode_t @mode_t@
+
+/* Define to `unsigned short' if not defined in system header files. */
+#cmakedefine nlink_t @nlink_t@
+
+/* Define to `long' if <sys/types.h> does not define. */
+#cmakedefine off_t @off_t@
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#cmakedefine size_t @size_t@
+
+/* Define to `int' if <sys/types.h> does not define. */
+#cmakedefine ssize_t @size_t@
+
+/* Define to `unsigned long' if not defined in system header files. */
+#cmakedefine socklen_t @socklen_t@
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#cmakedefine uid_t @uid_t@
+
+/* Define to `long long' if not defined in system header files. */
+#cmakedefine uint64_t @uint64_t@
diff --git a/Utilities/cmtar/decode.c b/Utilities/cmtar/decode.c
new file mode 100644
index 0000000..39077de
--- /dev/null
+++ b/Utilities/cmtar/decode.c
@@ -0,0 +1,136 @@
+/*
+** 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 <libtarint/internal.h>
+
+#include <stdio.h>
+
+#ifndef _MSC_VER
+#include <sys/param.h>
+#else
+#include <compat.h>
+#endif
+
+#ifndef WIN32
+#include <pwd.h>
+#include <grp.h>
+#endif
+
+#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)
+ 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;
+#ifndef WIN32
+ struct passwd *pw;
+
+ pw = getpwnam(t->th_buf.uname);
+ if (pw != NULL)
+ return pw->pw_uid;
+
+ /* if the password entry doesn't exist */
+#endif
+ sscanf(t->th_buf.uid, "%o", &uid);
+ return uid;
+}
+
+
+gid_t
+th_get_gid(TAR *t)
+{
+ int gid;
+#ifndef WIN32
+ struct group *gr;
+
+ gr = getgrnam(t->th_buf.gname);
+ if (gr != NULL)
+ return gr->gr_gid;
+
+ /* if the group entry doesn't exist */
+#endif
+ 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)
+ {
+#ifndef WIN32
+ case SYMTYPE:
+ mode |= S_IFLNK;
+ break;
+#endif
+ case CHRTYPE:
+ mode |= S_IFCHR;
+ break;
+ case BLKTYPE:
+ mode |= S_IFBLK;
+ break;
+ case DIRTYPE:
+ mode |= S_IFDIR;
+ break;
+#ifndef WIN32
+ case FIFOTYPE:
+ mode |= S_IFIFO;
+ break;
+#endif
+ 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/Utilities/cmtar/encode.c b/Utilities/cmtar/encode.c
new file mode 100644
index 0000000..cadac67
--- /dev/null
+++ b/Utilities/cmtar/encode.c
@@ -0,0 +1,234 @@
+/*
+** 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 <libtarint/internal.h>
+
+#include <stdio.h>
+#ifndef WIN32
+#include <pwd.h>
+#include <grp.h>
+#endif
+#include <sys/types.h>
+
+#ifdef STDC_HEADERS
+# include <string.h>
+# include <stdlib.h>
+#endif
+
+
+/* magic, version, and checksum */
+void
+th_finish(TAR *t)
+{
+ int i, sum = 0;
+
+ if (t->options & TAR_GNU)
+ strncpy(t->th_buf.magic, "ustar ", 8);
+ else
+ {
+ strncpy(t->th_buf.version, TVERSION, TVERSLEN);
+ strncpy(t->th_buf.magic, TMAGIC, TMAGLEN);
+ }
+
+ for (i = 0; i < T_BLOCKSIZE; i++)
+ sum += ((char *)(&(t->th_buf)))[i];
+ for (i = 0; i < 8; i++)
+ sum += (' ' - t->th_buf.chksum[i]);
+ int_to_oct(sum, t->th_buf.chksum, 8);
+}
+
+
+/* map a file mode to a typeflag */
+void
+th_set_type(TAR *t, mode_t mode)
+{
+#ifdef S_ISLNK
+ if (S_ISLNK(mode))
+ t->th_buf.typeflag = SYMTYPE;
+#endif
+ if (S_ISREG(mode))
+ t->th_buf.typeflag = REGTYPE;
+ if (S_ISDIR(mode))
+ t->th_buf.typeflag = DIRTYPE;
+#ifdef S_ISCHR
+ if (S_ISCHR(mode))
+ t->th_buf.typeflag = CHRTYPE;
+#endif
+ if (S_ISBLK(mode))
+ t->th_buf.typeflag = BLKTYPE;
+ if (S_ISFIFO(mode)
+#ifdef S_ISSOCK
+ || S_ISSOCK(mode))
+#else
+ )
+#endif
+ 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 && (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 && (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
+#ifndef major
+# define major(dev) ((int)(((dev) >> 8) & 0xff))
+#endif
+#ifndef minor
+# define minor(dev) ((int)((dev) & 0xff))
+#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)
+{
+#ifndef WIN32
+ struct passwd *pw;
+
+ pw = getpwuid(uid);
+ if (pw != NULL)
+ strlcpy(t->th_buf.uname, pw->pw_name, sizeof(t->th_buf.uname));
+#endif
+ int_to_oct(uid, t->th_buf.uid, 8);
+}
+
+
+/* encode group info */
+void
+th_set_group(TAR *t, gid_t gid)
+{
+#ifndef WIN32
+ struct group *gr;
+
+ gr = getgrgid(gid);
+ if (gr != NULL)
+ strlcpy(t->th_buf.gname, gr->gr_name, sizeof(t->th_buf.gname));
+#endif
+ int_to_oct(gid, t->th_buf.gid, 8);
+}
+
+
+/* encode file mode */
+void
+th_set_mode(TAR *t, mode_t fmode)
+{
+#ifndef WIN32
+ if (S_ISSOCK(fmode))
+ {
+ fmode &= ~S_IFSOCK;
+ fmode |= S_IFIFO;
+ }
+#endif
+ 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);
+#ifndef WIN32
+ if (S_ISCHR(s->st_mode) || S_ISBLK(s->st_mode))
+ th_set_device(t, s->st_rdev);
+#endif
+ 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/Utilities/cmtar/extract.c b/Utilities/cmtar/extract.c
new file mode 100644
index 0000000..4314325
--- /dev/null
+++ b/Utilities/cmtar/extract.c
@@ -0,0 +1,561 @@
+/*
+** 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 <libtarint/internal.h>
+
+#include <stdio.h>
+#include <libtar/compat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#ifdef _MSC_VER
+#include <sys/utime.h>
+#include <io.h>
+#include <direct.h>
+#else
+#include <utime.h>
+#include <sys/param.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <string.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+
+struct linkname
+{
+ char ln_save[MAXPATHLEN];
+ char ln_real[MAXPATHLEN];
+};
+typedef struct linkname linkname_t;
+
+
+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);
+
+ /* change owner/group */
+#ifndef WIN32
+ 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;
+ }
+
+#endif /* WIN32 */
+
+ return 0;
+}
+
+
+/* switchboard */
+int
+tar_extract_file(TAR *t, char *realname)
+{
+ int i;
+ linkname_t *lnp;
+
+ if (t->options & TAR_NOOVERWRITE)
+ {
+ struct stat s;
+
+#ifdef WIN32
+ if (stat(realname, &s) == 0 || errno != ENOENT)
+#else
+ if (lstat(realname, &s) == 0 || errno != ENOENT)
+#endif
+ {
+ errno = EEXIST;
+ return -1;
+ }
+ }
+
+ if (TH_ISDIR(t))
+ {
+ i = tar_extract_dir(t, realname);
+ if (i == 1)
+ i = 0;
+ }
+#ifndef _WIN32
+ else if (TH_ISLNK(t))
+ i = tar_extract_hardlink(t, realname);
+ else if (TH_ISSYM(t))
+ i = tar_extract_symlink(t, realname);
+ else if (TH_ISCHR(t))
+ i = tar_extract_chardev(t, realname);
+ else if (TH_ISBLK(t))
+ i = tar_extract_blockdev(t, realname);
+ else if (TH_ISFIFO(t))
+ i = tar_extract_fifo(t, realname);
+#endif
+ else /* if (TH_ISREG(t)) */
+ i = tar_extract_regfile(t, realname);
+
+ if (i != 0)
+ return i;
+
+ i = tar_set_file_perms(t, realname);
+ if (i != 0)
+ return i;
+
+ lnp = (linkname_t *)calloc(1, sizeof(linkname_t));
+ if (lnp == NULL)
+ return -1;
+ strlcpy(lnp->ln_save, th_get_pathname(t), sizeof(lnp->ln_save));
+ strlcpy(lnp->ln_real, realname, sizeof(lnp->ln_real));
+#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;
+
+ return 0;
+}
+
+
+/* extract regular file */
+int
+tar_extract_regfile(TAR *t, char *realname)
+{
+ mode_t mode;
+ size_t size;
+ uid_t uid;
+ gid_t gid;
+ int fdout;
+ int i, k;
+ char buf[T_BLOCKSIZE];
+ char *filename;
+
+#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);
+#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 -= 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
+
+ return 0;
+}
+
+
+/* skip regfile */
+int
+tar_skip_regfile(TAR *t)
+{
+ int i, k;
+ size_t size;
+ char buf[T_BLOCKSIZE];
+
+ if (!TH_ISREG(t))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ size = th_get_size(t);
+ for (i = size; i > 0; 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 *filename;
+ char *linktgt = NULL;
+ linkname_t *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 = (linkname_t *)libtar_hashptr_data(&hp);
+ linktgt = lnp->ln_real;
+ }
+ else
+ linktgt = th_get_linkname(t);
+
+#ifdef DEBUG
+ printf(" ==> extracting: %s (link to %s)\n", filename, linktgt);
+#endif
+#ifndef WIN32
+ if (link(linktgt, filename) == -1)
+#endif
+ {
+#ifdef DEBUG
+ perror("link()");
+#endif
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/* symlink */
+int
+tar_extract_symlink(TAR *t, char *realname)
+{
+ char *filename;
+
+#ifndef _WIN32
+ if (!TH_ISSYM(t))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+#endif
+
+ filename = (realname ? realname : th_get_pathname(t));
+ if (mkdirhier(dirname(filename)) == -1)
+ return -1;
+
+ if (unlink(filename) == -1 && errno != ENOENT)
+ return -1;
+
+#ifdef DEBUG
+ printf(" ==> extracting: %s (symlink to %s)\n",
+ filename, th_get_linkname(t));
+#endif
+#ifndef WIN32
+ if (symlink(th_get_linkname(t), filename) == -1)
+#endif
+ {
+#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;
+
+#ifndef _WIN32
+ if (!TH_ISCHR(t))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+#endif
+ 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
+#ifndef WIN32
+ if (mknod(filename, mode | S_IFCHR,
+ compat_makedev(devmaj, devmin)) == -1)
+#endif
+ {
+#ifdef DEBUG
+ perror("mknod()");
+#endif
+ return -1;
+ }
+
+ 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
+#ifndef WIN32
+ if (mknod(filename, mode | S_IFBLK,
+ compat_makedev(devmaj, devmin)) == -1)
+#endif
+ {
+#ifdef DEBUG
+ perror("mknod()");
+#endif
+ return -1;
+ }
+
+ 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)
+ return -1;
+
+#ifdef DEBUG
+ printf(" ==> extracting: %s (mode %04o, directory)\n", filename,
+ mode);
+#endif
+#ifdef WIN32
+ if (mkdir(filename) == -1)
+#else
+ if (mkdir(filename, mode) == -1)
+#endif
+ {
+ if (errno == EEXIST)
+ {
+ if (chmod(filename, mode) == -1)
+ {
+#ifdef DEBUG
+ perror("chmod()");
+#endif
+ return -1;
+ }
+ else
+ {
+#ifdef DEBUG
+ puts(" *** using existing directory");
+#endif
+ return 1;
+ }
+ }
+ 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
+#ifndef WIN32
+ if (mkfifo(filename, mode) == -1)
+#endif
+ {
+#ifdef DEBUG
+ perror("mkfifo()");
+#endif
+ return -1;
+ }
+
+ return 0;
+}
+
+
diff --git a/Utilities/cmtar/filesystem.c b/Utilities/cmtar/filesystem.c
new file mode 100644
index 0000000..cc4f912
--- /dev/null
+++ b/Utilities/cmtar/filesystem.c
@@ -0,0 +1,82 @@
+
+
+
+// First microsoft compilers
+
+#ifdef _MSC_VER
+#include <windows.h>
+#include <io.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <filesystem.h>
+
+
+kwDirectory * kwOpenDir(const char* name)
+{
+// struct _KWDIR ssss;
+ char* buf;
+ size_t n = strlen(name);
+ kwDirectory * dir = (kwDirectory *)malloc(sizeof (kwDirectory));
+ if(dir==NULL)
+ {
+ return NULL;
+ }
+ dir->EOD=0; //not the end of directory
+ if ( name[n - 1] == '/' )
+ {
+ buf = (char*) malloc(n + 1 + 1);
+// buf = new char[n + 1 + 1];
+ sprintf(buf, "%s*", name);
+ }
+ else
+ {
+ buf = (char*)malloc(n + 2 + 1);
+// buf = new char[n + 2 + 1];
+ sprintf(buf, "%s/*", name);
+ }
+
+ // Now put them into the file array
+ dir->SrchHandle = _findfirst(buf, &dir->Entry);
+ free(buf);
+
+ if ( dir->SrchHandle == -1 )
+ {
+ free(dir);
+ return NULL;
+ }
+ return dir;
+}
+
+kwDirEntry * kwReadDir(kwDirectory * dir)
+{
+ kwDirEntry * entry;
+ if(!dir || dir->EOD ==1)
+ {
+ return NULL;
+ }
+ entry = (kwDirEntry*)malloc(sizeof(kwDirEntry));
+ strncpy(entry->d_name,dir->Entry.name,MAXPATHLEN-1);
+ if(_findnext(dir->SrchHandle, &dir->Entry) == -1)
+ {
+ dir->EOD=1;
+ }
+ return entry;
+}
+int kwCloseDir(kwDirectory * dir)
+{
+ int r=-1;
+ if(dir)
+ {
+ r=_findclose(dir->SrchHandle);
+ free(dir);
+ }
+ if(r==-1) return 0;
+ return 1;
+}
+#endif
diff --git a/Utilities/cmtar/filesystem.h b/Utilities/cmtar/filesystem.h
new file mode 100644
index 0000000..f2ee202
--- /dev/null
+++ b/Utilities/cmtar/filesystem.h
@@ -0,0 +1,35 @@
+#ifndef _FILESYSTEM_H_
+#define _FILESYSTEM_H_
+
+#ifdef _MSC_VER
+#include <io.h>
+
+struct _KWDIR
+{
+#if _MSC_VER < 1300
+ long SrchHandle;
+#else
+ intptr_t SrchHandle;
+#endif
+ struct _finddata_t Entry; // data of current file
+ int EOD; //end of directory
+
+};
+#ifndef MAXPATHLEN
+#define MAXPATHLEN _MAX_PATH
+#endif
+typedef struct _KWDIRENTRY
+{
+ char d_name[MAXPATHLEN];
+}kwDirEntry;
+
+typedef struct _KWDIR kwDirectory;
+kwDirectory * kwOpenDir(const char* name);
+kwDirEntry * kwReadDir(kwDirectory * dir);
+int kwCloseDir(kwDirectory * dir);
+#else
+
+#endif //MSC
+
+
+#endif
diff --git a/Utilities/cmtar/handle.c b/Utilities/cmtar/handle.c
new file mode 100644
index 0000000..1fe053e
--- /dev/null
+++ b/Utilities/cmtar/handle.c
@@ -0,0 +1,136 @@
+/*
+** 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 <libtarint/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
+
+#ifdef _MSC_VER
+#include <io.h>
+//Yogi: hack. this should work on windows where there is no O_ACCMODE defined
+#ifndef O_ACCMODE
+# define O_ACCMODE 0x0003
+#endif
+#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/Utilities/cmtar/internal.h b/Utilities/cmtar/internal.h
new file mode 100644
index 0000000..434fbb0
--- /dev/null
+++ b/Utilities/cmtar/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 <libtar/config.h>
+#include <libtar/compat.h>
+
+#include <libtar/libtar.h>
+
diff --git a/Utilities/cmtar/libtar.c b/Utilities/cmtar/libtar.c
new file mode 100644
index 0000000..1068959
--- /dev/null
+++ b/Utilities/cmtar/libtar.c
@@ -0,0 +1,377 @@
+/*
+** Copyright 1998-2003 University of Illinois Board of Trustees
+** Copyright 1998-2003 Mark D. Roth
+** All rights reserved.
+**
+** libtar.c - demo driver program for libtar
+**
+** Mark D. Roth <roth@uiuc.edu>
+** Campus Information Technologies and Educational Services
+** University of Illinois at Urbana-Champaign
+*/
+#include <libtar/config.h>
+#include <libtar/libtar.h>
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#ifdef _MSC_VER
+#include <libtar/compat.h>
+#include <io.h>
+#else
+#include <sys/param.h>
+#endif
+
+#ifdef STDC_HEADERS
+# include <string.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef DEBUG
+# include <signal.h>
+#endif
+
+#ifdef HAVE_LIBZ
+# include <cmzlib/zlib.h>
+#endif
+
+#include <libtar/compat.h>
+
+
+char *progname;
+int verbose = 0;
+int use_gnu = 0;
+
+#ifdef DEBUG
+void
+segv_handler(int sig)
+{
+ puts("OOPS! Caught SIGSEGV, bailing out...");
+ fflush(stdout);
+ fflush(stderr);
+}
+#endif
+
+
+#ifdef HAVE_LIBZ
+
+int use_zlib = 0;
+
+int
+gzopen_frontend(char *pathname, int oflags, int mode)
+{
+ char *gzoflags;
+ gzFile gzf;
+ int fd;
+
+ switch (oflags & O_ACCMODE)
+ {
+ case O_WRONLY:
+ gzoflags = "wb";
+ break;
+ case O_RDONLY:
+ gzoflags = "rb";
+ break;
+ default:
+ case O_RDWR:
+ errno = EINVAL;
+ return -1;
+ }
+
+ fd = open(pathname, oflags, mode);
+ if (fd == -1)
+ return -1;
+
+#ifndef _MSC_VER
+ if ((oflags & O_CREAT) && fchmod(fd, mode))
+ return -1;
+#endif
+
+ gzf = gzdopen(fd, gzoflags);
+ if (!gzf)
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return (int)gzf;
+}
+
+tartype_t gztype = { (openfunc_t) gzopen_frontend, (closefunc_t) gzclose,
+ (readfunc_t) gzread, (writefunc_t) gzwrite
+};
+
+#endif /* HAVE_LIBZ */
+
+
+int
+create(char *tarfile, char *rootdir, libtar_list_t *l)
+{
+ TAR *t;
+ char *pathname;
+ char buf[MAXPATHLEN];
+ libtar_listptr_t lp;
+
+ if (tar_open(&t, tarfile,
+#ifdef HAVE_LIBZ
+ (use_zlib ? &gztype : NULL),
+#else
+ NULL,
+#endif
+ O_WRONLY | O_CREAT, 0644,
+ (verbose ? TAR_VERBOSE : 0)
+ | (use_gnu ? TAR_GNU : 0)) == -1)
+ {
+ fprintf(stderr, "tar_open(): %s\n", strerror(errno));
+ return -1;
+ }
+
+ libtar_listptr_reset(&lp);
+ while (libtar_list_next(l, &lp) != 0)
+ {
+ pathname = (char *)libtar_listptr_data(&lp);
+ if (pathname[0] != '/' && rootdir != NULL)
+ snprintf(buf, sizeof(buf), "%s/%s", rootdir, pathname);
+ else
+ strlcpy(buf, pathname, sizeof(buf));
+ if (tar_append_tree(t, buf, pathname) != 0)
+ {
+ fprintf(stderr,
+ "tar_append_tree(\"%s\", \"%s\"): %s\n", buf,
+ pathname, strerror(errno));
+ tar_close(t);
+ return -1;
+ }
+ }
+
+ if (tar_append_eof(t) != 0)
+ {
+ fprintf(stderr, "tar_append_eof(): %s\n", strerror(errno));
+ tar_close(t);
+ return -1;
+ }
+
+ if (tar_close(t) != 0)
+ {
+ fprintf(stderr, "tar_close(): %s\n", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int
+list(char *tarfile)
+{
+ TAR *t;
+ int i;
+
+ if (tar_open(&t, tarfile,
+#ifdef HAVE_LIBZ
+ (use_zlib ? &gztype : NULL),
+#else
+ NULL,
+#endif
+ O_RDONLY, 0,
+ (verbose ? TAR_VERBOSE : 0)
+ | (use_gnu ? TAR_GNU : 0)) == -1)
+ {
+ fprintf(stderr, "tar_open(): %s\n", strerror(errno));
+ return -1;
+ }
+
+ while ((i = th_read(t)) == 0)
+ {
+ th_print_long_ls(t);
+#ifdef DEBUG
+ th_print(t);
+#endif
+ if (TH_ISREG(t) && tar_skip_regfile(t) != 0)
+ {
+ fprintf(stderr, "tar_skip_regfile(): %s\n",
+ strerror(errno));
+ return -1;
+ }
+ }
+
+#ifdef DEBUG
+ printf("th_read() returned %d\n", i);
+ printf("EOF mark encountered after %ld bytes\n",
+# ifdef HAVE_LIBZ
+ (use_zlib
+ ? gzseek((gzFile) t->fd, 0, SEEK_CUR)
+ :
+# endif
+ lseek(t->fd, 0, SEEK_CUR)
+# ifdef HAVE_LIBZ
+ )
+# endif
+ );
+#endif
+
+ if (tar_close(t) != 0)
+ {
+ fprintf(stderr, "tar_close(): %s\n", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int
+extract(char *tarfile, char *rootdir)
+{
+ TAR *t;
+
+#ifdef DEBUG
+ puts("opening tarfile...");
+#endif
+ if (tar_open(&t, tarfile,
+#ifdef HAVE_LIBZ
+ (use_zlib ? &gztype : NULL),
+#else
+ NULL,
+#endif
+ O_RDONLY, 0,
+ (verbose ? TAR_VERBOSE : 0)
+ | (use_gnu ? TAR_GNU : 0)) == -1)
+ {
+ fprintf(stderr, "tar_open(): %s\n", strerror(errno));
+ return -1;
+ }
+
+#ifdef DEBUG
+ puts("extracting tarfile...");
+#endif
+ if (tar_extract_all(t, rootdir) != 0)
+ {
+ fprintf(stderr, "tar_extract_all(): %s\n", strerror(errno));
+ return -1;
+ }
+
+#ifdef DEBUG
+ puts("closing tarfile...");
+#endif
+ if (tar_close(t) != 0)
+ {
+ fprintf(stderr, "tar_close(): %s\n", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void
+usage()
+{
+ printf("Usage: %s [-C rootdir] [-g] [-z] -x|-t filename.tar\n",
+ progname);
+ printf(" %s [-C rootdir] [-g] [-z] -c filename.tar ...\n",
+ progname);
+ exit(-1);
+}
+
+
+#define MODE_LIST 1
+#define MODE_CREATE 2
+#define MODE_EXTRACT 3
+
+int
+main(int argc, char *argv[])
+{
+ char *tarfile = NULL;
+ char *rootdir = NULL;
+ int c;
+ int mode = 0;
+ libtar_list_t *l;
+#ifdef _WIN32
+ int optind;
+#endif
+ progname = basename(argv[0]);
+
+#ifndef _WIN32
+ while ((c = getopt(argc, argv, "cC:gtvVxz")) != -1)
+ switch (c)
+ {
+ case 'V':
+ printf("libtar %s by Mark D. Roth <roth@uiuc.edu>\n",
+ libtar_version);
+ break;
+ case 'C':
+ rootdir = strdup(optarg);
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'g':
+ use_gnu = 1;
+ break;
+ case 'c':
+ if (mode)
+ usage();
+ mode = MODE_CREATE;
+ break;
+ case 'x':
+ if (mode)
+ usage();
+ mode = MODE_EXTRACT;
+ break;
+ case 't':
+ if (mode)
+ usage();
+ mode = MODE_LIST;
+ break;
+#ifdef HAVE_LIBZ
+ case 'z':
+ use_zlib = 1;
+ break;
+#endif /* HAVE_LIBZ */
+ default:
+ usage();
+ }
+ if (!mode || ((argc - optind) < (mode == MODE_CREATE ? 2 : 1)))
+ {
+#ifdef DEBUG
+ printf("argc - optind == %d\tmode == %d\n", argc - optind,
+ mode);
+#endif
+ usage();
+ }
+
+#else
+ mode = MODE_EXTRACT;
+ use_zlib=1;
+ optind = 1;
+#endif
+
+#ifdef DEBUG
+ signal(SIGSEGV, segv_handler);
+#endif
+
+ switch (mode)
+ {
+ case MODE_EXTRACT:
+ return extract(argv[optind], rootdir);
+ case MODE_CREATE:
+ tarfile = argv[optind];
+ l = libtar_list_new(LIST_QUEUE, NULL);
+ for (c = optind + 1; c < argc; c++)
+ libtar_list_add(l, argv[c]);
+ return create(tarfile, rootdir, l);
+ case MODE_LIST:
+ return list(argv[optind]);
+ default:
+ break;
+ }
+
+ /* NOTREACHED */
+ return -2;
+}
+
+
diff --git a/Utilities/cmtar/libtar.h b/Utilities/cmtar/libtar.h
new file mode 100644
index 0000000..ef822ea
--- /dev/null
+++ b/Utilities/cmtar/libtar.h
@@ -0,0 +1,295 @@
+/*
+** 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 <libtar/tar.h>
+
+#include <libtar/libtar_listhash.h>
+#include <libtar/compat.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'
+
+/* 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;
+};
+
+
+/***** 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 */
+
+/* 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)
+
+/* 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);
+
+/* extract different file types */
+int tar_extract_dir(TAR *t, char *realname);
+int tar_extract_hardlink(TAR *t, char *realname);
+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);
+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);
+#define th_crc_ok(t) (th_get_crc(t) == th_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);
+
+
+/***** wrapper.c **********************************************************/
+
+/* extract groups of files */
+int tar_extract_glob(TAR *t, char *globname, char *prefix);
+int tar_extract_all(TAR *t, char *prefix);
+
+/* add a whole tree of files */
+int tar_append_tree(TAR *t, char *realdir, char *savedir);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ! LIBTAR_H */
+
diff --git a/Utilities/cmtar/listhash/hash.c.in b/Utilities/cmtar/listhash/hash.c.in
new file mode 100644
index 0000000..41a1618
--- /dev/null
+++ b/Utilities/cmtar/listhash/hash.c.in
@@ -0,0 +1,344 @@
+/* @configure_input@ */
+
+/*
+** Copyright 1998-2002 University of Illinois Board of Trustees
+** Copyright 1998-2002 Mark D. Roth
+** All rights reserved.
+**
+** @LISTHASH_PREFIX@_hash.c - hash table routines
+**
+** Mark D. Roth <roth@uiuc.edu>
+** Campus Information Technologies and Educational Services
+** University of Illinois at Urbana-Champaign
+*/
+
+#include <@LISTHASH_PREFIX@/config.h>
+#include <@LISTHASH_PREFIX@/compat.h>
+
+#include <@LISTHASH_PREFIX@/@LISTHASH_PREFIX@_listhash.h>
+
+#include <stdio.h>
+#include <errno.h>
+
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+#endif
+
+
+/*
+** @LISTHASH_PREFIX@_hashptr_reset() - reset a hash pointer
+*/
+void
+@LISTHASH_PREFIX@_hashptr_reset(@LISTHASH_PREFIX@_hashptr_t *hp)
+{
+ @LISTHASH_PREFIX@_listptr_reset(&(hp->node));
+ hp->bucket = -1;
+}
+
+
+/*
+** @LISTHASH_PREFIX@_hashptr_data() - retrieve the data being pointed to
+*/
+void *
+@LISTHASH_PREFIX@_hashptr_data(@LISTHASH_PREFIX@_hashptr_t *hp)
+{
+ return @LISTHASH_PREFIX@_listptr_data(&(hp->node));
+}
+
+
+/*
+** @LISTHASH_PREFIX@_str_hashfunc() - default hash function, optimized for
+** 7-bit strings
+*/
+unsigned int
+@LISTHASH_PREFIX@_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
+}
+
+
+/*
+** @LISTHASH_PREFIX@_hash_nents() - return number of elements from hash
+*/
+unsigned int
+@LISTHASH_PREFIX@_hash_nents(@LISTHASH_PREFIX@_hash_t *h)
+{
+ return h->nents;
+}
+
+
+/*
+** @LISTHASH_PREFIX@_hash_new() - create a new hash
+*/
+@LISTHASH_PREFIX@_hash_t *
+@LISTHASH_PREFIX@_hash_new(int num, @LISTHASH_PREFIX@_hashfunc_t hashfunc)
+{
+ @LISTHASH_PREFIX@_hash_t *hash;
+
+ hash = (@LISTHASH_PREFIX@_hash_t *)calloc(1, sizeof(@LISTHASH_PREFIX@_hash_t));
+ if (hash == NULL)
+ return NULL;
+ hash->numbuckets = num;
+ if (hashfunc != NULL)
+ hash->hashfunc = hashfunc;
+ else
+ hash->hashfunc = (@LISTHASH_PREFIX@_hashfunc_t)@LISTHASH_PREFIX@_str_hashfunc;
+
+ hash->table = (@LISTHASH_PREFIX@_list_t **)calloc(num, sizeof(@LISTHASH_PREFIX@_list_t *));
+ if (hash->table == NULL)
+ {
+ free(hash);
+ return NULL;
+ }
+
+ return hash;
+}
+
+
+/*
+** @LISTHASH_PREFIX@_hash_next() - get next element in hash
+** returns:
+** 1 data found
+** 0 end of list
+*/
+int
+@LISTHASH_PREFIX@_hash_next(@LISTHASH_PREFIX@_hash_t *h,
+ @LISTHASH_PREFIX@_hashptr_t *hp)
+{
+#ifdef DS_DEBUG
+ printf("==> @LISTHASH_PREFIX@_hash_next(h=0x%lx, hp={%d,0x%lx})\n",
+ h, hp->bucket, hp->node);
+#endif
+
+ if (hp->bucket >= 0 && hp->node != NULL &&
+ @LISTHASH_PREFIX@_list_next(h->table[hp->bucket], &(hp->node)) != 0)
+ {
+#ifdef DS_DEBUG
+ printf(" @LISTHASH_PREFIX@_hash_next(): found additional "
+ "data in current bucket (%d), returing 1\n",
+ hp->bucket);
+#endif
+ return 1;
+ }
+
+#ifdef DS_DEBUG
+ printf(" @LISTHASH_PREFIX@_hash_next(): done with bucket %d\n",
+ hp->bucket);
+#endif
+
+ for (hp->bucket++; hp->bucket < h->numbuckets; hp->bucket++)
+ {
+#ifdef DS_DEBUG
+ printf(" @LISTHASH_PREFIX@_hash_next(): "
+ "checking bucket %d\n", hp->bucket);
+#endif
+ hp->node = NULL;
+ if (h->table[hp->bucket] != NULL &&
+ @LISTHASH_PREFIX@_list_next(h->table[hp->bucket],
+ &(hp->node)) != 0)
+ {
+#ifdef DS_DEBUG
+ printf(" @LISTHASH_PREFIX@_hash_next(): "
+ "found data in bucket %d, returing 1\n",
+ hp->bucket);
+#endif
+ return 1;
+ }
+ }
+
+ if (hp->bucket == h->numbuckets)
+ {
+#ifdef DS_DEBUG
+ printf(" @LISTHASH_PREFIX@_hash_next(): hash pointer "
+ "wrapped to 0\n");
+#endif
+ hp->bucket = -1;
+ hp->node = NULL;
+ }
+
+#ifdef DS_DEBUG
+ printf("<== @LISTHASH_PREFIX@_hash_next(): no more data, "
+ "returning 0\n");
+#endif
+ return 0;
+}
+
+
+/*
+** @LISTHASH_PREFIX@_hash_del() - delete an entry from the hash
+** returns:
+** 0 success
+** -1 (and sets errno) failure
+*/
+int
+@LISTHASH_PREFIX@_hash_del(@LISTHASH_PREFIX@_hash_t *h,
+ @LISTHASH_PREFIX@_hashptr_t *hp)
+{
+ if (hp->bucket < 0
+ || hp->bucket >= h->numbuckets
+ || h->table[hp->bucket] == NULL
+ || hp->node == NULL)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ @LISTHASH_PREFIX@_list_del(h->table[hp->bucket], &(hp->node));
+ h->nents--;
+ return 0;
+}
+
+
+/*
+** @LISTHASH_PREFIX@_hash_empty() - empty the hash
+*/
+void
+@LISTHASH_PREFIX@_hash_empty(@LISTHASH_PREFIX@_hash_t *h, @LISTHASH_PREFIX@_freefunc_t freefunc)
+{
+ int i;
+
+ for (i = 0; i < h->numbuckets; i++)
+ if (h->table[i] != NULL)
+ @LISTHASH_PREFIX@_list_empty(h->table[i], freefunc);
+
+ h->nents = 0;
+}
+
+
+/*
+** @LISTHASH_PREFIX@_hash_free() - delete all of the nodes in the hash
+*/
+void
+@LISTHASH_PREFIX@_hash_free(@LISTHASH_PREFIX@_hash_t *h, @LISTHASH_PREFIX@_freefunc_t freefunc)
+{
+ int i;
+
+ for (i = 0; i < h->numbuckets; i++)
+ if (h->table[i] != NULL)
+ @LISTHASH_PREFIX@_list_free(h->table[i], freefunc);
+
+ free(h->table);
+ free(h);
+}
+
+
+/*
+** @LISTHASH_PREFIX@_hash_search() - iterative search for an element in a hash
+** returns:
+** 1 match found
+** 0 no match
+*/
+int
+@LISTHASH_PREFIX@_hash_search(@LISTHASH_PREFIX@_hash_t *h,
+ @LISTHASH_PREFIX@_hashptr_t *hp, void *data,
+ @LISTHASH_PREFIX@_matchfunc_t matchfunc)
+{
+ while (@LISTHASH_PREFIX@_hash_next(h, hp) != 0)
+ if ((*matchfunc)(data, @LISTHASH_PREFIX@_listptr_data(&(hp->node))) != 0)
+ return 1;
+
+ return 0;
+}
+
+
+/*
+** @LISTHASH_PREFIX@_hash_getkey() - hash-based search for an element in a hash
+** returns:
+** 1 match found
+** 0 no match
+*/
+int
+@LISTHASH_PREFIX@_hash_getkey(@LISTHASH_PREFIX@_hash_t *h,
+ @LISTHASH_PREFIX@_hashptr_t *hp, void *key,
+ @LISTHASH_PREFIX@_matchfunc_t matchfunc)
+{
+#ifdef DS_DEBUG
+ printf("==> @LISTHASH_PREFIX@_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(" @LISTHASH_PREFIX@_hash_getkey(): hp->bucket "
+ "set to %d\n", hp->bucket);
+#endif
+ }
+
+ if (h->table[hp->bucket] == NULL)
+ {
+#ifdef DS_DEBUG
+ printf(" @LISTHASH_PREFIX@_hash_getkey(): no list "
+ "for bucket %d, returning 0\n", hp->bucket);
+#endif
+ hp->bucket = -1;
+ return 0;
+ }
+
+#ifdef DS_DEBUG
+ printf("<== @LISTHASH_PREFIX@_hash_getkey(): "
+ "returning @LISTHASH_PREFIX@_list_search()\n");
+#endif
+ return @LISTHASH_PREFIX@_list_search(h->table[hp->bucket], &(hp->node),
+ key, matchfunc);
+}
+
+
+/*
+** @LISTHASH_PREFIX@_hash_add() - add an element to the hash
+** returns:
+** 0 success
+** -1 (and sets errno) failure
+*/
+int
+@LISTHASH_PREFIX@_hash_add(@LISTHASH_PREFIX@_hash_t *h, void *data)
+{
+ int bucket, i;
+
+#ifdef DS_DEBUG
+ printf("==> @LISTHASH_PREFIX@_hash_add(h=0x%lx, data=0x%lx)\n",
+ h, data);
+#endif
+
+ bucket = (*(h->hashfunc))(data, h->numbuckets);
+#ifdef DS_DEBUG
+ printf(" @LISTHASH_PREFIX@_hash_add(): inserting in bucket %d\n",
+ bucket);
+#endif
+ if (h->table[bucket] == NULL)
+ {
+#ifdef DS_DEBUG
+ printf(" @LISTHASH_PREFIX@_hash_add(): creating new list\n");
+#endif
+ h->table[bucket] = @LISTHASH_PREFIX@_list_new(LIST_QUEUE, NULL);
+ }
+
+#ifdef DS_DEBUG
+ printf("<== @LISTHASH_PREFIX@_hash_add(): "
+ "returning @LISTHASH_PREFIX@_list_add()\n");
+#endif
+ i = @LISTHASH_PREFIX@_list_add(h->table[bucket], data);
+ if (i == 0)
+ h->nents++;
+ return i;
+}
+
+
diff --git a/Utilities/cmtar/listhash/list.c.in b/Utilities/cmtar/listhash/list.c.in
new file mode 100644
index 0000000..71c5bf6
--- /dev/null
+++ b/Utilities/cmtar/listhash/list.c.in
@@ -0,0 +1,457 @@
+/* @configure_input@ */
+
+/*
+** Copyright 1998-2002 University of Illinois Board of Trustees
+** Copyright 1998-2002 Mark D. Roth
+** All rights reserved.
+**
+** @LISTHASH_PREFIX@_list.c - linked list routines
+**
+** Mark D. Roth <roth@uiuc.edu>
+** Campus Information Technologies and Educational Services
+** University of Illinois at Urbana-Champaign
+*/
+
+#include <@LISTHASH_PREFIX@/config.h>
+#include <@LISTHASH_PREFIX@/compat.h>
+
+#include <@LISTHASH_PREFIX@/@LISTHASH_PREFIX@_listhash.h>
+
+#include <stdio.h>
+#include <errno.h>
+
+#ifdef STDC_HEADERS
+# include <string.h>
+# include <stdlib.h>
+#endif
+
+
+/*
+** @LISTHASH_PREFIX@_listptr_reset() - reset a list pointer
+*/
+void
+@LISTHASH_PREFIX@_listptr_reset(@LISTHASH_PREFIX@_listptr_t *lp)
+{
+ *lp = NULL;
+}
+
+
+/*
+** @LISTHASH_PREFIX@_listptr_data() - retrieve the data pointed to by lp
+*/
+void *
+@LISTHASH_PREFIX@_listptr_data(@LISTHASH_PREFIX@_listptr_t *lp)
+{
+ return (*lp)->data;
+}
+
+
+/*
+** @LISTHASH_PREFIX@_list_new() - create a new, empty list
+*/
+@LISTHASH_PREFIX@_list_t *
+@LISTHASH_PREFIX@_list_new(int flags, @LISTHASH_PREFIX@_cmpfunc_t cmpfunc)
+{
+ @LISTHASH_PREFIX@_list_t *newlist;
+
+#ifdef DS_DEBUG
+ printf("in @LISTHASH_PREFIX@_list_new(%d, 0x%lx)\n", flags, cmpfunc);
+#endif
+
+ if (flags != LIST_USERFUNC
+ && flags != LIST_STACK
+ && flags != LIST_QUEUE)
+ {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ newlist = (@LISTHASH_PREFIX@_list_t *)calloc(1, sizeof(@LISTHASH_PREFIX@_list_t));
+ if (cmpfunc != NULL)
+ newlist->cmpfunc = cmpfunc;
+ else
+ newlist->cmpfunc = (@LISTHASH_PREFIX@_cmpfunc_t)strcmp;
+ newlist->flags = flags;
+
+ return newlist;
+}
+
+
+/*
+** @LISTHASH_PREFIX@_list_iterate() - call a function for every element
+** in a list
+*/
+int
+@LISTHASH_PREFIX@_list_iterate(@LISTHASH_PREFIX@_list_t *l,
+ @LISTHASH_PREFIX@_iterate_func_t plugin,
+ void *state)
+{
+ @LISTHASH_PREFIX@_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;
+}
+
+
+/*
+** @LISTHASH_PREFIX@_list_empty() - empty the list
+*/
+void
+@LISTHASH_PREFIX@_list_empty(@LISTHASH_PREFIX@_list_t *l, @LISTHASH_PREFIX@_freefunc_t freefunc)
+{
+ @LISTHASH_PREFIX@_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;
+}
+
+
+/*
+** @LISTHASH_PREFIX@_list_free() - remove and free() the whole list
+*/
+void
+@LISTHASH_PREFIX@_list_free(@LISTHASH_PREFIX@_list_t *l, @LISTHASH_PREFIX@_freefunc_t freefunc)
+{
+ @LISTHASH_PREFIX@_list_empty(l, freefunc);
+ free(l);
+}
+
+
+/*
+** @LISTHASH_PREFIX@_list_nents() - return number of elements in the list
+*/
+unsigned int
+@LISTHASH_PREFIX@_list_nents(@LISTHASH_PREFIX@_list_t *l)
+{
+ return l->nents;
+}
+
+
+/*
+** @LISTHASH_PREFIX@_list_add() - adds an element to the list
+** returns:
+** 0 success
+** -1 (and sets errno) failure
+*/
+int
+@LISTHASH_PREFIX@_list_add(@LISTHASH_PREFIX@_list_t *l, void *data)
+{
+ @LISTHASH_PREFIX@_listptr_t n, m;
+
+#ifdef DS_DEBUG
+ printf("==> @LISTHASH_PREFIX@_list_add(\"%s\")\n", (char *)data);
+#endif
+
+ n = (@LISTHASH_PREFIX@_listptr_t)malloc(sizeof(struct @LISTHASH_PREFIX@_node));
+ if (n == NULL)
+ return -1;
+ n->data = data;
+ l->nents++;
+
+#ifdef DS_DEBUG
+ printf(" @LISTHASH_PREFIX@_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("<== @LISTHASH_PREFIX@_list_add(): list was empty; "
+ "added first element and returning 0\n");
+#endif
+ return 0;
+ }
+
+#ifdef DS_DEBUG
+ printf(" @LISTHASH_PREFIX@_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("<== @LISTHASH_PREFIX@_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("<== @LISTHASH_PREFIX@_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(" @LISTHASH_PREFIX@_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("<== @LISTHASH_PREFIX@_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("<== @LISTHASH_PREFIX@_list_add(): added middle,"
+ " returning 0\n");
+#endif
+ return 0;
+ }
+
+#ifdef DS_DEBUG
+ printf(" @LISTHASH_PREFIX@_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("<== @LISTHASH_PREFIX@_list_add(): added end, returning 0\n");
+#endif
+ return 0;
+}
+
+
+/*
+** @LISTHASH_PREFIX@_list_del() - remove the element pointed to by n
+** from the list l
+*/
+void
+@LISTHASH_PREFIX@_list_del(@LISTHASH_PREFIX@_list_t *l, @LISTHASH_PREFIX@_listptr_t *n)
+{
+ @LISTHASH_PREFIX@_listptr_t m;
+
+#ifdef DS_DEBUG
+ printf("==> @LISTHASH_PREFIX@_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;
+}
+
+
+/*
+** @LISTHASH_PREFIX@_list_next() - get the next element in the list
+** returns:
+** 1 success
+** 0 end of list
+*/
+int
+@LISTHASH_PREFIX@_list_next(@LISTHASH_PREFIX@_list_t *l,
+ @LISTHASH_PREFIX@_listptr_t *n)
+{
+ if (*n == NULL)
+ *n = l->first;
+ else
+ *n = (*n)->next;
+
+ return (*n != NULL ? 1 : 0);
+}
+
+
+/*
+** @LISTHASH_PREFIX@_list_prev() - get the previous element in the list
+** returns:
+** 1 success
+** 0 end of list
+*/
+int
+@LISTHASH_PREFIX@_list_prev(@LISTHASH_PREFIX@_list_t *l,
+ @LISTHASH_PREFIX@_listptr_t *n)
+{
+ if (*n == NULL)
+ *n = l->last;
+ else
+ *n = (*n)->prev;
+
+ return (*n != NULL ? 1 : 0);
+}
+
+
+/*
+** @LISTHASH_PREFIX@_str_match() - string matching function
+** returns:
+** 1 match
+** 0 no match
+*/
+int
+@LISTHASH_PREFIX@_str_match(char *check, char *data)
+{
+ return !strcmp(check, data);
+}
+
+
+/*
+** @LISTHASH_PREFIX@_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
+@LISTHASH_PREFIX@_list_add_str(@LISTHASH_PREFIX@_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 (@LISTHASH_PREFIX@_list_add(l, strdup(tokp)))
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+** @LISTHASH_PREFIX@_list_search() - find an entry in a list
+** returns:
+** 1 match found
+** 0 no match
+*/
+int
+@LISTHASH_PREFIX@_list_search(@LISTHASH_PREFIX@_list_t *l,
+ @LISTHASH_PREFIX@_listptr_t *n, void *data,
+ @LISTHASH_PREFIX@_matchfunc_t matchfunc)
+{
+#ifdef DS_DEBUG
+ printf("==> @LISTHASH_PREFIX@_list_search(l=0x%lx, n=0x%lx, \"%s\")\n",
+ l, n, (char *)data);
+#endif
+
+ if (matchfunc == NULL)
+ matchfunc = (@LISTHASH_PREFIX@_matchfunc_t)@LISTHASH_PREFIX@_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;
+}
+
+
+/*
+** @LISTHASH_PREFIX@_list_dup() - copy an existing list
+*/
+@LISTHASH_PREFIX@_list_t *
+@LISTHASH_PREFIX@_list_dup(@LISTHASH_PREFIX@_list_t *l)
+{
+ @LISTHASH_PREFIX@_list_t *newlist;
+ @LISTHASH_PREFIX@_listptr_t n;
+
+ newlist = @LISTHASH_PREFIX@_list_new(l->flags, l->cmpfunc);
+ for (n = l->first; n != NULL; n = n->next)
+ @LISTHASH_PREFIX@_list_add(newlist, n->data);
+
+#ifdef DS_DEBUG
+ printf("returning from @LISTHASH_PREFIX@_list_dup()\n");
+#endif
+ return newlist;
+}
+
+
+/*
+** @LISTHASH_PREFIX@_list_merge() - merge two lists into a new list
+*/
+@LISTHASH_PREFIX@_list_t *
+@LISTHASH_PREFIX@_list_merge(@LISTHASH_PREFIX@_cmpfunc_t cmpfunc, int flags,
+ @LISTHASH_PREFIX@_list_t *list1,
+ @LISTHASH_PREFIX@_list_t *list2)
+{
+ @LISTHASH_PREFIX@_list_t *newlist;
+ @LISTHASH_PREFIX@_listptr_t n;
+
+ newlist = @LISTHASH_PREFIX@_list_new(flags, cmpfunc);
+
+ n = NULL;
+ while (@LISTHASH_PREFIX@_list_next(list1, &n) != 0)
+ @LISTHASH_PREFIX@_list_add(newlist, n->data);
+ n = NULL;
+ while (@LISTHASH_PREFIX@_list_next(list2, &n) != 0)
+ @LISTHASH_PREFIX@_list_add(newlist, n->data);
+
+ return newlist;
+}
+
+
diff --git a/Utilities/cmtar/listhash/listhash.h.in b/Utilities/cmtar/listhash/listhash.h.in
new file mode 100644
index 0000000..4ab5fdf
--- /dev/null
+++ b/Utilities/cmtar/listhash/listhash.h.in
@@ -0,0 +1,196 @@
+/* @configure_input@ */
+
+/*
+** Copyright 1998-2002 University of Illinois Board of Trustees
+** Copyright 1998-2002 Mark D. Roth
+** All rights reserved.
+**
+** @LISTHASH_PREFIX@_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 @LISTHASH_PREFIX@_LISTHASH_H
+#define @LISTHASH_PREFIX@_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 (*@LISTHASH_PREFIX@_cmpfunc_t)(void *, void *);
+
+/*
+** Free function (for freeing allocated memory in each element)
+*/
+typedef void (*@LISTHASH_PREFIX@_freefunc_t)(void *);
+
+/*
+** Plugin function for @LISTHASH_PREFIX@_list_iterate()
+*/
+typedef int (*@LISTHASH_PREFIX@_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 (*@LISTHASH_PREFIX@_matchfunc_t)(void *, void *);
+
+
+struct @LISTHASH_PREFIX@_node
+{
+ void *data;
+ struct @LISTHASH_PREFIX@_node *next;
+ struct @LISTHASH_PREFIX@_node *prev;
+};
+typedef struct @LISTHASH_PREFIX@_node *@LISTHASH_PREFIX@_listptr_t;
+
+struct @LISTHASH_PREFIX@_list
+{
+ @LISTHASH_PREFIX@_listptr_t first;
+ @LISTHASH_PREFIX@_listptr_t last;
+ @LISTHASH_PREFIX@_cmpfunc_t cmpfunc;
+ int flags;
+ unsigned int nents;
+};
+typedef struct @LISTHASH_PREFIX@_list @LISTHASH_PREFIX@_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 @LISTHASH_PREFIX@_listptr_reset(@LISTHASH_PREFIX@_listptr_t *);
+
+/* retrieve the data being pointed to */
+void *@LISTHASH_PREFIX@_listptr_data(@LISTHASH_PREFIX@_listptr_t *);
+
+/* creates a new, empty list */
+@LISTHASH_PREFIX@_list_t *@LISTHASH_PREFIX@_list_new(int, @LISTHASH_PREFIX@_cmpfunc_t);
+
+/* call a function for every element in a list */
+int @LISTHASH_PREFIX@_list_iterate(@LISTHASH_PREFIX@_list_t *,
+ @LISTHASH_PREFIX@_iterate_func_t, void *);
+
+/* empty the list */
+void @LISTHASH_PREFIX@_list_empty(@LISTHASH_PREFIX@_list_t *,
+ @LISTHASH_PREFIX@_freefunc_t);
+
+/* remove and free() the entire list */
+void @LISTHASH_PREFIX@_list_free(@LISTHASH_PREFIX@_list_t *,
+ @LISTHASH_PREFIX@_freefunc_t);
+
+/* add elements */
+int @LISTHASH_PREFIX@_list_add(@LISTHASH_PREFIX@_list_t *, void *);
+
+/* removes an element from the list - returns -1 on error */
+void @LISTHASH_PREFIX@_list_del(@LISTHASH_PREFIX@_list_t *,
+ @LISTHASH_PREFIX@_listptr_t *);
+
+/* returns 1 when valid data is returned, or 0 at end of list */
+int @LISTHASH_PREFIX@_list_next(@LISTHASH_PREFIX@_list_t *,
+ @LISTHASH_PREFIX@_listptr_t *);
+
+/* returns 1 when valid data is returned, or 0 at end of list */
+int @LISTHASH_PREFIX@_list_prev(@LISTHASH_PREFIX@_list_t *,
+ @LISTHASH_PREFIX@_listptr_t *);
+
+/* return 1 if the data matches a list entry, 0 otherwise */
+int @LISTHASH_PREFIX@_list_search(@LISTHASH_PREFIX@_list_t *,
+ @LISTHASH_PREFIX@_listptr_t *, void *,
+ @LISTHASH_PREFIX@_matchfunc_t);
+
+/* return number of elements from list */
+unsigned int @LISTHASH_PREFIX@_list_nents(@LISTHASH_PREFIX@_list_t *);
+
+/* adds elements from a string delimited by delim */
+int @LISTHASH_PREFIX@_list_add_str(@LISTHASH_PREFIX@_list_t *, char *, char *);
+
+/* string matching function */
+int @LISTHASH_PREFIX@_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 (*@LISTHASH_PREFIX@_hashfunc_t)(void *, unsigned int);
+
+
+struct @LISTHASH_PREFIX@_hashptr
+{
+ int bucket;
+ @LISTHASH_PREFIX@_listptr_t node;
+};
+typedef struct @LISTHASH_PREFIX@_hashptr @LISTHASH_PREFIX@_hashptr_t;
+
+struct @LISTHASH_PREFIX@_hash
+{
+ int numbuckets;
+ @LISTHASH_PREFIX@_list_t **table;
+ @LISTHASH_PREFIX@_hashfunc_t hashfunc;
+ unsigned int nents;
+};
+typedef struct @LISTHASH_PREFIX@_hash @LISTHASH_PREFIX@_hash_t;
+
+
+/* reset a hash pointer */
+void @LISTHASH_PREFIX@_hashptr_reset(@LISTHASH_PREFIX@_hashptr_t *);
+
+/* retrieve the data being pointed to */
+void *@LISTHASH_PREFIX@_hashptr_data(@LISTHASH_PREFIX@_hashptr_t *);
+
+/* default hash function, optimized for 7-bit strings */
+unsigned int @LISTHASH_PREFIX@_str_hashfunc(char *, unsigned int);
+
+/* return number of elements from hash */
+unsigned int @LISTHASH_PREFIX@_hash_nents(@LISTHASH_PREFIX@_hash_t *);
+
+/* create a new hash */
+@LISTHASH_PREFIX@_hash_t *@LISTHASH_PREFIX@_hash_new(int, @LISTHASH_PREFIX@_hashfunc_t);
+
+/* empty the hash */
+void @LISTHASH_PREFIX@_hash_empty(@LISTHASH_PREFIX@_hash_t *,
+ @LISTHASH_PREFIX@_freefunc_t);
+
+/* delete all the @LISTHASH_PREFIX@_nodes of the hash and clean up */
+void @LISTHASH_PREFIX@_hash_free(@LISTHASH_PREFIX@_hash_t *,
+ @LISTHASH_PREFIX@_freefunc_t);
+
+/* returns 1 when valid data is returned, or 0 at end of list */
+int @LISTHASH_PREFIX@_hash_next(@LISTHASH_PREFIX@_hash_t *,
+ @LISTHASH_PREFIX@_hashptr_t *);
+
+/* return 1 if the data matches a list entry, 0 otherwise */
+int @LISTHASH_PREFIX@_hash_search(@LISTHASH_PREFIX@_hash_t *,
+ @LISTHASH_PREFIX@_hashptr_t *, void *,
+ @LISTHASH_PREFIX@_matchfunc_t);
+
+/* return 1 if the key matches a list entry, 0 otherwise */
+int @LISTHASH_PREFIX@_hash_getkey(@LISTHASH_PREFIX@_hash_t *,
+ @LISTHASH_PREFIX@_hashptr_t *, void *,
+ @LISTHASH_PREFIX@_matchfunc_t);
+
+/* inserting data */
+int @LISTHASH_PREFIX@_hash_add(@LISTHASH_PREFIX@_hash_t *, void *);
+
+/* delete an entry */
+int @LISTHASH_PREFIX@_hash_del(@LISTHASH_PREFIX@_hash_t *,
+ @LISTHASH_PREFIX@_hashptr_t *);
+
+#endif /* ! @LISTHASH_PREFIX@_LISTHASH_H */
+
diff --git a/Utilities/cmtar/output.c b/Utilities/cmtar/output.c
new file mode 100644
index 0000000..5bd69c7
--- /dev/null
+++ b/Utilities/cmtar/output.c
@@ -0,0 +1,145 @@
+/*
+** 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 <libtarint/internal.h>
+
+#include <stdio.h>
+#ifndef WIN32
+#include <pwd.h>
+#include <grp.h>
+#endif
+#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];
+#ifndef WIN32
+ struct passwd *pw;
+ struct group *gr;
+#endif
+ 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);
+#ifndef WIN32
+ pw = getpwuid(uid);
+ if (pw != NULL)
+ strlcpy(username, pw->pw_name, sizeof(username));
+ else
+#endif
+ snprintf(username, sizeof(username), "%d", uid);
+ gid = th_get_gid(t);
+#ifndef WIN32
+ gr = getgrgid(gid);
+ if (gr != NULL)
+ strlcpy(groupname, gr->gr_name, sizeof(groupname));
+ else
+#endif
+ snprintf(groupname, sizeof(groupname), "%d", gid);
+
+ strmode(th_get_mode(t), modestring);
+ printf("%.10s %-8.8s %-8.8s ", modestring, username, groupname);
+
+#ifndef WIN32
+ 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));
+#endif
+
+ 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));
+
+#ifndef _WIN32
+ 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);
+ }
+#endif
+
+ putchar('\n');
+}
+
+
diff --git a/Utilities/cmtar/tar.h b/Utilities/cmtar/tar.h
new file mode 100644
index 0000000..da11c14
--- /dev/null
+++ b/Utilities/cmtar/tar.h
@@ -0,0 +1,71 @@
+/* $NetBSD: tar.h,v 1.4 2003/08/07 09:44:11 agc Exp $ */
+
+/*-
+ * Copyright (c) 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chuck Karish of Mindcraft, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)tar.h 8.2 (Berkeley) 1/4/94
+ */
+
+#ifndef _TAR_H
+#define _TAR_H
+
+#define TMAGIC "ustar" /* ustar and a null */
+#define TMAGLEN 6
+#define TVERSION "00" /* 00 and no null */
+#define TVERSLEN 2
+
+/* Values used in typeflag field */
+#define REGTYPE '0' /* Regular file */
+#define AREGTYPE '\0' /* Regular file */
+#define LNKTYPE '1' /* Link */
+#define SYMTYPE '2' /* Reserved */
+#define CHRTYPE '3' /* Character special */
+#define BLKTYPE '4' /* Block special */
+#define DIRTYPE '5' /* Directory */
+#define FIFOTYPE '6' /* FIFO special */
+#define CONTTYPE '7' /* Reserved */
+
+/* Bits used in the mode field - values in octal */
+#define TSUID 04000 /* Set UID on execution */
+#define TSGID 02000 /* Set GID on execution */
+#define TSVTX 01000 /* Reserved */
+ /* File permissions */
+#define TUREAD 00400 /* Read by owner */
+#define TUWRITE 00200 /* Write by owner */
+#define TUEXEC 00100 /* Execute/Search by owner */
+#define TGREAD 00040 /* Read by group */
+#define TGWRITE 00020 /* Write by group */
+#define TGEXEC 00010 /* Execute/Search by group */
+#define TOREAD 00004 /* Read by other */
+#define TOWRITE 00002 /* Write by other */
+#define TOEXEC 00001 /* Execute/Search by other */
+
+#endif
diff --git a/Utilities/cmtar/util.c b/Utilities/cmtar/util.c
new file mode 100644
index 0000000..007ed93
--- /dev/null
+++ b/Utilities/cmtar/util.c
@@ -0,0 +1,158 @@
+/*
+** 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 <libtarint/internal.h>
+
+#include <stdio.h>
+#include <libtar/compat.h>
+#include <errno.h>
+
+#ifdef STDC_HEADERS
+# include <string.h>
+#endif
+
+#ifdef _MSC_VER
+#include <direct.h>
+#else
+#include <sys/param.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);
+#ifndef _MSC_VER
+ if (mkdir(dst, 0777) == -1)
+#else
+ if (mkdir(dst) == -1)
+#endif
+ {
+ 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;
+}
+
+
+/* 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/Utilities/cmtar/wrapper.c b/Utilities/cmtar/wrapper.c
new file mode 100644
index 0000000..fd80f39
--- /dev/null
+++ b/Utilities/cmtar/wrapper.c
@@ -0,0 +1,183 @@
+/*
+** 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
+*/
+
+#include <libtarint/internal.h>
+
+#include <stdio.h>
+#include <libtar/compat.h>
+#ifdef _MSC_VER
+#include <filesystem.h>
+#else
+#include <sys/param.h>
+#include <dirent.h>
+#endif
+#include <errno.h>
+
+#ifdef HAVE_FNMATCH_H
+#include <fnmatch.h>
+#endif
+
+#ifdef STDC_HEADERS
+# include <string.h>
+#endif
+
+
+int
+tar_extract_glob(TAR *t, char *globname, char *prefix)
+{
+ char *filename;
+ char buf[MAXPATHLEN];
+ int i;
+
+ 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) != 0)
+ return -1;
+ }
+
+ return (i == 1 ? 0 : -1);
+}
+
+
+int
+tar_extract_all(TAR *t, char *prefix)
+{
+ char *filename;
+ char buf[MAXPATHLEN];
+ int i;
+
+#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
+ if (tar_extract_file(t, buf) != 0)
+ return -1;
+ }
+
+ return (i == 1 ? 0 : -1);
+}
+
+
+int
+tar_append_tree(TAR *t, char *realdir, char *savedir)
+{
+ char realpath[MAXPATHLEN];
+ char savepath[MAXPATHLEN];
+#ifndef _MSC_VER
+ struct dirent *dent;
+ DIR *dp;
+#else
+ kwDirEntry * dent;
+ kwDirectory *dp;
+#endif
+ struct stat s;
+
+#ifdef DEBUG
+ printf("==> tar_append_tree(0x%lx, \"%s\", \"%s\")\n",
+ t, realdir, (savedir ? savedir : "[NULL]"));
+#endif
+
+ if (tar_append_file(t, realdir, savedir) != 0)
+ return -1;
+
+#ifdef DEBUG
+ puts(" tar_append_tree(): done with tar_append_file()...");
+#endif
+
+#ifdef _MSC_VER
+ dp = kwOpenDir(realdir);
+#else
+ dp = opendir(realdir);
+#endif
+
+ if (dp == NULL)
+ {
+ if (errno == ENOTDIR)
+ return 0;
+ return -1;
+ }
+#ifdef _MSC_VER
+ while ((dent = kwReadDir(dp)) != NULL)
+#else
+ while ((dent = readdir(dp)) != NULL)
+#endif
+ {
+ if (strcmp(dent->d_name, ".") == 0 ||
+ strcmp(dent->d_name, "..") == 0)
+ continue;
+
+ snprintf(realpath, MAXPATHLEN, "%s/%s", realdir,
+ dent->d_name);
+ if (savedir)
+ snprintf(savepath, MAXPATHLEN, "%s/%s", savedir,
+ dent->d_name);
+
+#ifndef WIN32
+ if (lstat(realpath, &s) != 0)
+ return -1;
+#else
+ if (stat(realpath, &s) != 0)
+ return -1;
+#endif
+ if (S_ISDIR(s.st_mode))
+ {
+ if (tar_append_tree(t, realpath,
+ (savedir ? savepath : NULL)) != 0)
+ return -1;
+ continue;
+ }
+
+ if (tar_append_file(t, realpath,
+ (savedir ? savepath : NULL)) != 0)
+ return -1;
+ }
+
+#ifdef _MSC_VER
+ kwCloseDir(dp);
+#else
+ closedir(dp);
+#endif
+
+ return 0;
+}
+
+