js-dos 8.1.4 → 8.1.6

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 (141) hide show
  1. package/README.md +1 -1
  2. package/dist/emulators/emulators.js +2 -0
  3. package/dist/emulators/emulators.js.map +1 -0
  4. package/dist/emulators/types/build.d.ts +28 -0
  5. package/dist/emulators/types/dos/bundle/dos-bundle.d.ts +20 -0
  6. package/dist/emulators/types/dos/dosbox/ts/direct.d.ts +3 -0
  7. package/dist/emulators/types/dos/dosbox/ts/worker.d.ts +3 -0
  8. package/dist/emulators/types/emulators.d.ts +76 -0
  9. package/dist/emulators/types/http.d.ts +9 -0
  10. package/dist/emulators/types/impl/ci-impl.d.ts +29 -0
  11. package/dist/emulators/types/impl/emulators-impl.d.ts +26 -0
  12. package/dist/emulators/types/impl/modules.d.ts +38 -0
  13. package/dist/emulators/types/libzip/libzip.d.ts +16 -0
  14. package/dist/emulators/types/protocol/messages-queue.d.ts +8 -0
  15. package/dist/emulators/types/protocol/protocol.d.ts +128 -0
  16. package/dist/emulators/wdosbox-x.js +55 -0
  17. package/dist/emulators/wdosbox-x.js.symbols +8760 -0
  18. package/dist/emulators/wdosbox-x.wasm +0 -0
  19. package/dist/emulators/wdosbox.js +55 -0
  20. package/dist/emulators/wdosbox.js.symbols +3001 -0
  21. package/dist/emulators/wdosbox.wasm +0 -0
  22. package/dist/emulators/wlibzip.js +21 -0
  23. package/dist/emulators/wlibzip.js.symbols +268 -0
  24. package/dist/emulators/wlibzip.wasm +0 -0
  25. package/dist/js-dos.css +1 -0
  26. package/dist/js-dos.js +22 -0
  27. package/dist/js-dos.js.map +1 -0
  28. package/package.json +1 -1
  29. package/release.zip +0 -0
  30. package/.eslintrc.json +0 -43
  31. package/.github/workflows/build.yml +0 -51
  32. package/.gitmodules +0 -4
  33. package/index.html +0 -110
  34. package/postcss.config.cjs +0 -8
  35. package/src/app.css +0 -14
  36. package/src/base.css +0 -10
  37. package/src/components/checkbox.tsx +0 -41
  38. package/src/components/close-button.tsx +0 -17
  39. package/src/components/components.css +0 -28
  40. package/src/components/dos-option-checkbox.tsx +0 -94
  41. package/src/components/dos-option-select.tsx +0 -108
  42. package/src/components/dos-option-slider.tsx +0 -35
  43. package/src/components/error.tsx +0 -16
  44. package/src/components/loading.tsx +0 -26
  45. package/src/components/lock.tsx +0 -10
  46. package/src/components/select.tsx +0 -33
  47. package/src/components/slider.tsx +0 -69
  48. package/src/download-file.ts +0 -18
  49. package/src/frame/account-frame.tsx +0 -156
  50. package/src/frame/editor/defaults.ts +0 -419
  51. package/src/frame/editor/editor-conf-frame.tsx +0 -227
  52. package/src/frame/editor/editor-frame.css +0 -55
  53. package/src/frame/editor/editor-fs-frame.tsx +0 -314
  54. package/src/frame/fat-drives-frame.tsx +0 -199
  55. package/src/frame/frame.css +0 -119
  56. package/src/frame/frame.tsx +0 -34
  57. package/src/frame/image-rendering-frame.tsx +0 -8
  58. package/src/frame/network-frame.tsx +0 -157
  59. package/src/frame/quick-save-frame.tsx +0 -98
  60. package/src/frame/settings-frame.tsx +0 -14
  61. package/src/frame/stats-frame.tsx +0 -87
  62. package/src/host/bundle-storage.ts +0 -91
  63. package/src/host/fullscreen.ts +0 -35
  64. package/src/host/lcache.ts +0 -203
  65. package/src/host/lstorage.ts +0 -156
  66. package/src/i18n.ts +0 -185
  67. package/src/index.css +0 -7
  68. package/src/load.ts +0 -132
  69. package/src/login/login.css +0 -9
  70. package/src/login/login.tsx +0 -77
  71. package/src/main.tsx +0 -197
  72. package/src/public/types.ts +0 -45
  73. package/src/sidebar/account-button.tsx +0 -33
  74. package/src/sidebar/cloud-save-button.tsx +0 -89
  75. package/src/sidebar/diskette-icon.tsx +0 -14
  76. package/src/sidebar/fullscreen-button.tsx +0 -44
  77. package/src/sidebar/network-button.tsx +0 -39
  78. package/src/sidebar/sidebar-button.tsx +0 -244
  79. package/src/sidebar/sidebar.css +0 -47
  80. package/src/sidebar/sidebar.tsx +0 -30
  81. package/src/sockdrive/LICENSE +0 -674
  82. package/src/sockdrive/README.md +0 -45
  83. package/src/sockdrive/include/sockdrive.h +0 -23
  84. package/src/sockdrive/js/.eslintrc.json +0 -43
  85. package/src/sockdrive/js/package.json +0 -29
  86. package/src/sockdrive/js/src/fatfs/chains.js +0 -318
  87. package/src/sockdrive/js/src/fatfs/dir.js +0 -385
  88. package/src/sockdrive/js/src/fatfs/helpers.js +0 -210
  89. package/src/sockdrive/js/src/fatfs/index.js +0 -606
  90. package/src/sockdrive/js/src/fatfs/structs.js +0 -255
  91. package/src/sockdrive/js/src/fatfs/vol.js +0 -166
  92. package/src/sockdrive/js/src/sockdrive/cache.ts +0 -56
  93. package/src/sockdrive/js/src/sockdrive/drive.ts +0 -471
  94. package/src/sockdrive/js/src/sockdrive/lru.ts +0 -221
  95. package/src/sockdrive/js/src/sockdrive/types.ts +0 -14
  96. package/src/sockdrive/js/src/sockdrive-fat.d.ts +0 -64
  97. package/src/sockdrive/js/src/sockdrive-fat.ts +0 -226
  98. package/src/sockdrive/js/src/sockdrive-native.ts +0 -100
  99. package/src/sockdrive/js/src/test/test.ts +0 -289
  100. package/src/sockdrive/js/tsconfig.json +0 -11
  101. package/src/sockdrive/js/webpack.config.js +0 -68
  102. package/src/sockdrive/js/yarn.lock +0 -1808
  103. package/src/store/auth.ts +0 -115
  104. package/src/store/dos.ts +0 -305
  105. package/src/store/editor.ts +0 -61
  106. package/src/store/init.ts +0 -48
  107. package/src/store/storage.ts +0 -32
  108. package/src/store/ui.ts +0 -191
  109. package/src/store.tsx +0 -116
  110. package/src/ui.tsx +0 -140
  111. package/src/v8/changes.ts +0 -56
  112. package/src/v8/config.ts +0 -20
  113. package/src/v8/subscriptions.ts +0 -62
  114. package/src/vite-env.d.ts +0 -5
  115. package/src/window/dos/controls/keyboard.ts +0 -32
  116. package/src/window/dos/controls/keys.ts +0 -331
  117. package/src/window/dos/controls/mouse/mount.ts +0 -99
  118. package/src/window/dos/controls/mouse/mouse-locked.ts +0 -51
  119. package/src/window/dos/controls/mouse/mouse-not-locked.ts +0 -84
  120. package/src/window/dos/controls/mouse/mouse-swipe.ts +0 -57
  121. package/src/window/dos/controls/mouse/pointer.ts +0 -85
  122. package/src/window/dos/controls/mouse.ts +0 -21
  123. package/src/window/dos/dos-dhry2.tsx +0 -191
  124. package/src/window/dos/dos-runtime.tsx +0 -216
  125. package/src/window/dos/dos-window.tsx +0 -91
  126. package/src/window/dos/render/canvas.ts +0 -65
  127. package/src/window/dos/render/resize.ts +0 -31
  128. package/src/window/dos/render/webgl.ts +0 -173
  129. package/src/window/dos/sound/audio-node.ts +0 -148
  130. package/src/window/error-window.tsx +0 -9
  131. package/src/window/loading-window.tsx +0 -54
  132. package/src/window/prerun-window.tsx +0 -121
  133. package/src/window/select-window.tsx +0 -118
  134. package/src/window/window.css +0 -78
  135. package/src/window/window.tsx +0 -49
  136. package/src/ws/ws-sockdrive.ts +0 -123
  137. package/src/ws/ws-transport-layer.ts +0 -468
  138. package/tailwind.config.cjs +0 -48
  139. package/tsconfig.json +0 -32
  140. package/tsconfig.node.json +0 -9
  141. package/vite.config.ts +0 -25
