[glib: 1/3] ginputstream: Don’t skip off the end of resizable streams




commit 58c6e0e5d45f545040b799ca676da79690d146b7
Author: Philip Withnall <pwithnall endlessos org>
Date:   Mon Feb 15 14:58:04 2021 +0000

    ginputstream: Don’t skip off the end of resizable streams
    
    The default implementation of `g_input_stream_skip()` can skip off the
    end of resizable streams, as that’s the behaviour of `g_seekable_seek()`
    for that type of stream.
    
    This has previously been fixed for local file input streams (commit
    89f961583580b16b5b67b2138d609ffd52f59c75), and a unit test added there.
    However, the fix should be more generally made in `GInputStream`.
    
    This commit reworks an old patch by Dan Winship on
    https://bugzilla.gnome.org/show_bug.cgi?id=681374, which took that
    approach.
    
    Signed-off-by: Philip Withnall <pwithnall endlessos org>
    
    Fixes: #587

 gio/ginputstream.c | 39 ++++++++++++++++++++++++++++++++++-----
 1 file changed, 34 insertions(+), 5 deletions(-)
---
diff --git a/gio/ginputstream.c b/gio/ginputstream.c
index 20cece53d..383495162 100644
--- a/gio/ginputstream.c
+++ b/gio/ginputstream.c
@@ -411,12 +411,41 @@ g_input_stream_real_skip (GInputStream  *stream,
 
   if (G_IS_SEEKABLE (stream) && g_seekable_can_seek (G_SEEKABLE (stream)))
     {
+      GSeekable *seekable = G_SEEKABLE (stream);
+      goffset start, end;
+      gboolean success;
+
+      /* g_seekable_seek() may try to set pending itself */
+      stream->priv->pending = FALSE;
+
+      start = g_seekable_tell (seekable);
+
       if (g_seekable_seek (G_SEEKABLE (stream),
-                          count,
-                          G_SEEK_CUR,
-                          cancellable,
-                          NULL))
-       return count;
+                           0,
+                           G_SEEK_END,
+                           cancellable,
+                           NULL))
+        {
+          end = g_seekable_tell (seekable);
+          g_assert (end >= start);
+          if (start > G_MAXSIZE - count || start + count > end)
+            {
+              stream->priv->pending = TRUE;
+              return end - start;
+            }
+
+          success = g_seekable_seek (G_SEEKABLE (stream),
+                                     start + count,
+                                     G_SEEK_SET,
+                                     cancellable,
+                                     error);
+          stream->priv->pending = TRUE;
+
+          if (success)
+            return count;
+          else
+            return -1;
+        }
     }
 
   /* If not seekable, or seek failed, fall back to reading data: */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]