Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WASMFS] Fix remaining TODO items with wasmfs + noderawfs #23617

Merged
merged 1 commit into from
Feb 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/lib/libsigs.js
Original file line number Diff line number Diff line change
Expand Up @@ -402,14 +402,19 @@ sigs = {
_wasmfs_jsimpl_write__sig: 'ippppj',
_wasmfs_node_close__sig: 'ii',
_wasmfs_node_fstat_size__sig: 'iip',
_wasmfs_node_ftruncate__sig: 'iij',
_wasmfs_node_get_mode__sig: 'ipp',
_wasmfs_node_insert_directory__sig: 'ipi',
_wasmfs_node_insert_file__sig: 'ipi',
_wasmfs_node_open__sig: 'ipp',
_wasmfs_node_read__sig: 'iipiip',
_wasmfs_node_readdir__sig: 'ipp',
_wasmfs_node_readlink__sig: 'ippi',
_wasmfs_node_rename__sig: 'ipp',
_wasmfs_node_rmdir__sig: 'ip',
_wasmfs_node_stat_size__sig: 'ipp',
_wasmfs_node_symlink__sig: 'ipp',
_wasmfs_node_truncate__sig: 'ipj',
_wasmfs_node_unlink__sig: 'ip',
_wasmfs_node_write__sig: 'iipiip',
_wasmfs_opfs_close_access__sig: 'vpip',
Expand Down
35 changes: 32 additions & 3 deletions src/lib/libwasmfs_node.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,39 @@ addToLibrary({
});
},

_wasmfs_node_truncate__i53abi: true,
_wasmfs_node_truncate__deps : ['$wasmfsTry'],
_wasmfs_node_truncate : (path_p, len) => {
return wasmfsTry(() => fs.truncateSync(UTF8ToString(path_p), len));
},

_wasmfs_node_ftruncate__i53abi: true,
_wasmfs_node_ftruncate__deps : ['$wasmfsTry'],
_wasmfs_node_ftruncate : (fd, len) => {
return wasmfsTry(() => fs.ftruncateSync(fd, len));
},

_wasmfs_node_open__deps: ['$wasmfsTry'],
_wasmfs_node_open: (path_p, mode_p) => {
return wasmfsTry(() =>
fs.openSync(UTF8ToString(path_p), UTF8ToString(mode_p))
);
return wasmfsTry(() => fs.openSync(UTF8ToString(path_p), UTF8ToString(mode_p)));
},

_wasmfs_node_rename__deps: ['$wasmfsTry'],
_wasmfs_node_rename: (from_path_p, to_path_p) => {
return wasmfsTry(() => fs.renameSync(UTF8ToString(from_path_p), UTF8ToString(to_path_p)));
},

_wasmfs_node_symlink__deps: ['$wasmfsTry'],
_wasmfs_node_symlink: (target_path_p, linkpath_path_p) => {
return wasmfsTry(() => fs.symlinkSync(UTF8ToString(target_path_p), UTF8ToString(linkpath_path_p)));
},

_wasmfs_node_readlink__deps: ['$wasmfsTry'],
_wasmfs_node_readlink: (path_p, target_p, bufsize) => {
return wasmfsTry(() => {
var target = fs.readlinkSync(UTF8ToString(path_p));
return stringToUTF8(target, target_p, bufsize);
});
},

_wasmfs_node_close__deps: [],
Expand Down Expand Up @@ -192,4 +220,5 @@ addToLibrary({
// implicitly return 0
});
},

});
52 changes: 45 additions & 7 deletions system/lib/wasmfs/backends/node_backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,13 @@ class NodeState {
result = _wasmfs_node_open(path.c_str(), "r");
break;
case O_WRONLY:
result = _wasmfs_node_open(path.c_str(), "w");
break;
// TODO(sbc): Specific handling of O_WRONLY.
// There is no simple way to map O_WRONLY to an fopen-style
// mode string since the only two modes that are write only
// are `w` and `a`. The problem with the former is that it
// truncates to file. The problem with the latter is that it
// opens for appending. For now simply opening in O_RDWR
// mode is enough to pass all our tests.
case O_RDWR:
result = _wasmfs_node_open(path.c_str(), "r+");
break;
Expand Down Expand Up @@ -118,7 +123,10 @@ class NodeFile : public DataFile {
}

int setSize(off_t size) override {
WASMFS_UNREACHABLE("TODO: implement NodeFile::setSize");
if (state.isOpen()) {
return _wasmfs_node_ftruncate(state.getFD(), size);
}
return _wasmfs_node_truncate(state.path.c_str(), size);
}

int open(oflags_t flags) override { return state.open(flags); }
Expand Down Expand Up @@ -147,6 +155,22 @@ class NodeFile : public DataFile {
}
};

