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] Support utime() #16262

Merged
merged 13 commits into from
Feb 14, 2022
Merged
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ jobs:
- run-tests:
# also add a little select testing for wasm2js in -O3
# also add a little select wasmfs testing
test_targets: "core3 wasm2js3.test_memorygrowth_2 wasmfs.test_hello_world wasmfs.test_hello_world_standalone wasmfs.test_unistd_links* wasmfs.test_atexit_standalone wasmfs.test_emscripten_get_now wasmfs.test_dyncall_specific_minimal_runtime core2ss.test_pthread_dylink"
test_targets: "core3 wasm2js3.test_memorygrowth_2 wasmfs.test_hello_world wasmfs.test_hello_world_standalone wasmfs.test_unistd_links* wasmfs.test_atexit_standalone wasmfs.test_emscripten_get_now wasmfs.test_dyncall_specific_minimal_runtime core2ss.test_pthread_dylink wasmfs.test_utime"
test-wasm2js1:
executor: bionic
steps:
Expand Down
17 changes: 0 additions & 17 deletions src/library.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,23 +96,6 @@ LibraryManager.library = {
},
#endif

utime__deps: ['$setFileTime'],
utime__proxy: 'sync',
utime__sig: 'iii',
utime: function(path, times) {
{{{ from64('times') }}};
// int utime(const char *path, const struct utimbuf *times);
// http://pubs.opengroup.org/onlinepubs/009695399/basedefs/utime.h.html
var time;
if (times) {
// NOTE: We don't keep track of access timestamps.
time = {{{ makeGetValue('times', C_STRUCTS.utimbuf.modtime, 'i32') }}} * 1000;
} else {
time = Date.now();
}
return setFileTime(path, time);
},

utimes__deps: ['$setFileTime'],
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this can be removed too (perhaps as a followup).

