diff --git a/vlib/os/os_c.v b/vlib/os/os_c.v index 316166f5af..9b398ed08b 100644 --- a/vlib/os/os_c.v +++ b/vlib/os/os_c.v @@ -33,6 +33,10 @@ fn C._wstat64(&char, voidptr) u64 fn C.chown(&char, int, int) int +fn C.ftruncate(voidptr, u64) int + +fn C._chsize_s(voidptr, u64) int + // fn C.proc_pidpath(int, byteptr, int) int struct C.stat { st_size u64 @@ -130,7 +134,28 @@ pub fn read_file(path string) ?string { } // ***************************** OS ops ************************ -// file_size returns the size of the file located in `path`. + +// truncate changes the size of the file located in `path` to `len`. +pub fn truncate(path string, len u64) ? { + fp := C.open(&char(path.str), o_wronly | o_trunc) + defer { + C.close(fp) + } + if fp < 0 { + return error('open file failed') + } + $if windows { + if C._chsize_s(fp, len) != 0 { + return error_with_code(posix_get_error_msg(C.errno), C.errno) + } + } $else { + if C.ftruncate(fp, len) != 0 { + return error_with_code(posix_get_error_msg(C.errno), C.errno) + } + } +} + +// file_size returns the size of the file located in `path`. In case of error -1 is returned. pub fn file_size(path string) u64 { mut s := C.stat{} unsafe { @@ -157,7 +182,7 @@ pub fn file_size(path string) u64 { } } } - return 0 + return -1 } // mv moves files or folders from `src` to `dst`. @@ -201,16 +226,18 @@ pub fn cp(src string, dst string) ? { return error_with_code('cp (permission): failed to write to $dst (fp_to: $fp_to)', int(fp_to)) } + // TODO use defer{} to close files in case of error or return. + // Currently there is a C-Error when building. mut buf := [1024]byte{} mut count := 0 for { - // FIXME: use sizeof, bug: 'os__buf' undeclared - // count = C.read(fp_from, buf, sizeof(buf)) - count = C.read(fp_from, &buf[0], 1024) + count = C.read(fp_from, &buf[0], sizeof(buf)) if count == 0 { break } if C.write(fp_to, &buf[0], count) < 0 { + C.close(fp_to) + C.close(fp_from) return error_with_code('cp: failed to write to $dst', int(-1)) } } @@ -219,6 +246,8 @@ pub fn cp(src string, dst string) ? { C.stat(&char(src.str), &from_attr) } if C.chmod(&char(dst.str), from_attr.st_mode) < 0 { + C.close(fp_to) + C.close(fp_from) return error_with_code('failed to set permissions for $dst', int(-1)) } C.close(fp_to) @@ -830,11 +859,11 @@ pub fn flush() { // Octals like `0o600` can be used. pub fn chmod(path string, mode int) { if C.chmod(&char(path.str), mode) != 0 { - panic(posix_get_error_msg(C.errno)) + panic('chmod failed: ' + posix_get_error_msg(C.errno)) } } -// chown change owner and group attributes of path to `owner` and `group`. +// chown changes the owner and group attributes of `path` to `owner` and `group`. pub fn chown(path string, owner int, group int) ? { $if windows { return error('os.chown() not implemented for Windows') diff --git a/vlib/os/os_test.v b/vlib/os/os_test.v index 37136b73de..0f16d028d2 100644 --- a/vlib/os/os_test.v +++ b/vlib/os/os_test.v @@ -573,3 +573,16 @@ fn test_exists_in_system_path() { } assert os.exists_in_system_path('ls') } + +fn test_truncate() { + filename := './test_trunc.txt' + hello := 'hello world!' + mut f := os.create(filename) or { panic(err) } + f.write_string(hello) or { panic(err) } + f.close() + assert hello.len == os.file_size(filename) + newlen := u64(40000) + os.truncate(filename, newlen) or { panic(err) } + assert newlen == os.file_size(filename) + os.rm(filename) or { panic(err) } +}