1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

os: fix file read end-of-file detection (#10070)

This commit is contained in:
Leigh McCulloch
2021-05-12 23:48:55 -07:00
committed by GitHub
parent ebe58dcafa
commit 49deeac71e
3 changed files with 110 additions and 63 deletions

View File

@@ -321,6 +321,31 @@ pub fn (mut f File) write_ptr_at(data voidptr, size int, pos u64) int {
}
// **************************** Read ops ***************************
// fread wraps C.fread and handles error and end-of-file detection.
fn fread(ptr voidptr, item_size int, items int, stream &C.FILE) ?int {
nbytes := int(C.fread(ptr, item_size, items, stream))
// If no bytes were read, check for errors and end-of-file.
if nbytes <= 0 {
// If fread encountered end-of-file return the none error. Note that fread
// may read data and encounter the end-of-file, but we shouldn't return none
// in that case which is why we only check for end-of-file if no data was
// read. The caller will get none on their next call because there will be
// no data available and the end-of-file will be encountered again.
if C.feof(stream) != 0 {
return none
}
// If fread encountered an error, return it. Note that fread and ferror do
// not tell us what the error was, so we can't return anything more specific
// than there was an error. This is because fread and ferror do not set
// errno.
if C.ferror(stream) != 0 {
return error('file read error')
}
}
return nbytes
}
// read_bytes reads bytes from the beginning of the file.
// Utility method, same as .read_bytes_at(size, 0).
pub fn (f &File) read_bytes(size int) []byte {
@@ -348,23 +373,14 @@ pub fn (f &File) read_bytes_into(pos u64, mut buf []byte) ?int {
$if windows {
// Note: fseek errors if pos == os.file_size, which we accept
C._fseeki64(f.cfile, pos, C.SEEK_SET)
// errno is only set if fread fails, so clear it first to tell
C.errno = 0
nbytes := int(C.fread(buf.data, 1, buf.len, f.cfile))
if C.errno != 0 {
return error(posix_get_error_msg(C.errno))
}
nbytes := fread(buf.data, 1, buf.len, f.cfile) ?
$if debug {
C._fseeki64(f.cfile, 0, C.SEEK_SET)
}
return nbytes
} $else {
C.fseeko(f.cfile, pos, C.SEEK_SET)
C.errno = 0
nbytes := int(C.fread(buf.data, 1, buf.len, f.cfile))
if C.errno != 0 {
return error(posix_get_error_msg(C.errno))
}
nbytes := fread(buf.data, 1, buf.len, f.cfile) ?
$if debug {
C.fseeko(f.cfile, 0, C.SEEK_SET)
}
@@ -373,11 +389,7 @@ pub fn (f &File) read_bytes_into(pos u64, mut buf []byte) ?int {
}
$if x32 {
C.fseek(f.cfile, pos, C.SEEK_SET)
C.errno = 0
nbytes := int(C.fread(buf.data, 1, buf.len, f.cfile))
if C.errno != 0 {
return error(posix_get_error_msg(C.errno))
}
nbytes := fread(buf.data, 1, buf.len, f.cfile) ?
$if debug {
C.fseek(f.cfile, 0, C.SEEK_SET)
}
@@ -391,11 +403,7 @@ pub fn (f &File) read(mut buf []byte) ?int {
if buf.len == 0 {
return 0
}
C.errno = 0
nbytes := int(C.fread(buf.data, 1, buf.len, f.cfile))
if C.errno != 0 {
return error(posix_get_error_msg(C.errno))
}
nbytes := fread(buf.data, 1, buf.len, f.cfile) ?
return nbytes
}
@@ -417,20 +425,12 @@ pub fn (f &File) read_from(pos u64, mut buf []byte) ?int {
C.fseeko(f.cfile, pos, C.SEEK_SET)
}
C.errno = 0
nbytes := int(C.fread(buf.data, 1, buf.len, f.cfile))
if C.errno != 0 {
return error(posix_get_error_msg(C.errno))
}
nbytes := fread(buf.data, 1, buf.len, f.cfile) ?
return nbytes
}
$if x32 {
C.fseek(f.cfile, pos, C.SEEK_SET)
C.errno = 0
nbytes := int(C.fread(buf.data, 1, buf.len, f.cfile))
if C.errno != 0 {
return error(posix_get_error_msg(C.errno))
}
nbytes := fread(buf.data, 1, buf.len, f.cfile) ?
return nbytes
}
return error('Could not read file')
@@ -461,11 +461,7 @@ pub fn (mut f File) read_struct<T>(mut t T) ? {
if tsize == 0 {
return none
}
C.errno = 0
nbytes := int(C.fread(t, 1, tsize, f.cfile))
if C.errno != 0 {
return error(posix_get_error_msg(C.errno))
}
nbytes := fread(t, 1, tsize, f.cfile) ?
if nbytes != tsize {
return error_with_code('incomplete struct read', nbytes)
}
@@ -480,27 +476,23 @@ pub fn (mut f File) read_struct_at<T>(mut t T, pos u64) ? {
if tsize == 0 {
return none
}
C.errno = 0
mut nbytes := 0
$if x64 {
$if windows {
C._fseeki64(f.cfile, pos, C.SEEK_SET)
nbytes = int(C.fread(t, 1, tsize, f.cfile))
nbytes = fread(t, 1, tsize, f.cfile) ?
C._fseeki64(f.cfile, 0, C.SEEK_END)
} $else {
C.fseeko(f.cfile, pos, C.SEEK_SET)
nbytes = int(C.fread(t, 1, tsize, f.cfile))
nbytes = fread(t, 1, tsize, f.cfile) ?
C.fseeko(f.cfile, 0, C.SEEK_END)
}
}
$if x32 {
C.fseek(f.cfile, pos, C.SEEK_SET)
nbytes = int(C.fread(t, 1, tsize, f.cfile))
nbytes = fread(t, 1, tsize, f.cfile) ?
C.fseek(f.cfile, 0, C.SEEK_END)
}
if C.errno != 0 {
return error(posix_get_error_msg(C.errno))
}
if nbytes != tsize {
return error_with_code('incomplete struct read', nbytes)
}
@@ -515,12 +507,8 @@ pub fn (mut f File) read_raw<T>() ?T {
if tsize == 0 {
return none
}
C.errno = 0
mut t := T{}
nbytes := int(C.fread(&t, 1, tsize, f.cfile))
if C.errno != 0 {
return error(posix_get_error_msg(C.errno))
}
nbytes := fread(&t, 1, tsize, f.cfile) ?
if nbytes != tsize {
return error_with_code('incomplete struct read', nbytes)
}
@@ -536,7 +524,6 @@ pub fn (mut f File) read_raw_at<T>(pos u64) ?T {
if tsize == 0 {
return none
}
C.errno = 0
mut nbytes := 0
mut t := T{}
$if x64 {
@@ -544,10 +531,7 @@ pub fn (mut f File) read_raw_at<T>(pos u64) ?T {
if C._fseeki64(f.cfile, pos, C.SEEK_SET) != 0 {
return error(posix_get_error_msg(C.errno))
}
nbytes = int(C.fread(&t, 1, tsize, f.cfile))
if C.errno != 0 {
return error(posix_get_error_msg(C.errno))
}
nbytes = fread(&t, 1, tsize, f.cfile) ?
if C._fseeki64(f.cfile, 0, C.SEEK_END) != 0 {
return error(posix_get_error_msg(C.errno))
}
@@ -555,10 +539,7 @@ pub fn (mut f File) read_raw_at<T>(pos u64) ?T {
if C.fseeko(f.cfile, pos, C.SEEK_SET) != 0 {
return error(posix_get_error_msg(C.errno))
}
nbytes = int(C.fread(&t, 1, tsize, f.cfile))
if C.errno != 0 {
return error(posix_get_error_msg(C.errno))
}
nbytes = fread(&t, 1, tsize, f.cfile) ?
if C.fseeko(f.cfile, 0, C.SEEK_END) != 0 {
return error(posix_get_error_msg(C.errno))
}
@@ -568,10 +549,7 @@ pub fn (mut f File) read_raw_at<T>(pos u64) ?T {
if C.fseek(f.cfile, pos, C.SEEK_SET) != 0 {
return error(posix_get_error_msg(C.errno))
}
nbytes = int(C.fread(&t, 1, tsize, f.cfile))
if C.errno != 0 {
return error(posix_get_error_msg(C.errno))
}
nbytes = fread(&t, 1, tsize, f.cfile) ?
if C.fseek(f.cfile, 0, C.SEEK_END) != 0 {
return error(posix_get_error_msg(C.errno))
}