utimes__proxy: 'sync',
utimes__sig: 'iii',
Expand Down
19 changes: 16 additions & 3 deletions system/lib/wasmfs/file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ size_t Symlink::getSize() {

ParsedPath getParsedPath(std::vector<std::string> pathParts,
long& err,
std::shared_ptr<File> forbiddenAncestor) {
std::shared_ptr<File> forbiddenAncestor,
std::optional<__wasi_fd_t> baseFD) {
std::shared_ptr<Directory> curr;
auto begin = pathParts.begin();

Expand All @@ -132,7 +133,20 @@ ParsedPath getParsedPath(std::vector<std::string> pathParts,
return ParsedPath{curr->locked(), curr};
}
} else {
curr = wasmFS.getCWD();
// This is a relative path. It is either relative to the current working
// directory if no base FD is given, or if the base FD is the special value
// indicating the CWD.
if (baseFD && *baseFD != AT_FDCWD) {
auto lockedOpenDir = wasmFS.getLockedFileTable()[*baseFD].locked();
auto openDir = lockedOpenDir.getFile();
if (!openDir->is<Directory>()) {
err = -EBADF;
return ParsedPath{{}, nullptr};
}
curr = openDir->dynCast<Directory>();
} else {
curr = wasmFS.getCWD();
}
}

for (auto pathPart = begin; pathPart != pathParts.end() - 1; ++pathPart) {
Expand Down Expand Up @@ -255,5 +269,4 @@ std::vector<std::string> splitPath(char* pathname) {

return pathParts;
}

} // namespace wasmfs
9 changes: 6 additions & 3 deletions system/lib/wasmfs/file.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ using backend_t = Backend*;
const backend_t NullBackend = nullptr;

class File : public std::enable_shared_from_this<File> {

public:
enum FileKind { DataFileKind = 0, DirectoryKind, SymlinkKind };

Expand Down Expand Up @@ -134,7 +133,6 @@ class File : public std::enable_shared_from_this<File> {
};

class DataFile : public File {

virtual __wasi_errno_t read(uint8_t* buf, size_t len, off_t offset) = 0;
virtual __wasi_errno_t
write(const uint8_t* buf, size_t len, off_t offset) = 0;
Expand Down Expand Up @@ -271,12 +269,17 @@ struct ParsedPath {
// TODO: When locking the directory structure is refactored, parent should be
// returned as a pointer, similar to child.
// Will return an empty handle if the parent is not a directory.
//
// Will error if the forbiddenAncestor is encountered while processing.
// If the forbiddenAncestor is encountered, err will be set to EINVAL and
// an empty parent handle will be returned.
//
// If baseFD is provided, and the path is relative, then it will be interpreted
// relative to the base. That is the behavior that the *at() syscalls require.
ParsedPath getParsedPath(std::vector<std::string> pathParts,
long& err,
std::shared_ptr<File> forbiddenAncestor = nullptr);
std::shared_ptr<File> forbiddenAncestor = nullptr,
std::optional<__wasi_fd_t> baseFD = {});

// Call getDir if one needs a parent directory of a file path.
// TODO: Remove this when directory structure locking is refactored and use
Expand Down
65 changes: 49 additions & 16 deletions system/lib/wasmfs/syscalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -458,24 +458,31 @@ static long doMkdir(char* path, long mode, backend_t backend = NullBackend) {
// Check if the requested directory already exists.
if (parsedPath.child) {
return -EEXIST;
} else {
// Mask rwx permissions for user, group and others, and the sticky bit.
// This prevents users from entering S_IFREG for example.
// https://www.gnu.org/software/libc/manual/html_node/Permission-Bits.html
mode &= S_IRWXUGO | S_ISVTX;

// By default, the backend that the directory is created in is the same as
// the parent directory. However, if a backend is passed as a parameter,
// then that backend is used.
if (!backend) {
backend = parsedPath.parent->unlocked()->getBackend();
}
// Create an empty in-memory directory.
auto created = backend->createDirectory(mode);
}

parsedPath.parent->setEntry(pathParts.back(), created);
return 0;
// Mask rwx permissions for user, group and others, and the sticky bit.
// This prevents users from entering S_IFREG for example.
// https://www.gnu.org/software/libc/manual/html_node/Permission-Bits.html
mode &= S_IRWXUGO | S_ISVTX;

// By default, the backend that the directory is created in is the same as
// the parent directory. However, if a backend is passed as a parameter,
// then that backend is used.
if (!backend) {
backend = parsedPath.parent->unlocked()->getBackend();
}
// Create an empty in-memory directory.
auto created = backend->createDirectory(mode);
parsedPath.parent->setEntry(pathParts.back(), created);

// Update the times.
auto lockedFile = created->locked();
time_t now = time(NULL);
lockedFile.atime() = now;
lockedFile.mtime() = now;
lockedFile.ctime() = now;

return 0;
}

// This function is exposed to users and allows users to specify a particular
Expand Down Expand Up @@ -936,4 +943,30 @@ long __syscall_readlink(char* path, char* buf, size_t bufSize) {

return bytes;
}

long __syscall_utimensat(int dirFD,
char* path,
const struct timespec times[2],
int flags) {
// TODO: support flags here
assert(flags == 0);

auto pathParts = splitPath(path);

long err;
auto parsedPath = getParsedPath(pathParts, err, nullptr, dirFD);
if (!parsedPath.parent) {
return err;
}

// TODO: tv_nsec (nanoseconds) as well? but time_t is seconds as an integer
auto aSeconds = times[0].tv_sec;
auto mSeconds = times[1].tv_sec;

auto locked = parsedPath.child->locked();
locked.atime() = aSeconds;
locked.mtime() = mSeconds;

return 0;
}
}
1 change: 1 addition & 0 deletions tools/system_libs.py
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,7 @@ def get_files(self):
'nanosleep.c',
'clock_nanosleep.c',
'ctime_r.c',
'utime.c',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Way better!

])
libc_files += files_in_path(
path='system/lib/libc/musl/src/legacy',
Expand Down