@@ -1,385 +0,0 @@
1
- const S = require("./structs.js");
2
- const _ = require("./helpers.js");
3
-
4
- const dir = exports;
5
-
6
- dir.iterator = function(dirChain, opts) {
7
- opts || (opts = {});
8
-
9
- const cache = { buffer: null, n: null };
10
- function getSectorBuffer(n, cb) {
11
- if (cache.n === n) cb(null, cache.buffer);
12
- else {
13
- cache.n = cache.buffer = null, dirChain.readSectors(n, _.allocBuffer(dirChain.sectorSize), function(e, d) {
14
- if (e) cb(e);
15
- else if (!d) return cb(null, null);
16
- else {
17
- cache.n = n;
18
- cache.buffer = d;
19
- getSectorBuffer(n, cb);
20
- }
21
- });
22
- }
23
- }
24
-
25
- let secIdx = 0;
26
- const off = { bytes: 0 };
27
- let long = null;
28
- function getNextEntry(cb) {
29
- if (off.bytes >= dirChain.sectorSize) {
30
- secIdx += 1;
31
- off.bytes -= dirChain.sectorSize;
32
- }
33
- const entryPos = { chain: dirChain, sector: secIdx, offset: off.bytes };
34
- getSectorBuffer(secIdx, function(e, buf) {
35
- if (e) return cb(S.err.IO());
36
- else if (!buf) return cb(null, null, entryPos);
37
-
38
- const entryIdx = off.bytes;
39
- const signalByte = buf[entryIdx];
40
- if (signalByte === S.entryDoneFlag) return cb(null, null, entryPos);
41
- else if (signalByte === S.entryFreeFlag) {
42
- off.bytes += S.dirEntry.size;
43
- long = null;
44
- if (opts.includeFree) return cb(null, { _free: true, _pos: entryPos }, entryPos);
45
- else return getNextEntry(cb); // usually just skip these
46
- }
47
-
48
- const attrByte = buf[entryIdx+S.dirEntry.fields.Attr.offset];
49
- const entryType = (attrByte === S.longDirFlag) ? S.longDirEntry : S.dirEntry_simple;
50
- const entry = entryType.valueFromBytes(buf, off);
51
- entry._pos = entryPos;
52
- _.log(_.log.DBG, "entry:", entry, secIdx, entryIdx);
53
- if (entryType === S.longDirEntry) {
54
- let firstEntry;
55
- if (entry.Ord & S.lastLongFlag) {
56
- firstEntry = true;
57
- entry.Ord &= ~S.lastLongFlag;
58
- long = {
59
- name: -1,
60
- sum: entry.Chksum,
61
- _rem: entry.Ord-1,
62
- _arr: [],
63
- };
64
- }
65
- if (firstEntry || long && entry.Chksum === long.sum && entry.Ord === long._rem--) {
66
- const S_lde_f = S.longDirEntry.fields;
67
- let namepart = entry.Name1;
68
- if (entry.Name1.length === S_lde_f.Name1.size/2) {
69
- namepart += entry.Name2;
70
- if (entry.Name2.length === S_lde_f.Name2.size/2) {
71
- namepart += entry.Name3;
72
- }
73
- }
74
- long._arr.push(namepart);
75
- if (!long._rem) {
76
- long.name = long._arr.reverse().join("");
77
- delete long._arr;
78
- delete long._rem;
79
- }
80
- } else long = null;
81
- } else if ((attrByte & 0x08) === 0) { // NOTE: checks `!entry.Attr.volume_id`
82
- let bestName = null;
83
- if (long && long.name) {
84
- const pos = entryIdx + S.dirEntry.fields["Name"].offset;
85
- const sum = _.checksumName(buf, pos);
86
- if (sum === long.sum) bestName = long.name;
87
- }
88
- if (!bestName) {
89
- if (signalByte === S.entryIsE5Flag) entry.Name.filename = "\u00E5"+entry.Name.filename.slice(1);
90
-
91
- const nam = entry.Name.filename.replace(/ +$/, "");
92
- const ext = entry.Name.extension.replace(/ +$/, "");
93
- // TODO: lowercase bits http://en.wikipedia.org/wiki/8.3_filename#Compatibility
94
- // via NTRes, bits 0x08 and 0x10 http://www.fdos.org/kernel/fatplus.txt.1
95
- bestName = (ext) ? nam+"."+ext : nam;
96
- }
97
- entry._name = bestName;
98
-
99
- // OPTIMIZATION: avoid processing any fields for non-matching entries
100
- // TODO: we could make this automatic via getters, but…?
101
- const _entryBuffer = buf.slice(off.bytes-S.dirEntry.size, off.bytes);
102
- entry._full = function() {
103
- const _entry = S.dirEntry.valueFromBytes(_entryBuffer);
104
- _.extend(entry, _entry);
105
- entry._size = entry.FileSize;
106
- entry._firstCluster = (entry.FstClusHI << 16) + entry.FstClusLO;
107
- return entry;
108
- };
109
-
110
- long = null;
111
- return cb(null, entry, entryPos);
112
- } else long = null;
113
- getNextEntry(cb);
114
- });
115
- }
116
-
117
- function iter(cb) {
118
- getNextEntry(cb);
119
- return iter; // TODO: previous value can't be re-used, so why make caller re-assign?
120
- }
121
- return iter;
122
- };
123
-
124
- function _updateEntry(vol, entry, newStats) {
125
- if ("size" in newStats) entry._size = entry.FileSize = newStats.size;
126
-
127
- if ("_touch" in newStats) newStats.archive = newStats.atime = newStats.mtime = true;
128
- if ("archive" in newStats) entry.Attr.archive = true; // TODO: also via newStats.mode?
129
-
130
- let _now;
131
- function applyDate(d, prefix, timeToo, tenthToo) {
132
- if (d === true) d = _now || (_now = new Date());
133
- entry[prefix+"Date"] = { year: d.getFullYear()-1980, month: d.getMonth()+1, day: d.getDate() };
134
- if (timeToo) {
135
- entry[prefix+"Time"] = { hours: d.getHours(), minutes: d.getMinutes(), seconds_2: d.getSeconds()>>>1 };
136
- if (tenthToo) {
137
- const msec = (d.getSeconds() % 2)*1000 + d.getMilliseconds();
138
- entry[prefix+"TimeTenth"] = Math.floor(msec / 100);
139
- }
140
- }
141
- }
142
- if ("ctime" in newStats) applyDate(newStats.ctime, "Crt", true, true);
143
- if ("mtime" in newStats) applyDate(newStats.mtime, "Wrt", true);
144
- if ("atime" in newStats) applyDate(newStats.atime, "LstAcc");
145
-
146
- if ("mode" in newStats) {
147
- entry.Attr.directory = (newStats.mode & S._I.FDIR) ? true : false;
148
- entry.Attr.volume_id = (newStats.mode & S._I.FREG) ? false : true;
149
- if (vol.opts.modmode === 0o111) {
150
- entry.Attr.archive = (newStats.mode & S._I.XUSR) ? true : false;
151
- entry.Attr.system = (newStats.mode & S._I.XGRP) ? true : false;
152
- entry.Attr.hidden = (newStats.mode & S._I.XOTH) ? true : false;
153
- entry.Attr.readonly = (newStats.mode & S._I.WUSR) ? false : true;
154
- } else if (vol.opts.modmode === 0o7000) {
155
- entry.Attr.archive = (newStats.mode & S._I.SVTX) ? true : false;
156
- entry.Attr.system = (newStats.mode & S._I.SGID) ? true : false;
157
- entry.Attr.hidden = (newStats.mode & S._I.SUID) ? true : false;
158
- entry.Attr.readonly = (
159
- newStats.mode & S._I.WUSR ||
160
- newStats.mode & S._I.WGRP ||
161
- newStats.mode & S._I.WOTH
162
- ) ? false : true;
163
- }
164
- }
165
-
166
- if ("firstCluster" in newStats) {
167
- entry.FstClusLO = newStats.firstCluster & 0xFFFF;
168
- entry.FstClusHI = newStats.firstCluster >>> 16;
169
- entry._firstCluster = newStats.firstCluster;
170
- }
171
- return entry;
172
- }
173
-
174
- dir.makeStat = function(vol, entry) {
175
- const stats = {}; // TODO: return an actual `instanceof fs.Stat` somehow?
176
-
177
- stats.isFile = function() {
178
- return (!entry.Attr.volume_id && !entry.Attr.directory);
179
- };
180
- stats.isDirectory = function() {
181
- return entry.Attr.directory;
182
- };
183
- stats.isBlockDevice = function() {
184
- return false;
185
- };
186
- stats.isCharacterDevice = function() {
187
- return false;
188
- };
189
- stats.isSymbolicLink = function() {
190
- return false;
191
- };
192
- stats.isFIFO = function() {
193
- return false;
194
- };
195
- stats.isSocket = function() {
196
- return false;
197
- };
198
- stats.size = entry.FileSize;
199
- stats.blksize = vol._sectorsPerCluster*vol._sectorSize;
200
- stats.blocks = Math.ceil(stats.size / stats.blksize) || 1;
201
- stats.nlink = 1;
202
-
203
- stats.mode = S._I.RUSR | S._I.RGRP | S._I.ROTH;
204
- if (!entry.Attr.readonly) stats.mode |= S._I.WUSR | S._I.WGRP | S._I.WOTH;
205
- if (entry.Attr.directory) stats.mode |= S._I.FDIR;
206
- else if (!entry.Attr.volume_id) stats.mode |= S._I.FREG;
207
- // NOTE: discussion at https://github.com/natevw/fatfs/issues/7
208
- if (vol.opts.modmode === 0o111) {
209
- // expose using executable bits, like Samba
210
- if (entry.Attr.archive) stats.mode |= S._I.XUSR;
211
- if (entry.Attr.system) stats.mode |= S._I.XGRP;
212
- if (entry.Attr.hidden) stats.mode |= S._I.XOTH;
213
- } else if (vol.opts.modmode === 0o7000) {
214
- // expose using setXid/sticky bits, like MKS
215
- if (entry.Attr.archive) stats.mode |= S._I.SVTX;
216
- if (entry.Attr.system) stats.mode |= S._I.SGID;
217
- if (entry.Attr.hidden) stats.mode |= S._I.SUID;
218
- }
219
-
220
- stats.mode &= ~vol.opts.umask;
221
- stats.uid = vol.opts.uid;
222
- stats.gid = vol.opts.gid;
223
-
224
- function extractDate(prefix) {
225
- const date = entry[prefix+"Date"];
226
- const time = entry[prefix+"Time"] || { hours: 0, minutes: 0, seconds_2: 0 };
227
- let secs = time.seconds_2 * 2;
228
- let sect = entry[prefix+"TimeTenth"] || 0;
229
- if (sect > 100) {
230
- secs += 1;
231
- sect -= 100;
232
- }
233
- return new Date(date.year+1980, date.month-1, date.day, time.hours, time.minutes, secs, sect*100);
234
- }
235
- stats.atime = extractDate("LstAcc");
236
- stats.mtime = extractDate("Wrt");
237
- stats.ctime = extractDate("Crt");
238
-
239
- entry = { // keep immutable copy (with only the fields we need)
240
- Attr: _.extend({}, entry.Attr),
241
- };
242
-
243
- return stats;
244
- };
245
-
246
- dir.init = function(vol, dirInfo, cb) {
247
- const dirChain = dirInfo.chain;
248
- const isRootDir = ("numSectors" in dirChain); // HACK: all others would be a clusterChain
249
- const initialCluster = _.allocBuffer(dirChain.sectorSize*vol._sectorsPerCluster);
250
- const entriesOffset = { bytes: 0 };
251
- initialCluster.fill(0);
252
- function writeEntry(name, clusterNum) {
253
- while (name.length < 8) name += " ";
254
- S.dirEntry.bytesFromValue(_updateEntry(vol, {
255
- Name: { filename: name, extension: " " },
256
- Attr: { directory: true },
257
- }, { firstCluster: clusterNum, _touch: true, ctime: true }), initialCluster, entriesOffset);
258
- }
259
- if (!isRootDir) {
260
- writeEntry(".", dirChain.firstCluster);
261
- writeEntry("..", dirInfo.parent.chain.firstCluster);
262
- };
263
- dirChain.writeToPosition(0, initialCluster, cb);
264
- };
265
-
266
- dir.addFile = function(vol, dirChain, entryInfo, opts, cb) {
267
- if (typeof opts === "function") {
268
- cb = opts;
269
- opts = {};
270
- }
271
- var name = entryInfo.name;
272
- const entries = []; let mainEntry;
273
- entries.push(mainEntry = {
274
- Name: _.shortname(name),
275
- Attr: { directory: opts.dir||false },
276
- _name: name,
277
- });
278
- if (1 || mainEntry.Name._lossy) { // HACK: always write long names until `._lossy` is more useful!
279
- const workaroundTessel427 = ("\uFFFF".length !== 1);
280
- if (workaroundTessel427) throw Error("Your JS runtime does not have proper Unicode string support. (If Tessel, is your firmware up-to-date?)");
281
-
282
- // name entries should be 0x0000-terminated and 0xFFFF-filled
283
- const S_lde_f = S.longDirEntry.fields;
284
- const ENTRY_CHUNK_LEN = (S_lde_f.Name1.size + S_lde_f.Name2.size + S_lde_f.Name3.size)/2;
285
- const partialLen = name.length % ENTRY_CHUNK_LEN;
286
- let paddingNeeded = partialLen && (ENTRY_CHUNK_LEN - partialLen);
287
- if (paddingNeeded--) name += "\u0000";
288
- while (paddingNeeded-- > 0) name += "\uFFFF";
289
- // now fill in as many entries as it takes
290
- let off = 0;
291
- let ord = 1;
292
- while (off < name.length) {
293
- entries.push({
294
- Ord: ord++,
295
- Name1: name.slice(off, off+=S_lde_f.Name1.size/2),
296
- Attr_raw: S.longDirFlag,
297
- Chksum: null,
298
- Name2: name.slice(off, off+=S_lde_f.Name2.size/2),
299
- Name3: name.slice(off, off+=S_lde_f.Name3.size/2),
300
- });
301
- }
302
- entries[entries.length - 1].Ord |= S.lastLongFlag;
303
- }
304
-
305
- if (entryInfo.tail) {
306
- var name = mainEntry.Name.filename;
307
- const suffix = "~"+entryInfo.tail;
308
- const endIdx = name.indexOf(" ");
309
- const sufIdx = (~endIdx) ? Math.min(endIdx, name.length-suffix.length) : name.length-suffix.length;
310
- if (sufIdx < 0) return cb(S.err.NAMETOOLONG()); // TODO: would EXIST be more correct?
311
- mainEntry.Name.filename = name.slice(0, sufIdx)+suffix+name.slice(sufIdx+suffix.length);
312
- _.log(_.log.DBG, "Shortname amended to:", mainEntry.Name);
313
- }
314
-
315
- vol.allocateInFAT(dirChain.firstCluster || 2, function(e, fileCluster) {
316
- if (e) return cb(e);
317
-
318
- const nameBuf = S.dirEntry.fields["Name"].bytesFromValue(mainEntry.Name);
319
- const nameSum = _.checksumName(nameBuf);
320
- // TODO: finalize initial properties… (via `opts.mode` instead?)
321
- _updateEntry(vol, mainEntry, { firstCluster: fileCluster, size: 0, ctime: true, _touch: true });
322
- mainEntry._pos = _.adjustedPos(vol, entryInfo.target, S.dirEntry.size*(entries.length-1));
323
- entries.slice(1).forEach(function(entry) {
324
- entry.Chksum = nameSum;
325
- });
326
- entries.reverse();
327
- if (entryInfo.lastEntry) entries.push({});
328
-
329
- const entriesData = _.allocBuffer(S.dirEntry.size*entries.length);
330
- const dataOffset = { bytes: 0 };
331
- entries.forEach(function(entry) {
332
- const entryType = ("Ord" in entry) ? S.longDirEntry : S.dirEntry;
333
- entryType.bytesFromValue(entry, entriesData, dataOffset);
334
- });
335
-
336
- _.log(_.log.DBG, "Writing", entriesData.length, "byte directory entry", mainEntry, "into", dirChain.toJSON(), "at", entryInfo.target);
337
- dirChain.writeToPosition(entryInfo.target, entriesData, function(e) {
338
- // TODO: if we get error, what/should we clean up?
339
- if (e) cb(e);
340
- else cb(null, mainEntry, vol.chainForCluster(fileCluster, dirChain));
341
- });
342
- });
343
- };
344
-
345
- dir.findInDirectory = function(vol, dirChain, name, opts, cb) {
346
- const matchName = name.toUpperCase();
347
- const tailName = (opts.prepareForCreate) ? _.shortname(name) : null;
348
- let maxTail = 0;
349
-
350
- function processNext(next) {
351
- next = next(function(e, d, entryPos) {
352
- if (e) cb(e);
353
- else if (!d) cb(S.err.NOENT(), { tail: maxTail, target: entryPos, lastEntry: true });
354
- else if (d._free) processNext(next); // TODO: look for long enough reusable run
355
- else if (d._name.toUpperCase() === matchName) return cb(null, d._full());
356
- else if (!opts.prepareForCreate) processNext(next);
357
- else {
358
- let dNum = 1;
359
- let dName = d.Name.filename;
360
- const dTail = dName.match(/(.*)~(\d+)/);
361
- if (dTail) {
362
- dNum = +dTail[2];
363
- dName = dTail[1];
364
- }
365
- if (tailName.extension === d.Name.extension &&
366
- tailName.filename.indexOf(dName) === 0) {
367
- maxTail = Math.max(dNum+1, maxTail);
368
- }
369
- processNext(next);
370
- }
371
- });
372
- }
373
- processNext(dir.iterator(dirChain, { includeFree: (0 && opts.prepareForCreate) }));
374
- };
375
-
376
- dir.updateEntry = function(vol, entry, newStats, cb) {
377
- if (!entry._pos || !entry._pos.chain) throw Error("Entry source unknown!");
378
-
379
- const entryPos = entry._pos;
380
- const newEntry = _updateEntry(vol, entry, newStats);
381
- const data = S.dirEntry.bytesFromValue(newEntry);
382
- _.log(_.log.DBG, "UPDATING ENTRY", newStats, newEntry, entryPos, data);
383
- // TODO: if write fails, then entry becomes corrupt!
384
- entryPos.chain.writeToPosition(entryPos, data, cb);
385
- };
@@ -1,210 +0,0 @@
1
- const S = require("./structs.js");
2
- const _xok = require("xok");
3
-
4
- // ponyfills for older node.js
5
- exports.allocBuffer = Buffer.alloc || function(len, val) {
6
- const b = Buffer(len);
7
- if (arguments.length > 1) b.fill(val);
8
- return b;
9
- };
10
- exports.bufferFrom = Buffer.from || function(arg0, arg1) {
11
- return (arguments.length > 1) ? Buffer(arg0, arg1) : Buffer(arg0);
12
- };
13
-
14
- // flag for WORKAROUND: https://github.com/tessel/beta/issues/380
15
- exports.workaroundTessel380 = !Buffer.from && function() {
16
- const b = Buffer([0]);
17
- const s = b.slice(0);
18
- return ((s[0] = 0xFF) !== b[0]);
19
- }();
20
-
21
-
22
- // WORKAROUND: https://github.com/tessel/beta/issues/433
23
- let oldslice;
24
- if (!Buffer.alloc && Buffer(5).slice(10).length < 0) {
25
- oldslice = Buffer.prototype.slice, Buffer.prototype.slice = function(s, e) {
26
- if (s > this.length) s = this.length;
27
- // ~WORKAROUND: https://github.com/tessel/beta/issues/434
28
- return (arguments.length > 1) ? oldslice.call(this, s, e) : oldslice.call(this, s);
29
- };
30
- }
31
-
32
- exports.absoluteSteps = function(path) {
33
- const steps = [];
34
- path.split("/").forEach(function(str) {
35
- // NOTE: these should actually be fine, just wasteful…
36
- if (str === "..") steps.pop();
37
- else if (str && str !== ".") steps.push(str);
38
- });
39
- return steps.map(exports.longname);
40
- };
41
-
42
- exports.absolutePath = function(path) {
43
- return "/"+exports.absoluteSteps(path).join("/");
44
- };
45
-
46
- exports.parseFlags = function(flags) {
47
- // read, write, append, create, truncate, exclusive
48
- let info; let _dir; // NOTE: there might be more clever ways to "parse", but…
49
- if (flags[0] === "\\") {
50
- // internal flag used internally to `fs.open` directories without `S.err.ISDIR()`
51
- flags = flags.slice(1);
52
- _dir = true;
53
- }
54
- switch (flags) {
55
- case "r": info = { read: true, write: false, create: false }; break;
56
- case "r+": info = { read: true, write: true, create: false }; break;
57
- case "rs": info = { read: true, write: false, create: false, sync: true }; break;
58
- case "rs+": info = { read: true, write: true, create: false, sync: true }; break;
59
- case "w": info = { read: false, write: true, create: true, truncate: true }; break;
60
- case "wx": info = { read: false, write: true, create: true, exclusive: true }; break;
61
- case "w+": info = { read: true, write: true, create: true, truncate: true }; break;
62
- case "wx+": info = { read: true, write: true, create: true, exclusive: true }; break;
63
- case "a": info = { read: false, write: true, create: true, append: true }; break;
64
- case "ax": info = { read: false, write: true, create: true, append: true, exclusive: true }; break;
65
- case "a+": info = { read: true, write: true, create: true, append: true }; break;
66
- case "ax+": info = { read: true, write: true, create: true, append: true, exclusive: true }; break;
67
- default: throw Error("Uknown mode: "+flags); // TODO: throw as `S.err.INVAL`
68
- }
69
- if (info.sync) throw Error("Mode not implemented."); // TODO: what would this require of us?
70
- if (_dir) info._openDir = true;
71
- return info;
72
- };
73
-
74
-
75
- // TODO: these are great candidates for special test coverage!
76
- const _snInvalid = /[^A-Z0-9$%'-_@~`!(){}^#&.]/g; // NOTE: '.' is not valid but we split it away
77
- exports.shortname = function(name) {
78
- let lossy = false;
79
- // TODO: support preservation of case for otherwise non-lossy name!
80
- name = name.toUpperCase().replace(/ /g, "").replace(/^\.+/, "");
81
- name = name.replace(_snInvalid, function() {
82
- lossy = true;
83
- return "_";
84
- });
85
-
86
- const parts = name.split(".");
87
- let basis3 = parts.pop();
88
- let basis8 = parts.join("");
89
- if (!parts.length) {
90
- basis8 = basis3;
91
- basis3 = " ";
92
- }
93
- if (basis8.length > 8) {
94
- basis8 = basis8.slice(0, 8);
95
- // NOTE: technically, spec's "lossy conversion" flag is NOT set by excess length.
96
- // But since lossy conversion and truncated names both need a numeric tail…
97
- lossy = true;
98
- } else while (basis8.length < 8) basis8 += " ";
99
- if (basis3.length > 3) {
100
- basis3 = basis3.slice(0, 3);
101
- lossy = true;
102
- } else while (basis3.length < 3) basis3 += " ";
103
-
104
- return { filename: basis8, extension: basis3, _lossy: lossy };
105
- return { basis: [basis8, basis3], lossy: lossy };
106
- };
107
- // shortname("autoexec.bat") => {basis:['AUTOEXEC','BAT'],lossy:false}
108
- // shortname("autoexecutable.batch") => {basis:['AUTOEXEC','BAT'],lossy:true}
109
- // TODO: OS X stores `shortname("._.Trashes")` as ['~1', 'TRA'] — should we?
110
-
111
- const _lnInvalid = /[^a-zA-Z0-9$%'-_@~`!(){}^#&.+,;=[\] ]/g;
112
- exports.longname = function(name) {
113
- name = name.trim().replace(/\.+$/, "").replace(_lnInvalid, function(c) {
114
- if (c.length > 1) throw Error("Internal problem: unexpected match length!");
115
- if (c.charCodeAt(0) > 127) return c;
116
- else throw Error("Invalid character "+JSON.stringify(c)+" in name.");
117
- lossy = true;
118
- return "_";
119
- });
120
- if (name.length > 255) throw Error("Name is too long.");
121
- return name;
122
- };
123
-
124
- function nameChkSum(sum, c) {
125
- return ((sum & 1) ? 0x80 : 0) + (sum >>> 1) + c & 0xFF;
126
- }
127
-
128
- // WORKAROUND: https://github.com/tessel/beta/issues/335
129
- function reduceBuffer(buf, start, end, fn, res) {
130
- // NOTE: does not handle missing `res` like Array.prototype.reduce would
131
- for (let i = start; i < end; ++i) {
132
- res = fn(res, buf[i]);
133
- }
134
- return res;
135
- }
136
-
137
- exports.checksumName = function(buf, off) {
138
- off || (off = 0);
139
- const len = S.dirEntry.fields["Name"].size;
140
- return reduceBuffer(buf, off, off+len, nameChkSum, 0);
141
- };
142
-
143
-
144
- /* comparing C rounding trick from FAT spec with Math.ceil
145
- function tryBoth(d) {
146
- var a = ((D.RootEntCnt * 32) + (D.BytsPerSec - 1)) / D.BytsPerSec >>> 0,
147
- b = Math.ceil((D.RootEntCnt * 32) / D.BytsPerSec);
148
- if (b !== a) console.log("try", b, a, (b === a) ? '' : '*');
149
- return (b === a);
150
- }
151
- // BytsPerSec — "may take on only the following values: 512, 1024, 2048 or 4096"
152
- [512, 1024, 2048, 4096].forEach(function (bps) {
153
- // RootEntCnt — "a count that when multiplied by 32 results in an even multiple of BPB_BytsPerSec"
154
- for (var evenMultiplier = 0; evenMultiplier < 1024*1024*16; evenMultiplier += 2) {
155
- var rec = (bps * evenMultiplier) / 32;
156
- tryBoth({RootEntCnt:rec, BytsPerSec:bps});
157
- }
158
- });
159
- */
160
-
161
- exports.fmtHex = function(n, ff) {
162
- return (1+ff+n).toString(16).slice(1);
163
- };
164
-
165
- exports.delayedCall = function(fn) {
166
- if (!fn) throw Error("No function provided!"); // debug aid
167
- const ctx = this;
168
- const args = Array.prototype.slice.call(arguments, 1);
169
- // @caiiiycuk: TODO invesitgate, is setImmediate acually needed?
170
- // console.warn("setImmediate emulation, please remote it!");
171
- // setTimeout(function() {
172
- fn.apply(ctx, args);
173
- // }, 4);
174
- };
175
-
176
- exports.adjustedPos = function(vol, pos, bytes) {
177
- const _pos = {
178
- chain: pos.chain,
179
- sector: pos.sector,
180
- offset: pos.offset + bytes,
181
- }; const secSize = vol._sectorSize;
182
- while (_pos.offset >= secSize) {
183
- _pos.sector += 1;
184
- _pos.offset -= secSize;
185
- }
186
- return _pos;
187
- };
188
-
189
- exports.extend = _xok;
190
-
191
- let _prevDbg = Date.now();
192
- const _thresh = 50;
193
-
194
- function log(level) {
195
- if (level < log.level) return;
196
-
197
- const now = Date.now();
198
- const diff = now - _prevDbg;
199
- arguments[0] = ((diff < _thresh) ? " " : "") + diff.toFixed(0) + "ms";
200
- console.log.apply(console, arguments);
201
- _prevDbg = now;
202
- }
203
- log.DBG = -4;
204
- log.INFO = -3;
205
- log.WARN = -2;
206
- log.ERR = -1;
207
-
208
- log.level = log.WARN;
209
-
210
- exports.log = log;