mirror of
https://github.com/vlang/v.git
synced 2025-09-13 22:42:26 +03:00
os: simplify file.c.v using cross platform f.seek/2 calls, add EINTR handling to f.write_full_buffer/2 (fix #25107)
This commit is contained in:
parent
bbb61ab368
commit
c4ef79d146
1 changed files with 50 additions and 226 deletions
276
vlib/os/file.c.v
276
vlib/os/file.c.v
|
@ -105,23 +105,20 @@ pub fn open_file(path string, mode string, options ...int) !File {
|
||||||
if fd == -1 {
|
if fd == -1 {
|
||||||
return error(posix_get_error_msg(C.errno))
|
return error(posix_get_error_msg(C.errno))
|
||||||
}
|
}
|
||||||
cfile := C.fdopen(fd, &char(mode.str))
|
mut cfile := C.fdopen(fd, &char(mode.str))
|
||||||
if isnil(cfile) {
|
if isnil(cfile) {
|
||||||
return error('Failed to open or create file "${path}"')
|
return error('Failed to open or create file "${path}"')
|
||||||
}
|
}
|
||||||
if seek_to_end {
|
mut res := File{
|
||||||
// ensure appending will work, even on bsd/macos systems:
|
|
||||||
$if windows {
|
|
||||||
C._fseeki64(cfile, 0, C.SEEK_END)
|
|
||||||
} $else {
|
|
||||||
C.fseeko(cfile, 0, C.SEEK_END)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return File{
|
|
||||||
cfile: cfile
|
cfile: cfile
|
||||||
fd: fd
|
fd: fd
|
||||||
is_opened: true
|
is_opened: true
|
||||||
}
|
}
|
||||||
|
if seek_to_end {
|
||||||
|
// ensure appending will work, even on bsd/macos systems:
|
||||||
|
res.seek(0, .end) or {}
|
||||||
|
}
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// open tries to open a file from a given path for reading.
|
// open tries to open a file from a given path for reading.
|
||||||
|
@ -304,35 +301,13 @@ pub fn (mut f File) write_to(pos u64, buf []u8) !int {
|
||||||
if !f.is_opened {
|
if !f.is_opened {
|
||||||
return error_file_not_opened()
|
return error_file_not_opened()
|
||||||
}
|
}
|
||||||
$if x64 {
|
f.seek(pos, .start) or {}
|
||||||
$if windows {
|
res := int(C.fwrite(buf.data, 1, buf.len, f.cfile))
|
||||||
C._fseeki64(f.cfile, pos, C.SEEK_SET)
|
if res == 0 && buf.len != 0 {
|
||||||
res := int(C.fwrite(buf.data, 1, buf.len, f.cfile))
|
return error('0 bytes written')
|
||||||
if res == 0 && buf.len != 0 {
|
|
||||||
return error('0 bytes written')
|
|
||||||
}
|
|
||||||
C._fseeki64(f.cfile, 0, C.SEEK_END)
|
|
||||||
return res
|
|
||||||
} $else {
|
|
||||||
C.fseeko(f.cfile, pos, C.SEEK_SET)
|
|
||||||
res := int(C.fwrite(buf.data, 1, buf.len, f.cfile))
|
|
||||||
if res == 0 && buf.len != 0 {
|
|
||||||
return error('0 bytes written')
|
|
||||||
}
|
|
||||||
C.fseeko(f.cfile, 0, C.SEEK_END)
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$if x32 {
|
f.seek(0, .end) or {}
|
||||||
C.fseek(f.cfile, pos, C.SEEK_SET)
|
return res
|
||||||
res := int(C.fwrite(buf.data, 1, buf.len, f.cfile))
|
|
||||||
if res == 0 && buf.len != 0 {
|
|
||||||
return error('0 bytes written')
|
|
||||||
}
|
|
||||||
C.fseek(f.cfile, 0, C.SEEK_END)
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
return error('Could not write to file')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// write_ptr writes `size` bytes to the file, starting from the address in `data`.
|
// write_ptr writes `size` bytes to the file, starting from the address in `data`.
|
||||||
|
@ -358,9 +333,17 @@ pub fn (mut f File) write_full_buffer(buffer voidptr, buffer_len usize) ! {
|
||||||
mut remaining_bytes := i64(buffer_len)
|
mut remaining_bytes := i64(buffer_len)
|
||||||
for remaining_bytes > 0 {
|
for remaining_bytes > 0 {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
C.errno = 0
|
||||||
x := i64(C.fwrite(ptr, 1, remaining_bytes, f.cfile))
|
x := i64(C.fwrite(ptr, 1, remaining_bytes, f.cfile))
|
||||||
|
cerror := C.errno
|
||||||
ptr += x
|
ptr += x
|
||||||
remaining_bytes -= x
|
remaining_bytes -= x
|
||||||
|
if cerror != 0 {
|
||||||
|
if cerror == C.EINTR {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return error(posix_get_error_msg(cerror))
|
||||||
|
}
|
||||||
if x <= 0 {
|
if x <= 0 {
|
||||||
return error('C.fwrite returned 0')
|
return error('C.fwrite returned 0')
|
||||||
}
|
}
|
||||||
|
@ -374,26 +357,10 @@ pub fn (mut f File) write_full_buffer(buffer voidptr, buffer_len usize) ! {
|
||||||
// pointers to it, it will cause your programs to segfault.
|
// pointers to it, it will cause your programs to segfault.
|
||||||
@[unsafe]
|
@[unsafe]
|
||||||
pub fn (mut f File) write_ptr_at(data voidptr, size int, pos u64) int {
|
pub fn (mut f File) write_ptr_at(data voidptr, size int, pos u64) int {
|
||||||
$if x64 {
|
f.seek(pos, .start) or {}
|
||||||
$if windows {
|
res := int(C.fwrite(data, 1, size, f.cfile))
|
||||||
C._fseeki64(f.cfile, pos, C.SEEK_SET)
|
f.seek(0, .end) or {}
|
||||||
res := int(C.fwrite(data, 1, size, f.cfile))
|
return res
|
||||||
C._fseeki64(f.cfile, 0, C.SEEK_END)
|
|
||||||
return res
|
|
||||||
} $else {
|
|
||||||
C.fseeko(f.cfile, pos, C.SEEK_SET)
|
|
||||||
res := int(C.fwrite(data, 1, size, f.cfile))
|
|
||||||
C.fseeko(f.cfile, 0, C.SEEK_END)
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$if x32 {
|
|
||||||
C.fseek(f.cfile, pos, C.SEEK_SET)
|
|
||||||
res := int(C.fwrite(data, 1, size, f.cfile))
|
|
||||||
C.fseek(f.cfile, 0, C.SEEK_END)
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// **************************** Read ops ***************************
|
// **************************** Read ops ***************************
|
||||||
|
@ -485,34 +452,13 @@ pub fn (f &File) read_bytes_into(pos u64, mut buf []u8) !int {
|
||||||
if buf.len == 0 {
|
if buf.len == 0 {
|
||||||
return error(@FN + ': `buf.len` == 0')
|
return error(@FN + ': `buf.len` == 0')
|
||||||
}
|
}
|
||||||
$if x64 {
|
// Note: fseek errors if pos == os.file_size, which we accept
|
||||||
$if windows {
|
unsafe { f.seek(pos, .start) or {} }
|
||||||
// Note: fseek errors if pos == os.file_size, which we accept
|
nbytes := fread(buf.data, 1, buf.len, f.cfile)!
|
||||||
C._fseeki64(f.cfile, pos, C.SEEK_SET)
|
$if debug {
|
||||||
nbytes := fread(buf.data, 1, buf.len, f.cfile)!
|
unsafe { f.seek(0, end) or {} }
|
||||||
$if debug {
|
|
||||||
C._fseeki64(f.cfile, 0, C.SEEK_SET)
|
|
||||||
}
|
|
||||||
return nbytes
|
|
||||||
} $else {
|
|
||||||
C.fseeko(f.cfile, pos, C.SEEK_SET)
|
|
||||||
// TODO(alex): require casts for voidptrs? &C.FILE(f.cfile)
|
|
||||||
nbytes := fread(buf.data, 1, buf.len, f.cfile)!
|
|
||||||
$if debug {
|
|
||||||
C.fseeko(f.cfile, 0, C.SEEK_SET)
|
|
||||||
}
|
|
||||||
return nbytes
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$if x32 {
|
return nbytes
|
||||||
C.fseek(f.cfile, pos, C.SEEK_SET)
|
|
||||||
nbytes := fread(buf.data, 1, buf.len, f.cfile)!
|
|
||||||
$if debug {
|
|
||||||
C.fseek(f.cfile, 0, C.SEEK_SET)
|
|
||||||
}
|
|
||||||
return nbytes
|
|
||||||
}
|
|
||||||
return error('Could not read file')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// read_from implements the RandomReader interface.
|
// read_from implements the RandomReader interface.
|
||||||
|
@ -520,22 +466,9 @@ pub fn (f &File) read_from(pos u64, mut buf []u8) !int {
|
||||||
if buf.len == 0 {
|
if buf.len == 0 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
$if x64 {
|
unsafe { f.seek(pos, .start) or {} }
|
||||||
$if windows {
|
nbytes := fread(buf.data, 1, buf.len, f.cfile)!
|
||||||
C._fseeki64(f.cfile, pos, C.SEEK_SET)
|
return nbytes
|
||||||
} $else {
|
|
||||||
C.fseeko(f.cfile, pos, C.SEEK_SET)
|
|
||||||
}
|
|
||||||
|
|
||||||
nbytes := fread(buf.data, 1, buf.len, f.cfile)!
|
|
||||||
return nbytes
|
|
||||||
}
|
|
||||||
$if x32 {
|
|
||||||
C.fseek(f.cfile, pos, C.SEEK_SET)
|
|
||||||
nbytes := fread(buf.data, 1, buf.len, f.cfile)!
|
|
||||||
return nbytes
|
|
||||||
}
|
|
||||||
return error('Could not read file')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// read_into_ptr reads at most `max_size` bytes from the file and writes it into ptr.
|
// read_into_ptr reads at most `max_size` bytes from the file and writes it into ptr.
|
||||||
|
@ -602,23 +535,9 @@ pub fn (mut f File) read_struct_at[T](mut t T, pos u64) ! {
|
||||||
if tsize == 0 {
|
if tsize == 0 {
|
||||||
return error_size_of_type_0()
|
return error_size_of_type_0()
|
||||||
}
|
}
|
||||||
mut nbytes := 0
|
f.seek(pos, .start) or {}
|
||||||
$if x64 {
|
nbytes := fread(t, 1, tsize, f.cfile)!
|
||||||
$if windows {
|
f.seek(0, .end) or {}
|
||||||
C._fseeki64(f.cfile, pos, C.SEEK_SET)
|
|
||||||
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 = 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 = fread(t, 1, tsize, f.cfile)!
|
|
||||||
C.fseek(f.cfile, 0, C.SEEK_END)
|
|
||||||
}
|
|
||||||
if nbytes != tsize {
|
if nbytes != tsize {
|
||||||
return error_with_code('incomplete struct read', nbytes)
|
return error_with_code('incomplete struct read', nbytes)
|
||||||
}
|
}
|
||||||
|
@ -650,37 +569,10 @@ pub fn (mut f File) read_raw_at[T](pos u64) !T {
|
||||||
if tsize == 0 {
|
if tsize == 0 {
|
||||||
return error_size_of_type_0()
|
return error_size_of_type_0()
|
||||||
}
|
}
|
||||||
mut nbytes := 0
|
|
||||||
mut t := T{}
|
mut t := T{}
|
||||||
$if x64 {
|
f.seek(pos, .start)!
|
||||||
$if windows {
|
nbytes := fread(&t, 1, tsize, f.cfile)!
|
||||||
if C._fseeki64(f.cfile, pos, C.SEEK_SET) != 0 {
|
f.seek(0, .end)!
|
||||||
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))
|
|
||||||
}
|
|
||||||
} $else {
|
|
||||||
if C.fseeko(f.cfile, pos, C.SEEK_SET) != 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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$if x32 {
|
|
||||||
if C.fseek(f.cfile, pos, C.SEEK_SET) != 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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if nbytes != tsize {
|
if nbytes != tsize {
|
||||||
return error_with_code('incomplete struct read', nbytes)
|
return error_with_code('incomplete struct read', nbytes)
|
||||||
}
|
}
|
||||||
|
@ -711,34 +603,13 @@ pub fn (mut f File) write_struct_at[T](t &T, pos u64) ! {
|
||||||
if !f.is_opened {
|
if !f.is_opened {
|
||||||
return error_file_not_opened()
|
return error_file_not_opened()
|
||||||
}
|
}
|
||||||
tsize := int(sizeof(T))
|
tsize := usize(sizeof(T))
|
||||||
if tsize == 0 {
|
if tsize == 0 {
|
||||||
return error_size_of_type_0()
|
return error_size_of_type_0()
|
||||||
}
|
}
|
||||||
C.errno = 0
|
f.seek(pos, .start) or {}
|
||||||
mut nbytes := 0
|
unsafe { f.write_full_buffer(t, tsize)! }
|
||||||
$if x64 {
|
f.seek(0, .end) or {}
|
||||||
$if windows {
|
|
||||||
C._fseeki64(f.cfile, pos, C.SEEK_SET)
|
|
||||||
nbytes = int(C.fwrite(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.fwrite(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.fwrite(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 write', nbytes)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: `write_raw[_at]` implementations are copy-pasted from `write_struct[_at]`
|
// TODO: `write_raw[_at]` implementations are copy-pasted from `write_struct[_at]`
|
||||||
|
@ -748,18 +619,11 @@ pub fn (mut f File) write_raw[T](t &T) ! {
|
||||||
if !f.is_opened {
|
if !f.is_opened {
|
||||||
return error_file_not_opened()
|
return error_file_not_opened()
|
||||||
}
|
}
|
||||||
tsize := int(sizeof(T))
|
tsize := usize(sizeof(T))
|
||||||
if tsize == 0 {
|
if tsize == 0 {
|
||||||
return error_size_of_type_0()
|
return error_size_of_type_0()
|
||||||
}
|
}
|
||||||
C.errno = 0
|
unsafe { f.write_full_buffer(t, tsize)! }
|
||||||
nbytes := int(C.fwrite(t, 1, tsize, f.cfile))
|
|
||||||
if C.errno != 0 {
|
|
||||||
return error(posix_get_error_msg(C.errno))
|
|
||||||
}
|
|
||||||
if nbytes != tsize {
|
|
||||||
return error_with_code('incomplete struct write', nbytes)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// write_raw_at writes a single instance of type `T` starting at file byte offset `pos`.
|
// write_raw_at writes a single instance of type `T` starting at file byte offset `pos`.
|
||||||
|
@ -767,53 +631,13 @@ pub fn (mut f File) write_raw_at[T](t &T, pos u64) ! {
|
||||||
if !f.is_opened {
|
if !f.is_opened {
|
||||||
return error_file_not_opened()
|
return error_file_not_opened()
|
||||||
}
|
}
|
||||||
tsize := int(sizeof(T))
|
tsize := usize(sizeof(T))
|
||||||
if tsize == 0 {
|
if tsize == 0 {
|
||||||
return error_size_of_type_0()
|
return error_size_of_type_0()
|
||||||
}
|
}
|
||||||
mut nbytes := 0
|
f.seek(pos, .start)!
|
||||||
|
unsafe { f.write_full_buffer(t, tsize)! }
|
||||||
$if x64 {
|
f.seek(0, .end)!
|
||||||
$if windows {
|
|
||||||
if C._fseeki64(f.cfile, pos, C.SEEK_SET) != 0 {
|
|
||||||
return error(posix_get_error_msg(C.errno))
|
|
||||||
}
|
|
||||||
nbytes = int(C.fwrite(t, 1, tsize, f.cfile))
|
|
||||||
if C.errno != 0 {
|
|
||||||
return error(posix_get_error_msg(C.errno))
|
|
||||||
}
|
|
||||||
if C._fseeki64(f.cfile, 0, C.SEEK_END) != 0 {
|
|
||||||
return error(posix_get_error_msg(C.errno))
|
|
||||||
}
|
|
||||||
} $else {
|
|
||||||
if C.fseeko(f.cfile, pos, C.SEEK_SET) != 0 {
|
|
||||||
return error(posix_get_error_msg(C.errno))
|
|
||||||
}
|
|
||||||
nbytes = int(C.fwrite(t, 1, tsize, f.cfile))
|
|
||||||
if C.errno != 0 {
|
|
||||||
return error(posix_get_error_msg(C.errno))
|
|
||||||
}
|
|
||||||
if C.fseeko(f.cfile, 0, C.SEEK_END) != 0 {
|
|
||||||
return error(posix_get_error_msg(C.errno))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$if x32 {
|
|
||||||
if C.fseek(f.cfile, pos, C.SEEK_SET) != 0 {
|
|
||||||
return error(posix_get_error_msg(C.errno))
|
|
||||||
}
|
|
||||||
nbytes = int(C.fwrite(t, 1, tsize, f.cfile))
|
|
||||||
if C.errno != 0 {
|
|
||||||
return error(posix_get_error_msg(C.errno))
|
|
||||||
}
|
|
||||||
if C.fseek(f.cfile, 0, C.SEEK_END) != 0 {
|
|
||||||
return error(posix_get_error_msg(C.errno))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if nbytes != tsize {
|
|
||||||
return error_with_code('incomplete struct write', nbytes)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum SeekMode {
|
pub enum SeekMode {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue