From 78eaf928d30d0b16e05d8d63c55a3632a135ed9a Mon Sep 17 00:00:00 2001 From: Guillem Jover Date: Thu, 4 Nov 2010 00:51:13 +0100 Subject: [PATCH] dpkg-deb: Use fd instead of stream based buffered I/O Behaviour of fflush() on input streams is undefined per POSIX, avoid mixing stream and file descriptor based I/O, and only use the latter instead. Upstream-Status: Backport of revision 2d420ee1d05033d237462a0075facfe406b08043 (in 1.16.x) --- dpkg-deb/extract.c | 83 ++++++++++++++++++++++++++++++++++++++------------- 1 files changed, 62 insertions(+), 21 deletions(-) diff --git a/dpkg-deb/extract.c b/dpkg-deb/extract.c index 22aea98..0f5ac88 100644 --- a/dpkg-deb/extract.c +++ b/dpkg-deb/extract.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -61,13 +62,41 @@ static void movecontrolfiles(const char *thing) { } static void DPKG_ATTR_NORET -readfail(FILE *a, const char *filename, const char *what) +read_fail(int rc, const char *filename, const char *what) { - if (ferror(a)) { - ohshite(_("error reading %s from file %.255s"), what, filename); - } else { + if (rc == 0) ohshit(_("unexpected end of file in %s in %.255s"),what,filename); + else + ohshite(_("error reading %s from file %.255s"), what, filename); +} + +static ssize_t +read_line(int fd, char *buf, size_t min_size, size_t max_size) +{ + ssize_t line_size = 0; + size_t n = min_size; + + while (line_size < (ssize_t)max_size) { + ssize_t r; + char *nl; + + r = read(fd, buf + line_size, n); + if (r <= 0) + return r; + + nl = strchr(buf + line_size, '\n'); + line_size += r; + + if (nl != NULL) { + nl[1] = '\0'; + return line_size; + } + + n = 1; } + + buf[line_size] = '\0'; + return line_size; } static size_t @@ -115,19 +144,26 @@ void extracthalf(const char *debar, const char *directory, char versionbuf[40]; float versionnum; size_t ctrllennum, memberlen= 0; + ssize_t r; int dummy; pid_t c1=0,c2,c3; int p1[2], p2[2]; - FILE *ar; + int arfd; struct stat stab; char nlc; int adminmember; bool oldformat, header_done; struct compressor *decompressor = &compressor_gzip; - ar= fopen(debar,"r"); if (!ar) ohshite(_("failed to read archive `%.255s'"),debar); - if (fstat(fileno(ar),&stab)) ohshite(_("failed to fstat archive")); - if (!fgets(versionbuf,sizeof(versionbuf),ar)) readfail(ar,debar,_("version number")); + arfd = open(debar, O_RDONLY); + if (arfd < 0) + ohshite(_("failed to read archive `%.255s'"), debar); + if (fstat(arfd, &stab)) + ohshite(_("failed to fstat archive")); + + r = read_line(arfd, versionbuf, strlen(DPKG_AR_MAGIC), sizeof(versionbuf)); + if (r < 0) + read_fail(r, debar, _("archive magic version number")); if (!strcmp(versionbuf, DPKG_AR_MAGIC)) { oldformat = false; @@ -137,8 +173,9 @@ void extracthalf(const char *debar, const char *directory, for (;;) { struct ar_hdr arh; - if (fread(&arh,1,sizeof(arh),ar) != sizeof(arh)) - readfail(ar,debar,_("between members")); + r = read(arfd, &arh, sizeof(arh)); + if (r != sizeof(arh)) + read_fail(r, debar, _("archive member header")); dpkg_ar_normalize_name(&arh); @@ -153,8 +190,9 @@ void extracthalf(const char *debar, const char *directory, if (strncmp(arh.ar_name, DEBMAGIC, sizeof(arh.ar_name)) != 0) ohshit(_("file `%.250s' is not a debian binary archive (try dpkg-split?)"),debar); infobuf= m_malloc(memberlen+1); - if (fread(infobuf,1, memberlen + (memberlen&1), ar) != memberlen + (memberlen&1)) - readfail(ar,debar,_("header info member")); + r = read(arfd, infobuf, memberlen + (memberlen & 1)); + if ((size_t)r != (memberlen + (memberlen & 1))) + read_fail(r, debar, _("archive information header member")); infobuf[memberlen] = '\0'; cur= strchr(infobuf,'\n'); if (!cur) ohshit(_("archive has no newlines in header")); @@ -174,7 +212,8 @@ void extracthalf(const char *debar, const char *directory, /* Members with `_' are noncritical, and if we don't understand them * we skip them. */ - stream_null_copy(ar, memberlen + (memberlen&1),_("skipped member data from %s"), debar); + fd_null_copy(arfd, memberlen + (memberlen & 1), + _("skipped archive member data from %s"), debar); } else { if (strncmp(arh.ar_name, ADMINMEMBER, sizeof(arh.ar_name)) == 0) adminmember = 1; @@ -198,7 +237,8 @@ void extracthalf(const char *debar, const char *directory, ctrllennum= memberlen; } if (!adminmember != !admininfo) { - stream_null_copy(ar, memberlen + (memberlen&1),_("skipped member data from %s"), debar); + fd_null_copy(arfd, memberlen + (memberlen & 1), + _("skipped archive member data from %s"), debar); } else { break; /* Yes ! - found it. */ } @@ -221,8 +261,10 @@ void extracthalf(const char *debar, const char *directory, l = strlen(versionbuf); if (l && versionbuf[l - 1] == '\n') versionbuf[l - 1] = '\0'; - if (!fgets(ctrllenbuf,sizeof(ctrllenbuf),ar)) - readfail(ar, debar, _("control information length")); + + r = read_line(arfd, ctrllenbuf, 1, sizeof(ctrllenbuf)); + if (r < 0) + read_fail(r, debar, _("archive control member size")); if (sscanf(ctrllenbuf,"%zi%c%d",&ctrllennum,&nlc,&dummy) !=2 || nlc != '\n') ohshit(_("archive has malformatted control length `%s'"), ctrllenbuf); @@ -230,7 +272,8 @@ void extracthalf(const char *debar, const char *directory, memberlen = ctrllennum; } else { memberlen = stab.st_size - ctrllennum - strlen(ctrllenbuf) - l; - stream_null_copy(ar, ctrllennum, _("skipped control area from %s"), debar); + fd_null_copy(arfd, ctrllennum, + _("skipped archive control member data from %s"), debar); } if (admininfo >= 2) { @@ -252,13 +295,11 @@ void extracthalf(const char *debar, const char *directory, } - safe_fflush(ar); - m_pipe(p1); c1 = subproc_fork(); if (!c1) { close(p1[0]); - stream_fd_copy(ar, p1[1], memberlen, _("failed to write to pipe in copy")); + fd_fd_copy(arfd, p1[1], memberlen, _("failed to write to pipe in copy")); if (close(p1[1])) ohshite(_("failed to close pipe in copy")); exit(0); @@ -275,7 +316,7 @@ void extracthalf(const char *debar, const char *directory, decompress_filter(decompressor, 0, 1, _("data")); } close(p1[0]); - fclose(ar); + close(arfd); if (taroption) close(p2[1]); if (taroption && directory) { -- 1.7.7.6