Skip to content

Commit aa49bc2

Browse files
authored
os: implement os.truncate() + improve error handling (#9752)
1 parent 8cb44ed commit aa49bc2

File tree

2 files changed

+49
-7
lines changed

2 files changed

+49
-7
lines changed

vlib/os/os_c.v

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ fn C._wstat64(&char, voidptr) u64
3333

3434
fn C.chown(&char, int, int) int
3535

36+
fn C.ftruncate(voidptr, u64) int
37+
38+
fn C._chsize_s(voidptr, u64) int
39+
3640
// fn C.proc_pidpath(int, byteptr, int) int
3741
struct C.stat {
3842
st_size u64
@@ -130,7 +134,28 @@ pub fn read_file(path string) ?string {
130134
}
131135

132136
// ***************************** OS ops ************************
133-
// file_size returns the size of the file located in `path`.
137+
138+
// truncate changes the size of the file located in `path` to `len`.
139+
pub fn truncate(path string, len u64) ? {
140+
fp := C.open(&char(path.str), o_wronly | o_trunc)
141+
defer {
142+
C.close(fp)
143+
}
144+
if fp < 0 {
145+
return error('open file failed')
146+
}
147+
$if windows {
148+
if C._chsize_s(fp, len) != 0 {
149+
return error_with_code(posix_get_error_msg(C.errno), C.errno)
150+
}
151+
} $else {
152+
if C.ftruncate(fp, len) != 0 {
153+
return error_with_code(posix_get_error_msg(C.errno), C.errno)
154+
}
155+
}
156+
}
157+
158+
// file_size returns the size of the file located in `path`. In case of error -1 is returned.
134159
pub fn file_size(path string) u64 {
135160
mut s := C.stat{}
136161
unsafe {
@@ -157,7 +182,7 @@ pub fn file_size(path string) u64 {
157182
}
158183
}
159184
}
160-
return 0
185+
return -1
161186
}
162187

163188
// mv moves files or folders from `src` to `dst`.
@@ -201,16 +226,18 @@ pub fn cp(src string, dst string) ? {
201226
return error_with_code('cp (permission): failed to write to $dst (fp_to: $fp_to)',
202227
int(fp_to))
203228
}
229+
// TODO use defer{} to close files in case of error or return.
230+
// Currently there is a C-Error when building.
204231
mut buf := [1024]byte{}
205232
mut count := 0
206233
for {
207-
// FIXME: use sizeof, bug: 'os__buf' undeclared
208-
// count = C.read(fp_from, buf, sizeof(buf))
209-
count = C.read(fp_from, &buf[0], 1024)
234+
count = C.read(fp_from, &buf[0], sizeof(buf))
210235
if count == 0 {
211236
break
212237
}
213238
if C.write(fp_to, &buf[0], count) < 0 {
239+
C.close(fp_to)
240+
C.close(fp_from)
214241
return error_with_code('cp: failed to write to $dst', int(-1))
215242
}
216243
}
@@ -219,6 +246,8 @@ pub fn cp(src string, dst string) ? {
219246
C.stat(&char(src.str), &from_attr)
220247
}
221248
if C.chmod(&char(dst.str), from_attr.st_mode) < 0 {
249+
C.close(fp_to)
250+
C.close(fp_from)
222251
return error_with_code('failed to set permissions for $dst', int(-1))
223252
}
224253
C.close(fp_to)
@@ -830,11 +859,11 @@ pub fn flush() {
830859
// Octals like `0o600` can be used.
831860
pub fn chmod(path string, mode int) {
832861
if C.chmod(&char(path.str), mode) != 0 {
833-
panic(posix_get_error_msg(C.errno))
862+
panic('chmod failed: ' + posix_get_error_msg(C.errno))
834863
}
835864
}
836865

837-
// chown change owner and group attributes of path to `owner` and `group`.
866+
// chown changes the owner and group attributes of `path` to `owner` and `group`.
838867
pub fn chown(path string, owner int, group int) ? {
839868
$if windows {
840869
return error('os.chown() not implemented for Windows')

vlib/os/os_test.v

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,3 +573,16 @@ fn test_exists_in_system_path() {
573573
}
574574
assert os.exists_in_system_path('ls')
575575
}
576+
577+
fn test_truncate() {
578+
filename := './test_trunc.txt'
579+
hello := 'hello world!'
580+
mut f := os.create(filename) or { panic(err) }
581+
f.write_string(hello) or { panic(err) }
582+
f.close()
583+
assert hello.len == os.file_size(filename)
584+
newlen := u64(40000)
585+
os.truncate(filename, newlen) or { panic(err) }
586+
assert newlen == os.file_size(filename)
587+
os.rm(filename) or { panic(err) }
588+
}

0 commit comments

Comments
 (0)