@@ -57,11 +57,20 @@ long __syscall_dup(long fd) {
57
57
return fileTable.add (openFile.unlocked ());
58
58
}
59
59
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 ) {
65
74
return __WASI_ERRNO_INVAL;
66
75
}
67
76
@@ -82,13 +91,22 @@ __wasi_errno_t __wasi_fd_write(__wasi_fd_t fd,
82
91
83
92
auto lockedFile = file->locked ();
84
93
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
+ };
86
104
for (size_t i = 0 ; i < iovs_len; i++) {
87
105
const uint8_t * buf = iovs[i].buf ;
88
- size_t len = iovs[i].buf_len ;
106
+ off_t len = iovs[i].buf_len ;
89
107
90
108
// 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)) {
92
110
return __WASI_ERRNO_FBIG;
93
111
}
94
112
@@ -98,25 +116,28 @@ __wasi_errno_t __wasi_fd_write(__wasi_fd_t fd,
98
116
return __WASI_ERRNO_INVAL;
99
117
}
100
118
101
- auto result = lockedFile.write (buf, len, offset );
119
+ auto result = lockedFile.write (buf, len, currOffset );
102
120
103
121
if (result != __WASI_ERRNO_SUCCESS) {
104
- *nwritten = offset - lockedOpenFile.position ();
105
- lockedOpenFile.position () = offset;
122
+ finish ();
106
123
return result;
107
124
}
108
- offset += len;
125
+ currOffset += len;
109
126
}
110
- *nwritten = offset - lockedOpenFile.position ();
111
- lockedOpenFile.position () = offset;
127
+ finish ();
112
128
return __WASI_ERRNO_SUCCESS;
113
129
}
114
130
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 ) {
120
141
return __WASI_ERRNO_INVAL;
121
142
}
122
143
@@ -137,11 +158,20 @@ __wasi_errno_t __wasi_fd_read(__wasi_fd_t fd,
137
158
138
159
auto lockedFile = file->locked ();
139
160
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
+ };
141
171
size_t size = lockedFile.size ();
142
172
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 ;
145
175
if (dataLeft <= 0 ) {
146
176
break ;
147
177
}
@@ -156,27 +186,49 @@ __wasi_errno_t __wasi_fd_read(__wasi_fd_t fd,
156
186
157
187
size_t bytesToRead = std::min (size_t (dataLeft), iovs[i].buf_len );
158
188
159
- auto result = lockedFile.read (buf, bytesToRead, offset );
189
+ auto result = lockedFile.read (buf, bytesToRead, currOffset );
160
190
161
191
if (result != __WASI_ERRNO_SUCCESS) {
162
- *nread = offset - lockedOpenFile.position ();
163
- lockedOpenFile.position () = offset;
192
+ finish ();
164
193
return result;
165
194
}
166
- offset += bytesToRead;
195
+ currOffset += bytesToRead;
167
196
}
168
- *nread = offset - lockedOpenFile.position ();
169
- lockedOpenFile.position () = offset;
197
+ finish ();
170
198
return __WASI_ERRNO_SUCCESS;
171
199
}
172
200
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);
180
232
}
181
233
182
234
__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) {
316
368
317
369
return FileTable::get ().add (openFile);
318
370
}
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
+ }
319
407
}
0 commit comments