1
0
Andy Cedilnik 20 жил өмнө
parent
commit
bc1548b236
38 өөрчлөгдсөн 7705 нэмэгдсэн , 0 устгасан
  1. 360 0
      Utilities/cmtar/CMakeLists.txt
  2. 35 0
      Utilities/cmtar/COPYRIGHT
  3. 272 0
      Utilities/cmtar/append.c
  4. 384 0
      Utilities/cmtar/block.c
  5. 12 0
      Utilities/cmtar/compat/README
  6. 75 0
      Utilities/cmtar/compat/basename.c
  7. 314 0
      Utilities/cmtar/compat/compat.h
  8. 78 0
      Utilities/cmtar/compat/dirname.c
  9. 237 0
      Utilities/cmtar/compat/fnmatch.c
  10. 41 0
      Utilities/cmtar/compat/gethostbyname_r.c
  11. 36 0
      Utilities/cmtar/compat/gethostname.c
  12. 41 0
      Utilities/cmtar/compat/getservbyname_r.c
  13. 874 0
      Utilities/cmtar/compat/glob.c
  14. 27 0
      Utilities/cmtar/compat/inet_aton.c
  15. 788 0
      Utilities/cmtar/compat/snprintf.c
  16. 62 0
      Utilities/cmtar/compat/strdup.c
  17. 72 0
      Utilities/cmtar/compat/strlcat.c
  18. 68 0
      Utilities/cmtar/compat/strlcpy.c
  19. 185 0
      Utilities/cmtar/compat/strmode.c
  20. 40 0
      Utilities/cmtar/compat/strrstr.c
  21. 87 0
      Utilities/cmtar/compat/strsep.c
  22. 190 0
      Utilities/cmtar/config.h.in
  23. 136 0
      Utilities/cmtar/decode.c
  24. 234 0
      Utilities/cmtar/encode.c
  25. 561 0
      Utilities/cmtar/extract.c
  26. 82 0
      Utilities/cmtar/filesystem.c
  27. 35 0
      Utilities/cmtar/filesystem.h
  28. 136 0
      Utilities/cmtar/handle.c
  29. 17 0
      Utilities/cmtar/internal.h
  30. 377 0
      Utilities/cmtar/libtar.c
  31. 295 0
      Utilities/cmtar/libtar.h
  32. 344 0
      Utilities/cmtar/listhash/hash.c.in
  33. 457 0
      Utilities/cmtar/listhash/list.c.in
  34. 196 0
      Utilities/cmtar/listhash/listhash.h.in
  35. 145 0
      Utilities/cmtar/output.c
  36. 71 0
      Utilities/cmtar/tar.h
  37. 158 0
      Utilities/cmtar/util.c
  38. 183 0
      Utilities/cmtar/wrapper.c

+ 360 - 0
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})
+

+ 35 - 0
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.
+

+ 272 - 0
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 <[email protected]>
+**  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;
+}
+
+

+ 384 - 0
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 <[email protected]>
+**  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;
+}
+
+

+ 12 - 0
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.
+

+ 75 - 0
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 <[email protected]>
+ * 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);
+}

+ 314 - 0
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

+ 78 - 0
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 <[email protected]>
+ * 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);
+}

+ 237 - 0
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 ([email protected])
+   */
+  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);
+}

+ 41 - 0
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 <[email protected]>
+**  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 */
+}
+
+

+ 36 - 0
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 <[email protected]>
+ * 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);
+}
+

+ 41 - 0
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 <[email protected]>
+**  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 */
+}
+
+

+ 874 - 0
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

+ 27 - 0
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 <[email protected]>
+**  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;
+}
+
+

+ 788 - 0
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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 01/27/98 for mutt 0.89i
+ *    The PGP code was using unsigned hexadecimal formats. 
+ *    Unfortunately, unsigned formats simply didn't work.
+ *
+ *  Michael Elkins <[email protected]> 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 */

+ 62 - 0
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);
+}

+ 72 - 0
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 <[email protected]>
+ * 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 */
+}

+ 68 - 0
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 <[email protected]>
+ * 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 */
+}

+ 185 - 0
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';
+}

+ 40 - 0
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 <[email protected]>
+**  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;
+}
+
+

+ 87 - 0
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 */

+ 190 - 0
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@

+ 136 - 0
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 <[email protected]>
+**  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;
+}
+
+

+ 234 - 0
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 <[email protected]>
+**  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);
+}
+
+

+ 561 - 0
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 <[email protected]>
+**  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;
+}
+
+

+ 82 - 0
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

+ 35 - 0
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

+ 136 - 0
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 <[email protected]>
+**  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;
+}
+
+

+ 17 - 0
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 <[email protected]>
+**  Campus Information Technologies and Educational Services
+**  University of Illinois at Urbana-Champaign
+*/
+
+#include <libtar/config.h>
+#include <libtar/compat.h>
+
+#include <libtar/libtar.h>
+

+ 377 - 0
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 <[email protected]>
+**  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 <[email protected]>\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;
+}
+
+

+ 295 - 0
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 <[email protected]>
+**  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 */
+

+ 344 - 0
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 <[email protected]>
+**  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;
+}
+
+

+ 457 - 0
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 <[email protected]>
+**  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;
+}
+
+

+ 196 - 0
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 <[email protected]>
+**  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 */
+

+ 145 - 0
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 <[email protected]>
+**  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');
+}
+
+

+ 71 - 0
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

+ 158 - 0
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 <[email protected]>
+**  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] = ' ';
+}
+
+

+ 183 - 0
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 <[email protected]>
+**  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;
+}
+
+