| |
| |
| |
| |
|
|
| |
|
|
| #include "file.h" |
| #include "wasmfs.h" |
| #include "wasmfs_internal.h" |
| #include <emscripten/threading.h> |
|
|
| namespace wasmfs { |
|
|
| |
| |
| |
|
|
| void DataFile::Handle::preloadFromJS(int index) { |
| |
| |
| std::vector<uint8_t> buffer(_wasmfs_get_preloaded_file_size(index)); |
|
|
| |
| assert(emscripten_is_main_runtime_thread()); |
|
|
| |
| _wasmfs_copy_preloaded_file_data(index, buffer.data()); |
|
|
| write((const uint8_t*)buffer.data(), buffer.size(), 0); |
| } |
|
|
| |
| |
| |
|
|
| void Directory::Handle::cacheChild(const std::string& name, |
| std::shared_ptr<File> child, |
| DCacheKind kind) { |
| |
| |
| |
| if (kind == DCacheKind::Mount || !getDir()->maintainsFileIdentity()) { |
| auto& dcache = getDir()->dcache; |
| [[maybe_unused]] auto [_, inserted] = dcache.insert({name, {kind, child}}); |
| assert(inserted && "inserted child already existed!"); |
| } |
| |
| assert(child->locked().getParent() == nullptr || |
| child->locked().getParent() == getDir()); |
| child->locked().setParent(getDir()); |
| } |
|
|
| std::shared_ptr<File> Directory::Handle::getChild(const std::string& name) { |
| |
| if (!getParent()) { |
| return nullptr; |
| } |
| if (name == ".") { |
| return file; |
| } |
| if (name == "..") { |
| return getParent(); |
| } |
| |
| auto& dcache = getDir()->dcache; |
| if (auto it = dcache.find(name); it != dcache.end()) { |
| return it->second.file; |
| } |
| |
| |
| auto child = getDir()->getChild(name); |
| if (!child) { |
| return nullptr; |
| } |
| cacheChild(name, child, DCacheKind::Normal); |
| return child; |
| } |
|
|
| bool Directory::Handle::mountChild(const std::string& name, |
| std::shared_ptr<File> child) { |
| assert(child); |
| |
| if (!getParent()) { |
| return false; |
| } |
| cacheChild(name, child, DCacheKind::Mount); |
| return true; |
| } |
|
|
| std::shared_ptr<DataFile> |
| Directory::Handle::insertDataFile(const std::string& name, mode_t mode) { |
| |
| if (!getParent()) { |
| return nullptr; |
| } |
| auto child = getDir()->insertDataFile(name, mode); |
| if (!child) { |
| return nullptr; |
| } |
| cacheChild(name, child, DCacheKind::Normal); |
| updateMTime(); |
| return child; |
| } |
|
|
| std::shared_ptr<Directory> |
| Directory::Handle::insertDirectory(const std::string& name, mode_t mode) { |
| |
| if (!getParent()) { |
| return nullptr; |
| } |
| auto child = getDir()->insertDirectory(name, mode); |
| if (!child) { |
| return nullptr; |
| } |
| cacheChild(name, child, DCacheKind::Normal); |
| updateMTime(); |
| return child; |
| } |
|
|
| std::shared_ptr<Symlink> |
| Directory::Handle::insertSymlink(const std::string& name, |
| const std::string& target) { |
| |
| if (!getParent()) { |
| return nullptr; |
| } |
| auto child = getDir()->insertSymlink(name, target); |
| if (!child) { |
| return nullptr; |
| } |
| cacheChild(name, child, DCacheKind::Normal); |
| updateMTime(); |
| return child; |
| } |
|
|
| |
| |
| |
| int Directory::Handle::insertMove(const std::string& name, |
| std::shared_ptr<File> file) { |
| |
| if (!getParent()) { |
| return -EPERM; |
| } |
|
|
| |
| auto oldParent = file->locked().getParent(); |
| auto& oldCache = oldParent->dcache; |
| auto oldIt = std::find_if(oldCache.begin(), oldCache.end(), [&](auto& kv) { |
| return kv.second.file == file; |
| }); |
|
|
| |
| |
|
|
| |
| if (auto err = getDir()->insertMove(name, file)) { |
| return err; |
| } |
|
|
| if (oldIt != oldCache.end()) { |
| |
| auto [oldName, entry] = *oldIt; |
| assert(oldName.size()); |
| |
| oldCache.erase(oldIt); |
| auto& newCache = getDir()->dcache; |
| auto [it, inserted] = newCache.insert({name, entry}); |
| if (!inserted) { |
| |
| it->second.file->locked().setParent(nullptr); |
| it->second = entry; |
| } |
| } else { |
| |
| assert(getDir()->maintainsFileIdentity()); |
| } |
|
|
| file->locked().setParent(getDir()); |
|
|
| |
| oldParent->locked().updateMTime(); |
| updateMTime(); |
|
|
| return 0; |
| } |
|
|
| int Directory::Handle::removeChild(const std::string& name) { |
| auto& dcache = getDir()->dcache; |
| auto entry = dcache.find(name); |
| |
| if (entry != dcache.end() && entry->second.kind == DCacheKind::Mount) { |
| dcache.erase(entry); |
| return 0; |
| } |
| if (auto err = getDir()->removeChild(name)) { |
| assert(err < 0); |
| return err; |
| } |
| if (entry != dcache.end()) { |
| entry->second.file->locked().setParent(nullptr); |
| dcache.erase(entry); |
| } |
| updateMTime(); |
| return 0; |
| } |
|
|
| std::string Directory::Handle::getName(std::shared_ptr<File> file) { |
| if (getDir()->maintainsFileIdentity()) { |
| return getDir()->getName(file); |
| } |
| auto& dcache = getDir()->dcache; |
| for (auto it = dcache.begin(); it != dcache.end(); ++it) { |
| if (it->second.file == file) { |
| return it->first; |
| } |
| } |
| return ""; |
| } |
|
|
| ssize_t Directory::Handle::getNumEntries() { |
| size_t mounts = 0; |
| auto& dcache = getDir()->dcache; |
| for (auto it = dcache.begin(); it != dcache.end(); ++it) { |
| if (it->second.kind == DCacheKind::Mount) { |
| ++mounts; |
| } |
| } |
| auto numReal = getDir()->getNumEntries(); |
| if (numReal < 0) { |
| return numReal; |
| } |
| return numReal + mounts; |
| } |
|
|
| Directory::MaybeEntries Directory::Handle::getEntries() { |
| auto entries = getDir()->getEntries(); |
| if (entries.getError()) { |
| return entries; |
| } |
| auto& dcache = getDir()->dcache; |
| for (auto it = dcache.begin(); it != dcache.end(); ++it) { |
| auto& [name, entry] = *it; |
| if (entry.kind == DCacheKind::Mount) { |
| entries->push_back({name, entry.file->kind, entry.file->getIno()}); |
| } |
| } |
| return entries; |
| } |
|
|
| } |
|
|