Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/system/lib/wasmfs/special_files.cpp
6174 views
1
// Copyright 2021 The Emscripten Authors. All rights reserved.
2
// Emscripten is available under two separate licenses, the MIT license and the
3
// University of Illinois/NCSA Open Source License. Both these licenses can be
4
// found in the LICENSE file.
5
6
// This file defines the standard streams.
7
8
#include <emscripten/html5.h>
9
#include <unistd.h>
10
#include <vector>
11
#include <wasi/api.h>
12
13
#include "special_files.h"
14
#include "wasmfs_internal.h"
15
16
namespace wasmfs::SpecialFiles {
17
18
namespace {
19
20
// No-op reads and writes: /dev/null
21
class NullFile : public DataFile {
22
int open(oflags_t) override { return 0; }
23
int close() override { return 0; }
24
25
ssize_t write(const uint8_t* buf, size_t len, off_t offset) override {
26
return len;
27
}
28
29
ssize_t read(uint8_t* buf, size_t len, off_t offset) override { return 0; }
30
31
int flush() override { return 0; }
32
off_t getSize() override { return 0; }
33
int setSize(off_t size) override { return -EPERM; }
34
35
public:
36
NullFile() : DataFile(S_IRUGO | S_IWUGO, NullBackend, S_IFCHR) {}
37
};
38
39
class StdinFile : public DataFile {
40
int open(oflags_t) override { return 0; }
41
int close() override { return 0; }
42
43
ssize_t write(const uint8_t* buf, size_t len, off_t offset) override {
44
return -__WASI_ERRNO_INVAL;
45
}
46
47
ssize_t read(uint8_t* buf, size_t len, off_t offset) override {
48
for (size_t i = 0; i < len; i++) {
49
auto c = _wasmfs_stdin_get_char();
50
if (c < 0) {
51
// No more input can be read, return what we did read.
52
return i;
53
}
54
buf[i] = c;
55
}
56
return len;
57
};
58
59
int flush() override { return 0; }
60
off_t getSize() override { return 0; }
61
int setSize(off_t size) override { return -EPERM; }
62
63
public:
64
StdinFile() : DataFile(S_IRUGO, NullBackend, S_IFCHR) { seekable = false; }
65
};
66
67
// A standard stream that writes: stdout or stderr.
68
class WritingStdFile : public DataFile {
69
protected:
70
std::vector<char> writeBuffer;
71
72
int open(oflags_t) override { return 0; }
73
int close() override { return 0; }
74
75
ssize_t read(uint8_t* buf, size_t len, off_t offset) override {
76
return -__WASI_ERRNO_INVAL;
77
};
78
79
int flush() override {
80
// Write a null to flush the output if we have content.
81
if (!writeBuffer.empty()) {
82
const uint8_t nothing = '\0';
83
write(&nothing, 1, 0);
84
}
85
return 0;
86
}
87
88
off_t getSize() override { return 0; }
89
int setSize(off_t size) override { return -EPERM; }
90
91
ssize_t writeToJS(const uint8_t* buf,
92
size_t len,
93
void (*console_write)(const char*),
94
std::vector<char>& fd_write_buffer) {
95
for (size_t j = 0; j < len; j++) {
96
uint8_t current = buf[j];
97
// Flush on either a null or a newline.
98
if (current == '\0' || current == '\n') {
99
fd_write_buffer.push_back('\0'); // for null-terminated C strings
100
console_write(fd_write_buffer.data());
101
fd_write_buffer.clear();
102
} else {
103
fd_write_buffer.push_back(current);
104
}
105
}
106
return len;
107
}
108
109
public:
110
WritingStdFile() : DataFile(S_IWUGO, NullBackend, S_IFCHR) {
111
seekable = false;
112
}
113
};
114
115
class StdoutFile : public WritingStdFile {
116
ssize_t write(const uint8_t* buf, size_t len, off_t offset) override {
117
// Node and worker threads issue in Emscripten:
118
// https://github.com/emscripten-core/emscripten/issues/14804.
119
// Issue filed in Node: https://github.com/nodejs/node/issues/40961
120
// This is confirmed to occur when running with EXIT_RUNTIME and
121
// PROXY_TO_PTHREAD. This results in only a single console.log statement
122
// being outputted. The solution for now is to use out() and err() instead.
123
return writeToJS(buf, len, &emscripten_out, writeBuffer);
124
}
125
126
public:
127
StdoutFile() {}
128
};
129
130
class StderrFile : public WritingStdFile {
131
ssize_t write(const uint8_t* buf, size_t len, off_t offset) override {
132
// Similar issue with Node and worker threads as emscripten_out.
133
// TODO: May not want to proxy stderr (fd == 2) to the main thread, as
134
// emscripten_err does.
135
// This will not show in HTML - a console.warn in a worker is
136
// sufficient. This would be a change from the current FS.
137
return writeToJS(buf, len, &emscripten_err, writeBuffer);
138
}
139
140
public:
141
StderrFile() {}
142
};
143
144
class RandomFile : public DataFile {
145
int open(oflags_t) override { return 0; }
146
int close() override { return 0; }
147
148
ssize_t write(const uint8_t* buf, size_t len, off_t offset) override {
149
return -__WASI_ERRNO_INVAL;
150
}
151
152
ssize_t read(uint8_t* buf, size_t len, off_t offset) override {
153
uint8_t* end = buf + len;
154
for (; buf < end; buf += 256) {
155
[[maybe_unused]] int err = getentropy(buf, std::min(end - buf, 256l));
156
assert(err == 0);
157
}
158
return len;
159
};
160
161
int flush() override { return 0; }
162
off_t getSize() override { return 0; }
163
int setSize(off_t size) override { return -EPERM; }
164
165
public:
166
RandomFile() : DataFile(S_IRUGO, NullBackend, S_IFCHR) { seekable = false; }
167
};
168
169
} // anonymous namespace
170
171
std::shared_ptr<DataFile> getNull() {
172
static auto null = std::make_shared<NullFile>();
173
return null;
174
}
175
176
std::shared_ptr<DataFile> getStdin() {
177
static auto stdin = std::make_shared<StdinFile>();
178
return stdin;
179
}
180
181
std::shared_ptr<DataFile> getStdout() {
182
static auto stdout = std::make_shared<StdoutFile>();
183
return stdout;
184
}
185
186
std::shared_ptr<DataFile> getStderr() {
187
static auto stderr = std::make_shared<StderrFile>();
188
return stderr;
189
}
190
191
std::shared_ptr<DataFile> getRandom() {
192
static auto random = std::make_shared<RandomFile>();
193
return random;
194
}
195
196
std::shared_ptr<DataFile> getURandom() {
197
static auto urandom = std::make_shared<RandomFile>();
198
return urandom;
199
}
200
201
} // namespace wasmfs::SpecialFiles
202
203