chpathtool: switch from C to Python version
authorFabian Groffen <grobian@gentoo.org>
Thu, 9 Feb 2012 07:58:56 +0000 (08:58 +0100)
committerFabian Groffen <grobian@gentoo.org>
Thu, 9 Feb 2012 07:58:56 +0000 (08:58 +0100)
To resolve bug #402413, use master's Python implementation of
chpathtool.  Removed the C implementation, which makes the need for
configure a lot less.

Makefile.am
bin/chpathtool.py
configure.in
man/chpathtool.5 [deleted file]
pym/_emerge/Binpkg.py
src/Makefile.am [deleted file]
src/bsd-flags/Makefile.in [deleted file]
src/chpathtool.c [deleted file]

index 1d7c2430df11563362ab98004eb41d93d41477ab..aef9678dbb888adc8f9c60beb28a2b2533e2a33a 100644 (file)
@@ -1,6 +1,6 @@
 SHELL = @PORTAGE_BASH@
 
-SUBDIRS = src man bin pym cnf
+SUBDIRS = man bin pym cnf
 
 AUTOMAKE_OPTIONS = dist-bzip2 no-dist-gzip
 
index d0d49cb6d79150688bc582dfc1d7f711150411fd..1ae4e7c1934137806d70f06f0f95c0657b614d55 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!@PREFIX_PORTAGE_PYTHON@
 # Copyright 2011 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
 
index 5b909be8dfd75dfd5d719569813e52193b0f6ae2..d18e59e94bf8fe0df45e9df7b3b4b3769fca4178 100644 (file)
@@ -45,108 +45,6 @@ GENTOO_PATH_GNUPROG(PORTAGE_FIND, [find])
 GENTOO_PATH_GNUPROG(PORTAGE_XARGS, [xargs])
 GENTOO_PATH_GNUPROG(PORTAGE_GREP, [grep])
 
