Skip to content

Commit 1c82149

Browse files
authored
wasip2: Handle the O_APPEND flag (WebAssembly#671)
I'm a bit surprised the Python test suite didn't cover this, but this nonetheless was broken and needed fixing.
1 parent 13637c0 commit 1c82149

File tree

4 files changed

+99
-17
lines changed

4 files changed

+99
-17
lines changed

libc-bottom-half/sources/wasip2_file.c

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,20 @@ static int file_get_write_stream(void *data,
8686
file_t *file = (file_t *)data;
8787
if (file->write_stream.__handle == 0) {
8888
filesystem_error_code_t error_code;
89-
bool ok = filesystem_method_descriptor_write_via_stream(
90-
filesystem_borrow_descriptor(file->file_handle),
91-
file->offset,
92-
&file->write_stream,
93-
&error_code);
89+
bool ok;
90+
91+
if (file->oflag & O_APPEND) {
92+
ok = filesystem_method_descriptor_append_via_stream(
93+
filesystem_borrow_descriptor(file->file_handle),
94+
&file->write_stream,
95+
&error_code);
96+
} else {
97+
ok = filesystem_method_descriptor_write_via_stream(
98+
filesystem_borrow_descriptor(file->file_handle),
99+
file->offset,
100+
&file->write_stream,
101+
&error_code);
102+
}
94103
if (!ok) {
95104
translate_error(error_code);
96105
return -1;
@@ -138,33 +147,53 @@ static int file_fstat(void *data, struct stat *buf) {
138147
return 0;
139148
}
140149

150+
static int file_seek_end(file_t *file) {
151+
filesystem_descriptor_stat_t stat;
152+
filesystem_error_code_t error;
153+
bool ok = filesystem_method_descriptor_stat(filesystem_borrow_descriptor(file->file_handle),
154+
&stat,
155+
&error);
156+
if (!ok) {
157+
translate_error(error);
158+
return -1;
159+
}
160+
file->offset = (off_t) stat.size;
161+
return 0;
162+
}
163+
141164
static off_t file_seek(void *data, off_t offset, int whence) {
142165
file_t *file = (file_t *)data;
166+
167+
// If this file is in append mode, reset our knowledge of the current cursor
168+
// to the current end of the file.
169+
if ((file->oflag & O_APPEND) && file_seek_end(file) < 0)
170+
return -1;
171+
172+
off_t result;
143173
switch (whence) {
144174
case SEEK_SET:
145-
file->offset = offset;
175+
result = offset;
146176
break;
147177
case SEEK_CUR:
148-
file->offset += offset;
178+
result = file->offset + offset;
149179
break;
150180
case SEEK_END: {
151-
// Get the file metadata
152-
filesystem_descriptor_stat_t stat;
153-
filesystem_error_code_t error;
154-
bool ok = filesystem_method_descriptor_stat(filesystem_borrow_descriptor(file->file_handle),
155-
&stat,
156-
&error);
157-
if (!ok) {
158-
translate_error(error);
181+
// If we're in append mode we already reset to the end, but if we're not
182+
// in append mode then do the reset to the end here.
183+
if (!(file->oflag & O_APPEND) && file_seek_end(file) < 0)
159184
return -1;
160-
}
161-
file->offset = ((off_t) stat.size) + offset;
185+
result = file->offset + offset;
162186
break;
163187
}
164188
default:
165189
errno = EINVAL;
166190
return -1;
167191
}
192+
if (result < 0) {
193+
errno = EINVAL;
194+
return -1;
195+
}
196+
file->offset = result;
168197
file_close_streams(data);
169198
return file->offset;
170199
}

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ endfunction()
278278
if (NOT TARGET_TRIPLE MATCHES "-threads")
279279
add_wasilibc_test(access.c FS)
280280
endif()
281+
add_wasilibc_test(append.c FS)
281282
add_wasilibc_test(argv_two_args.c ARGV foo bar)
282283
add_wasilibc_test(clock_nanosleep.c)
283284
add_wasilibc_test(chdir.c FS)

test/src/append.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#include <errno.h>
2+
#include <fcntl.h>
3+
#include <stdio.h>
4+
#include <stdlib.h>
5+
#include <string.h>
6+
#include <unistd.h>
7+
#include <sys/stat.h>
8+
#include <sys/uio.h>
9+
#include "test.h"
10+
11+
#define TEST(c) do { \
12+
errno = 0; \
13+
if (!(c)) \
14+
t_error("%s failed (errno = %d)\n", #c, errno); \
15+
} while(0)
16+
17+
int main(void) {
18+
char tmp[] = "testsuite-XXXXXX";
19+
int fd;
20+
TEST((fd = open(tmp, O_RDWR | O_CREAT | O_EXCL | O_APPEND, 0600)) > 2);
21+
22+
TEST(write(fd, "Hello, world!", 13) == 13);
23+
TEST(lseek(fd, 0, SEEK_CUR) == 13);
24+
TEST(lseek(fd, 0, SEEK_SET) == 0);
25+
TEST(write(fd, "Hello, world!", 13) == 13);
26+
TEST(lseek(fd, 0, SEEK_CUR) == 26);
27+
TEST(lseek(fd, 0, SEEK_SET) == 0);
28+
29+
TEST(close(fd) == 0);
30+
31+
int read_fd;
32+
TEST((read_fd = open(tmp, O_RDONLY)) > 2);
33+
34+
char buf[30];
35+
TEST(read(read_fd, buf, 30) == 26);
36+
TEST(memcmp(buf, "Hello, world!Hello, world!", 26) == 0);
37+
38+
TEST((fd = open(tmp, O_RDWR | O_APPEND, 0600)) > 2);
39+
TEST(write(fd, "hi", 2) == 2);
40+
TEST(close(fd) == 0);
41+
42+
TEST(lseek(read_fd, 0, SEEK_SET) == 0);
43+
TEST(read(read_fd, buf, 30) == 28);
44+
TEST(memcmp(buf, "Hello, world!Hello, world!hi", 28) == 0);
45+
46+
return t_status;
47+
}

test/src/lseek.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ int main(void) {
2121
TEST(lseek(fd, 0, SEEK_SET) == 0);
2222
TEST(lseek(fd, 0, SEEK_CUR) == 0);
2323

24+
TEST(lseek(fd, -1, SEEK_END) == -1);
25+
TEST(lseek(fd, -1, SEEK_CUR) == -1);
26+
TEST(lseek(fd, -1, SEEK_SET) == -1);
27+
TEST(lseek(fd, 0, SEEK_CUR) == 0);
28+
2429
TEST(write(fd, "Hello, World!", 13) == 13);
2530
TEST(lseek(fd, 0, SEEK_CUR) == 13);
2631
TEST(lseek(fd, 0, SEEK_SET) == 0);

0 commit comments

Comments
 (0)