Line data Source code
1 : /**
2 : Copyright (c) 2024 Stappler LLC <admin@stappler.dev>
3 :
4 : Permission is hereby granted, free of charge, to any person obtaining a copy
5 : of this software and associated documentation files (the "Software"), to deal
6 : in the Software without restriction, including without limitation the rights
7 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 : copies of the Software, and to permit persons to whom the Software is
9 : furnished to do so, subject to the following conditions:
10 :
11 : The above copyright notice and this permission notice shall be included in
12 : all copies or substantial portions of the Software.
13 :
14 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 : THE SOFTWARE.
21 : **/
22 :
23 : #include "SPWasm.h"
24 : #include "SPFilesystem.h"
25 :
26 : namespace stappler::wasm {
27 :
28 0 : static uint32_t StapplerFilesystemExists(wasm_exec_env_t exec_env, char *ptr, uint32_t size) {
29 0 : return filesystem::exists(StringView(ptr, size)) ? 1 : 0;
30 : }
31 :
32 : struct StatResult {
33 : uint64_t success;
34 : uint64_t size;
35 : uint64_t atime;
36 : uint64_t ctime;
37 : uint64_t mtime;
38 : uint64_t isDir;
39 : };
40 :
41 150 : static void StapplerFilesystemStat(wasm_exec_env_t exec_env, char *ptr, uint32_t size, StatResult *res) {
42 150 : filesystem::Stat stat;
43 150 : if (filesystem::stat(StringView(ptr, size), stat)) {
44 150 : res->success = false;
45 150 : res->size = stat.size;
46 150 : res->atime = stat.atime.toMicros();
47 150 : res->ctime = stat.ctime.toMicros();
48 150 : res->mtime = stat.mtime.toMicros();
49 150 : res->isDir = stat.isDir;
50 : } else {
51 0 : res->success = false;
52 : }
53 150 : }
54 :
55 0 : static void StapplerFilesystemWritablePath(wasm_exec_env_t exec_env, char *ptr, uint32_t size, bool rel, bool readOnly, ListOutput *target) {
56 0 : auto env = ExecEnv::get(exec_env);
57 :
58 0 : String result;
59 0 : if (readOnly) {
60 0 : result = filesystem::writablePathReadOnly<Interface>(StringView(ptr, size), rel);
61 : } else {
62 0 : result = filesystem::writablePath<Interface>(StringView(ptr, size), rel);
63 : }
64 :
65 0 : char *outStringBuffer = nullptr;
66 0 : auto outOffset = env->allocate(result.size() * sizeof(char), &outStringBuffer);
67 :
68 0 : memcpy(outStringBuffer, result.data(), result.size() * sizeof(char));
69 :
70 0 : target->ptr = outOffset;
71 0 : target->len = result.size();
72 0 : }
73 :
74 0 : static void StapplerFilesystemDocumentsPath(wasm_exec_env_t exec_env, char *ptr, uint32_t size, bool rel, bool readOnly, ListOutput *target) {
75 0 : auto env = ExecEnv::get(exec_env);
76 :
77 0 : String result;
78 0 : if (readOnly) {
79 0 : result = filesystem::documentsPathReadOnly<Interface>(StringView(ptr, size), rel);
80 : } else {
81 0 : result = filesystem::documentsPath<Interface>(StringView(ptr, size), rel);
82 : }
83 :
84 0 : char *outStringBuffer = nullptr;
85 0 : auto outOffset = env->allocate(result.size() * sizeof(char), &outStringBuffer);
86 :
87 0 : memcpy(outStringBuffer, result.data(), result.size() * sizeof(char));
88 :
89 0 : target->ptr = outOffset;
90 0 : target->len = result.size();
91 0 : }
92 :
93 0 : static void StapplerFilesystemCachesPath(wasm_exec_env_t exec_env, char *ptr, uint32_t size, bool rel, bool readOnly, ListOutput *target) {
94 0 : auto env = ExecEnv::get(exec_env);
95 :
96 0 : String result;
97 0 : if (readOnly) {
98 0 : result = filesystem::cachesPathReadOnly<Interface>(StringView(ptr, size), rel);
99 : } else {
100 0 : result = filesystem::cachesPath<Interface>(StringView(ptr, size), rel);
101 : }
102 :
103 0 : char *outStringBuffer = nullptr;
104 0 : auto outOffset = env->allocate(result.size() * sizeof(char), &outStringBuffer);
105 :
106 0 : memcpy(outStringBuffer, result.data(), result.size() * sizeof(char));
107 :
108 0 : target->ptr = outOffset;
109 0 : target->len = result.size();
110 0 : }
111 :
112 50 : static void StapplerFilesystemCurrentDir(wasm_exec_env_t exec_env, char *ptr, uint32_t size, bool rel, ListOutput *target) {
113 50 : auto env = ExecEnv::get(exec_env);
114 :
115 50 : String result = filesystem::currentDir<Interface>(StringView(ptr, size), rel);
116 :
117 50 : char *outStringBuffer = nullptr;
118 50 : auto outOffset = env->allocate(result.size() * sizeof(char), &outStringBuffer);
119 :
120 50 : memcpy(outStringBuffer, result.data(), result.size() * sizeof(char));
121 :
122 50 : target->ptr = outOffset;
123 50 : target->len = result.size();
124 50 : }
125 :
126 25 : static void StapplerFilesystemFtw(wasm_exec_env_t exec_env, char *ptr, uint32_t size, uint32_t fn, uint32_t arg, int32_t depth, bool dirFirst) {
127 25 : auto env = ExecEnv::get(exec_env);
128 25 : char *buf = nullptr;
129 :
130 25 : auto bufOffset = env->allocate(PATH_MAX, &buf);
131 :
132 : uint32_t args[4];
133 25 : args[0] = arg;
134 25 : args[1] = bufOffset;
135 :
136 25 : filesystem::ftw(StringView(ptr, size), [&] (StringView path, bool isFile) {
137 375 : buf = env->appToNative<char>(bufOffset);
138 375 : memcpy(buf, path.data(), path.size());
139 :
140 375 : args[2] = uint32_t(path.size());
141 375 : args[3] = uint32_t(isFile);
142 :
143 375 : wasm_runtime_call_indirect(exec_env, fn, 4, args);
144 375 : }, depth, dirFirst);
145 :
146 25 : env->free(bufOffset);
147 25 : }
148 :
149 0 : static uint32_t StapplerFilesystemFtwB(wasm_exec_env_t exec_env, char *ptr, uint32_t size, uint32_t fn, uint32_t arg, int32_t depth, bool dirFirst) {
150 0 : auto env = ExecEnv::get(exec_env);
151 0 : char *buf = nullptr;
152 :
153 0 : auto bufOffset = env->allocate(PATH_MAX, &buf);
154 :
155 : uint32_t args[4];
156 :
157 0 : auto ret = filesystem::ftw_b(StringView(ptr, size), [&] (StringView path, bool isFile) {
158 0 : buf = env->appToNative<char>(bufOffset);
159 0 : memcpy(buf, path.data(), path.size());
160 :
161 0 : args[0] = arg;
162 0 : args[1] = bufOffset;
163 0 : args[2] = uint32_t(path.size());
164 0 : args[3] = uint32_t(isFile);
165 :
166 0 : if (wasm_runtime_call_indirect(exec_env, fn, 4, args)) {
167 0 : return bool(args[0]);
168 : }
169 0 : return false;
170 : }, depth, dirFirst);
171 :
172 0 : env->free(bufOffset);
173 0 : return ret;
174 : }
175 :
176 25 : static uint32_t StapplerFilesystemOpen(wasm_exec_env_t exec_env, char *ptr, uint32_t size) {
177 25 : auto f = filesystem::openForReading(StringView(ptr, size));
178 25 : if (f) {
179 25 : auto env = ExecEnv::get(exec_env);
180 25 : auto mod = env->getInstance();
181 25 : auto obj = new filesystem::File(move(f));
182 :
183 50 : return mod->addHandle(obj, [obj] {
184 25 : delete obj;
185 25 : });
186 : }
187 0 : return ModuleInstance::InvalidHandle;
188 25 : }
189 :
190 0 : static uint32_t StapplerFilesystemOpenTmp(wasm_exec_env_t exec_env, char *ptr, uint32_t size, bool delOnClose) {
191 0 : auto f = filesystem::File::open_tmp(StringView(ptr, size), delOnClose);
192 0 : if (f) {
193 0 : auto env = ExecEnv::get(exec_env);
194 0 : auto mod = env->getInstance();
195 0 : auto obj = new filesystem::File(move(f));
196 :
197 0 : return mod->addHandle(obj, [obj] {
198 0 : delete obj;
199 0 : });
200 : }
201 0 : return ModuleInstance::InvalidHandle;
202 0 : }
203 :
204 25 : static void StapplerFilesystemFileDrop(wasm_exec_env_t exec_env, uint32_t handle) {
205 25 : auto mod = ExecEnv::get(exec_env)->getInstance();
206 25 : auto file = mod->getObject<filesystem::File>(handle);
207 25 : if (!file) {
208 0 : log::error("wasm::Runtime", "[resource-drop]file: invalid handle");
209 0 : return;
210 : }
211 :
212 25 : mod->removeHandle(handle);
213 : }
214 :
215 25 : static uint32_t StapplerFilesystemFileRead(wasm_exec_env_t exec_env, uint32_t handle, uint8_t *buf, uint32_t bufSize) {
216 25 : auto file = ExecEnv::get(exec_env)->getInstance()->getObject<filesystem::File>(handle);
217 25 : if (!file) {
218 0 : log::error("wasm::Runtime", "[method]file.read: invalid handle");
219 0 : return 0;
220 : }
221 :
222 25 : return file->read(buf, bufSize);
223 : }
224 :
225 0 : static uint64_t StapplerFilesystemFileSeek(wasm_exec_env_t exec_env, uint32_t handle, int64_t offset, io::Seek pos) {
226 0 : auto file = ExecEnv::get(exec_env)->getInstance()->getObject<filesystem::File>(handle);
227 0 : if (!file) {
228 0 : log::error("wasm::Runtime", "[method]file.seek: invalid handle");
229 0 : return 0;
230 : }
231 :
232 0 : return file->seek(offset, pos);
233 : }
234 :
235 0 : static uint64_t StapplerFilesystemFileTell(wasm_exec_env_t exec_env, uint32_t handle) {
236 0 : auto file = ExecEnv::get(exec_env)->getInstance()->getObject<filesystem::File>(handle);
237 0 : if (!file) {
238 0 : log::error("wasm::Runtime", "[method]file.tell: invalid handle");
239 0 : return 0;
240 : }
241 :
242 0 : return file->tell();
243 : }
244 :
245 25 : static uint64_t StapplerFilesystemFileSize(wasm_exec_env_t exec_env, uint32_t handle) {
246 25 : auto file = ExecEnv::get(exec_env)->getInstance()->getObject<filesystem::File>(handle);
247 25 : if (!file) {
248 0 : log::error("wasm::Runtime", "[method]file.size: invalid handle");
249 0 : return 0;
250 : }
251 :
252 25 : return file->size();
253 : }
254 :
255 0 : static int32_t StapplerFilesystemFileXsgetc(wasm_exec_env_t exec_env, uint32_t handle) {
256 0 : auto file = ExecEnv::get(exec_env)->getInstance()->getObject<filesystem::File>(handle);
257 0 : if (!file) {
258 0 : log::error("wasm::Runtime", "[method]file.xsgetc: invalid handle");
259 0 : return 0;
260 : }
261 :
262 0 : return file->xsgetc();
263 : }
264 :
265 0 : static int32_t StapplerFilesystemFileXsputc(wasm_exec_env_t exec_env, uint32_t handle, int32_t c) {
266 0 : auto file = ExecEnv::get(exec_env)->getInstance()->getObject<filesystem::File>(handle);
267 0 : if (!file) {
268 0 : log::error("wasm::Runtime", "[method]file.xsputc: invalid handle");
269 0 : return 0;
270 : }
271 :
272 0 : return file->xsputc(c);
273 : }
274 :
275 0 : static uint32_t StapplerFilesystemFileXsputn(wasm_exec_env_t exec_env, uint32_t handle, uint8_t *buf, uint32_t bufSize) {
276 0 : auto file = ExecEnv::get(exec_env)->getInstance()->getObject<filesystem::File>(handle);
277 0 : if (!file) {
278 0 : log::error("wasm::Runtime", "[method]file.xsputn: invalid handle");
279 0 : return 0;
280 : }
281 :
282 0 : return file->xsputn((const char *)buf, bufSize);
283 : }
284 :
285 0 : static uint32_t StapplerFilesystemFileXsgetn(wasm_exec_env_t exec_env, uint32_t handle, uint8_t *buf, uint32_t bufSize) {
286 0 : auto file = ExecEnv::get(exec_env)->getInstance()->getObject<filesystem::File>(handle);
287 0 : if (!file) {
288 0 : log::error("wasm::Runtime", "[method]file.xsgetn: invalid handle");
289 0 : return 0;
290 : }
291 :
292 0 : return file->xsgetn((char *)buf, bufSize);
293 : }
294 :
295 0 : static uint32_t StapplerFilesystemFileIsOpen(wasm_exec_env_t exec_env, uint32_t handle) {
296 0 : auto file = ExecEnv::get(exec_env)->getInstance()->getObject<filesystem::File>(handle);
297 0 : if (!file) {
298 0 : log::error("wasm::Runtime", "[method]file.is-open: invalid handle");
299 0 : return 0;
300 : }
301 :
302 0 : return file->is_open();
303 : }
304 :
305 0 : static uint32_t StapplerFilesystemFileEof(wasm_exec_env_t exec_env, uint32_t handle) {
306 0 : auto file = ExecEnv::get(exec_env)->getInstance()->getObject<filesystem::File>(handle);
307 0 : if (!file) {
308 0 : log::error("wasm::Runtime", "[method]file.eof: invalid handle");
309 0 : return 0;
310 : }
311 :
312 0 : return file->eof();
313 : }
314 :
315 0 : static void StapplerFilesystemFileClose(wasm_exec_env_t exec_env, uint32_t handle) {
316 0 : auto file = ExecEnv::get(exec_env)->getInstance()->getObject<filesystem::File>(handle);
317 0 : if (!file) {
318 0 : log::error("wasm::Runtime", "[method]file.close: invalid handle");
319 0 : return;
320 : }
321 :
322 0 : file->close();
323 : }
324 :
325 0 : static void StapplerFilesystemFileCloseRemove(wasm_exec_env_t exec_env, uint32_t handle) {
326 0 : auto file = ExecEnv::get(exec_env)->getInstance()->getObject<filesystem::File>(handle);
327 0 : if (!file) {
328 0 : log::error("wasm::Runtime", "[method]file.close-remove: invalid handle");
329 0 : return;
330 : }
331 :
332 0 : file->close_remove();
333 : }
334 :
335 0 : static void StapplerFilesystemFileCloseRename(wasm_exec_env_t exec_env, uint32_t handle, char *name, uint32_t len) {
336 0 : auto file = ExecEnv::get(exec_env)->getInstance()->getObject<filesystem::File>(handle);
337 0 : if (!file) {
338 0 : log::error("wasm::Runtime", "[method]file.close-rename: invalid handle");
339 0 : return;
340 : }
341 :
342 0 : file->close_rename(StringView(name, len));
343 : }
344 :
345 0 : static uint32_t StapplerFilesystemFileGetTmpPath(wasm_exec_env_t exec_env, uint32_t handle, char *buf, uint32_t len) {
346 0 : auto file = ExecEnv::get(exec_env)->getInstance()->getObject<filesystem::File>(handle);
347 0 : if (!file) {
348 0 : log::error("wasm::Runtime", "[method]file.get-tmp-path: invalid handle");
349 0 : return 0;
350 : }
351 :
352 0 : auto path = file->path();
353 0 : len = max(len, uint32_t(strlen(path)));
354 0 : memcpy(buf, path, len);
355 0 : return len;
356 : }
357 :
358 : static NativeSymbol stapper_filesystem_symbols[] = {
359 : NativeSymbol{"exists", (void *)&StapplerFilesystemExists, "(*~)i", NULL},
360 : NativeSymbol{"stat", (void *)&StapplerFilesystemStat, "(*~*)", NULL},
361 : NativeSymbol{"get-writable-path", (void *)&StapplerFilesystemWritablePath, "(*~ii*)", NULL},
362 : NativeSymbol{"get-documents-path", (void *)&StapplerFilesystemDocumentsPath, "(*~ii*)", NULL},
363 : NativeSymbol{"get-caches-path", (void *)&StapplerFilesystemCachesPath, "(*~ii*)", NULL},
364 : NativeSymbol{"get-current-work-dir", (void *)&StapplerFilesystemCurrentDir, "(*~i*)", NULL},
365 : NativeSymbol{"ftw", (void *)&StapplerFilesystemFtw, "(*~iiii)", NULL},
366 : NativeSymbol{"ftw-b", (void *)&StapplerFilesystemFtwB, "(*~iiii)i", NULL},
367 : NativeSymbol{"open", (void *)&StapplerFilesystemOpen, "(*~)i", NULL},
368 : NativeSymbol{"open-tmp", (void *)&StapplerFilesystemOpenTmp, "(*~i)i", NULL},
369 :
370 : NativeSymbol{"[method]file.read", (void *)&StapplerFilesystemFileRead, "(i*~)i", NULL},
371 : NativeSymbol{"[method]file.seek", (void *)&StapplerFilesystemFileSeek, "(iIi)I", NULL},
372 : NativeSymbol{"[method]file.tell", (void *)&StapplerFilesystemFileTell, "(i)I", NULL},
373 : NativeSymbol{"[method]file.size", (void *)&StapplerFilesystemFileSize, "(i)I", NULL},
374 : NativeSymbol{"[method]file.xsgetc", (void *)&StapplerFilesystemFileXsgetc, "(i)i", NULL},
375 : NativeSymbol{"[method]file.xsputc", (void *)&StapplerFilesystemFileXsputc, "(ii)i", NULL},
376 : NativeSymbol{"[method]file.xsputn", (void *)&StapplerFilesystemFileXsputn, "(i*~)i", NULL},
377 : NativeSymbol{"[method]file.xsgetn", (void *)&StapplerFilesystemFileXsgetn, "(i*~)i", NULL},
378 : NativeSymbol{"[method]file.is-open", (void *)&StapplerFilesystemFileIsOpen, "(i)i", NULL},
379 : NativeSymbol{"[method]file.eof", (void *)&StapplerFilesystemFileEof, "(i)i", NULL},
380 : NativeSymbol{"[method]file.close", (void *)&StapplerFilesystemFileClose, "(i)", NULL},
381 : NativeSymbol{"[method]file.close-remove", (void *)&StapplerFilesystemFileCloseRemove, "(i)", NULL},
382 : NativeSymbol{"[method]file.close-rename", (void *)&StapplerFilesystemFileCloseRename, "(i*~)", NULL},
383 : NativeSymbol{"[method]file.get-tmp-path", (void *)&StapplerFilesystemFileGetTmpPath, "(i*~)i", NULL},
384 :
385 : NativeSymbol{"[resource-drop]file", (void *)&StapplerFilesystemFileDrop, "(i)", NULL},
386 :
387 : };
388 :
389 : static NativeModule s_filesystemModule("stappler:wasm/filesystem", stapper_filesystem_symbols, sizeof(stapper_filesystem_symbols) / sizeof(NativeSymbol));
390 :
391 : }
|