js-dos 8.1.5 → 8.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/dist/emulators/emulators.js +2 -0
  2. package/dist/emulators/emulators.js.map +1 -0
  3. package/dist/emulators/types/build.d.ts +28 -0
  4. package/dist/emulators/types/dos/bundle/dos-bundle.d.ts +20 -0
  5. package/dist/emulators/types/dos/dosbox/ts/direct.d.ts +3 -0
  6. package/dist/emulators/types/dos/dosbox/ts/worker.d.ts +3 -0
  7. package/dist/emulators/types/emulators.d.ts +76 -0
  8. package/dist/emulators/types/http.d.ts +9 -0
  9. package/dist/emulators/types/impl/ci-impl.d.ts +29 -0
  10. package/dist/emulators/types/impl/emulators-impl.d.ts +26 -0
  11. package/dist/emulators/types/impl/modules.d.ts +38 -0
  12. package/dist/emulators/types/libzip/libzip.d.ts +16 -0
  13. package/dist/emulators/types/protocol/messages-queue.d.ts +8 -0
  14. package/dist/emulators/types/protocol/protocol.d.ts +128 -0
  15. package/dist/emulators/wdosbox-x.js +55 -0
  16. package/dist/emulators/wdosbox-x.js.symbols +8760 -0
  17. package/dist/emulators/wdosbox-x.wasm +0 -0
  18. package/dist/emulators/wdosbox.js +55 -0
  19. package/dist/emulators/wdosbox.js.symbols +3001 -0
  20. package/dist/emulators/wdosbox.wasm +0 -0
  21. package/dist/emulators/wlibzip.js +21 -0
  22. package/dist/emulators/wlibzip.js.symbols +268 -0
  23. package/dist/emulators/wlibzip.wasm +0 -0
  24. package/dist/js-dos.css +1 -0
  25. package/dist/js-dos.js +22 -0
  26. package/dist/js-dos.js.map +1 -0
  27. package/package.json +1 -1
  28. package/release.zip +0 -0
  29. package/.eslintrc.json +0 -43
  30. package/.github/workflows/build.yml +0 -51
  31. package/.gitmodules +0 -4
  32. package/index.html +0 -110
  33. package/postcss.config.cjs +0 -8
  34. package/src/app.css +0 -14
  35. package/src/base.css +0 -10
  36. package/src/components/checkbox.tsx +0 -41
  37. package/src/components/close-button.tsx +0 -17
  38. package/src/components/components.css +0 -28
  39. package/src/components/dos-option-checkbox.tsx +0 -94
  40. package/src/components/dos-option-select.tsx +0 -108
  41. package/src/components/dos-option-slider.tsx +0 -35
  42. package/src/components/error.tsx +0 -16
  43. package/src/components/loading.tsx +0 -26
  44. package/src/components/lock.tsx +0 -10
  45. package/src/components/select.tsx +0 -33
  46. package/src/components/slider.tsx +0 -69
  47. package/src/download-file.ts +0 -18
  48. package/src/frame/account-frame.tsx +0 -156
  49. package/src/frame/editor/defaults.ts +0 -419
  50. package/src/frame/editor/editor-conf-frame.tsx +0 -227
  51. package/src/frame/editor/editor-frame.css +0 -55
  52. package/src/frame/editor/editor-fs-frame.tsx +0 -314
  53. package/src/frame/fat-drives-frame.tsx +0 -199
  54. package/src/frame/frame.css +0 -119
  55. package/src/frame/frame.tsx +0 -34
  56. package/src/frame/image-rendering-frame.tsx +0 -8
  57. package/src/frame/network-frame.tsx +0 -157
  58. package/src/frame/quick-save-frame.tsx +0 -98
  59. package/src/frame/settings-frame.tsx +0 -14
  60. package/src/frame/stats-frame.tsx +0 -87
  61. package/src/host/bundle-storage.ts +0 -91
  62. package/src/host/fullscreen.ts +0 -35
  63. package/src/host/lcache.ts +0 -203
  64. package/src/host/lstorage.ts +0 -156
  65. package/src/i18n.ts +0 -185
  66. package/src/index.css +0 -7
  67. package/src/load.ts +0 -132
  68. package/src/login/login.css +0 -9
  69. package/src/login/login.tsx +0 -77
  70. package/src/main.tsx +0 -197
  71. package/src/public/types.ts +0 -45
  72. package/src/sidebar/account-button.tsx +0 -33
  73. package/src/sidebar/cloud-save-button.tsx +0 -89
  74. package/src/sidebar/diskette-icon.tsx +0 -14
  75. package/src/sidebar/fullscreen-button.tsx +0 -44
  76. package/src/sidebar/network-button.tsx +0 -39
  77. package/src/sidebar/sidebar-button.tsx +0 -244
  78. package/src/sidebar/sidebar.css +0 -47
  79. package/src/sidebar/sidebar.tsx +0 -30
  80. package/src/sockdrive/LICENSE +0 -674
  81. package/src/sockdrive/README.md +0 -45
  82. package/src/sockdrive/include/sockdrive.h +0 -23
  83. package/src/sockdrive/js/.eslintrc.json +0 -43
  84. package/src/sockdrive/js/package.json +0 -29
  85. package/src/sockdrive/js/src/fatfs/chains.js +0 -318
  86. package/src/sockdrive/js/src/fatfs/dir.js +0 -385
  87. package/src/sockdrive/js/src/fatfs/helpers.js +0 -210
  88. package/src/sockdrive/js/src/fatfs/index.js +0 -606
  89. package/src/sockdrive/js/src/fatfs/structs.js +0 -255
  90. package/src/sockdrive/js/src/fatfs/vol.js +0 -166
  91. package/src/sockdrive/js/src/sockdrive/cache.ts +0 -56
  92. package/src/sockdrive/js/src/sockdrive/drive.ts +0 -471
  93. package/src/sockdrive/js/src/sockdrive/lru.ts +0 -221
  94. package/src/sockdrive/js/src/sockdrive/types.ts +0 -14
  95. package/src/sockdrive/js/src/sockdrive-fat.d.ts +0 -64
  96. package/src/sockdrive/js/src/sockdrive-fat.ts +0 -226
  97. package/src/sockdrive/js/src/sockdrive-native.ts +0 -100
  98. package/src/sockdrive/js/src/test/test.ts +0 -289
  99. package/src/sockdrive/js/tsconfig.json +0 -11
  100. package/src/sockdrive/js/webpack.config.js +0 -68
  101. package/src/sockdrive/js/yarn.lock +0 -1808
  102. package/src/store/auth.ts +0 -115
  103. package/src/store/dos.ts +0 -305
  104. package/src/store/editor.ts +0 -61
  105. package/src/store/init.ts +0 -48
  106. package/src/store/storage.ts +0 -32
  107. package/src/store/ui.ts +0 -191
  108. package/src/store.tsx +0 -116
  109. package/src/ui.tsx +0 -140
  110. package/src/v8/changes.ts +0 -56
  111. package/src/v8/config.ts +0 -20
  112. package/src/v8/subscriptions.ts +0 -62
  113. package/src/vite-env.d.ts +0 -5
  114. package/src/window/dos/controls/keyboard.ts +0 -32
  115. package/src/window/dos/controls/keys.ts +0 -331
  116. package/src/window/dos/controls/mouse/mount.ts +0 -99
  117. package/src/window/dos/controls/mouse/mouse-locked.ts +0 -51
  118. package/src/window/dos/controls/mouse/mouse-not-locked.ts +0 -84
  119. package/src/window/dos/controls/mouse/mouse-swipe.ts +0 -57
  120. package/src/window/dos/controls/mouse/pointer.ts +0 -85
  121. package/src/window/dos/controls/mouse.ts +0 -21
  122. package/src/window/dos/dos-dhry2.tsx +0 -191
  123. package/src/window/dos/dos-runtime.tsx +0 -216
  124. package/src/window/dos/dos-window.tsx +0 -91
  125. package/src/window/dos/render/canvas.ts +0 -65
  126. package/src/window/dos/render/resize.ts +0 -31
  127. package/src/window/dos/render/webgl.ts +0 -173
  128. package/src/window/dos/sound/audio-node.ts +0 -148
  129. package/src/window/error-window.tsx +0 -9
  130. package/src/window/loading-window.tsx +0 -54
  131. package/src/window/prerun-window.tsx +0 -121
  132. package/src/window/select-window.tsx +0 -118
  133. package/src/window/window.css +0 -78
  134. package/src/window/window.tsx +0 -49
  135. package/src/ws/ws-sockdrive.ts +0 -123
  136. package/src/ws/ws-transport-layer.ts +0 -468
  137. package/tailwind.config.cjs +0 -48
  138. package/tsconfig.json +0 -32
  139. package/tsconfig.node.json +0 -9
  140. package/vite.config.ts +0 -25
