Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@
// Emscripten is available under two separate licenses, the MIT license and the
// University of Illinois/NCSA Open Source License. Both these licenses can be
// found in the LICENSE file.
// This file defines the memory file class of the new file system.
// This should be the only backend file type defined in a header since it is the
// default type. Current Status: Work in Progress. See
// https://github.com/emscripten-core/emscripten/issues/15041.

#include "memory_file.h"
// This file defines the memory file backend of the new file system.
// Current Status: Work in Progress.
// See https://github.com/emscripten-core/emscripten/issues/15041.

#include "backend.h"
#include "memory_backend.h"
#include "wasmfs.h"

namespace wasmfs {

__wasi_errno_t MemoryFile::write(const uint8_t* buf, size_t len, off_t offset) {
if (offset + len > buffer.size()) {
buffer.resize(offset + len);
Expand All @@ -27,4 +30,16 @@ __wasi_errno_t MemoryFile::read(uint8_t* buf, size_t len, off_t offset) {

return __WASI_ERRNO_SUCCESS;
}

class MemoryFileBackend : public Backend {
public:
std::shared_ptr<DataFile> createFile(mode_t mode) override {
return std::make_shared<MemoryFile>(mode, this);
}
};

backend_t createMemoryFileBackend() {
return wasmFS.addBackend(std::make_unique<MemoryFileBackend>());
}

} // namespace wasmfs
161 changes: 0 additions & 161 deletions system/lib/wasmfs/file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,165 +108,4 @@ size_t Symlink::getSize() {
return target.size();
}

//
// Path Parsing utilities
//

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

if (pathParts.empty()) {
err = -ENOENT;
return ParsedPath{{}, nullptr};
}

// Check if the first path element is '/', indicating an absolute path.
if (pathParts[0] == "/") {
curr = wasmFS.getRootDirectory();
begin++;
// If the pathname is the root directory, return the root as the child.
if (pathParts.size() == 1) {
return ParsedPath{curr->locked(), curr};
}
} else {
// 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) {
// Find the next entry in the current directory entry
#ifdef WASMFS_DEBUG
curr->locked().printKeys();
#endif
auto entry = curr->locked().getEntry(*pathPart);

if (forbiddenAncestor) {
if (entry == forbiddenAncestor) {
err = -EINVAL;
return ParsedPath{{}, nullptr};
}
}

// An entry is defined in the current directory's entries vector.
if (!entry) {
err = -ENOENT;
return ParsedPath{{}, nullptr};
}

curr = entry->dynCast<Directory>();

// If file is nullptr, then the file was not a Directory.
// TODO: Change this to accommodate symlinks
if (!curr) {
err = -ENOTDIR;
return ParsedPath{{}, nullptr};
}

#ifdef WASMFS_DEBUG
emscripten_console_log(*pathPart->c_str());
#endif
}

// Lock the parent once.
auto lockedCurr = curr->locked();
auto child = lockedCurr.getEntry(*(pathParts.end() - 1));
return ParsedPath{std::move(lockedCurr), child};
}

std::shared_ptr<Directory> getDir(std::vector<std::string>::iterator begin,
std::vector<std::string>::iterator end,
long& err,
std::shared_ptr<File> forbiddenAncestor) {

std::shared_ptr<File> curr;
// Check if the first path element is '/', indicating an absolute path.
if (*begin == "/") {
curr = wasmFS.getRootDirectory();
begin++;
} else {
curr = wasmFS.getCWD();
}

for (auto it = begin; it != end; ++it) {
auto directory = curr->dynCast<Directory>();

// If file is nullptr, then the file was not a Directory.
// TODO: Change this to accommodate symlinks
if (!directory) {
err = -ENOTDIR;
return nullptr;
}

// Find the next entry in the current directory entry
#ifdef WASMFS_DEBUG
directory->locked().printKeys();
#endif
curr = directory->locked().getEntry(*it);

if (forbiddenAncestor) {
if (curr == forbiddenAncestor) {
err = -EINVAL;
return nullptr;
}
}

// Requested entry (file or directory)
if (!curr) {
err = -ENOENT;
return nullptr;
}

#ifdef WASMFS_DEBUG
emscripten_console_log(it->c_str());
#endif
}

auto currDirectory = curr->dynCast<Directory>();

if (!currDirectory) {
err = -ENOTDIR;
return nullptr;
}

return currDirectory;
}

// TODO: Check for trailing slash, i.e. /foo/bar.txt/
// Currently any trailing slash is ignored.
std::vector<std::string> splitPath(char* pathname) {
std::vector<std::string> pathParts;
char newPathName[strlen(pathname) + 1];
strcpy(newPathName, pathname);

// TODO: Other path parsing edge cases.
char* current;
// Handle absolute path.
if (newPathName[0] == '/') {
pathParts.push_back("/");
}

current = strtok(newPathName, "/");
while (current != NULL) {
pathParts.push_back(current);
current = strtok(NULL, "/");
}

return pathParts;
}
} // namespace wasmfs
33 changes: 0 additions & 33 deletions system/lib/wasmfs/file.h
Original file line number Diff line number Diff line change
Expand Up @@ -264,37 +264,4 @@ struct ParsedPath {
std::shared_ptr<File> child;
};

// Call getParsedPath if one needs a locked handle to a parent dir and a
// shared_ptr to its child file, given a file path.
// 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::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
// getParsedPath instead. Obtains parent directory of a given pathname.
// Will return a nullptr 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 nullptr will be returned.
std::shared_ptr<Directory>
getDir(std::vector<std::string>::iterator begin,
std::vector<std::string>::iterator end,
long& err,
std::shared_ptr<File> forbiddenAncestor = nullptr);

// Return a vector of the '/'-delimited components of a path. The first
// element will be "/" iff the path is an absolute path.
std::vector<std::string> splitPath(char* pathname);

} // namespace wasmfs
1 change: 1 addition & 0 deletions system/lib/wasmfs/js_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <unistd.h>

#include "file.h"
#include "paths.h"

using namespace wasmfs;

Expand Down
File renamed without changes.
26 changes: 0 additions & 26 deletions system/lib/wasmfs/memory_file_backend.cpp

This file was deleted.

Loading