changeset 39718:9068bde9c37d

af_alg: Fail in continuable manner on Linux/powerpc64le. Reported by Assaf Gordon <assafgordon@gmail.com> in <https://lists.gnu.org/archive/html/coreutils/2018-06/msg00034.html>. * lib/af_alg.c (afalg_stream): On non-seekable streams, try a single- byte send() as the first round.
author Bruno Haible <bruno@clisp.org>
date Mon, 25 Jun 2018 04:18:30 +0200
parents d4d7547d5731
children 82f14d8df980
files ChangeLog lib/af_alg.c
diffstat 2 files changed, 25 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon Jun 25 00:41:03 2018 +0200
+++ b/ChangeLog	Mon Jun 25 04:18:30 2018 +0200
@@ -1,3 +1,11 @@
+2018-06-24  Bruno Haible  <bruno@clisp.org>
+
+	af_alg: Fail in continuable manner on Linux/powerpc64le.
+	Reported by Assaf Gordon <assafgordon@gmail.com>
+	in <https://lists.gnu.org/archive/html/coreutils/2018-06/msg00034.html>.
+	* lib/af_alg.c (afalg_stream): On non-seekable streams, try a single-
+	byte send() as the first round.
+
 2018-06-24  Bruno Haible  <bruno@clisp.org>
 
 	af_alg: Fix state of stream after sendfile() succeeds.
--- a/lib/af_alg.c	Mon Jun 25 00:41:03 2018 +0200
+++ b/lib/af_alg.c	Mon Jun 25 04:18:30 2018 +0200
@@ -157,7 +157,10 @@
       for (;;)
         {
           char buf[BLOCKSIZE];
-          ssize_t size = fread (buf, 1, sizeof buf, stream);
+          /* When the stream is not seekable, start with a single-byte block,
+             so that we can use ungetc() in the case that send() fails.  */
+          size_t blocksize = (nseek == 0 && off < 0 ? 1 : BLOCKSIZE);
+          ssize_t size = fread (buf, 1, blocksize, stream);
           if (size == 0)
             {
               /* On Linux < 4.9, the value for an empty stream is wrong (all 0).
@@ -170,8 +173,18 @@
           nseek -= size;
           if (send (ofd, buf, size, MSG_MORE) != size)
             {
-              result = (fseeko (stream, nseek, SEEK_CUR) == 0
-                        ? -EAFNOSUPPORT : -EIO);
+              if (nseek == -1)
+                {
+                  /* 1 byte of pushback buffer is guaranteed on stream, even
+                     if stream is not seekable.  */
+                  ungetc ((unsigned char) buf[0], stream);
+                  result = -EAFNOSUPPORT;
+                }
+              else if (fseeko (stream, nseek, SEEK_CUR) == 0)
+                /* The position of stream has been restored.  */
+                result = -EAFNOSUPPORT;
+              else
+                result = -EIO;
               break;
             }
 
@@ -187,6 +200,7 @@
       if (result == 0 && read (ofd, resblock, hashlen) != hashlen)
         {
           if (nseek == 0 || fseeko (stream, nseek, SEEK_CUR) == 0)
+            /* The position of stream has been restored.  */
             result = -EAFNOSUPPORT;
           else
             result = -EIO;