Skip to content

Commit

Permalink
Merge pull request emscripten-core#26 from rstz/add-realpath-support
Browse files Browse the repository at this point in the history
Add realpath support
  • Loading branch information
rstz authored Nov 17, 2021
2 parents 751a52a + 0bcfb68 commit 29c38d6
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 1 deletion.
65 changes: 65 additions & 0 deletions pthreadfs/examples/emscripten-tests/realpath.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@

#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

#include <emscripten.h>

void create_file(const char* path, const char* buffer, int mode) {
int fd = open(path, O_CREAT | O_TRUNC | O_RDWR, mode);
assert(fd >= 0);

int err = write(fd, buffer, sizeof(char) * strlen(buffer));
assert(err == (sizeof(char) * strlen(buffer)));

close(fd);
}

void setup() {
mkdir("persistent/folder", 0777);
mkdir("nonpersistent", 0777);
create_file("persistent/folder/file", "abcdef", 0777);
create_file("nonpersistent/file2", "ghijkl", 0777);
}

void cleanup() {
unlink("persistent/folder/file");
unlink("nonpersistent/file2");
rmdir("persistent/folder");
rmdir("nonpersistent");
}

bool test_path(const char* provided_path, const char* expected_path) {
char computed_path[PATH_MAX];
char* res = realpath(provided_path, computed_path);
int success = strcmp(expected_path, computed_path);
return res && success;
}

void test() {
const char* provided_paths[] = {"persistent/folder/../folder/file",
"persistent/../persistent/folder/file", "persistent/folder/./file", "/persistent/folder/file"};
const char* expected_paths[] = {"persistent/folder/file", "persistent/folder/file",
"persistent/folder/file", "persistent/folder/file"};
for (int i = 0; i < sizeof(provided_paths) / sizeof(char*); i++) {
if (!test_path(provided_paths[i], expected_paths[i])) {
char* errStr = strerror(errno);
printf("Realpath failed for path %d: %s. Error string: %s\n", i, provided_paths[i], errStr);
return;
}
}
puts("success");
}

int main() {
setup();
test();
cleanup();
return EXIT_SUCCESS;
}
21 changes: 20 additions & 1 deletion pthreadfs/pthreadfs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,18 @@ bool is_pthreadfs_file(std::string path) {
return path.rfind("/" PTHREADFS_FOLDER_NAME, 0) == 0 || path.rfind(PTHREADFS_FOLDER_NAME, 0) == 0;
}

bool is_pthreadfs_fd_link(std::string path) {
if (path.rfind("/proc/self/fd/", 0) == 0) {
char* p;
long fd = strtol(path.substr(14).c_str(), &p, 10);
// As defined in library_asyncfs.js, the minimum fd for PThreadFS is 4097.
if (*p == 0 && fd >= 4097) {
return true;
}
}
return false;
}

} // namespace emscripten

// Static functions calling resumFct and setting the return value.
Expand Down Expand Up @@ -235,8 +247,15 @@ SYS_CAPI_DEF(ioctl, 54, long fd, long request, ...) {
SYS_SYNC_TO_ASYNC_FD(ioctl, fd, request, arg);
}

// The implementation of readlink includes special handling for the file descriptor's symlinks in
// /proc/self/fd/. This is necessary for handling realpath.
SYS_CAPI_DEF(readlink, 85, long path, long buf, long bufsize) {
SYS_SYNC_TO_ASYNC_PATH(readlink, path, buf, bufsize);
std::string pathname((char*)path);
if (emscripten::is_pthreadfs_file(pathname) || emscripten::is_pthreadfs_fd_link(pathname)) {
SYS_SYNC_TO_ASYNC_NORETURN(readlink, path, buf, bufsize);
return resume_result_long;
}
return __sys_readlink(path, buf, bufsize);
}

SYS_CAPI_DEF(fchmod, 94, long fd, long mode) { SYS_SYNC_TO_ASYNC_FD(fchmod, fd, mode); }
Expand Down
3 changes: 3 additions & 0 deletions pthreadfs/pthreadfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,9 @@ class sync_to_async {

// Determines if `path` is a file in the special folder PTHREADFS_FOLDER.
bool is_pthreadfs_file(std::string path);
// Determines is `path` is a symlink in self/proc/fd/ that corresponds to a file in
// PTHREADFS_FOLDER.
bool is_pthreadfs_fd_link(std::string path);

} // namespace emscripten

Expand Down

0 comments on commit 29c38d6

Please sign in to comment.