summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-10-21 11:25:30 +0100
committerBram Moolenaar <Bram@vim.org>2022-10-21 11:25:30 +0100
commit5b2a3d77d320d76f12b1666938a9d58c2a848205 (patch)
tree435466e4c1e4d0ede36dd3e499e91ffebf0166e4
parent63c84731c1802bac36c1d1a82b3ef5960b35b089 (diff)
downloadvim-git-5b2a3d77d320d76f12b1666938a9d58c2a848205.tar.gz
patch 9.0.0810: readblob() returns empty when trying to read too muchv9.0.0810
Problem: readblob() returns empty when trying to read too much. Solution: Return what is available.
-rw-r--r--runtime/doc/builtin.txt6
-rw-r--r--src/blob.c26
-rw-r--r--src/testdir/test_blob.vim11
-rw-r--r--src/version.c2
4 files changed, 32 insertions, 13 deletions
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index 5b383fdfc..5cb0bd950 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -6866,8 +6866,10 @@ readblob({fname} [, {offset} [, {size}]]) *readblob()*
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()|.
diff --git a/src/blob.c b/src/blob.c
index a94316c13..311b87e49 100644
--- a/src/blob.c
+++ b/src/blob.c
@@ -199,24 +199,32 @@ read_blob(FILE *fd, typval_T *rettv, off_T offset, off_T size_arg)
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;
diff --git a/src/testdir/test_blob.vim b/src/testdir/test_blob.vim
index 47315ab84..4a957aa72 100644
--- 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
diff --git a/src/version.c b/src/version.c
index 94e5d5c95..4017c4720 100644
--- 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,