@@ -1,606 +0,0 @@
1
- const events = require("events");
2
- const streams = require("stream");
3
- const fifolock = require("fifolock");
4
- const S = require("./structs.js");
5
- const _ = require("./helpers.js");
6
-
7
- // _.log.level = _.log.DBG;
8
-
9
- exports.createFileSystem = function(volume, opts, cb) {
10
- if (typeof opts === "function") {
11
- cb = opts;
12
- opts = null;
13
- }
14
- opts = _.extend({
15
- // c.f. https://www.kernel.org/doc/Documentation/filesystems/vfat.txt
16
- ro: false,
17
- noatime: true,
18
- modmode: 0o111, // or `0o7000`
19
- umask: ("umask" in process) ? process.umask() : 0o022,
20
- uid: ("getuid" in process) ? process.getuid() : 0,
21
- gid: ("getgid" in process) ? process.getgid() : 0,
22
- }, opts);
23
- if (!volume.writeSectors) opts.ro = true;
24
- if (opts.ro) opts.noatime = true; // natch
25
-
26
- const fs = new events.EventEmitter();
27
- let vol = null;
28
- const dir = require("./dir.js");
29
- const c = require("./chains.js");
30
- const q = fifolock();
31
-
32
- const GROUP = (_.log.level < _.log.INFO) ? q.TRANSACTION_WRAPPER.bind({
33
- postAcquire: function(proceed) {
34
- _.log(_.log.DBG, "=== Starting GROUP ===");
35
- proceed();
36
- },
37
- preRelease: function(finish) {
38
- _.log(_.log.DBG, "=== Finishing GROUP ===");
39
- finish();
40
- },
41
- }) : q.TRANSACTION_WRAPPER;
42
-
43
- q.acquire(function(unlock) { // because of this, callers can start before 'ready'
44
- const d = _.allocBuffer(volume.sectorSize);
45
- volume.readSectors(0, d, function(e) {
46
- if (e) fs.emit("error", e);
47
- else {
48
- try {
49
- init(d);
50
- } catch (e) {
51
- fs.emit("error", e);
52
- unlock();
53
- return;
54
- }
55
- fs.emit("ready");
56
- }
57
- unlock();
58
- });
59
- });
60
-
61
- if (cb) fs.on("error", cb).on("ready", () => cb("ready", null));
62
-
63
- function init(bootSector) {
64
- vol = require("./vol.js").init(volume, opts, bootSector);
65
- fs._dirIterator = dir.iterator.bind(dir);
66
-
67
- const entryInfoByPath = {};
68
- const baseEntry = {
69
- _refs: 0,
70
- _record: function() {
71
- entryInfoByPath[this.path] = this;
72
- if (this.parent) this.parent.retain();
73
- return this;
74
- },
75
- retain: function() {
76
- if (!this._refs) this._record();
77
- this._refs += 1;
78
- return this;
79
- },
80
- release: function() {
81
- this._refs -= 1;
82
- if (!this._refs) this._rescind();
83
- },
84
- _rescind: function() {
85
- if (this.parent) this.parent.release();
86
- delete entryInfoByPath[this.path];
87
- },
88
- };
89
- fs._createSharedEntry = function(path, entry, chain, parent) {
90
- return _.extend(Object.create(baseEntry), {
91
- _refs: 0, // WORKAROUND: https://github.com/tessel/beta/issues/455
92
- path: path,
93
- entry: entry,
94
- chain: chain,
95
- parent: parent,
96
- }).retain();
97
- };
98
- fs._createSharedEntry("/", { Attr: { directory: true } }, vol.rootDirectoryChain);
99
- fs._sharedEntryForSteps = function(steps, opts, cb) { // NOTE: may `cb` before returning!
100
- const path = steps.join("/") || "/";
101
- const name = steps.pop(); // n.b.
102
- const info = entryInfoByPath[path];
103
- if (info) cb(null, info.retain());
104
- else {
105
- fs._sharedEntryForSteps(steps, {}, function(e, parentInfo) { // n.b. `steps` don't include `name`
106
- if (e) cb(e);
107
- else if (!parentInfo.entry.Attr.directory) cb(S.err.NOTDIR());
108
- else {
109
- dir.findInDirectory(vol, parentInfo.chain, name, opts, function(e, entry) {
110
- if (e && !opts.prepareForCreate) cb(e);
111
- else if (e) cb(e, { missingChild: _.extend(entry, { name: name }), parent: parentInfo });
112
- else cb(null, fs._createSharedEntry(path, entry, vol.chainForCluster(entry._firstCluster), parentInfo));
113
- });
114
- }
115
- });
116
- }
117
- };
118
-
119
- fs._updateEntry = dir.updateEntry.bind(dir, vol);
120
- fs._makeStat = dir.makeStat.bind(dir, vol);
121
- fs._addFile = dir.addFile.bind(dir, vol);
122
- fs._initDir = dir.init.bind(dir, vol);
123
- }
124
-
125
-
126
- /** ** ---- CORE API ---- ****/
127
-
128
- // NOTE: we really don't share namespace, but avoid first three anyway…
129
- const fileDescriptors = [null, null, null];
130
-
131
- fs.open = function(path, flags, mode, cb, _n_) {
132
- if (typeof mode === "function") {
133
- _n_ = cb;
134
- cb = mode;
135
- mode = 0o666;
136
- }
137
- cb = GROUP(cb, function() {
138
- const _fd = { flags: null, entry: null, chain: null, pos: 0 };
139
- const f = _.parseFlags(flags);
140
- if (vol.opts.ro && (f.write || f.create || f.truncate)) return _.delayedCall(cb, S.err.ROFS());
141
- else _fd.flags = f;
142
-
143
- fs._sharedEntryForSteps(_.absoluteSteps(path), { prepareForCreate: f.create }, function(e, info) {
144
- if (e && !(e.code === "NOENT" && f.create && info)) cb(e);
145
- else if (e) {
146
- fs._addFile(info.parent.chain, info.missingChild, { dir: f._openDir }, function(e, newEntry, newChain) {
147
- if (e) cb(e);
148
- else finish(fs._createSharedEntry(_.absolutePath(path), newEntry, newChain, info.parent));
149
- });
150
- } else if (info && f.exclusive) cb(S.err.EXIST());
151
- else if (info.entry.Attr.directory && !f._openDir) cb(S.err.ISDIR());
152
- else if (f.write && info.entry.Attr.readonly) cb(S.err.ACCES());
153
- else finish(info);
154
- function finish(fileInfo) {
155
- const fd = fileDescriptors.push(_fd)-1;
156
- _fd.info = fileInfo;
157
- _fd.entry = fileInfo.entry;
158
- _fd.chain = fileInfo.chain;
159
- if (f.append) _fd.pos = _fd.entry._size;
160
- if (f._openDir) _fd.chain.cacheAdvice = "WILLNEED";
161
- if (f.truncate && _fd.entry._size) {
162
- fs.ftruncate(fd, 0, function(e) {
163
- cb(e, fd);
164
- }, "_nested_");
165
- } else _.delayedCall(cb, null, fd); // (delay in case fs._sharedEntryForSteps all cached!)
166
- }
167
- });
168
- }, (_n_ === "_nested_"));
169
- };
170
-
171
- fs.fstat = function(fd, cb, _n_) {
172
- cb = GROUP(cb, function() {
173
- const _fd = fileDescriptors[fd];
174
- if (!_fd || !_fd.flags.read) _.delayedCall(cb, S.err.BADF());
175
- else _.delayedCall(cb, null, fs._makeStat(_fd.entry));
176
- }, (_n_ === "_nested_"));
177
- };
178
-
179
- fs.futimes = function(fd, atime, mtime, cb, _n_) {
180
- cb = GROUP(cb, function() {
181
- const _fd = fileDescriptors[fd];
182
- if (!_fd || !_fd.flags.write) _.delayedCall(cb, S.err.BADF());
183
- // NOTE: ctime would get touched on POSIX; but we map that to create time!
184
- else fs._updateEntry(_fd.entry, { atime: atime||true, mtime: mtime||true }, cb);
185
- }, (_n_ === "_nested_"));
186
- };
187
-
188
- fs.fchmod = function(fd, mode, cb, _n_) {
189
- cb = GROUP(cb, function() {
190
- const _fd = fileDescriptors[fd];
191
- if (!_fd || !_fd.flags.write) _.delayedCall(cb, S.err.BADF());
192
- else {
193
- mode &= S._I._chmoddable;
194
- if (_fd.entry.Attr.directory) mode |= S._I.FDIR;
195
- else if (!_fd.entry.Attr.volume_id) mode |= S._I.FREG;
196
- fs._updateEntry(_fd.entry, { mode: mode }, cb);
197
- }
198
- }, (_n_ === "_nested_"));
199
- };
200
-
201
- fs.read = function(fd, buf, off, len, pos, cb, _n_) {
202
- cb = GROUP(cb, function() {
203
- const _fd = fileDescriptors[fd];
204
- if (!_fd || !_fd.flags.read) return _.delayedCall(cb, S.err.BADF());
205
-
206
- const _pos = (pos === null) ? _fd.pos : pos;
207
- const _len = Math.min(len, _fd.entry._size - _pos);
208
- const _buf = buf.slice(off, off+_len);
209
- _fd.chain.readFromPosition(_pos, _buf, function(e, bytes, slice) {
210
- if (_.workaroundTessel380) _buf.copy(buf, off); // WORKAROUND: https://github.com/tessel/beta/issues/380
211
- _fd.pos = _pos + bytes;
212
- if (e || vol.opts.noatime) finish(e);
213
- else fs._updateEntry(_fd.entry, { atime: true }, finish);
214
- function finish(e) {
215
- cb(e, bytes, buf);
216
- }
217
- });
218
- }, (_n_ === "_nested_"));
219
- };
220
-
221
- fs._readdir = function(fd, cb, _n_) {
222
- cb = GROUP(cb, function() {
223
- const _fd = fileDescriptors[fd];
224
- if (!_fd || !_fd.flags.read) return _.delayedCall(cb, S.err.BADF());
225
-
226
- const entryNames = [];
227
- const getNextEntry = fs._dirIterator(_fd.chain);
228
- function processNext() {
229
- getNextEntry(function(e, d) {
230
- if (e) cb(e);
231
- else if (!d && !entryNames.length) cb(null, entryNames); // WORKAROUND: https://github.com/tessel/beta/issues/435
232
- else if (!d) cb(null, entryNames.sort()); // NOTE: sort not required, but… [simplifies tests for starters!]
233
- else {
234
- if (d._name !== "." && d._name !== "..") entryNames.push(d._name);
235
- processNext();
236
- }
237
- });
238
- }
239
- processNext();
240
- }, (_n_ === "_nested_"));
241
- };
242
-
243
- fs._mkdir = function(fd, cb, _n_) {
244
- cb = GROUP(cb, function() {
245
- const _fd = fileDescriptors[fd];
246
- if (!_fd || !_fd.flags.write) _.delayedCall(cb, S.err.BADF());
247
- else fs._initDir(_fd.info, cb);
248
- }, (_n_ === "_nested_"));
249
- };
250
-
251
- fs.write = function(fd, buf, off, len, pos, cb, _n_) {
252
- cb = GROUP(cb, function() {
253
- const _fd = fileDescriptors[fd];
254
- if (!_fd || !_fd.flags.write) return _.delayedCall(cb, S.err.BADF());
255
-
256
- let _pos = (pos === null || _fd.flags.append) ? _fd.pos : pos;
257
- let _buf = buf.slice(off, off+len);
258
- if (_pos > _fd.entry._size) {
259
- // TODO: handle huge jumps by zeroing clusters individually?
260
- const padLen = _pos - _fd.entry._size;
261
- const padBuf = _.allocBuffer(padLen + _buf.length);
262
- padBuf.fill(0x00, 0, padLen);
263
- _buf.copy(padBuf, padLen);
264
- _pos = _fd.entry._size;
265
- _buf = padBuf;
266
- }
267
- _fd.chain.writeToPosition(_pos, _buf, function(e) {
268
- _fd.pos = _pos + len;
269
- const newSize = Math.max(_fd.entry._size, _fd.pos);
270
- const newInfo = { size: newSize, _touch: true };
271
- fs._updateEntry(_fd.entry, newInfo, function(ee) {
272
- cb(e||ee, len, buf);
273
- });
274
- });
275
- }, (_n_ === "_nested_"));
276
- };
277
-
278
- fs.ftruncate = function(fd, len, cb, _n_) {
279
- cb = GROUP(cb, function() {
280
- const _fd = fileDescriptors[fd];
281
- if (!_fd || !_fd.flags.write) return _.delayedCall(cb, S.err.BADF());
282
-
283
- const newStats = { size: len, _touch: true };
284
- // NOTE: we order operations for best state in case of only partial success
285
- if (len === _fd.entry._size) _.delayedCall(cb);
286
- else if (len < _fd.entry._size) {
287
- fs._updateEntry(_fd.entry, newStats, function(e) {
288
- if (e) cb(e);
289
- else _fd.chain.truncate(Math.ceil(len / _fd.chain.sectorSize), cb);
290
- });
291
- } // TODO: handle huge file expansions without as much memory pressure
292
- else {
293
- _fd.chain.writeToPosition(_fd.entry._size, _.allocBuffer(len-_fd.entry._size, 0x00), function(e) {
294
- if (e) cb(e);
295
- else fs._updateEntry(_fd.entry, newStats, cb);
296
- });
297
- }
298
- }, (_n_ === "_nested_"));
299
- };
300
-
301
- // 'NORMAL', 'SEQUENTIAL', 'RANDOM', 'WILLNEED', 'DONTNEED', 'NOREUSE'
302
- fs._fadviseSync = function(fd, off, len, advice) {
303
- if (off !== 0 || len !== 0) throw Error("Cache advise can currently be given only for whole file!");
304
- const _fd = fileDescriptors[fd];
305
- if (!_fd) throw S.err.BADF();
306
- else _fd.chain.cacheAdvice = advice;
307
- };
308
-
309
- fs.fsync = function(fd, cb) {
310
- // NOTE: we'll need to flush write cache here once we have one…
311
- const _fd = fileDescriptors[fd];
312
- if (!_fd) _.delayedCall(cb, S.err.BADF());
313
- else _.delayedCall(cb);
314
- };
315
-
316
- fs.close = function(fd, cb) {
317
- const _fd = fileDescriptors[fd];
318
- if (!_fd) _.delayedCall(cb, S.err.BADF());
319
- else setTimeout(_fd.info.release.bind(_fd.info), 500), _.delayedCall(cb, fileDescriptors[fd] = null);
320
- };
321
-
322
-
323
- /* STREAM WRAPPERS */
324
-
325
- let workaroundTessel436;
326
- try {
327
- new require("stream").Readable({ encoding: "utf8" });
328
- new streams.Readable({ encoding: "utf8" });
329
- } catch (e) {
330
- workaroundTessel436 = true;
331
- }
332
-
333
- function _createStream(StreamType, path, opts) {
334
- // [NOT REALLY A] WORKAROUND: https://github.com/tessel/beta/issues/436
335
- if (workaroundTessel436 && "encoding" in opts) {
336
- console.warn("Tessel does not currently support encoding option for Readable streams, discarding!");
337
- delete opts.encoding;
338
- }
339
-
340
- let fd = (opts.fd !== null) ? opts.fd : "_opening_";
341
- let pos = opts.start;
342
- const stream = new StreamType(opts);
343
-
344
- if (fd === "_opening_") {
345
- fs.open(path, opts.flags, opts.mode, function(e, _fd) {
346
- if (e) {
347
- fd = "_open_error_";
348
- stream.emit("error", e);
349
- } else {
350
- fd = _fd;
351
- fs._fadviseSync(fd, 0, 0, "SEQUENTIAL");
352
- stream.emit("open", fd);
353
- }
354
- });
355
- }
356
-
357
- function autoClose(tombstone) { // NOTE: assumes caller will clear `fd`
358
- if (opts.autoClose) {
359
- fs.close(fd, function(e) {
360
- if (e) stream.emit("error", e);
361
- else stream.emit("close");
362
- });
363
- }
364
- fd = tombstone;
365
- }
366
-
367
- if (StreamType === streams.Readable) {
368
- stream._read = function(n) {
369
- let buf;
370
- // TODO: optimize to fetch at least a full sector regardless of `n`…
371
- n = Math.min(n, opts.end-pos);
372
- if (fd === "_opening_") {
373
- stream.once("open", function() {
374
- stream._read(n);
375
- });
376
- } else if (pos > opts.end) stream.push(null);
377
- else if (n > 0) {
378
- buf = _.allocBuffer(n), fs.read(fd, buf, 0, n, pos, function(e, n, d) {
379
- if (e) {
380
- autoClose("_read_error_");
381
- stream.emit("error", e);
382
- } else stream.push((n) ? d.slice(0, n) : null);
383
- }), pos += n;
384
- } else stream.push(null);
385
- };
386
-
387
- stream.once("end", function() {
388
- autoClose("_ended_");
389
- });
390
- } else if (StreamType === streams.Writable) {
391
- stream.bytesWritten = 0;
392
-
393
- stream._write = function(data, _enc, cb) {
394
- if (fd === "_opening_") {
395
- stream.once("open", function() {
396
- stream._write(data, null, cb);
397
- });
398
- } else {
399
- fs.write(fd, data, 0, data.length, pos, function(e, n) {
400
- if (e) {
401
- autoClose("_write_error_");
402
- cb(e);
403
- } else {
404
- stream.bytesWritten += n;
405
- cb();
406
- }
407
- }), pos += data.length;
408
- }
409
- };
410
-
411
- stream.once("finish", function() {
412
- autoClose("_finished_");
413
- });
414
- }
415
-
416
- return stream;
417
- }
418
-
419
- fs.createReadStream = function(path, opts) {
420
- return _createStream(streams.Readable, path, _.extend({
421
- start: 0,
422
- end: Infinity,
423
- flags: "r",
424
- mode: 0o666,
425
- encoding: null,
426
- fd: null, // ??? see https://github.com/joyent/node/issues/7708
427
- autoClose: true,
428
- }, opts));
429
- };
430
-
431
- fs.createWriteStream = function(path, opts) {
432
- return _createStream(streams.Writable, path, _.extend({
433
- start: 0,
434
- flags: "w",
435
- mode: 0o666,
436
- // encoding: null, // see https://github.com/joyent/node/issues/7710
437
- fd: null, // ??? see https://github.com/joyent/node/issues/7708
438
- autoClose: true,
439
- }, opts, { decodeStrings: true, objectMode: false }));
440
- };
441
-
442
-
443
- /* PATH WRAPPERS (albeit the only public interface for some folder operations) */
444
-
445
- function _fdOperation(path, opts, fn, cb) {
446
- cb = GROUP(cb, function() {
447
- opts.advice || (opts.advice = "NORMAL");
448
- fs.open(path, opts.flag, function(e, fd) {
449
- if (e) cb(e);
450
- else {
451
- fs._fadviseSync(fd, 0, 0, opts.advice), fn(fd, function() {
452
- const ctx = this; const args = arguments;
453
- fs.close(fd, function(closeErr) {
454
- cb.apply(ctx, args);
455
- }, "_nested_");
456
- });
457
- }
458
- }, "_nested_");
459
- });
460
- }
461
-
462
- fs.stat = fs.lstat = function(path, cb) {
463
- _fdOperation(path, { flag: "r" }, function(fd, cb) {
464
- fs.fstat(fd, cb, "_nested_");
465
- }, cb);
466
- };
467
-
468
- fs.exists = function(path, cb) {
469
- fs.stat(path, function(err) {
470
- cb(err ? false : true);
471
- });
472
- };
473
-
474
- fs.readFile = function(path, opts, cb) {
475
- if (typeof opts === "function") {
476
- cb = opts;
477
- opts = {};
478
- }
479
- opts.flag || (opts.flag = "r");
480
- opts.advice || (opts.advice = "NOREUSE");
481
- _fdOperation(path, opts, function(fd, cb) {
482
- fs.fstat(fd, function(e, stat) {
483
- if (e) return cb(e);
484
- else {
485
- const buffer = _.allocBuffer(stat.size);
486
- fs.read(fd, buffer, 0, buffer.length, null, function(e) {
487
- if (e) cb(e);
488
- else cb(null, (opts.encoding) ? buffer.toString(opts.encoding) : buffer);
489
- }, "_nested_");
490
- }
491
- }, "_nested_");
492
- }, cb);
493
- };
494
-
495
- fs.writeFile = function(path, data, opts, cb) {
496
- if (typeof opts === "function") {
497
- cb = opts;
498
- opts = {};
499
- }
500
- opts.flag || (opts.flag = "w");
501
- opts.advice || (opts.advice = "NOREUSE");
502
- _fdOperation(path, opts, function(fd, cb) {
503
- if (typeof data === "string") data = _.bufferFrom(data, opts.encoding || "utf8");
504
- fs.write(fd, data, 0, data.length, null, function(e) {
505
- cb(e);
506
- }, "_nested_");
507
- }, cb);
508
- };
509
-
510
- fs.appendFile = function(path, data, opts, cb) {
511
- if (typeof opts === "function") {
512
- cb = opts;
513
- opts = {};
514
- }
515
- opts.flag || (opts.flag = "a");
516
- fs.writeFile(path, data, opts, cb);
517
- };
518
-
519
- fs.truncate = function(path, len, cb) {
520
- _fdOperation(path, { flag: "r+" }, function(fd, cb) {
521
- fs.ftruncate(fd, len, cb, "_nested_");
522
- }, cb);
523
- };
524
-
525
- fs.readdir = function(path, cb) {
526
- _fdOperation(path, { flag: "\\r" }, function(fd, cb) {
527
- fs._readdir(fd, cb, "_nested_");
528
- }, cb);
529
- };
530
-
531
- fs.mkdir = function(path, mode, cb) {
532
- if (typeof mode === "function") {
533
- cb = mode;
534
- mode = 0o777;
535
- }
536
- _fdOperation(path, { flag: "\\wx" }, function(fd, cb) {
537
- fs._mkdir(fd, cb, "_nested_");
538
- }, cb);
539
- };
540
-
541
- fs.utimes = function(path, atime, mtime, cb) {
542
- _fdOperation(path, { flag: "r+" }, function(fd, cb) {
543
- fs.futimes(fd, atime, mtime, cb, "_nested_");
544
- }, cb);
545
- };
546
-
547
- fs.chmod = fs.lchmod = function(path, mode, cb) {
548
- _fdOperation(path, { flag: "\\r+" }, function(fd, cb) {
549
- fs.fchmod(fd, mode, cb, "_nested_");
550
- }, cb);
551
- };
552
-
553
- fs.chown = fs.lchown = function(path, uid, gid, cb) {
554
- _fdOperation(path, { flag: "\\r+" }, function(fd, cb) {
555
- fs.fchown(fd, uid, gid, cb, "_nested_");
556
- }, cb);
557
- };
558
-
559
-
560
- /* STUBS */
561
-
562
- fs.link = function(src, dst, cb) {
563
- // NOTE: theoretically we _could_ do hard links [with untracked `stat.nlink` count…]
564
- _.delayedCall(cb, S.err.NOSYS());
565
- };
566
-
567
- fs.symlink = function(src, dst, type, cb) {
568
- if (typeof type === "function") {
569
- cb = type;
570
- type = null;
571
- }
572
- _.delayedCall(cb, S.err.NOSYS());
573
- };
574
-
575
- fs.readlink = function(path, cb) {
576
- _fdOperation(path, { flag: "\\r" }, function(fd, cb) {
577
- // the named file is *never* a symbolic link…
578
- // NOTE: we still use _fdOperation for catching e.g. NOENT/NOTDIR errors…
579
- cb(S.err.INVAL());
580
- }, cb);
581
- };
582
-
583
- fs.realpath = function(path, cache, cb) {
584
- if (typeof cache === "function") {
585
- cb = cache;
586
- cache = null;
587
- }
588
- if (cache) _.delayedCall(cb, S.err.NOSYS()); // TODO: what would be involved here?
589
- else {
590
- _fdOperation(path, { flag: "\\r" }, function(fd, cb) {
591
- cb(null, _.absolutePath(path));
592
- }, cb);
593
- }
594
- };
595
-
596
- fs.fchown = function(fd, uid, gid, cb, _n_) {
597
- cb = GROUP(cb, function() {
598
- const _fd = fileDescriptors[fd];
599
- if (!_fd || !_fd.flags.write) _.delayedCall(cb, S.err.BADF());
600
- else _.delayedCall(cb, S.err.NOSYS());
601
- }, (_n_ === "_nested_"));
602
- };
603
-
604
-
605
- return fs;
606
- };