Buckets:
| // Copyright 2021 The Emscripten Authors. All rights reserved. | |
| // 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 standard streams. | |
| namespace wasmfs::SpecialFiles { | |
| namespace { | |
| // No-op reads and writes: /dev/null | |
| class NullFile : public DataFile { | |
| int open(oflags_t) override { return 0; } | |
| int close() override { return 0; } | |
| ssize_t write(const uint8_t* buf, size_t len, off_t offset) override { | |
| return len; | |
| } | |
| ssize_t read(uint8_t* buf, size_t len, off_t offset) override { return 0; } | |
| int flush() override { return 0; } | |
| off_t getSize() override { return 0; } | |
| int setSize(off_t size) override { return -EPERM; } | |
| public: | |
| NullFile() : DataFile(S_IRUGO | S_IWUGO, NullBackend, S_IFCHR) {} | |
| }; | |
| class StdinFile : public DataFile { | |
| int open(oflags_t) override { return 0; } | |
| int close() override { return 0; } | |
| ssize_t write(const uint8_t* buf, size_t len, off_t offset) override { | |
| return -__WASI_ERRNO_INVAL; | |
| } | |
| ssize_t read(uint8_t* buf, size_t len, off_t offset) override { | |
| for (size_t i = 0; i < len; i++) { | |
| auto c = _wasmfs_stdin_get_char(); | |
| if (c < 0) { | |
| // No more input can be read, return what we did read. | |
| return i; | |
| } | |
| buf[i] = c; | |
| } | |
| return len; | |
| }; | |
| int flush() override { return 0; } | |
| off_t getSize() override { return 0; } | |
| int setSize(off_t size) override { return -EPERM; } | |
| public: | |
| StdinFile() : DataFile(S_IRUGO, NullBackend, S_IFCHR) { seekable = false; } | |
| }; | |
| // A standard stream that writes: stdout or stderr. | |
| class WritingStdFile : public DataFile { | |
| protected: | |
| std::vector<char> writeBuffer; | |
| int open(oflags_t) override { return 0; } | |
| int close() override { return 0; } | |
| ssize_t read(uint8_t* buf, size_t len, off_t offset) override { | |
| return -__WASI_ERRNO_INVAL; | |
| }; | |
| int flush() override { | |
| // Write a null to flush the output if we have content. | |
| if (!writeBuffer.empty()) { | |
| const uint8_t nothing = '\0'; | |
| write(¬hing, 1, 0); | |
| } | |
| return 0; | |
| } | |
| off_t getSize() override { return 0; } | |
| int setSize(off_t size) override { return -EPERM; } | |
| ssize_t writeToJS(const uint8_t* buf, | |
| size_t len, | |
| void (*console_write)(const char*), | |
| std::vector<char>& fd_write_buffer) { | |
| for (size_t j = 0; j < len; j++) { | |
| uint8_t current = buf[j]; | |
| // Flush on either a null or a newline. | |
| if (current == '\0' || current == '\n') { | |
| fd_write_buffer.push_back('\0'); // for null-terminated C strings | |
| console_write(fd_write_buffer.data()); | |
| fd_write_buffer.clear(); | |
| } else { | |
| fd_write_buffer.push_back(current); | |
| } | |
| } | |
| return len; | |
| } | |
| public: | |
| WritingStdFile() : DataFile(S_IWUGO, NullBackend, S_IFCHR) { | |
| seekable = false; | |
| } | |
| }; | |
| class StdoutFile : public WritingStdFile { | |
| ssize_t write(const uint8_t* buf, size_t len, off_t offset) override { | |
| // Node and worker threads issue in Emscripten: | |
| // https://github.com/emscripten-core/emscripten/issues/14804. | |
| // Issue filed in Node: https://github.com/nodejs/node/issues/40961 | |
| // This is confirmed to occur when running with EXIT_RUNTIME and | |
| // PROXY_TO_PTHREAD. This results in only a single console.log statement | |
| // being outputted. The solution for now is to use out() and err() instead. | |
| return writeToJS(buf, len, &emscripten_out, writeBuffer); | |
| } | |
| public: | |
| StdoutFile() {} | |
| }; | |
| class StderrFile : public WritingStdFile { | |
| ssize_t write(const uint8_t* buf, size_t len, off_t offset) override { | |
| // Similar issue with Node and worker threads as emscripten_out. | |
| // TODO: May not want to proxy stderr (fd == 2) to the main thread, as | |
| // emscripten_err does. | |
| // This will not show in HTML - a console.warn in a worker is | |
| // sufficient. This would be a change from the current FS. | |
| return writeToJS(buf, len, &emscripten_err, writeBuffer); | |
| } | |
| public: | |
| StderrFile() {} | |
| }; | |
| class RandomFile : public DataFile { | |
| int open(oflags_t) override { return 0; } | |
| int close() override { return 0; } | |
| ssize_t write(const uint8_t* buf, size_t len, off_t offset) override { | |
| return -__WASI_ERRNO_INVAL; | |
| } | |
| ssize_t read(uint8_t* buf, size_t len, off_t offset) override { | |
| uint8_t* end = buf + len; | |
| for (; buf < end; buf += 256) { | |
| [[maybe_unused]] int err = getentropy(buf, std::min(end - buf, 256l)); | |
| assert(err == 0); | |
| } | |
| return len; | |
| }; | |
| int flush() override { return 0; } | |
| off_t getSize() override { return 0; } | |
| int setSize(off_t size) override { return -EPERM; } | |
| public: | |
| RandomFile() : DataFile(S_IRUGO, NullBackend, S_IFCHR) { seekable = false; } | |
| }; | |
| } // anonymous namespace | |
| std::shared_ptr<DataFile> getNull() { | |
| static auto null = std::make_shared<NullFile>(); | |
| return null; | |
| } | |
| std::shared_ptr<DataFile> getStdin() { | |
| static auto stdin = std::make_shared<StdinFile>(); | |
| return stdin; | |
| } | |
| std::shared_ptr<DataFile> getStdout() { | |
| static auto stdout = std::make_shared<StdoutFile>(); | |
| return stdout; | |
| } | |
| std::shared_ptr<DataFile> getStderr() { | |
| static auto stderr = std::make_shared<StderrFile>(); | |
| return stderr; | |
| } | |
| std::shared_ptr<DataFile> getRandom() { | |
| static auto random = std::make_shared<RandomFile>(); | |
| return random; | |
| } | |
| std::shared_ptr<DataFile> getURandom() { | |
| static auto urandom = std::make_shared<RandomFile>(); | |
| return urandom; | |
| } | |
| } // namespace wasmfs::SpecialFiles | |
Xet Storage Details
- Size:
- 5.73 kB
- Xet hash:
- 1584f4ca7f7b4f38a20e09c50ce9d4dacfebc93c1b84956b7e86eecde6c2cc27
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.