From 78eaf928d30d0b16e05d8d63c55a3632a135ed9a Mon Sep 17 00:00:00 2001
From: Guillem Jover <guillem@debian.org>
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 <ctype.h>
 #include <string.h>
 #include <dirent.h>
+#include <fcntl.h>
 #include <unistd.h>
 #include <ar.h>
 #include <stdbool.h>
@@ -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

