Hi, somewhere I read that a reimplementation of mksplit.pl in C was needed in order to remove a dependency of dpkg on Perl, but I can't find the reference anymore. Oddly enough I don't see a dependency of dpkg on perl either:
Package: dpkg Version: 1.15.6.1 Replaces: manpages-de (<= 0.4-3), manpages-pl (<= 20051117-1) Pre-Depends: libbz2-1.0, libc6 (>= 2.3), libselinux1 (>= 1.32), zlib1g (>= 1:1.1.4), coreutils (>= 5.93-1), xz-utils Suggests: apt Conflicts: apt (<< 0.7.7), aptitude (<< 0.4.7-1), dpkg-dev (<< 1.14.16), dpkg-iasearch (<< 0.11), sysvinit (<< 2.82-1) Breaks: emacs21 (<< 21.4a+1-5.7), emacs21-nox (<< 21.4a+1-5.7), emacs22 (<= 22.3+1-1), emacs22-gtk (<= 22.3+1-1), emacs22-nox (<= 22.3+1-1), jed (<< 1:0.99.18+dfsg.1-13), jed-extra (<= 2.5.3-2), konqueror (<= 4:4.2.96-1), pinfo (<< 0.6.9-3.1), tkinfo (<< 2.8-3.1), xemacs21-support (<< 21.4.22-2), xjed (<< 1:0.99.18+dfsg.1-13) Anyways, attached is a patch to do just that. It's implemented against the master Git branch. As indicated in the patch, this is a straight translation and it would like to have some refactoring love. I did compare the output with the Perl version in several test cases and it's identical. Please Cc: me, I'm not subscribed. Cheers, Marcelo
>From 267685fb5750a47b536ab817a72597836abe5c5f Mon Sep 17 00:00:00 2001 From: Marcelo E. Magallon <mmaga...@debian.org> Date: Fri, 2 Apr 2010 22:27:50 -0600 Subject: [PATCH] Reimplement mksplit in C My original intention was to do without some of the pipes, but for the initial implementation this is just a translation of the original Perl program into C, without much in the way of optimization. It produces the same output and exits in the same way as the original program (mod exit status probably). The reimplementation can use some refactoring love. --- dpkg-split/Makefile.am | 10 ++- dpkg-split/mksplit.c | 279 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 287 insertions(+), 2 deletions(-) create mode 100644 dpkg-split/mksplit.c diff --git a/dpkg-split/Makefile.am b/dpkg-split/Makefile.am index 6f6043c..c43025d 100644 --- a/dpkg-split/Makefile.am +++ b/dpkg-split/Makefile.am @@ -9,7 +9,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/lib -bin_PROGRAMS = dpkg-split +bin_PROGRAMS = dpkg-split mksplit dpkg_split_SOURCES = \ dpkg-split.h \ @@ -24,9 +24,15 @@ dpkg_split_LDADD = \ ../lib/compat/libcompat.a \ $(LIBINTL) +mksplit_SOURCES = \ + mksplit.c + +mksplit_LDADD = \ + ../lib/dpkg/libdpkg.a \ + ../lib/compat/libcompat.a \ + $(LIBINTL) pkglib_SCRIPTS = mksplit -EXTRA_DIST = mksplit.pl CLEANFILES = $(pkglib_SCRIPTS) diff --git a/dpkg-split/mksplit.c b/dpkg-split/mksplit.c new file mode 100644 index 0000000..5ca34d6 --- /dev/null +++ b/dpkg-split/mksplit.c @@ -0,0 +1,279 @@ +/* This program is only supposed to be called by dpkg-split. + * Its arguments are: + * <sourcefile> <partsize> <prefix> <totalsize> <partsizeallow> <msdostruncyesno> + * Stdin is also redirected from the source archive by dpkg-split. + * + * Copyright © 1995 Ian Jackson <i...@chiark.greenend.org.uk> + * Copyright © 2010 Marcelo E. Magallon <mmaga...@debian.org> + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <limits.h> +#include <error.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <unistd.h> + +#define MSDOS_PATH_MAX 10 + +void checked_free(void *ptr) +{ + if (ptr) free(ptr); +} + +void add(FILE *stream, char* id, char* data, size_t len) +{ + time_t current_time; + + current_time = time(NULL); + fprintf(stream, "%-16s%-12d0 0 100644 %-10d%c\n", + id, (int)current_time, (int)len, 0140); + fwrite(data, 1, len, stream); + fprintf(stream, "%s", (len & 1) ? "\n" : ""); +} + +char* output(char *cmd) +{ + FILE * file = NULL; + int len = getpagesize(); + char *result = (char *)malloc(len); + char *p = result; + + if (result == NULL) + goto error_out; + + if ((file = popen(cmd, "r")) == NULL) + goto error_out; + + while (len > 0 && !feof(file)) + { + int n; + n = fread(p, 1, len, file); + if (ferror(file)) + goto error_out; + p += n; + len -= n; + } + goto out; + +error_out: + if (result) + { + free(result); + result = NULL; + } + +out: + if (file) + pclose(file); + return result; +} + +char* get_field(char *filename, char *field) +{ + char *result; + char cmd[PATH_MAX]; + sprintf(cmd, "dpkg-deb --field %s %s", filename, field); + + result = output(cmd); + if (result) + { + char *p; + for (p = result + strlen(result) - 1; p >= result && isspace(*p); --p) + *p = 0; + } + + return result; +} + +char* get_md5sum(char *filename) +{ + char *result; + char cmd[PATH_MAX]; + sprintf(cmd, "md5sum <%s", filename); + + result = output(cmd); + if (result) + { + char *p; + for(p = result; *p && *p != ' '; ++p); + if (*p) *p = 0; + } + + return result; +} + +int main(int argc, char* argv[]) +{ + char *sourcefile; + char *prefix; + char basename[PATH_MAX]; + char *prefixdir = NULL; + char *cleanprefix = NULL; + char *package = NULL; + char *myversion = "2.1"; + char *version = NULL; + char *revision = NULL; + char *csum = NULL; + char *data = NULL; + int partsize; + int orgsize; + size_t partsizeallow; + int msdos; /* yes = true, anything else = false */ + int nparts; + int startat; + int showpartnum = 1; + + if (argc != 7) + error(1, 0, "bad invocation\n"); + + sourcefile = argv[1]; + partsize = atoi(argv[2]); + prefix = argv[3]; + orgsize = atoi(argv[4]); + partsizeallow = (size_t)atoi(argv[5]); + msdos = strcmp(argv[6], "yes") == 0 ? 1 : 0; + + package = get_field(sourcefile, "Package"); + version = get_field(sourcefile, "Version"); + revision = get_field(sourcefile, "Package_Revision"); + + if (version && revision && strlen(revision) > 0) + { + int n = strlen(version) + 1 + strlen(revision) + 1; + char *tmp = (char *)malloc(n*sizeof(char)); + sprintf(tmp, "%s-%s", version, revision); + free(version); + version = tmp; + } + + csum = get_md5sum(sourcefile); + nparts=(orgsize+partsize-1)/partsize; + + printf("Splitting package %s into %d parts: ", package, nparts); + + if (msdos) + { + char *p, *q; + prefixdir = strdup(prefix); + p = strrchr(prefixdir, '/'); + if (p) + { + ++p; + cleanprefix = strdup(p); + *p = 0; + } + else + { + cleanprefix = strdup(prefix); + *prefixdir = 0; + } + + for(p = q = cleanprefix; *p; ++p) + { + if (*p == '+') + *q++ = *p = 'x'; + else if (isupper(*p)) + *q++ = *p = tolower(*p); + else if (islower(*p) || isdigit(*p)) + *q++ = *p; + } + + *q = 0; + } + + data = malloc(partsize); + + for(startat = 0; startat < orgsize; startat += partsize) + { + char tmp[17]; + char dsp[1024]; + FILE *output; + size_t thispartreallen; + + if (msdos) + { + int len; + char *p = basename; + len = snprintf(basename, MSDOS_PATH_MAX, + "%dof%d", showpartnum, nparts); + p += snprintf(p, PATH_MAX, "%s/", prefixdir); + p += snprintf(p, MSDOS_PATH_MAX - len, "%s", cleanprefix); + snprintf(p, PATH_MAX - (p - basename), + "%dof%d.deb", showpartnum, nparts); + } + else + { + snprintf(basename, PATH_MAX, "%s.%dof%d.deb", + prefix, showpartnum, nparts); + } + + output = fopen(basename, "w"); + + if (!output) + { + error(1, errno, "open %s", basename); + } + + fprintf(output, "!<arch>\n"); + printf("%d ", showpartnum); + + snprintf(dsp, sizeof(dsp)/sizeof(*dsp), + "%s\n" + "%s\n" + "%s\n" + "%s\n" + "%d\n" + "%d\n" + "%d/%d\n", + myversion, package, version, csum, orgsize, partsize, + showpartnum, nparts); + add(output, "debian-split", dsp, strlen(dsp)); + + thispartreallen = fread(data, 1, partsize, stdin); + + snprintf(tmp, sizeof(tmp)/sizeof(*tmp), "data.%d", showpartnum); + add(output, tmp, data, thispartreallen); + + if (thispartreallen > partsizeallow) + { + error(1, 0, + "Header is too long, making part too long. " + "Your package name or version\n" + "numbers must be extraordinarily long, or something. " + "Giving up.\n"); + } + + fclose(output); + + ++showpartnum; + } + + printf("done\n"); + + checked_free(data); + checked_free(prefixdir); + checked_free(cleanprefix); + checked_free(package); + checked_free(version); + checked_free(revision); + checked_free(csum); + + return 0; +} -- 1.7.0.3