Jérémy Bobbio: > Here are four patches based on the current master (1e059955) that will > write files in deterministic order in the control and data archives. > File names are sorted by forking `sort` before being piped to `tar`.
Attached are the patch based on current master (36eda4c1bc). -- Lunar .''`. lu...@debian.org : :Ⓐ : # apt-get install anarchism `. `'` `-
From 05791de26a9cc119aa4742bbb61c58d19348b176 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Bobbio?= <lu...@debian.org> Date: Tue, 27 Aug 2013 18:10:15 +0200 Subject: [PATCH 1/4] Ensure deterministic file order in data.tar.* files Address: #719845 --- dpkg-deb/build.c | 42 ++++++++++++++++++++++++++++++------------ lib/dpkg/dpkg.h | 1 + 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/dpkg-deb/build.c b/dpkg-deb/build.c index 442298d..eccc27f 100644 --- a/dpkg-deb/build.c +++ b/dpkg-deb/build.c @@ -168,19 +168,36 @@ file_info_list_free(struct file_info *fi) static void file_treewalk_feed(const char *dir, int fd_out) { - int pipefd[2]; - pid_t pid; + int sort_pipefd[2], find_pipefd[2]; + pid_t sort_pid, find_pid; struct file_info *fi; struct file_info *symlist = NULL; struct file_info *symlist_end = NULL; - m_pipe(pipefd); + m_pipe(find_pipefd); + m_pipe(sort_pipefd); + + sort_pid = subproc_fork(); + if (sort_pid == 0) { + m_dup2(find_pipefd[0], 0); + close(find_pipefd[0]); + close(find_pipefd[1]); + m_dup2(sort_pipefd[1], 1); + close(sort_pipefd[0]); + close(sort_pipefd[1]); + if (setenv("LC_ALL", "C", 1 /* overwrite */)) + ohshite(_("unable to setenv")); + execlp(SORT, "sort", "--zero-terminated", NULL); + ohshite(_("unable to execute %s (%s)"), "sort", SORT); + } + close(find_pipefd[0]); + close(sort_pipefd[1]); - pid = subproc_fork(); - if (pid == 0) { - m_dup2(pipefd[1], 1); - close(pipefd[0]); - close(pipefd[1]); + find_pid = subproc_fork(); + if (find_pid == 0) { + m_dup2(find_pipefd[1], 1); + close(find_pipefd[0]); + close(find_pipefd[1]); if (chdir(dir)) ohshite(_("failed to chdir to `%.255s'"), dir); @@ -189,11 +206,11 @@ file_treewalk_feed(const char *dir, int fd_out) "-print0", NULL); ohshite(_("unable to execute %s (%s)"), "find", FIND); } - close(pipefd[1]); + close(find_pipefd[1]); /* We need to reorder the files so we can make sure that symlinks * will not appear before their target. */ - while ((fi = file_info_get(dir, pipefd[0])) != NULL) { + while ((fi = file_info_get(dir, sort_pipefd[0])) != NULL) { if (S_ISLNK(fi->st.st_mode)) { file_info_list_append(&symlist, &symlist_end, fi); } else { @@ -204,8 +221,9 @@ file_treewalk_feed(const char *dir, int fd_out) } } - close(pipefd[0]); - subproc_reap(pid, "find", 0); + close(sort_pipefd[0]); + subproc_reap(find_pid, "find", 0); + subproc_reap(sort_pid, "sort", 0); for (fi = symlist; fi; fi = fi->next) if (fd_write(fd_out, fi->fn, strlen(fi->fn) + 1) < 0) diff --git a/lib/dpkg/dpkg.h b/lib/dpkg/dpkg.h index 1dfef96..8bbad67 100644 --- a/lib/dpkg/dpkg.h +++ b/lib/dpkg/dpkg.h @@ -112,6 +112,7 @@ DPKG_BEGIN_DECLS #define CAT "cat" #define FIND "find" #define DIFF "diff" +#define SORT "sort" #define FIND_EXPRSTARTCHARS "-(),!" -- 1.7.10.4
From e27bef15519d4641cc37553660d39eb830b76daa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Bobbio?= <lu...@debian.org> Date: Fri, 17 Jan 2014 12:56:13 +0100 Subject: [PATCH 2/4] Extract the creation of the control tarball to a dedicated function --- dpkg-deb/build.c | 73 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 30 deletions(-) diff --git a/dpkg-deb/build.c b/dpkg-deb/build.c index eccc27f..3059954 100644 --- a/dpkg-deb/build.c +++ b/dpkg-deb/build.c @@ -232,6 +232,40 @@ file_treewalk_feed(const char *dir, int fd_out) file_info_list_free(symlist); } +static void +create_control_tar(const char *dir, struct compress_params *control_compress_params, + int gzfd) +{ + int p1[2]; + pid_t c1, c2; + + /* Fork a tar to package the control-section of the package. */ + unsetenv("TAR_OPTIONS"); + m_pipe(p1); + c1 = subproc_fork(); + if (!c1) { + m_dup2(p1[1],1); close(p1[0]); close(p1[1]); + if (chdir(dir)) + ohshite(_("failed to chdir to `%.255s'"), dir); + if (chdir(BUILDCONTROLDIR)) + ohshite(_("failed to chdir to `%.255s'"), ".../DEBIAN"); + execlp(TAR, "tar", "-cf", "-", "--format=gnu", ".", NULL); + ohshite(_("unable to execute %s (%s)"), "tar -cf", TAR); + } + close(p1[1]); + + /* And run the compressor on our control archive. */ + + c2 = subproc_fork(); + if (!c2) { + compress_filter(control_compress_params, p1[0], gzfd, _("compressing control member")); + exit(0); + } + close(p1[0]); + subproc_reap(c2, "gzip -9c", 0); + subproc_reap(c1, "tar -cf", 0); +} + static const char *const maintainerscripts[] = { PREINSTFILE, POSTINSTFILE, @@ -469,20 +503,15 @@ do_build(const char *const *argv) arfd = creat(debar, 0644); if (arfd < 0) ohshite(_("unable to create `%.255s'"), debar); - /* Fork a tar to package the control-section of the package. */ - unsetenv("TAR_OPTIONS"); - m_pipe(p1); - c1 = subproc_fork(); - if (!c1) { - m_dup2(p1[1],1); close(p1[0]); close(p1[1]); - if (chdir(dir)) - ohshite(_("failed to chdir to `%.255s'"), dir); - if (chdir(BUILDCONTROLDIR)) - ohshite(_("failed to chdir to `%.255s'"), ".../DEBIAN"); - execlp(TAR, "tar", "-cf", "-", "--format=gnu", ".", NULL); - ohshite(_("unable to execute %s (%s)"), "tar -cf", TAR); + + if (opt_uniform_compression) { + control_compress_params = compress_params; + } else { + control_compress_params.type = COMPRESSOR_TYPE_GZIP; + control_compress_params.strategy = COMPRESSOR_STRATEGY_NONE; + control_compress_params.level = -1; } - close(p1[1]); + /* Create a temporary file to store the control data in. Immediately * unlink our temporary file so others can't mess with it. */ tfbuf = path_make_temp_template("dpkg-deb"); @@ -495,23 +524,7 @@ do_build(const char *const *argv) tfbuf); free(tfbuf); - /* And run the compressor on our control archive. */ - if (opt_uniform_compression) { - control_compress_params = compress_params; - } else { - control_compress_params.type = COMPRESSOR_TYPE_GZIP; - control_compress_params.strategy = COMPRESSOR_STRATEGY_NONE; - control_compress_params.level = -1; - } - - c2 = subproc_fork(); - if (!c2) { - compress_filter(&control_compress_params, p1[0], gzfd, _("compressing control member")); - exit(0); - } - close(p1[0]); - subproc_reap(c2, "gzip -9c", 0); - subproc_reap(c1, "tar -cf", 0); + create_control_tar(dir, &control_compress_params, gzfd); if (lseek(gzfd, 0, SEEK_SET)) ohshite(_("failed to rewind temporary file (%s)"), _("control member")); -- 1.7.10.4
From 8ec7a9ca719cc81f9191eff21b3b0ec26a532ac3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Bobbio?= <lu...@debian.org> Date: Fri, 17 Jan 2014 12:58:15 +0100 Subject: [PATCH 3/4] Rename create_control_tar() variables to more meaningful names --- dpkg-deb/build.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/dpkg-deb/build.c b/dpkg-deb/build.c index 3059954..40b4856 100644 --- a/dpkg-deb/build.c +++ b/dpkg-deb/build.c @@ -236,15 +236,15 @@ static void create_control_tar(const char *dir, struct compress_params *control_compress_params, int gzfd) { - int p1[2]; - pid_t c1, c2; + int tar_pipefd[2]; + pid_t tar_pid, gzip_pid; /* Fork a tar to package the control-section of the package. */ unsetenv("TAR_OPTIONS"); - m_pipe(p1); - c1 = subproc_fork(); - if (!c1) { - m_dup2(p1[1],1); close(p1[0]); close(p1[1]); + m_pipe(tar_pipefd); + tar_pid = subproc_fork(); + if (!tar_pid) { + m_dup2(tar_pipefd[1],1); close(tar_pipefd[0]); close(tar_pipefd[1]); if (chdir(dir)) ohshite(_("failed to chdir to `%.255s'"), dir); if (chdir(BUILDCONTROLDIR)) @@ -252,18 +252,18 @@ create_control_tar(const char *dir, struct compress_params *control_compress_par execlp(TAR, "tar", "-cf", "-", "--format=gnu", ".", NULL); ohshite(_("unable to execute %s (%s)"), "tar -cf", TAR); } - close(p1[1]); + close(tar_pipefd[1]); /* And run the compressor on our control archive. */ - c2 = subproc_fork(); - if (!c2) { - compress_filter(control_compress_params, p1[0], gzfd, _("compressing control member")); + gzip_pid = subproc_fork(); + if (!gzip_pid) { + compress_filter(control_compress_params, tar_pipefd[0], gzfd, _("compressing control member")); exit(0); } - close(p1[0]); - subproc_reap(c2, "gzip -9c", 0); - subproc_reap(c1, "tar -cf", 0); + close(tar_pipefd[0]); + subproc_reap(gzip_pid, "gzip -9c", 0); + subproc_reap(tar_pid, "tar -cf", 0); } static const char *const maintainerscripts[] = { -- 1.7.10.4
From 633d37bf913593a2ccf921964620f2dc537c6d1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Bobbio?= <lu...@debian.org> Date: Tue, 27 Aug 2013 23:03:49 +0200 Subject: [PATCH 4/4] Also write control.tar.gz in deterministic order Closes: #719845 --- dpkg-deb/build.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 7 deletions(-) diff --git a/dpkg-deb/build.c b/dpkg-deb/build.c index 40b4856..e48b4bf 100644 --- a/dpkg-deb/build.c +++ b/dpkg-deb/build.c @@ -236,32 +236,80 @@ static void create_control_tar(const char *dir, struct compress_params *control_compress_params, int gzfd) { - int tar_pipefd[2]; - pid_t tar_pid, gzip_pid; + int tar_pipefd[2], gzip_pipefd[2], sort_pipefd[2]; + pid_t tar_pid, gzip_pid, sort_pid, find_pid; /* Fork a tar to package the control-section of the package. */ unsetenv("TAR_OPTIONS"); m_pipe(tar_pipefd); + m_pipe(gzip_pipefd); tar_pid = subproc_fork(); if (!tar_pid) { - m_dup2(tar_pipefd[1],1); close(tar_pipefd[0]); close(tar_pipefd[1]); + m_dup2(tar_pipefd[0], 0); + close(tar_pipefd[0]); + close(tar_pipefd[1]); + m_dup2(gzip_pipefd[1], 1); + close(gzip_pipefd[0]); + close(gzip_pipefd[1]); if (chdir(dir)) ohshite(_("failed to chdir to `%.255s'"), dir); if (chdir(BUILDCONTROLDIR)) ohshite(_("failed to chdir to `%.255s'"), ".../DEBIAN"); - execlp(TAR, "tar", "-cf", "-", "--format=gnu", ".", NULL); + execlp(TAR, "tar", "-cf", "-", "--format=gnu", "--null", "--no-unquote", + "-T", "-", "--no-recursion", NULL); ohshite(_("unable to execute %s (%s)"), "tar -cf", TAR); } - close(tar_pipefd[1]); + close(tar_pipefd[0]); + close(gzip_pipefd[1]); /* And run the compressor on our control archive. */ gzip_pid = subproc_fork(); if (!gzip_pid) { - compress_filter(control_compress_params, tar_pipefd[0], gzfd, _("compressing control member")); + close(tar_pipefd[1]); + compress_filter(control_compress_params, gzip_pipefd[0], gzfd, _("compressing control member")); exit(0); } - close(tar_pipefd[0]); + close(gzip_pipefd[0]); + + /* We pipe the filename to sort between find and tar to get deterministic + * builds. */ + m_pipe(sort_pipefd); + sort_pid = subproc_fork(); + if (!sort_pid) { + m_dup2(sort_pipefd[0], 0); + close(sort_pipefd[0]); + close(sort_pipefd[1]); + m_dup2(tar_pipefd[1], 1); + close(tar_pipefd[0]); + close(tar_pipefd[1]); + if (setenv("LC_ALL", "C", 1 /* overwrite */)) + ohshite(_("unable to setenv")); + execlp(SORT, "sort", "--zero-terminated", NULL); + ohshite(_("unable to execute %s (%s)"), "sort", SORT); + } + close(sort_pipefd[0]); + close(tar_pipefd[1]); + + /* All the pipes are set, now lets run find, and start feeding + * filenames to tar. */ + find_pid = subproc_fork(); + if (!find_pid) { + m_dup2(sort_pipefd[1], 1); + close(sort_pipefd[0]); + close(sort_pipefd[1]); + if (chdir(dir)) + ohshite(_("failed to chdir to `%.255s'"), dir); + if (chdir(BUILDCONTROLDIR)) + ohshite(_("failed to chdir to `%.255s'"), ".../DEBIAN"); + execlp(FIND, "find", ".", "-path", "./" BUILDCONTROLDIR, "-prune", "-o", + "-print0", NULL); + ohshite(_("unable to execute %s (%s)"), "find", FIND); + } + close(sort_pipefd[1]); + + subproc_reap(find_pid, "find", 0); + subproc_reap(sort_pid, "sort", 0); subproc_reap(gzip_pid, "gzip -9c", 0); subproc_reap(tar_pid, "tar -cf", 0); } -- 1.7.10.4
signature.asc
Description: Digital signature