class NodeSymlink : public Symlink {
public:
std::string path;

NodeSymlink(backend_t backend, std::string path)
: Symlink(backend), path(path) {}

virtual std::string getTarget() const {
char buf[PATH_MAX];
if (_wasmfs_node_readlink(path.c_str(), buf, PATH_MAX) < 0) {
WASMFS_UNREACHABLE("getTarget cannot fail");
}
return std::string(buf);
}
};

class NodeDirectory : public Directory {
public:
NodeState state;
Expand All @@ -172,8 +196,7 @@ class NodeDirectory : public Directory {
} else if (S_ISDIR(mode)) {
return std::make_shared<NodeDirectory>(mode, getBackend(), childPath);
} else if (S_ISLNK(mode)) {
// return std::make_shared<NodeSymlink>(mode, getBackend(), childPath);
return nullptr;
return std::make_shared<NodeSymlink>(getBackend(), childPath);
} else {
// Unrecognized file kind not made visible to WasmFS.
return nullptr;
Expand Down Expand Up @@ -212,11 +235,26 @@ class NodeDirectory : public Directory {

std::shared_ptr<Symlink> insertSymlink(const std::string& name,
const std::string& target) override {
WASMFS_UNREACHABLE("TODO: implement NodeDirectory::insertSymlink");
auto childPath = getChildPath(name);
if (_wasmfs_node_symlink(target.c_str(), childPath.c_str())) {
return nullptr;
}
return std::make_shared<NodeSymlink>(getBackend(), childPath);
}

int insertMove(const std::string& name, std::shared_ptr<File> file) override {
WASMFS_UNREACHABLE("TODO: implement NodeDirectory::insertMove");
std::string fromPath;

if (file->is<DataFile>()) {
auto nodeFile = std::static_pointer_cast<NodeFile>(file);
fromPath = nodeFile->state.path;
} else {
auto nodeDir = std::static_pointer_cast<NodeDirectory>(file);
fromPath = nodeDir->state.path;
}

auto childPath = getChildPath(name);
return _wasmfs_node_rename(fromPath.c_str(), childPath.c_str());
}

ssize_t getNumEntries() override {
Expand Down
12 changes: 11 additions & 1 deletion system/lib/wasmfs/backends/node_backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ int _wasmfs_node_insert_directory(const char* path, mode_t mode);
int _wasmfs_node_unlink(const char* path);
int _wasmfs_node_rmdir(const char* path);

int _wasmfs_node_truncate(const char* path, off_t len);
int _wasmfs_node_ftruncate(int fd, off_t len);

int _wasmfs_node_rename(const char* oldpath, const char* newpath);

int _wasmfs_node_symlink(const char *target, const char *linkpath);

int _wasmfs_node_readlink(const char *path, const char *buf, int bufsize);

// Open the file and return the underlying file descriptor.
[[nodiscard]] int _wasmfs_node_open(const char* path, const char* mode);

Expand All @@ -42,4 +51,5 @@ int _wasmfs_node_read(
// the number of bytes written to `nread`. Return 0 on success or an error code.
int _wasmfs_node_write(
int fd, const void* buf, uint32_t len, uint32_t pos, uint32_t* nwritten);
}

} // extern "C"
6 changes: 5 additions & 1 deletion test/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,9 @@ def metafunc(self, fs, *args, **kwargs):
self.setup_noderawfs_test()
elif fs == 'wasmfs':
self.setup_wasmfs_test()
elif fs == 'wasmfs_rawfs':
self.setup_wasmfs_test()
self.setup_noderawfs_test()
else:
self.emcc_args += ['-DMEMFS']
assert fs is None
Expand All @@ -458,7 +461,8 @@ def metafunc(self, fs, *args, **kwargs):
parameterize(metafunc, {'': (None,),
'nodefs': ('nodefs',),
'rawfs': ('rawfs',),
'wasmfs': ('wasmfs',)})
'wasmfs': ('wasmfs',),
'wasmfs_rawfs': ('wasmfs_rawfs',)})
return metafunc


Expand Down
5 changes: 5 additions & 0 deletions test/fs/test_stat_unnamed_file_descriptor.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,18 @@ int main() {
int fd = open("file.txt", O_RDWR | O_CREAT, 0666);
unlink("file.txt");
int res;

struct stat buf;
res = fstat(fd, &buf);
assert(res == 0);
assert(buf.st_atime > 1000000000);
printf("done stat: %d\n", res);

res = fchmod(fd, 0777);
assert(res == 0);

res = ftruncate(fd, 10);
assert(res == 0);

printf("success\n");
}
2 changes: 1 addition & 1 deletion test/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -5922,7 +5922,7 @@ def test_unistd_access(self):
# We also report all files as executable since there is no x bit
# recorded there.
# See https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/chmod-wchmod?view=msvc-170#remarks
if WINDOWS and '-DNODERAWFS' in self.emcc_args:
if WINDOWS and '-DNODERAWFS' in self.emcc_args and not self.get_setting('WASMFS'):
out_suffix = '.win'
else:
out_suffix = ''
Expand Down
26 changes: 22 additions & 4 deletions test/unistd/truncate.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* found in the LICENSE file.
*/

#include <assert.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
Expand All @@ -13,26 +14,35 @@
#include <string.h>

void setup() {
int rtn;

FILE* f = fopen("towrite", "w");
fwrite("abcdef", 6, 1, f);
assert(f);
rtn = fwrite("abcdef", 6, 1, f);
assert(rtn = 6);
fclose(f);

f = fopen("toread", "w");
fwrite("abcdef", 6, 1, f);
assert(f);
rtn = fwrite("abcdef", 6, 1, f);
assert(rtn = 6);
fclose(f);

chmod("toread", 0444);
assert(chmod("toread", 0444) == 0);
}

int main() {
setup();

struct stat s;
int f = open("towrite", O_WRONLY);
assert(f);
int f2 = open("toread", O_RDONLY);
printf("f2: %d\n", f2);
assert(f2);

fstat(f, &s);
printf("st_size: %lld\n", s.st_size);
assert(s.st_size == 6);
memset(&s, 0, sizeof s);
errno = 0;
printf("\n");
Expand All @@ -41,6 +51,7 @@ int main() {
printf("errno: %s\n", strerror(errno));
fstat(f, &s);
printf("st_size: %lld\n", s.st_size);
assert(s.st_size == 10);
memset(&s, 0, sizeof s);
errno = 0;
printf("\n");
Expand All @@ -49,6 +60,7 @@ int main() {
printf("errno: %s\n", strerror(errno));
fstat(f, &s);
printf("st_size: %lld\n", s.st_size);
assert(s.st_size == 4);
memset(&s, 0, sizeof s);
errno = 0;
printf("\n");
Expand All @@ -57,6 +69,7 @@ int main() {
printf("errno: %s\n", strerror(errno));
fstat(f, &s);
printf("st_size: %lld\n", s.st_size);
assert(s.st_size == 4);
memset(&s, 0, sizeof s);
errno = 0;
printf("\n");
Expand All @@ -65,6 +78,7 @@ int main() {
printf("errno: %s\n", strerror(errno));
fstat(f, &s);
printf("st_size: %lld\n", s.st_size);
assert(s.st_size == 2);
memset(&s, 0, sizeof s);
errno = 0;
printf("\n");
Expand All @@ -74,6 +88,7 @@ int main() {
printf("errno: %s\n", strerror(errno));
fstat(f, &s);
printf("st_size: %lld\n", s.st_size);
assert(s.st_size == 0);
memset(&s, 0, sizeof s);
errno = 0;
printf("\n");
Expand All @@ -82,6 +97,7 @@ int main() {
printf("errno: %s\n", strerror(errno));
fstat(f2, &s);
printf("st_size: %lld\n", s.st_size);
assert(s.st_size == 6);
memset(&s, 0, sizeof s);
errno = 0;
printf("\n");
Expand All @@ -94,6 +110,7 @@ int main() {
printf("errno: %s\n", strerror(errno));
fstat(f2, &s);
printf("st_size: %lld\n", s.st_size);
assert(s.st_size == 6);
memset(&s, 0, sizeof s);
errno = 0;
printf("\n");
Expand All @@ -103,6 +120,7 @@ int main() {
printf("errno: %s\n", strerror(errno));
fstat(f2, &s);
printf("st_size: %lld\n", s.st_size);
assert(s.st_size == 6);
memset(&s, 0, sizeof s);
errno = 0;

Expand Down
1 change: 1 addition & 0 deletions tools/emscripten.py
Original file line number Diff line number Diff line change
Expand Up @@ -1070,6 +1070,7 @@ def create_pointer_conversion_wrappers(metadata):
'_wasmfs_get_cwd': 'p_',
'_wasmfs_identify': '_p',
'_wasmfs_read_file': 'pp',
'_wasmfs_node_record_dirent': '_pp_',
'__dl_seterr': '_pp',
'_emscripten_run_on_main_thread_js': '__p_p_',
'_emscripten_proxy_execute_task_queue': '_p',
Expand Down