changeset 30952:61558a67630a v9.0.0810

patch 9.0.0810: readblob() returns empty when trying to read too much Commit: https://github.com/vim/vim/commit/5b2a3d77d320d76f12b1666938a9d58c2a848205 Author: Bram Moolenaar <Bram@vim.org> Date: Fri Oct 21 11:25:30 2022 +0100 patch 9.0.0810: readblob() returns empty when trying to read too much Problem: readblob() returns empty when trying to read too much. Solution: Return what is available.
author Bram Moolenaar <Bram@vim.org>
date Fri, 21 Oct 2022 12:30:05 +0200
parents f2dd117ca94c
children e0b47ccd75a4
files runtime/doc/builtin.txt src/blob.c src/testdir/test_blob.vim src/version.c
diffstat 4 files changed, 32 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -6866,8 +6866,10 @@ readblob({fname} [, {offset} [, {size}]]
 			readblob('/dev/ttyS0', 0, 10)
 <		When the file can't be opened an error message is given and
 		the result is an empty |Blob|.
-		When trying to read bytes beyond the end of the file the
-		result is an empty blob.
+		When the offset is beyond the end of the file the result is an
+		empty blob.
+		When trying to read more bytes than are available the result
+		is truncated.
 		Also see |readfile()| and |writefile()|.
 
 
--- a/src/blob.c
+++ b/src/blob.c
@@ -199,24 +199,32 @@ read_blob(FILE *fd, typval_T *rettv, off
 
     if (offset >= 0)
     {
-	if (size == -1)
+	// The size defaults to the whole file.  If a size is given it is
+	// limited to not go past the end of the file.
+	if (size == -1 || (size > st.st_size - offset
+#ifdef S_ISCHR
+		    && !S_ISCHR(st.st_mode)
+#endif
+		    ))
 	    // size may become negative, checked below
 	    size = st.st_size - offset;
 	whence = SEEK_SET;
     }
     else
     {
-	if (size == -1)
+	// limit the offset to not go before the start of the file
+	if (-offset > st.st_size
+#ifdef S_ISCHR
+		    && !S_ISCHR(st.st_mode)
+#endif
+		    )
+	    offset = -st.st_size;
+	// Size defaults to reading until the end of the file.
+	if (size == -1 || size > -offset)
 	    size = -offset;
 	whence = SEEK_END;
     }
-    // Trying to read bytes that aren't there results in an empty blob, not an
-    // error.
-    if (size <= 0 || (
-#ifdef S_ISCHR
-		!S_ISCHR(st.st_mode) &&
-#endif
-		size > st.st_size))
+    if (size <= 0)
 	return OK;
     if (offset != 0 && vim_fseek(fd, offset, whence) != 0)
 	return OK;
--- a/src/testdir/test_blob.vim
+++ b/src/testdir/test_blob.vim
@@ -499,10 +499,17 @@ func Test_blob_read_write()
       VAR br6 = readblob('Xblob', -3, 2)
       call assert_equal(b[-3 : -2], br6)
       
+      #" reading past end of file, empty result
       VAR br1e = readblob('Xblob', 10000)
       call assert_equal(0z, br1e)
-      VAR br2e = readblob('Xblob', -10000)
-      call assert_equal(0z, br2e)
+
+      #" reading too much, result is truncated
+      VAR blong = readblob('Xblob', -1000)
+      call assert_equal(b, blong)
+      LET blong = readblob('Xblob', -10, 8)
+      call assert_equal(b, blong)
+      LET blong = readblob('Xblob', 0, 10)
+      call assert_equal(b, blong)
 
       call delete('Xblob')
   END
--- a/src/version.c
+++ b/src/version.c
@@ -696,6 +696,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    810,
+/**/
     809,
 /**/
     808,