Skip to content

Commit f978c50

Browse files
authored
[WASMFS] Seek Syscall (#15321)
Relevant Issue: #15041 - Implement seek syscall - Add new `wasmfs_seek.c` test
1 parent 0a98bdf commit f978c50

File tree

6 files changed

+326
-194
lines changed

6 files changed

+326
-194
lines changed

system/lib/wasmfs/wasmfs.cpp

Lines changed: 123 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,20 @@ long __syscall_dup(long fd) {
5757
return fileTable.add(openFile.unlocked());
5858
}
5959

60-
__wasi_errno_t __wasi_fd_write(__wasi_fd_t fd,
61-
const __wasi_ciovec_t* iovs,
62-
size_t iovs_len,
63-
__wasi_size_t* nwritten) {
64-
if (iovs_len < 0) {
60+
// This enum specifies whether file offset will be provided by the open file
61+
// state or provided by argument in the case of pread or pwrite.
62+
enum class OffsetHandling { OpenFileState, Argument };
63+
64+
// Internal write function called by __wasi_fd_write and __wasi_fd_pwrite
65+
// Receives an open file state offset.
66+
// Optionally sets open file state offset.
67+
static __wasi_errno_t writeAtOffset(OffsetHandling setOffset,
68+
__wasi_fd_t fd,
69+
const __wasi_ciovec_t* iovs,
70+
size_t iovs_len,
71+
__wasi_size_t* nwritten,
72+
__wasi_filesize_t offset = 0) {
73+
if (iovs_len < 0 || offset < 0) {
6574
return __WASI_ERRNO_INVAL;
6675
}
6776

@@ -82,13 +91,22 @@ __wasi_errno_t __wasi_fd_write(__wasi_fd_t fd,
8291

8392
auto lockedFile = file->locked();
8493

85-
off_t offset = lockedOpenFile.position();
94+
off_t currOffset = setOffset == OffsetHandling::OpenFileState
95+
? lockedOpenFile.position()
96+
: offset;
97+
off_t oldOffset = currOffset;
98+
auto finish = [&] {
99+
*nwritten = currOffset - oldOffset;
100+
if (setOffset == OffsetHandling::OpenFileState) {
101+
lockedOpenFile.position() = currOffset;
102+
}
103+
};
86104
for (size_t i = 0; i < iovs_len; i++) {
87105
const uint8_t* buf = iovs[i].buf;
88-
size_t len = iovs[i].buf_len;
106+
off_t len = iovs[i].buf_len;
89107

90108
// Check if the sum of the buf_len values overflows an off_t (63 bits).
91-
if (addWillOverFlow(offset, off_t(len))) {
109+
if (addWillOverFlow(currOffset, len)) {
92110
return __WASI_ERRNO_FBIG;
93111
}
94112

@@ -98,25 +116,28 @@ __wasi_errno_t __wasi_fd_write(__wasi_fd_t fd,
98116
return __WASI_ERRNO_INVAL;
99117
}
100118

101-
auto result = lockedFile.write(buf, len, offset);
119+
auto result = lockedFile.write(buf, len, currOffset);
102120

103121
if (result != __WASI_ERRNO_SUCCESS) {
104-
*nwritten = offset - lockedOpenFile.position();
105-
lockedOpenFile.position() = offset;
122+
finish();
106123
return result;
107124
}
108-
offset += len;
125+
currOffset += len;
109126
}
110-
*nwritten = offset - lockedOpenFile.position();
111-
lockedOpenFile.position() = offset;
127+
finish();
112128
return __WASI_ERRNO_SUCCESS;
113129
}
114130

115-
__wasi_errno_t __wasi_fd_read(__wasi_fd_t fd,
116-
const __wasi_iovec_t* iovs,
117-
size_t iovs_len,
118-
__wasi_size_t* nread) {
119-
if (iovs_len < 0) {
131+
// Internal read function called by __wasi_fd_read and __wasi_fd_pread
132+
// Receives an open file state offset.
133+
// Optionally sets open file state offset.
134+
static __wasi_errno_t readAtOffset(OffsetHandling setOffset,
135+
__wasi_fd_t fd,
136+
const __wasi_iovec_t* iovs,
137+
size_t iovs_len,
138+
__wasi_size_t* nread,
139+
__wasi_filesize_t offset = 0) {
140+
if (iovs_len < 0 || offset < 0) {
120141
return __WASI_ERRNO_INVAL;
121142
}
122143

@@ -137,11 +158,20 @@ __wasi_errno_t __wasi_fd_read(__wasi_fd_t fd,
137158

138159
auto lockedFile = file->locked();
139160

140-
off_t offset = lockedOpenFile.position();
161+
off_t currOffset = setOffset == OffsetHandling::OpenFileState
162+
? lockedOpenFile.position()
163+
: offset;
164+
off_t oldOffset = currOffset;
165+
auto finish = [&] {
166+
*nread = currOffset - oldOffset;
167+
if (setOffset == OffsetHandling::OpenFileState) {
168+
lockedOpenFile.position() = currOffset;
169+
}
170+
};
141171
size_t size = lockedFile.size();
142172
for (size_t i = 0; i < iovs_len; i++) {
143-
// Check if offset has exceeded the size of file data.
144-
ssize_t dataLeft = size - offset;
173+
// Check if currOffset has exceeded size of file data.
174+
ssize_t dataLeft = size - currOffset;
145175
if (dataLeft <= 0) {
146176
break;
147177
}
@@ -156,27 +186,49 @@ __wasi_errno_t __wasi_fd_read(__wasi_fd_t fd,
156186

157187
size_t bytesToRead = std::min(size_t(dataLeft), iovs[i].buf_len);
158188

159-
auto result = lockedFile.read(buf, bytesToRead, offset);
189+
auto result = lockedFile.read(buf, bytesToRead, currOffset);
160190

161191
if (result != __WASI_ERRNO_SUCCESS) {
162-
*nread = offset - lockedOpenFile.position();
163-
lockedOpenFile.position() = offset;
192+
finish();
164193
return result;
165194
}
166-
offset += bytesToRead;
195+
currOffset += bytesToRead;
167196
}
168-
*nread = offset - lockedOpenFile.position();
169-
lockedOpenFile.position() = offset;
197+
finish();
170198
return __WASI_ERRNO_SUCCESS;
171199
}
172200

173-
__wasi_errno_t __wasi_fd_seek(__wasi_fd_t fd,
174-
__wasi_filedelta_t offset,
175-
__wasi_whence_t whence,
176-
__wasi_filesize_t* newoffset) {
177-
emscripten_console_log(
178-
"__wasi_fd_seek has been temporarily stubbed and is inert");
179-
abort();
201+
__wasi_errno_t __wasi_fd_write(__wasi_fd_t fd,
202+
const __wasi_ciovec_t* iovs,
203+
size_t iovs_len,
204+
__wasi_size_t* nwritten) {
205+
return writeAtOffset(
206+
OffsetHandling::OpenFileState, fd, iovs, iovs_len, nwritten);
207+
}
208+
209+
__wasi_errno_t __wasi_fd_read(__wasi_fd_t fd,
210+
const __wasi_iovec_t* iovs,
211+
size_t iovs_len,
212+
__wasi_size_t* nread) {
213+
return readAtOffset(OffsetHandling::OpenFileState, fd, iovs, iovs_len, nread);
214+
}
215+
216+
__wasi_errno_t __wasi_fd_pwrite(__wasi_fd_t fd,
217+
const __wasi_ciovec_t* iovs,
218+
size_t iovs_len,
219+
__wasi_filesize_t offset,
220+
__wasi_size_t* nwritten) {
221+
return writeAtOffset(
222+
OffsetHandling::Argument, fd, iovs, iovs_len, nwritten, offset);
223+
}
224+
225+
__wasi_errno_t __wasi_fd_pread(__wasi_fd_t fd,
226+
const __wasi_iovec_t* iovs,
227+
size_t iovs_len,
228+
__wasi_filesize_t offset,
229+
__wasi_size_t* nread) {
230+
return readAtOffset(
231+
OffsetHandling::Argument, fd, iovs, iovs_len, nread, offset);
180232
}
181233

182234
__wasi_errno_t __wasi_fd_close(__wasi_fd_t fd) {
@@ -316,4 +368,40 @@ __wasi_fd_t __syscall_open(long pathname, long flags, long mode) {
316368

317369
return FileTable::get().add(openFile);
318370
}
371+
372+
__wasi_errno_t __wasi_fd_seek(__wasi_fd_t fd,
373+
__wasi_filedelta_t offset,
374+
__wasi_whence_t whence,
375+
__wasi_filesize_t* newoffset) {
376+
auto openFile = FileTable::get()[fd];
377+
if (!openFile) {
378+
return __WASI_ERRNO_BADF;
379+
}
380+
auto lockedOpenFile = openFile.locked();
381+
382+
off_t position;
383+
if (whence == SEEK_SET) {
384+
position = offset;
385+
} else if (whence == SEEK_CUR) {
386+
position = lockedOpenFile.position() + offset;
387+
} else if (whence == SEEK_END) {
388+
// Only the open file stat is altered in seek. Locking the underlying data
389+
// file here once is sufficient.
390+
position = lockedOpenFile.getFile()->locked().size() + offset;
391+
} else {
392+
return __WASI_ERRNO_INVAL;
393+
}
394+
395+
if (position < 0) {
396+
return __WASI_ERRNO_INVAL;
397+
}
398+
399+
lockedOpenFile.position() = position;
400+
401+
if (newoffset) {
402+
*newoffset = position;
403+
}
404+
405+
return __WASI_ERRNO_SUCCESS;
406+
}
319407
}

tests/test_other.py

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,20 @@ def parse_wasm(filename):
116116
return imports, exports, funcs
117117

118118

119+
def with_wasmfs(f):
120+
def metafunc(self, wasmfs):
121+
if wasmfs:
122+
self.set_setting('WASMFS')
123+
f(self)
124+
else:
125+
f(self)
126+
127+
metafunc._parameterize = {'': (False,),
128+
'wasmfs': (True,)}
129+
130+
return metafunc
131+
132+
119133
class other(RunnerCore):
120134
def assertIsObjectFile(self, filename):
121135
self.assertTrue(building.is_wasm(filename))
@@ -11143,18 +11157,26 @@ def test_unistd_fstatfs(self):
1114311157

1114411158
# WASMFS tests
1114511159

11146-
def test_wasmfs_unistd_dup(self):
11160+
@with_wasmfs
11161+
def test_unistd_dup(self):
1114711162
self.set_setting('WASMFS')
1114811163
self.do_run_in_out_file_test('wasmfs/wasmfs_dup.c')
1114911164

11150-
def test_wasmfs_unistd_open(self):
11165+
@with_wasmfs
11166+
def test_unistd_open(self):
1115111167
self.set_setting('WASMFS')
1115211168
self.do_run_in_out_file_test('wasmfs/wasmfs_open.c')
1115311169

11154-
def test_wasmfs_unistd_fstat(self):
11170+
@with_wasmfs
11171+
def test_unistd_fstat(self):
1115511172
self.set_setting('WASMFS')
1115611173
self.do_run_in_out_file_test('wasmfs/wasmfs_fstat.c')
1115711174

11158-
def test_wasmfs_unistd_create(self):
11175+
@with_wasmfs
11176+
def test_unistd_create(self):
1115911177
self.set_setting('WASMFS')
1116011178
self.do_run_in_out_file_test('wasmfs/wasmfs_create.c')
11179+
11180+
@with_wasmfs
11181+
def test_unistd_seek(self):
11182+
self.do_run_in_out_file_test('wasmfs/wasmfs_seek.c')

tests/unistd/io.c

Lines changed: 1 addition & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -110,104 +110,7 @@ int main() {
110110
printf("open write-only device from createDevice for write, errno: %d\n\n", errno);
111111
errno = 0;
112112

113-
int f = open("/working/file", O_RDWR);
114-
printf("read from file: %zd\n", read(f, readBuffer, sizeof readBuffer));
115-
printf("data: %s\n", readBuffer);
116-
memset(readBuffer, 0, sizeof readBuffer);
117-
printf("errno: %d\n\n", errno);
118-
errno = 0;
119-
120-
printf("pread past end of file: %zd\n", pread(f, readBuffer, sizeof readBuffer, 999999999));
121-
printf("data: %s\n", readBuffer);
122-
memset(readBuffer, 0, sizeof readBuffer);
123-
printf("errno: %d\n\n", errno);
124-
errno = 0;
125-
126-
printf("seek: %lld\n", lseek(f, 3, SEEK_SET));
127-
printf("errno: %d\n\n", errno);
128-
printf("partial read from file: %zd\n", read(f, readBuffer, 3));
129-
printf("data: %s\n", readBuffer);
130-
memset(readBuffer, 0, sizeof readBuffer);
131-
printf("errno: %d\n\n", errno);
132-
errno = 0;
133-
134-
printf("seek: %lld\n", lseek(f, -2, SEEK_END));
135-
printf("errno: %d\n", errno);
136-
errno = 0;
137-
printf("partial read from end of file: %zd\n", read(f, readBuffer, 3));
138-
printf("data: %s\n", readBuffer);
139-
memset(readBuffer, 0, sizeof readBuffer);
140-
printf("errno: %d\n\n", errno);
141-
errno = 0;
142-
143-
printf("seek: %lld\n", lseek(f, -15, SEEK_CUR));
144-
printf("errno: %d\n", errno);
145-
errno = 0;
146-
printf("partial read from before start of file: %zd\n", read(f, readBuffer, 3));
147-
printf("data: %s\n", readBuffer);
148-
memset(readBuffer, 0, sizeof readBuffer);
149-
printf("errno: %d\n\n", errno);
150-
errno = 0;
151-
152-
printf("seek: %lld\n", lseek(f, 0, SEEK_SET));
153-
printf("write to start of file: %zd\n", write(f, writeBuffer, 3));
154-
printf("errno: %d\n\n", errno);
155-
errno = 0;
156-
157-
printf("seek: %lld\n", lseek(f, 0, SEEK_END));
158-
printf("write to end of file: %zd\n", write(f, writeBuffer, 3));
159-
printf("errno: %d\n\n", errno);
160-
errno = 0;
161-
162-
printf("seek: %lld\n", lseek(f, 10, SEEK_END));
163-
printf("write after end of file: %zd\n", write(f, writeBuffer, sizeof writeBuffer));
164-
printf("errno: %d\n\n", errno);
165-
errno = 0;
166-
167-
printf("pwrite to the middle of file: %zd\n", pwrite(f, writeBuffer + 2, 3, 17));
168-
printf("errno: %d\n", errno);
169-
printf("seek: %lld\n\n", lseek(f, 0, SEEK_CUR));
170-
errno = 0;
171-
172-
printf("pwrite past end of file: %zd\n", pwrite(f, writeBuffer, 5, 32));
173-
printf("errno: %d\n", errno);
174-
printf("seek: %lld\n\n", lseek(f, 0, SEEK_CUR));
175-
errno = 0;
176-
177-
ssize_t bytesRead;
178-
printf("seek: %lld\n", lseek(f, 0, SEEK_SET));
179-
printf("read after write: %zd\n", bytesRead = read(f, readBuffer, sizeof readBuffer));
180-
printf("errno: %d\n", errno);
181-
errno = 0;
182-
printf("final: ");
183-
for (ssize_t i = 0; i < bytesRead; i++) {
184-
if (readBuffer[i] == 0) {
185-
printf("\\0");
186-
} else {
187-
printf("%c", readBuffer[i]);
188-
}
189-
}
190-
printf("\n");
191-
192-
// readv
193-
printf("\n");
194-
memset(readBuffer, 0, sizeof readBuffer);
195-
struct iovec iov;
196-
iov.iov_base = readBuffer;
197-
iov.iov_len = sizeof readBuffer;
198-
printf("seek: %lld\n", lseek(f, 0, SEEK_SET));
199-
printf("read after write: %zd\n", bytesRead = readv(f, &iov, 1));
200-
printf("errno: %d\n", errno);
201-
errno = 0;
202-
printf("final: ");
203-
for (ssize_t i = 0; i < bytesRead; i++) {
204-
if (readBuffer[i] == 0) {
205-
printf("\\0");
206-
} else {
207-
printf("%c", readBuffer[i]);
208-
}
209-
}
210-
printf("\n");
113+
// This part of the test has moved to wasmfs/wasmfs_seek.c
211114

212115
#ifdef REPORT_RESULT
213116
REPORT_RESULT(0);

0 commit comments

Comments
 (0)