diff options
author | Guillem Jover <guillem@debian.org> | 2010-07-02 06:15:26 +0200 |
---|---|---|
committer | Guillem Jover <guillem@debian.org> | 2010-07-03 07:09:46 +0200 |
commit | f2115151c19ff37b305296c23225807b0832086b (patch) | |
tree | 32ceb7e800ab4bd6a0dc9d120ece9d3361fdb72e /dpkg-split/split.c | |
parent | 28ca2d0e5c8d47abf2907b697a7711e6a7689293 (diff) | |
download | dpkg-f2115151c19ff37b305296c23225807b0832086b.tar.gz |
dpkg-split: Rewrite mksplit in C
Diffstat (limited to 'dpkg-split/split.c')
-rw-r--r-- | dpkg-split/split.c | 225 |
1 files changed, 209 insertions, 16 deletions
diff --git a/dpkg-split/split.c b/dpkg-split/split.c index b583a46dc..d5d75f65b 100644 --- a/dpkg-split/split.c +++ b/dpkg-split/split.c @@ -3,6 +3,7 @@ * split.c - splitting archives * * Copyright © 1995 Ian Jackson <ian@chiark.greenend.org.uk> + * Copyright © 2010 Guillem Jover <guillem@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 @@ -21,11 +22,17 @@ #include <config.h> #include <compat.h> +#include <sys/types.h> #include <sys/stat.h> +#include <sys/wait.h> #include <limits.h> +#include <errno.h> #include <fcntl.h> +#include <libgen.h> #include <string.h> +#include <ctype.h> +#include <time.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> @@ -33,16 +40,210 @@ #include <dpkg/i18n.h> #include <dpkg/dpkg.h> #include <dpkg/dpkg-db.h> +#include <dpkg/subproc.h> +#include <dpkg/buffer.h> +#include <dpkg/ar.h> #include <dpkg/myopt.h> #include "dpkg-split.h" +static char * +deb_field(const char *filename, const char *field) +{ + pid_t pid; + int p[2]; + struct varbuf buf = VARBUF_INIT; + char *end; + + m_pipe(p); + + pid = subproc_fork(); + if (pid == 0) { + /* Child writes to pipe. */ + m_dup2(p[1], 1); + close(p[0]); + close(p[1]); + + execlp(BACKEND, BACKEND, "--field", filename, field, NULL); + ohshite(_("failed to exec dpkg-deb to extract field value")); + } + close(p[1]); + + /* Parant reads from pipe. */ + varbufreset(&buf); + fd_vbuf_copy(p[0], &buf, -1, _("dpkg-deb field extraction")); + varbufaddc(&buf, '\0'); + + close(p[0]); + + subproc_wait_check(pid, _("dpkg-deb field extraction"), PROCPIPE); + + /* Trim down trailing junk. */ + for (end = buf.buf + strlen(buf.buf) - 1; end - buf.buf >= 1; end--) + if (isspace(*end)) + *end = '\0'; + else + break; + + return varbuf_detach(&buf); +} + +/* Cleanup filename for use in crippled msdos systems. */ +static char * +clean_msdos_filename(char *filename) +{ + char *d, *s; + + for (s = d = filename; *s; d++, s++) { + if (*s == '+') + *d = 'x'; + else if (isupper(*s)) + *d = tolower(*s); + else if (islower(*s) || isdigit(*s)) + *d = *s; + else + s++; + } + + return filename; +} + +static int +mksplit(const char *file_src, const char *prefix, size_t partsize, + size_t maxpartsize, bool msdos) +{ + int fd_src; + struct stat st; + char hash[MD5HASHLEN + 1]; + char *package, *version; + int nparts, curpart; + off_t startat; + char *prefixdir = NULL, *msdos_prefix = NULL; + struct varbuf file_dst = VARBUF_INIT; + struct varbuf partmagic = VARBUF_INIT; + struct varbuf partname = VARBUF_INIT; + char *partdata; + + fd_src = open(file_src, O_RDONLY); + if (fd_src < 0) + ohshite(_("unable to open source file `%.250s'"), file_src); + if (fstat(fd_src, &st)) + ohshite(_("unable to fstat source file")); + if (!S_ISREG(st.st_mode)) + ohshit(_("source file `%.250s' not a plain file"), file_src); + + fd_md5(fd_src, hash, -1, "md5hash"); + lseek(fd_src, 0, SEEK_SET); + + /* FIXME: Use libdpkg-deb. */ + package = deb_field(file_src, "Package"); + version = deb_field(file_src, "Version"); + + nparts = (st.st_size + partsize - 1) / partsize; + + setvbuf(stdout, NULL, _IONBF, 0); + + printf("Splitting package %s into %d parts: ", package, nparts); + + if (msdos) { + char *t; + + t = m_strdup(prefix); + prefixdir = m_strdup(dirname(t)); + free(t); + + t = m_strdup(prefix); + msdos_prefix = m_strdup(basename(t)); + free(t); + + prefix = clean_msdos_filename(msdos_prefix); + } + + partdata = m_malloc(partsize); + curpart = 1; + + for (startat = 0; startat < st.st_size; startat += partsize) { + int fd_dst; + ssize_t partrealsize; + + varbufreset(&file_dst); + /* Generate output filename. */ + if (msdos) { + struct varbuf refname = VARBUF_INIT; + int prefix_max; + + varbufprintf(&refname, "%dof%d", curpart, nparts); + prefix_max = max(8 - strlen(refname.buf), 0); + varbufprintf(&file_dst, "%s/%.*s%.8s.deb", + prefixdir, prefix_max, prefix, + refname.buf); + varbuf_destroy(&refname); + } else { + varbufprintf(&file_dst, "%s.%dof%d.deb", + prefix, curpart, nparts); + } + + /* Read data from the original package. */ + partrealsize = read(fd_src, partdata, partsize); + if (partrealsize < 0) + ohshite("mksplit: read"); + + if ((size_t)partrealsize > maxpartsize) { + ohshit("Header is too long, making part too long. " + "Your package name or version\n" + "numbers must be extraordinarily long, " + "or something. Giving up.\n"); + } + + /* Split the data. */ + fd_dst = open(file_dst.buf, O_CREAT | O_WRONLY, 0644); + if (fd_dst < 0) + ohshite(_("unable to open file '%s'"), file_dst.buf); + + /* Write the ar header. */ + dpkg_ar_put_magic(file_dst.buf, fd_dst); + + /* Write the debian-split part. */ + varbufprintf(&partmagic, "%s\n%s\n%s\n%s\n%zu\n%zu\n%d/%d\n", + SPLITVERSION, package, version, hash, + st.st_size, partsize, curpart, nparts); + dpkg_ar_member_put_mem(file_dst.buf, fd_dst, PARTMAGIC, + partmagic.buf, partmagic.used); + varbufreset(&partmagic); + + /* Write the data part. */ + varbufprintf(&partname, "data.%d", curpart); + dpkg_ar_member_put_mem(file_dst.buf, fd_dst, partname.buf, + partdata, (size_t)partrealsize); + varbufreset(&partname); + + close(fd_dst); + + printf("%d ", curpart); + + curpart++; + } + + varbuf_destroy(&file_dst); + varbuf_destroy(&partname); + varbuf_destroy(&partmagic); + free(partdata); + + free(prefixdir); + free(msdos_prefix); + + close(fd_src); + + printf("done\n"); + + return 0; +} + void do_split(const char *const *argv) { const char *sourcefile, *prefix; char *palloc; - int l, fd; - char partsizebuf[30], lengthbuf[30], partsizeallowbuf[30]; - struct stat stab; + int l; + size_t partsize; sourcefile= *argv++; if (!sourcefile) @@ -60,17 +261,9 @@ void do_split(const char *const *argv) { } prefix= palloc; } - sprintf(partsizebuf,"%ld",maxpartsize-HEADERALLOWANCE); - sprintf(partsizeallowbuf,"%ld",maxpartsize); - fd= open(sourcefile,O_RDONLY); - if (fd < 0) - ohshite(_("unable to open source file `%.250s'"), sourcefile); - if (fstat(fd,&stab)) ohshite(_("unable to fstat source file")); - if (!S_ISREG(stab.st_mode)) ohshit(_("source file `%.250s' not a plain file"),sourcefile); - sprintf(lengthbuf,"%lu",(unsigned long)stab.st_size); - m_dup2(fd,0); - execl(MKSPLITSCRIPT,MKSPLITSCRIPT, - sourcefile,partsizebuf,prefix,lengthbuf,partsizeallowbuf,msdos?"yes":"no", - NULL); - ohshite(_("unable to exec mksplit")); + partsize = maxpartsize - HEADERALLOWANCE; + + mksplit(sourcefile, prefix, partsize, maxpartsize, msdos); + + exit(0); } |