-dnl Checks for header files.
-AC_CHECK_HEADERS([string.h strings.h errno.h unistd.h stdio.h stdlib.h])
-AC_CHECK_HEADERS([sys/stat.h sys/types.h dirent.h sys/time.h alloca.h])
-AC_CHECK_HEADERS([fcntl.h])
-AC_CHECK_HEADERS([utime.h])
-
-AC_SEARCH_LIBS([readdir], [c])
-AC_SEARCH_LIBS([strcpy], [c])
-AC_SEARCH_LIBS([strstr], [c])
-AC_SEARCH_LIBS([memcpy], [c])
-AC_CHECK_FUNCS([utimes])
-
-AC_MSG_CHECKING([for the *time fields in struct stat])
-AC_TRY_LINK([
-                        #include <sys/types.h>
-                        #include <sys/stat.h>
-                        #ifdef HAVE_FCNTL_H
-                        #include <fcntl.h>
-                        #endif
-                ], [
-                        struct stat s;
-                        s.st_atimespec.tv_sec = 0;
-                        s.st_mtimespec.tv_sec = 0;
-                ], [
-                        AC_DEFINE(ATIME_SEC, st_atimespec.tv_sec, [atime seconds for this platform])
-                        AC_DEFINE(ATIME_NSEC, st_atimespec.tv_nsec, [atime nanoseconds for this platform])
-                        AC_DEFINE(MTIME_SEC, st_mtimespec.tv_sec, [mtime seconds for this platform])
-                        AC_DEFINE(MTIME_NSEC, st_mtimespec.tv_nsec, [mtime nanoseconds for this platform])
-                        AC_MSG_RESULT([st_*timespec])
-                ], [
-AC_TRY_LINK([
-                        #include <sys/types.h>
-                        #include <sys/stat.h>
-                        #ifdef HAVE_FCNTL_H
-                        #include <fcntl.h>
-                        #endif
-                ], [
-                        struct stat s;
-                        s.st_atim.tv_sec = 0;
-                        s.st_mtim.tv_sec = 0;
-                ], [
-                        AC_DEFINE(ATIME_SEC, st_atim.tv_sec, [atime seconds for this platform])
-                        AC_DEFINE(ATIME_NSEC, st_atim.tv_nsec, [atime nanoseconds for this platform])
-                        AC_DEFINE(MTIME_SEC, st_mtim.tv_sec, [mtime seconds for this platform])
-                        AC_DEFINE(MTIME_NSEC, st_mtim.tv_nsec, [mtime nanoseconds for this platform])
-                        AC_MSG_RESULT([st_*tim])
-                ], [
-AC_TRY_LINK([
-                        #include <sys/types.h>
-                        #include <sys/stat.h>
-                        #ifdef HAVE_FCNTL_H
-                        #include <fcntl.h>
-                        #endif
-                ], [
-                        struct stat s;
-                        s.st_atime = 0;
-                        s.st_mtime = 0;
-                ], [
-                        AC_DEFINE(ATIME_SEC, st_atime, [atime seconds for this platform])
-                        AC_DEFINE(MTIME_SEC, st_mtime, [mtime seconds for this platform])
-                        AC_MSG_RESULT([st_*time])
-                ], [
-                       AC_MSG_ERROR([cannot determine])
-                ]
-)
-                ]
-)
-                ]
-)
-
-AC_MSG_CHECKING([if S_ISWHT can be used])
-AC_TRY_LINK([
-                        #include <sys/types.h>
-                        #include <sys/stat.h>
-                        #ifdef HAVE_FCNTL_H
-                        #include <fcntl.h>
-                        #endif
-                ], [
-                        struct stat s;
-                        if (S_ISWHT(s.st_mode)) {}
-                ], [
-                        AC_DEFINE(HAVE_S_ISWHT, 1, [defined when S_ISWHT exists])
-                        AC_MSG_RESULT([yes])
-                ], [
-                        AC_MSG_RESULT([no])
-                ]
-)
-
-AC_MSG_CHECKING([if lchown exists])
-AC_TRY_LINK([
-                        #include <sys/types.h>
-                        #include <unistd.h>
-                ], [
-                        lchown("", -1, -1);
-                ], [
-                        AC_DEFINE(HAVE_LCHOWN, 1, [defined when LCHOWN exists])
-                        AC_MSG_RESULT([yes])
-                ], [
-                        AC_MSG_RESULT([no])
-                ]
-)
-
 AC_ARG_WITH(portage-user,
 AC_HELP_STRING([--with-portage-user=myuser],[use user 'myuser' as portage owner (default portage)]),
 [case "${withval}" in
@@ -233,7 +131,6 @@ AC_SUBST(PORTAGE_GREP)
 AC_CONFIG_FILES([subst-install], [chmod +x subst-install])
 AC_CONFIG_FILES([
                                 Makefile
-                                src/Makefile
                                 man/Makefile
                                 bin/Makefile
                                 pym/Makefile
diff --git a/man/chpathtool.5 b/man/chpathtool.5
deleted file mode 100644 (file)
index ce6dbcf..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-.TH "CHPATHTOOL" "5" "May 2011" "Portage 2.2-prefix" "Portage"
-.SH NAME
-chpathtool \- changes paths inside files
-.SH SYNOPSIS
-.B chpathtool
-.R [-q]
-.I in-file
-.I out-file
-.I magic
-.I value
-.SH DESCRIPTION
-.B chpathtool
-is an application that changes occurences of
-.I magic
-into
-.I value
-for the given
-.I in-file
-and writes the modified file as
-.IR outfile ".
-.RB "The important difference of " chpathtool " when compared to e.g.
-.BR sed "(1)
-is that for the strings it replaces, it maintains the original string
-.RI "length of " magic " by prepending as much '/'-characters as needed
-.RI "to the " value " string to match the size of " magic " for binary files."
-.P
-.RB "For efficiency, " chpathtool " will operate recursively if
-.IR in-file " is a directory.  In that case, " out-file " is assumed
-to be a directory as well.  Best efforts are made to retain the
-properties of the original file in the output file.  Currently,
-.BR chpathtool " sets permissions, ownership and modification times.
-.P
-.BR chpathtool " is meant for the Prefix branch of Portage to relocate
-packages from one prefix offset to another.  This ability allows for the
-use of binary packages, even though built for a different offset prefix.
-.P
-.RB "When " chpathtool " has found a match inside a binary file,
-it simply uses the replacement string which has been prepended with as
-many '/'-characters as necessary to match the size of the to be replaced
-string.  This strategy makes an awkward but correct path on UNIX
-systems, and has the advantage of being as long as the original path.
-This is in particular important for binary files that may store
-information about the original string.  An example is C-code where the
-optimizer replaced a strlen(static_path_var) with the actual length of
-that string.  The strings cannot be just shortened also because in
-binaries typically offsets are used to find relevant pieces of data.
-Changing the size here would break those offsets.
-.P
-For text files, it avoids adding many '/'-characters because the
-previously mentioned string length problem is typically is not going to
-be a problem.  Here,
-.B chpathtool
-replaces
-the string, and searches for the end of the string in the form of a
-zero-byte ('\\0').  At this byte, the neccessary padding bytes are
-inserted, such that the file internally doesn't change in size, if it
-happens to have zero-bytes in it.  It is to be expected that for text
-files, this zero-byte is never found, and
-.BR "chpathtool " will " not "
-write out the padding zero-bytes, and produce a warning about this
-instead.
-.P
-.RB "Because " chpathtool " attempts not to change the internal file
-.RI "structure, it can only operate if the length of " value " is not
-.RI "greater than the length of " magic ".
-.SH OPTIONS
-.TP
-.B -q
-Suppress messages about padding bytes which could not be written.
-.SH EXAMPLES
-.B chpathtool
-/var/tmp/my/old/prefix /var/tmp/new/prefix "/my/old/prefix" "/new/prefix"
-.SH "REPORTING BUGS"
-Please report bugs via http://bugs.gentoo.org/
-.SH AUTHORS
-Fabian Groffen <grobian@gentoo.org>
index e6e2e21d5f78f4e0288375255c1d5c2ddf25f924..6c70b19f0fc6aa57f823f9a9856ec84342168ee9 100644 (file)
@@ -5,7 +5,6 @@ from _emerge.EbuildPhase import EbuildPhase
 from _emerge.BinpkgFetcher import BinpkgFetcher
 from _emerge.BinpkgEnvExtractor import BinpkgEnvExtractor
 from _emerge.BinpkgExtractorAsync import BinpkgExtractorAsync
-from _emerge.BinpkgChpathtoolAsync import BinpkgChpathtoolAsync
 from _emerge.CompositeTask import CompositeTask
 from _emerge.BinpkgVerifier import BinpkgVerifier
 from _emerge.EbuildMerge import EbuildMerge
@@ -23,7 +22,6 @@ import io
 import logging
 import textwrap
 from portage.output import colorize
-from portage.const import EPREFIX
 
 class Binpkg(CompositeTask):
 
@@ -52,7 +50,6 @@ class Binpkg(CompositeTask):
                dir_path = os.path.join(os.path.realpath(settings["PORTAGE_TMPDIR"]),
                        "portage", pkg.category, pkg.pf)
                self._image_dir = os.path.join(dir_path, "image")
-               self._work_dir = os.path.join(dir_path, "work")
                self._infloc = os.path.join(dir_path, "build-info")
                self._ebuild_path = os.path.join(self._infloc, pkg.pf + ".ebuild")
                settings["EBUILD"] = self._ebuild_path
@@ -225,7 +222,7 @@ class Binpkg(CompositeTask):
                pkg_path = self._pkg_path
 
                dir_mode = 0o755
-               for mydir in (dir_path, self._image_dir, self._work_dir, infloc):
+               for mydir in (dir_path, self._image_dir, infloc):
                        portage.util.ensure_dirs(mydir, uid=portage.data.portage_uid,
                                gid=portage.data.portage_gid, mode=dir_mode)
 
@@ -270,25 +267,6 @@ class Binpkg(CompositeTask):
                finally:
                        f.close()
 
-               # PREFIX LOCAL: deal with EPREFIX from binpkg
-               # Retrieve the EPREFIX this package was built with
-               self._build_prefix = pkg_xpak.getfile(_unicode_encode("EPREFIX",
-                       encoding=_encodings['repo.content']))
-               if not self._buil_dprefix:
-                       self._build_prefix = ''
-               else:
-                       self._build_prefix = self._build_prefix.strip()
-               # We want to install in "our" prefix, not the binary one
-               self.settings["EPREFIX"] = EPREFIX
-               f = io.open(_unicode_encode(os.path.join(infloc, 'EPREFIX'),
-                       encoding=_encodings['fs'], errors='strict'),
-                       mode='w', encoding=_encodings['content'], errors='strict')
-               try:
-                       f.write(_unicode_decode(EPREFIX + "\n"))
-               finally:
-                       f.close()
-               # END PREFIX LOCAL
-
                env_extractor = BinpkgEnvExtractor(background=self.background,
                        scheduler=self.scheduler, settings=self.settings)
 
@@ -314,18 +292,9 @@ class Binpkg(CompositeTask):
                        self.wait()
                        return
 
-               # PREFIX LOCAL:
-               # if the prefix differs, we copy it to the image after
-               # extraction using chpathtool
-               if (self._build_prefix != EPREFIX):
-                       pkgloc = self._work_dir
-               else:
-                       pkgloc = self._image_dir
-               # END PREFIX LOCAL
-
                extractor = BinpkgExtractorAsync(background=self.background,
                        env=self.settings.environ(),
-                       image_dir=pkgloc,
+                       image_dir=self._image_dir,
                        pkg=self.pkg, pkg_path=self._pkg_path,
                        logfile=self.settings.get("PORTAGE_LOG_FILE"),
                        scheduler=self.scheduler)
@@ -340,17 +309,30 @@ class Binpkg(CompositeTask):
                        self.wait()
                        return
 
-               # PREFIX LOCAL: use chpathtool binary
-               if self._build_prefix != EPREFIX:
-                       chpathtool = BinpkgChpathtoolAsync(background=self.background,
-                               image_dir=self._image_dir, work_dir=self._work_dir,
-                               buildprefix=self._build_prefix, eprefix=EPREFIX,
-                               pkg=self.pkg, scheduler=self.scheduler)
-                       self._writemsg_level(">>> Adjusting Prefix to %s\n" % EPREFIX)
-                       self._start_task(chpathtool, self._chpathtool_exit)
-               else:
+               try:
+                       with io.open(_unicode_encode(os.path.join(self._infloc, "EPREFIX"),
+                               encoding=_encodings['fs'], errors='strict'), mode='r',
+                               encoding=_encodings['repo.content'], errors='replace') as f:
+                               self._build_prefix = f.read().rstrip('\n')
+               except IOError:
+                       self._build_prefix = ""
+
+               if self._build_prefix == self.settings["EPREFIX"]:
+                       ensure_dirs(self.settings["ED"])
+                       self._current_task = None
+                       self.returncode = os.EX_OK
                        self.wait()
-               # END PREFIX LOCAL
+                       return
+
+               chpathtool = SpawnProcess(
+                       args=[portage._python_interpreter,
+                       os.path.join(self.settings["PORTAGE_BIN_PATH"], "chpathtool.py"),
+                       self.settings["D"], self._build_prefix, self.settings["EPREFIX"]],
+                       background=self.background, env=self.settings.environ(), 
+                       scheduler=self.scheduler,
+                       logfile=self.settings.get('PORTAGE_LOG_FILE'))
+               self._writemsg_level(">>> Adjusting Prefix to %s\n" % self.settings["EPREFIX"])
+               self._start_task(chpathtool, self._chpathtool_exit)
 
        def _chpathtool_exit(self, chpathtool):
                if self._final_exit(chpathtool) != os.EX_OK:
@@ -361,6 +343,27 @@ class Binpkg(CompositeTask):
                        self.wait()
                        return
 
+               # We want to install in "our" prefix, not the binary one
+               with io.open(_unicode_encode(os.path.join(self._infloc, "EPREFIX"),
+                       encoding=_encodings['fs'], errors='strict'), mode='w',
+                       encoding=_encodings['repo.content'], errors='strict') as f:
+                       f.write(self.settings["EPREFIX"] + "\n")
+
+               # Move the files to the correct location for merge.
+               image_tmp_dir = os.path.join(
+                       self.settings["PORTAGE_BUILDDIR"], "image_tmp")
+               build_d = os.path.join(self.settings["D"],
+                       self._build_prefix.lstrip(os.sep))
+               if not os.path.isdir(build_d):
+                       # Assume this is a virtual package or something.
+                       shutil.rmtree(self._image_dir)
+                       ensure_dirs(self.settings["ED"])
+               else:
+                       os.rename(build_d, image_tmp_dir)
+                       shutil.rmtree(self._image_dir)
+                       ensure_dirs(os.path.dirname(self.settings["ED"].rstrip(os.sep)))
+                       os.rename(image_tmp_dir, self.settings["ED"])
+
                self.wait()
 
        def _unlock_builddir(self):
diff --git a/src/Makefile.am b/src/Makefile.am
deleted file mode 100644 (file)
index 0d5151f..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-SHELL = @PORTAGE_BASH@
-
-SUBDIRS        =
-
-bin_PROGRAMS   = chpathtool
-bindir = @PORTAGE_BASE@/bin
-
-chpathtool_SOURCES = chpathtool.c
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/src/bsd-flags/Makefile.in b/src/bsd-flags/Makefile.in
deleted file mode 100644 (file)
index b126e4e..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-srcdir = @srcdir@
-abs_builddir = @abs_builddir@
-abs_srcdir = @abs_srcdir@
-
-INSTALL        = @INSTALL@
-
-DISTFILES =    setup.py        \
-               Makefile.in     \
-               PKG-INFO        \
-               README          \
-               missingos.c     \
-               setup.cfg       \
-               ChangeLog       
-
-all: builddir
-       setup.py build
-
-builddir:
-       test "${abs_builddir}" != "${abs_srcdir}" \
-       && for x in $(DISTFILES) \
-        ; do $(INSTALL) ${abs_srcdir}/$${x} ${abs_builddir}/$${x} \
-        ; done
-
-clean-builddir:
-       if test "${abs_builddir}" != "${abs_srcdir}" \
-        ; then for x in $(DISTFILES) \
-             ; do rm -f ${abs_builddir}/$${x} \
-             ; done \
-        ; fi
-
-install: builddir
-       setup.py install --root $(DESTDIR)/
-
-distdir:
-       for x in $(DISTFILES); do \
-               $(INSTALL) -D ${srcdir}/$${x} $(distdir)/$${x}; \
-       done
-       chmod 755 $(distdir)/setup.py
-
-distclean: clean-builddir
-
-clean maintainer-clean:
-.PHONY:        all install distdir builddir
-.PHONY: distclean clean maintainer-clean clean-builddir
-
diff --git a/src/chpathtool.c b/src/chpathtool.c
deleted file mode 100644 (file)
index 7a74567..0000000
+++ /dev/null
@@ -1,530 +0,0 @@
-/* Copyright Gentoo Foundation 2006-2010
- * Author: Fabian Groffen <grobian@gentoo.org>
- *
- * chpathtool replaces a given string (magic) into another (value),
- * thereby paying attention to the original size of magic in order not
- * to change offsets in the file changed.  To achieve this goal, value
- * may not be greater in size than magic, and for binary files, the
- * difference in size between the two is compensated by prepending
- * '/'-characters to value uptil it matches the size of magic.  For text
- * files magic is just replaced with value, with the additional logic
- * that the end of a string is considered to be at the first NULL-byte
- * encountered after magic.  If no such NULL-byte is found, the padding
- * NULL-bytes are silently dropped.  Since this is done on text files,
- * this is likely the case.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <dirent.h>
-#include <unistd.h>
-#ifdef HAVE_ALLOCA_H
-#include <alloca.h>
-#endif
-#ifdef HAVE_UTIME_H
-#include <utime.h>
-#endif
-#include <sys/time.h>
-#include <fcntl.h>
-
-/* Don't allocate too much, or you'll be paying for waiting on IO,
- * size -1 to align in memory. */
-#define BUFSIZE 8095
-/* POSIX says 256 on this one, but I can hardly believe that really is
- * the limit of most popular systems.  XOPEN says 1024, taking that
- * value, hoping it is enough */
-#define MAX_PATH 1024
-
-/* structure to track and trace hardlinks */
-typedef struct _file_hlink {
-       dev_t    st_dev;            /* device inode resides on */
-       ino_t    st_ino;            /* inode's number */
-       char     path[MAX_PATH];    /* the file's path + name */
-       struct _file_hlink* next;   /* pointer to the next in the list */
-} file_hlink;
-
-static char *magic;
-static char *value;
-static size_t magiclen;
-static size_t valuelen;
-static char quiet;
-static file_hlink *hlinks = NULL;
-
-/**
- * Writes padding zero-bytes after the first encountered zero-byte.
- * Returns padding if no zero-byte was seen, or 0 if padding was
- * applied.
- */
-static size_t padonwrite(size_t padding, char *buf, size_t len, FILE *fout) {
-       char *z;
-       if (padding == 0 || (z = memchr(buf, '\0', len)) == NULL) {
-               /* cheap case, nothing complicated to do here */
-               fwrite(buf, len, 1, fout);
-       } else {
-               /* found a zero-byte, insert padding */
-               fwrite(buf, z - buf, 1, fout);
-               /* now pad with zeros so we don't screw up
-                * the positions in the file */
-               buf[0] = '\0';
-               while (padding > 0) {
-                       fwrite(buf, 1, 1, fout);
-                       padding--;
-               }
-               fwrite(z, len - (z - buf), 1, fout);
-       }
-
-       return(padding);
-}
-
-/**
- * Searches buf for an occurrence of needle, doing a byte-based match,
- * disregarding end of string markers (zero-bytes), as strstr does.
- * Returns a pointer to the first occurrence of needle in buf, or NULL
- * if not found.  If a partial match is found at the end of the buffer
- * (size < strlen(needle)) it is returned as well.
- */
-static char *memstr(const char *buf, const char *needle, size_t len) {
-       const char *ret;
-       size_t off;
-       for (ret = buf; ret - buf < len; ret++) {
-               off = 0;
-               while (needle[off] != '\0' &&
-                               (ret - buf) + off < len &&
-                               needle[off] == ret[off])
-               {
-                       off++;
-               }
-               if (needle[off] == '\0' || (ret - buf) + off == len)
-                       return((char *)ret);
-       }
-       return(NULL);
-}
-
-/**
- * Copies the given file to the output file with prefix transformations
- * on the fly.
- */
-static int chpath(const char *fi, const char *fo) {
-       FILE *fin;
-       FILE *fout;
-       size_t len;
-       size_t pos;
-       size_t padding;
-       char *tmp;
-       char buf[BUFSIZE + 1];
-       char firstblock;
-       char *lvalue = value;
-       size_t lvaluelen = valuelen;
-
-       /* make sure there is a trailing zero-byte, such that strstr and
-        * strchr won't go out of bounds causing segfaults.  */
-       buf[BUFSIZE] = '\0';
-
-       fin  = fopen(fi, "r");
-       if (fin == NULL) {
-               fprintf(stderr, "unable to open %s: %s\n", fi, strerror(errno));
-               return(-1);
-       }
-       fout = fopen(fo, "w");
-       if (fout == NULL) {
-               fprintf(stderr, "unable to open %s: %s\n", fo, strerror(errno));
-               return(-1);
-       }
-
-       pos = 0;
-       padding = 0;
-       firstblock = 1;
-       while ((len = fread(buf + pos, 1, BUFSIZE - pos, fin)) != 0 || pos > 0) {
-               if (firstblock == 1) {
-                       firstblock = 0;
-                       /* examine the bytes we read to judge if they are binary or
-                        * text; in case of the latter we can avoid writing ugly
-                        * paths with zilions of slashes */
-                       for (pos = 0; pos < len; pos++) {
-                               /* this is a very stupid assumption, but I don't know
-                                * anything better: if we find a byte that's out of
-                                * ASCII character scope, we assume this is binary */
-                               if ((buf[pos] < ' ' || buf[pos] > '~') &&
-                                               strchr("\t\r\n", buf[pos]) == NULL)
-                               {
-                                       /* Make sure we don't mess up code, GCC for instance
-                                        * hardcodes the result of strlen("string") in
-                                        * object code.  This means we can nicely replace
-                                        * this string with a shorter NULL-terminated one,
-                                        * but that won't change the hardcoded output of the
-                                        * original strlen.  Hence, pad the value with
-                                        * slashes until it is of same size as magic. */
-                                       lvalue = alloca(sizeof(char) * (magiclen + 1));
-                                       lvaluelen = magiclen;
-                                       snprintf(lvalue, lvaluelen + 1, "%*s",
-                                                       (int)magiclen, value);
-                                       tmp = lvalue;
-                                       while (*tmp == ' ')
-                                               *tmp++ = '/';
-                                       break;
-                               }
-                       }
-                       pos = 0;
-               }
-               len += pos;
-               if ((tmp = memstr(buf, magic, len)) != NULL) {
-                       /* if binary : */
-                       if (tmp == buf) {
-                               if (len < magiclen) {
-                                       /* must be last piece */
-                                       padding = padonwrite(padding, buf, len, fout);
-                                       break;
-                               }
-                               /* do some magic, overwrite it basically */
-                               fwrite(lvalue, lvaluelen, 1, fout);
-                               /* store what we need to correct */
-                               padding += magiclen - lvaluelen;
-                               /* move away the magic */
-                               pos = len - magiclen;
-                               memmove(buf, buf + magiclen, pos);
-                               continue;
-                       } else {
-                               /* move this bunch to the front */
-                               pos = len - (tmp - buf);
-                       }
-               } else {
-                       /* magic is not in here, since memchr also returns a match
-                        * if incomplete but at the end of the string, here we can
-                        * always read a new block. */
-                       if (len != BUFSIZE) {
-                               /* last piece */
-                               padding = padonwrite(padding, buf, len, fout);
-                               break;
-                       } else {
-                               pos = 0;
-                               tmp = buf + len;
-                       }
-               }
-               padding = padonwrite(padding, buf, len - pos, fout);
-               if (pos > 0)
-                       memmove(buf, tmp, pos);
-       }
-       fflush(fout);
-       fclose(fout);
-       fclose(fin);
-
-       if (padding != 0 && quiet == 0) {
-               fprintf(stdout, "warning: couldn't find a location to write "
-                               "%zd padding bytes in %s\n", padding, fo);
-       }
-
-       return(0);
-}
-
-int dirwalk(char *src, char *srcp, char *trg, char *trgp) {
-       DIR *d;
-       struct dirent *de;
-       struct stat s;
-       struct timeval times[2];
-#ifndef HAVE_UTIMES
-       struct utimbuf ub;
-#endif
-       char *st;
-       char *tt;
-
-       if (lstat(trg, &s) != 0) {
-               /* initially create directory read/writable by owner, set
-                * permissions like src when we're done processing this
-                * directory. */
-               if (mkdir(trg, S_IRWXU) != 0) {
-                       fprintf(stderr, "failed to create directory %s: %s\n",
-                                       trg, strerror(errno));
-                       return(-1);
-               }
-       } else {
-               fprintf(stderr, "directory already exists: %s\n", trg);
-               return(-1);
-       }
-
-       if ((d = opendir(src)) == NULL) {
-               fprintf(stderr, "cannot read directory %s: %s\n", src, strerror(errno));
-               return(-1);
-       }
-       /* store the end of the string pointer */
-       st = srcp;
-       tt = trgp;
-       while ((de = readdir(d)) != NULL) {
-               if (strcmp(de->d_name, "..") == 0 || strcmp(de->d_name, ".") == 0)
-                       continue;
-
-               *st = '/';
-               strcpy(st + 1, de->d_name);
-               *tt = '/';
-               strcpy(tt + 1, de->d_name);
-               st += 1 + strlen(de->d_name);
-               tt += 1 + strlen(de->d_name);
-
-               if (lstat(src, &s) != 0) {
-                       fprintf(stderr, "cannot stat %s: %s\n", src, strerror(errno));
-                       closedir(d);
-                       return(-1);
-               }
-               if (
-                               S_ISBLK(s.st_mode) ||
-                               S_ISCHR(s.st_mode) ||
-                               S_ISFIFO(s.st_mode) ||
-#ifdef HAVE_S_ISWHT
-                               S_ISWHT(s.st_mode) ||
-#endif
-                               S_ISSOCK(s.st_mode)
-                  )
-               {
-                       fprintf(stderr, "missing implementation for copying "
-                                       "object %s\n", src);
-                       closedir(d);
-                       return(-1);
-               } else if (
-                               S_ISDIR(s.st_mode)
-                               )
-               {
-                       /* recurse */
-                       if (dirwalk(src, st, trg, tt) != 0)
-                               return(-1);
-               } else if (
-                               S_ISREG(s.st_mode)
-                               )
-               {
-                       /* handle hard links, match each of them to a list of known
-                        * files (with st_nlink > 1), such that we only process each
-                        * file once, and are able to restore the hard link. */
-                       if (s.st_nlink > 1) {
-                               if (hlinks == NULL) {
-                                       hlinks = malloc(sizeof(file_hlink));
-                                       hlinks->st_dev = s.st_dev;
-                                       hlinks->st_ino = s.st_ino;
-                                       strcpy(hlinks->path, src);
-                                       hlinks->next = NULL;
-                               } else {
-                                       /* look for this file */
-                                       file_hlink *hl = NULL;
-                                       do {
-                                               hl = (hl == NULL ? hlinks : hl->next);
-                                               if (hl->st_dev == s.st_dev && hl->st_ino == s.st_ino) {
-                                                       /* this is the same file, make a hard link */
-                                                       if (link(hl->path, trg) != 0) {
-                                                               fprintf(stderr, "failed to create hard link "
-                                                                               "%s: %s\n", trg, strerror(errno));
-                                                               return(-1);
-                                                       }
-                                                       hl = NULL;
-                                                       break;
-                                               }
-                                       } while (hl->next != NULL);
-                                       /* we didn't know this one yet, add it */
-                                       if (hl != NULL) {
-                                               hl = hl->next = malloc(sizeof(file_hlink));
-                                               hl->st_dev = s.st_dev;
-                                               hl->st_ino = s.st_ino;
-                                               strcpy(hl->path, src);
-                                               hl->next = NULL;
-                                       } else {
-                                               /* don't "copy" the file, we already made a hard
-                                                * link to it, just restore modified path */
-                                               st = srcp;
-                                               tt = trgp;
-                                               *st = *tt = '\0';
-                                               continue;
-                                       }
-                               }
-                       }
-
-                       /* copy */
-                       if (chpath(src, trg) != 0) {
-                               closedir(d);
-                               return(-1);
-                       }
-                       /* fix permissions */
-                       if (chmod(trg, s.st_mode) != 0) {
-                               fprintf(stderr, "failed to set permissions of %s: %s\n",
-                                               trg, strerror(errno));
-                               return(-1);
-                       }
-                       if (chown(trg, s.st_uid, s.st_gid) != 0) {
-                               fprintf(stderr, "failed to set ownership of %s: %s\n",
-                                               trg, strerror(errno));
-                               return(-1);
-                       }
-                       times[0].tv_sec = s.ATIME_SEC;
-#ifdef ATIME_NSEC
-                       times[0].tv_usec = (s.ATIME_NSEC) / 1000;
-#else
-                       times[0].tv_usec = 0;
-#endif
-                       times[1].tv_sec = s.MTIME_SEC;
-#ifdef MTIME_NSEC
-                       times[1].tv_usec = (s.MTIME_NSEC) / 1000;
-#else
-                       times[1].tv_usec = 0;
-#endif
-#ifdef HAVE_UTIMES
-                       if (utimes(trg, times) != 0) {
-                               fprintf(stderr, "failed to set utimes of %s: %s\n",
-                                               trg, strerror(errno));
-                               return(-1);
-                       }
-#else
-                       ub.actime = s.ATIME_SEC;
-                       ub.modtime = s.MTIME_SEC;
-                       if (utime(trg, &ub) != 0) {
-                               fprintf(stderr, "failed to set utime of %s: %s\n",
-                                               trg, strerror(errno));
-                               return(-1);
-                       }
-#endif
-               } else if (
-                               S_ISLNK(s.st_mode)
-                               )
-               {
-                       char buf[MAX_PATH];
-                       char rep[MAX_PATH];
-                       char *pb = buf;
-                       char *pr = rep;
-                       char *p = NULL;
-                       int len = readlink(src, buf, MAX_PATH - 1);
-                       buf[len] = '\0';
-                       /* replace occurences of magic by value in the string if
-                        * absolute */
-                       if (buf[0] == '/') while ((p = strstr(pb, magic)) != NULL) {
-                               memcpy(pr, pb, p - pb);
-                               pr += p - pb;
-                               memcpy(pr, value, valuelen);
-                               pr += valuelen;
-                               pb += magiclen;
-                       }
-                       len = (&buf[0] + len) - pb;
-                       memcpy(pr, pb, len);
-                       pr[len] = '\0';
-
-                       if (symlink(rep, trg) != 0) {
-                               fprintf(stderr, "failed to create symlink %s -> %s: %s\n",
-                                               trg, rep, strerror(errno));
-                               return(-1);
-                       }
-
-#ifdef HAVE_LCHOWN
-                       if (lchown(trg, s.st_uid, s.st_gid) != 0) {
-                               fprintf(stderr, "failed to set ownership of %s: %s\n",
-                                               trg, strerror(errno));
-                               return(-1);
-                       }
-#endif
-               }
-
-               /* restore modified path */
-               st = srcp;
-               tt = trgp;
-               *st = *tt = '\0';
-       }
-       closedir(d);
-
-       /* fix permissions/ownership etc. */
-       if (lstat(src, &s) != 0) {
-               fprintf(stderr, "cannot stat %s: %s\n", src, strerror(errno));
-               return(-1);
-       }
-       if (chmod(trg, s.st_mode) != 0) {
-               fprintf(stderr, "failed to set permissions of %s: %s\n",
-                               trg, strerror(errno));
-               return(-1);
-       }
-       if (chown(trg, s.st_uid, s.st_gid) != 0) {
-               fprintf(stderr, "failed to set ownership of %s: %s\n",
-                               trg, strerror(errno));
-               return(-1);
-       }
-       times[0].tv_sec = s.ATIME_SEC;
-#ifdef ATIME_NSEC
-       times[0].tv_usec = (s.ATIME_NSEC) / 1000;
-#else
-       times[0].tv_usec = 0;
-#endif
-       times[1].tv_sec = s.MTIME_SEC;
-#ifdef MTIME_NSEC
-       times[1].tv_usec = (s.MTIME_NSEC) / 1000;
-#else
-       times[1].tv_usec = 0;
-#endif
-#ifdef HAVE_UTIMES
-       if (utimes(trg, times) != 0) {
-               fprintf(stderr, "failed to set utimes of %s: %s\n",
-                               trg, strerror(errno));
-               return(-1);
-       }
-#else
-       ub.actime = s.ATIME_SEC;
-       ub.modtime = s.MTIME_SEC;
-       if (utime(trg, &ub) != 0) {
-               fprintf(stderr, "failed to set utime of %s: %s\n",
-                               trg, strerror(errno));
-               return(-1);
-       }
-#endif
-
-       return(0);
-}
-
-int main(int argc, char **argv) {
-       struct stat file;
-       int o = 0;
-
-       quiet = 0;
-       if (argc >= 2 && strcmp(argv[1], "-q") == 0) {
-               argc--;
-               o++;
-               quiet = 1;
-       }
-
-       if (argc != 5) {
-               fprintf(stderr, "usage: [-q] in-file out-file magic value\n");
-               fprintf(stderr, "       if in-file is a directory, out-file is "
-                               "treated as one too\n");
-               fprintf(stderr, " -q  suppress messages about being unable to "
-                               "write padding bytes\n");
-               return(-1);
-       }
-
-       magic    = argv[o + 3];
-       value    = argv[o + 4];
-       magiclen = strlen(magic);
-       valuelen = strlen(value);
-
-       if (magiclen < valuelen) {
-               fprintf(stderr, "value length (%zd) is bigger than "
-                               "the magic length (%zd)\n", valuelen, magiclen);
-               return(-1);
-       }
-       if (magiclen > BUFSIZE) {
-               fprintf(stderr, "magic length (%zd) is bigger than "
-                               "BUFSIZE (%d), unable to process\n", magiclen, BUFSIZE);
-               return(-1);
-       }
-
-       if (lstat(argv[o + 1], &file) != 0) {
-               fprintf(stderr, "unable to stat %s: %s\n",
-                               argv[o + 1], strerror(errno));
-               return(-1);
-       }
-       if (S_ISDIR(file.st_mode)) {
-               char *src = alloca(sizeof(char) * MAX_PATH);
-               char *trg = alloca(sizeof(char) * MAX_PATH);
-               strcpy(src, argv[o + 1]);
-               strcpy(trg, argv[o + 2]);
-               /* walk this directory and process recursively */
-               return(dirwalk(src, src + strlen(argv[o + 1]),
-                                       trg, trg + strlen(argv[o + 2])));
-       } else {
-               /* process as normal file */
-               return(chpath(argv[o + 1], argv[o + 2]));
-       }
-}
-