Skip to content

Commit 8f98f1d

Browse files
authored
os: fix os.open_file('text.txt', 'wb', 0o666), add test (#15420)
1 parent cae7bc9 commit 8f98f1d

File tree

3 files changed

+62
-28
lines changed

3 files changed

+62
-28
lines changed

vlib/os/const_nix.c.v

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
module os
22

3-
// File modes
43
const (
5-
o_rdonly = 0o00000000 // open the file read-only.
6-
o_wronly = 0o00000001 // open the file write-only.
7-
o_rdwr = 0o00000002 // open the file read-write.
8-
o_binary = 0o00000000 // input and output is not translated; the default on unix
9-
o_create = 0o00000100 // create a new file if none exists.
10-
o_excl = 0o00000200 // used with o_create, file must not exist.
11-
o_noctty = 0o00000400 // if file is terminal, don't make it the controller terminal
12-
o_trunc = 0o00001000 // truncate regular writable file when opened.
13-
o_append = 0o00002000 // append data to the file when writing.
14-
o_nonblock = 0o00004000 // prevents blocking when opening files
15-
o_sync = 0o04010000 // open for synchronous I/O.
4+
o_binary = 0 // input and output is not translated; the default on unix
5+
o_rdonly = C.O_RDONLY // open the file read-only.
6+
o_wronly = C.O_WRONLY // open the file write-only.
7+
o_rdwr = C.O_RDWR // open the file read-write.
8+
o_create = C.O_CREAT // create a new file if none exists.
9+
o_excl = C.O_EXCL // used with o_create, file must not exist.
10+
o_noctty = C.O_NOCTTY // if file is terminal, don't make it the controller terminal
11+
o_trunc = C.O_TRUNC // truncate regular writable file when opened.
12+
o_append = C.O_APPEND // append data to the file when writing.
13+
o_nonblock = C.O_NONBLOCK // prevents blocking when opening files
14+
o_sync = C.O_SYNC // open for synchronous I/O.
1615
)

vlib/os/file.c.v

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -54,28 +54,41 @@ fn fix_windows_path(path string) string {
5454
// open_file can be used to open or create a file with custom flags and permissions and returns a `File` object.
5555
pub fn open_file(path string, mode string, options ...int) ?File {
5656
mut flags := 0
57+
mut seek_to_end := false
5758
for m in mode {
5859
match m {
59-
`w` { flags |= o_create | o_trunc }
60-
`a` { flags |= o_create | o_append }
61-
`r` { flags |= o_rdonly }
62-
`b` { flags |= o_binary }
63-
`s` { flags |= o_sync }
64-
`n` { flags |= o_nonblock }
65-
`c` { flags |= o_noctty }
66-
`+` { flags |= o_rdwr }
60+
`w` {
61+
flags |= o_create | o_trunc | o_wronly
62+
}
63+
`a` {
64+
flags |= o_create | o_append | o_wronly
65+
seek_to_end = true
66+
}
67+
`r` {
68+
flags |= o_rdonly
69+
}
70+
`b` {
71+
flags |= o_binary
72+
}
73+
`s` {
74+
flags |= o_sync
75+
}
76+
`n` {
77+
flags |= o_nonblock
78+
}
79+
`c` {
80+
flags |= o_noctty
81+
}
82+
`+` {
83+
flags &= ~o_wronly
84+
flags |= o_rdwr
85+
}
6786
else {}
6887
}
6988
}
7089
if mode == 'r+' {
7190
flags = o_rdwr
7291
}
73-
if mode == 'w' {
74-
flags = o_wronly | o_create | o_trunc
75-
}
76-
if mode == 'a' {
77-
flags = o_wronly | o_create | o_append
78-
}
7992
mut permission := 0o666
8093
if options.len > 0 {
8194
permission = options[0]
@@ -92,10 +105,19 @@ pub fn open_file(path string, mode string, options ...int) ?File {
92105
if fd == -1 {
93106
return error(posix_get_error_msg(C.errno))
94107
}
95-
cfile := C.fdopen(fd, &char(mode.str))
108+
fdopen_mode := mode.replace('b', '')
109+
cfile := C.fdopen(fd, &char(fdopen_mode.str))
96110
if isnil(cfile) {
97111
return error('Failed to open or create file "$path"')
98112
}
113+
if seek_to_end {
114+
// ensure appending will work, even on bsd/macos systems:
115+
$if windows {
116+
C._fseeki64(cfile, 0, C.SEEK_END)
117+
} $else {
118+
C.fseeko(cfile, 0, C.SEEK_END)
119+
}
120+
}
99121
return File{
100122
cfile: cfile
101123
fd: fd

vlib/os/file_test.v

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ fn test_reopen() ? {
388388
f2.reopen(tfile1, 'r')?
389389
assert !f2.eof()
390390

391-
z := f2.read(mut line_buffer)?
391+
z := f2.read(mut line_buffer) or { panic(err) }
392392
assert f2.eof()
393393
assert z > 0
394394
content := line_buffer#[..z].bytestr()
@@ -406,3 +406,16 @@ fn test_eof() ? {
406406
f.read_bytes(100)
407407
assert f.eof()
408408
}
409+
410+
fn test_open_file_wb_ab() ? {
411+
os.rm(tfile) or {}
412+
mut wfile := os.open_file('text.txt', 'wb', 0o666)?
413+
wfile.write_string('hello')?
414+
wfile.close()
415+
assert os.read_file('text.txt')? == 'hello'
416+
//
417+
mut afile := os.open_file('text.txt', 'ab', 0o666)?
418+
afile.write_string('hello')?
419+
afile.close()
420+
assert os.read_file('text.txt')? == 'hellohello'
421+
}

0 commit comments

Comments
 (0)