From 89f961583580b16b5b67b2138d609ffd52f59c75 Mon Sep 17 00:00:00 2001 From: Ross Lagerwall Date: Tue, 29 Oct 2013 06:02:59 +0200 Subject: [PATCH] gio: Don't allow skipping past the end of GLocalFileInputStream The overridden implementation of the skip method for GLocalFileInputStream allows skipping past the end of the file which is inconsistent with the documentation. Prevent this by first seeking to the end of the file and then seeking backwards from there as much as is necessary. https://bugzilla.gnome.org/show_bug.cgi?id=711048 --- gio/glocalfileinputstream.c | 23 +++++++++++++++++++---- gio/tests/readwrite.c | 12 ++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/gio/glocalfileinputstream.c b/gio/glocalfileinputstream.c index 5d4acf66f..2c32353e1 100644 --- a/gio/glocalfileinputstream.c +++ b/gio/glocalfileinputstream.c @@ -185,7 +185,7 @@ g_local_file_input_stream_skip (GInputStream *stream, GCancellable *cancellable, GError **error) { - off_t res, start; + off_t start, end; GLocalFileInputStream *file; file = G_LOCAL_FILE_INPUT_STREAM (stream); @@ -205,8 +205,8 @@ g_local_file_input_stream_skip (GInputStream *stream, return -1; } - res = lseek (file->priv->fd, count, SEEK_CUR); - if (res == -1) + end = lseek (file->priv->fd, 0, SEEK_END); + if (end == -1) { int errsv = errno; @@ -217,7 +217,22 @@ g_local_file_input_stream_skip (GInputStream *stream, return -1; } - return res - start; + if (end - start > count) + { + end = lseek (file->priv->fd, count - (end - start), SEEK_CUR); + if (end == -1) + { + int errsv = errno; + + g_set_error (error, G_IO_ERROR, + g_io_error_from_errno (errsv), + _("Error seeking in file: %s"), + g_strerror (errsv)); + return -1; + } + } + + return end - start; } static gboolean diff --git a/gio/tests/readwrite.c b/gio/tests/readwrite.c index 0484d186a..5ac2f6ff2 100644 --- a/gio/tests/readwrite.c +++ b/gio/tests/readwrite.c @@ -62,6 +62,18 @@ verify_iostream (GFileIOStream *file_iostream) verify_pos (iostream, strlen (original_data)); + res = g_seekable_seek (G_SEEKABLE (iostream), + 10, G_SEEK_SET, + NULL, NULL); + + res = g_input_stream_skip (in, 5, NULL, NULL); + g_assert (res == 5); + verify_pos (iostream, 15); + + res = g_input_stream_skip (in, 10000, NULL, NULL); + g_assert (res == strlen (original_data) - 15); + verify_pos (iostream, strlen (original_data)); + res = g_seekable_seek (G_SEEKABLE (iostream), 10, G_SEEK_SET, NULL, NULL);