FsaNodeFs.js 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.FsaNodeFs = void 0;
  4. const tslib_1 = require("tslib");
  5. const optHelpers = require("../node/options");
  6. const util = require("../node/util");
  7. const buffer_1 = require("../internal/buffer");
  8. const FsPromises_1 = require("../node/FsPromises");
  9. const util_1 = require("./util");
  10. const constants_1 = require("../node/constants");
  11. const encoding_1 = require("../encoding");
  12. const FsaNodeDirent_1 = require("./FsaNodeDirent");
  13. const constants_2 = require("../constants");
  14. const FsaNodeStats_1 = require("./FsaNodeStats");
  15. const queueMicrotask_1 = require("../queueMicrotask");
  16. const FsaNodeWriteStream_1 = require("./FsaNodeWriteStream");
  17. const FsaNodeReadStream_1 = require("./FsaNodeReadStream");
  18. const FsaNodeCore_1 = require("./FsaNodeCore");
  19. const FileHandle_1 = require("../node/FileHandle");
  20. const util_2 = require("../core/util");
  21. const notSupported = () => {
  22. throw new Error('Method not supported by the File System Access API.');
  23. };
  24. const notImplemented = () => {
  25. throw new Error('Not implemented');
  26. };
  27. const noop = () => { };
  28. /**
  29. * Constructs a Node.js `fs` API from a File System Access API
  30. * [`FileSystemDirectoryHandle` object](https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryHandle).
  31. */
  32. class FsaNodeFs extends FsaNodeCore_1.FsaNodeCore {
  33. constructor() {
  34. // ------------------------------------------------------------ FsPromisesApi
  35. super(...arguments);
  36. this.promises = new FsPromises_1.FsPromises(this, FileHandle_1.FileHandle);
  37. // ------------------------------------------------------------ FsCallbackApi
  38. this.open = (path, flags, a, b) => {
  39. let mode = a;
  40. let callback = b;
  41. if (typeof a === 'function') {
  42. mode = 438 /* MODE.DEFAULT */;
  43. callback = a;
  44. }
  45. mode = mode || 438 /* MODE.DEFAULT */;
  46. const modeNum = util.modeToNumber(mode);
  47. const filename = util.pathToFilename(path);
  48. const flagsNum = util.flagsToNumber(flags);
  49. this.__open(filename, flagsNum, modeNum).then(openFile => callback(null, openFile.fd), error => callback(error));
  50. };
  51. this.close = (fd, callback) => {
  52. (0, util_2.validateFd)(fd);
  53. this.__close(fd).then(() => callback(null), error => callback(error));
  54. };
  55. this.read = (fd, buffer, offset, length, position, callback) => {
  56. util.validateCallback(callback);
  57. // This `if` branch is from Node.js
  58. if (length === 0) {
  59. return (0, queueMicrotask_1.default)(() => {
  60. if (callback)
  61. callback(null, 0, buffer);
  62. });
  63. }
  64. (async () => {
  65. const openFile = await this.getFileByFd(fd, 'read');
  66. const file = await openFile.file.getFile();
  67. const src = await file.arrayBuffer();
  68. position = Number(position);
  69. length = Number(length);
  70. const slice = position > src.byteLength
  71. ? new Uint8Array(0)
  72. : new Uint8Array(src, position, Math.min(length, src.byteLength - position));
  73. const dest = new Uint8Array(buffer.buffer, buffer.byteOffset + offset, slice.length);
  74. dest.set(slice, 0);
  75. return slice.length;
  76. })().then(bytesWritten => callback(null, bytesWritten, buffer), error => callback(error));
  77. };
  78. this.readFile = (id, a, b) => {
  79. const [opts, callback] = optHelpers.optsAndCbGenerator(optHelpers.getReadFileOptions)(a, b);
  80. const flagsNum = util.flagsToNumber(opts.flag);
  81. (async () => {
  82. let fd = typeof id === 'number' ? id : -1;
  83. const originalFd = fd;
  84. try {
  85. if (fd === -1) {
  86. const filename = util.pathToFilename(id);
  87. fd = (await this.__open(filename, flagsNum, 0)).fd;
  88. }
  89. const handle = await this.__getFileById(fd, 'readFile');
  90. const file = await handle.getFile();
  91. const buffer = buffer_1.Buffer.from(await file.arrayBuffer());
  92. return util.bufferToEncoding(buffer, opts.encoding);
  93. }
  94. finally {
  95. try {
  96. const idWasFd = typeof originalFd === 'number' && originalFd >= 0;
  97. if (idWasFd)
  98. await this.__close(originalFd);
  99. }
  100. catch (_a) { }
  101. }
  102. })()
  103. .then(data => callback(null, data))
  104. .catch(error => callback(error));
  105. };
  106. this.write = (fd, a, b, c, d, e) => {
  107. const [, asStr, buf, offset, length, position, cb] = util.getWriteArgs(fd, a, b, c, d, e);
  108. (async () => {
  109. const openFile = await this.getFileByFd(fd, 'write');
  110. const data = buf.subarray(offset, offset + length);
  111. await openFile.write(data, position);
  112. return length;
  113. })().then(bytesWritten => cb(null, bytesWritten, asStr ? a : buf), error => cb(error));
  114. };
  115. this.writev = (fd, buffers, a, b) => {
  116. (0, util_2.validateFd)(fd);
  117. let position = null;
  118. let callback;
  119. if (typeof a === 'function') {
  120. callback = a;
  121. }
  122. else {
  123. position = Number(a);
  124. callback = b;
  125. }
  126. util.validateCallback(callback);
  127. (async () => {
  128. const openFile = await this.getFileByFd(fd, 'writev');
  129. const length = buffers.length;
  130. let bytesWritten = 0;
  131. for (let i = 0; i < length; i++) {
  132. const data = buffers[i];
  133. await openFile.write(data, position);
  134. bytesWritten += data.byteLength;
  135. position = null;
  136. }
  137. return bytesWritten;
  138. })().then(bytesWritten => callback(null, bytesWritten, buffers), error => callback(error));
  139. };
  140. this.writeFile = (id, data, a, b) => {
  141. let options = a;
  142. let callback = b;
  143. if (typeof a === 'function') {
  144. options = optHelpers.writeFileDefaults;
  145. callback = a;
  146. }
  147. const cb = util.validateCallback(callback);
  148. const opts = optHelpers.getWriteFileOptions(options);
  149. const flagsNum = util.flagsToNumber(opts.flag);
  150. const modeNum = util.modeToNumber(opts.mode);
  151. const buf = (0, util_2.dataToBuffer)(data, opts.encoding);
  152. (async () => {
  153. let fd = typeof id === 'number' ? id : -1;
  154. const originalFd = fd;
  155. try {
  156. if (fd === -1) {
  157. const filename = util.pathToFilename(id);
  158. fd = (await this.__open(filename, flagsNum, modeNum)).fd;
  159. }
  160. const file = await this.__getFileById(fd, 'writeFile');
  161. const writable = await file.createWritable({ keepExistingData: false });
  162. await writable.write(buf);
  163. await writable.close();
  164. }
  165. finally {
  166. try {
  167. const idWasFd = typeof originalFd === 'number' && originalFd >= 0;
  168. if (idWasFd)
  169. await this.__close(originalFd);
  170. }
  171. catch (_a) { }
  172. }
  173. })().then(() => cb(null), error => cb(error));
  174. };
  175. this.copyFile = (src, dest, a, b) => {
  176. const srcFilename = util.pathToFilename(src);
  177. const destFilename = util.pathToFilename(dest);
  178. let flags;
  179. let callback;
  180. if (typeof a === 'function') {
  181. flags = 0;
  182. callback = a;
  183. }
  184. else {
  185. flags = a;
  186. callback = b;
  187. }
  188. util.validateCallback(callback);
  189. const [oldFolder, oldName] = (0, util_1.pathToLocation)(srcFilename);
  190. const [newFolder, newName] = (0, util_1.pathToLocation)(destFilename);
  191. (async () => {
  192. const oldFile = await this.getFile(oldFolder, oldName, 'copyFile');
  193. const newDir = await this.getDir(newFolder, false, 'copyFile');
  194. const newFile = await newDir.getFileHandle(newName, { create: true });
  195. const writable = await newFile.createWritable({ keepExistingData: false });
  196. const oldData = await oldFile.getFile();
  197. await writable.write(await oldData.arrayBuffer());
  198. await writable.close();
  199. })().then(() => callback(null), error => callback(error));
  200. };
  201. /**
  202. * @todo There is a proposal for native "self remove" operation.
  203. * @see https://github.com/whatwg/fs/blob/main/proposals/Remove.md
  204. */
  205. this.unlink = (path, callback) => {
  206. const filename = util.pathToFilename(path);
  207. const [folder, name] = (0, util_1.pathToLocation)(filename);
  208. this.getDir(folder, false, 'unlink')
  209. .then(dir => dir.removeEntry(name))
  210. .then(() => callback(null), error => {
  211. if (error && typeof error === 'object') {
  212. switch (error.name) {
  213. case 'NotFoundError': {
  214. callback(util.createError('ENOENT', 'unlink', filename));
  215. return;
  216. }
  217. case 'InvalidModificationError': {
  218. callback(util.createError('EISDIR', 'unlink', filename));
  219. return;
  220. }
  221. }
  222. }
  223. callback(error);
  224. });
  225. };
  226. this.realpath = (path, a, b) => {
  227. const [opts, callback] = optHelpers.getRealpathOptsAndCb(a, b);
  228. let pathFilename = util.pathToFilename(path);
  229. if (pathFilename[0] !== "/" /* FsaToNodeConstants.Separator */)
  230. pathFilename = "/" /* FsaToNodeConstants.Separator */ + pathFilename;
  231. callback(null, (0, encoding_1.strToEncoding)(pathFilename, opts.encoding));
  232. };
  233. this.stat = (path, a, b) => {
  234. const [{ bigint = false, throwIfNoEntry = true }, callback] = optHelpers.getStatOptsAndCb(a, b);
  235. const filename = util.pathToFilename(path);
  236. const [folder, name] = (0, util_1.pathToLocation)(filename);
  237. (async () => {
  238. const handle = await this.getFileOrDir(folder, name, 'stat');
  239. return await this.getHandleStats(bigint, handle);
  240. })().then(stats => callback(null, stats), error => callback(error));
  241. };
  242. this.lstat = this.stat;
  243. this.fstat = (fd, a, b) => {
  244. const [{ bigint = false, throwIfNoEntry = true }, callback] = optHelpers.getStatOptsAndCb(a, b);
  245. (async () => {
  246. const openFile = await this.getFileByFd(fd, 'fstat');
  247. return await this.getHandleStats(bigint, openFile.file);
  248. })().then(stats => callback(null, stats), error => callback(error));
  249. };
  250. /**
  251. * @todo There is a proposal for native move support.
  252. * @see https://github.com/whatwg/fs/blob/main/proposals/MovingNonOpfsFiles.md
  253. */
  254. this.rename = (oldPath, newPath, callback) => {
  255. const oldPathFilename = util.pathToFilename(oldPath);
  256. const newPathFilename = util.pathToFilename(newPath);
  257. const [oldFolder, oldName] = (0, util_1.pathToLocation)(oldPathFilename);
  258. const [newFolder, newName] = (0, util_1.pathToLocation)(newPathFilename);
  259. (async () => {
  260. const oldFile = await this.getFile(oldFolder, oldName, 'rename');
  261. const newDir = await this.getDir(newFolder, false, 'rename');
  262. const newFile = await newDir.getFileHandle(newName, { create: true });
  263. const writable = await newFile.createWritable({ keepExistingData: false });
  264. const oldData = await oldFile.getFile();
  265. await writable.write(await oldData.arrayBuffer());
  266. await writable.close();
  267. const oldDir = await this.getDir(oldFolder, false, 'rename');
  268. await oldDir.removeEntry(oldName);
  269. })().then(() => callback(null), error => callback(error));
  270. };
  271. this.exists = (path, callback) => {
  272. const filename = util.pathToFilename(path);
  273. if (typeof callback !== 'function')
  274. throw Error(constants_1.ERRSTR.CB);
  275. this.access(path, 0 /* AMODE.F_OK */, error => callback(!error));
  276. };
  277. this.access = (path, a, b) => {
  278. let mode = 0 /* AMODE.F_OK */;
  279. let callback;
  280. if (typeof a !== 'function') {
  281. mode = a | 0; // cast to number
  282. callback = util.validateCallback(b);
  283. }
  284. else {
  285. callback = a;
  286. }
  287. const filename = util.pathToFilename(path);
  288. const [folder, name] = (0, util_1.pathToLocation)(filename);
  289. (async () => {
  290. const node = folder.length || name ? await this.getFileOrDir(folder, name, 'access') : await this.root;
  291. const checkIfCanExecute = mode & 1 /* AMODE.X_OK */;
  292. if (checkIfCanExecute)
  293. throw util.createError('EACCESS', 'access', filename);
  294. const checkIfCanWrite = mode & 2 /* AMODE.W_OK */;
  295. switch (node.kind) {
  296. case 'file': {
  297. if (checkIfCanWrite) {
  298. try {
  299. const file = node;
  300. const writable = await file.createWritable();
  301. await writable.close();
  302. }
  303. catch (_a) {
  304. throw util.createError('EACCESS', 'access', filename);
  305. }
  306. }
  307. break;
  308. }
  309. case 'directory': {
  310. if (checkIfCanWrite) {
  311. const dir = node;
  312. const canWrite = await (0, util_1.testDirectoryIsWritable)(dir);
  313. if (!canWrite)
  314. throw util.createError('EACCESS', 'access', filename);
  315. }
  316. break;
  317. }
  318. default: {
  319. throw util.createError('EACCESS', 'access', filename);
  320. }
  321. }
  322. })().then(() => callback(null), error => callback(error));
  323. };
  324. this.appendFile = (id, data, a, b) => {
  325. const [opts, callback] = optHelpers.getAppendFileOptsAndCb(a, b);
  326. const buffer = (0, util_2.dataToBuffer)(data, opts.encoding);
  327. this.getFileByIdOrCreate(id, 'appendFile')
  328. .then(file => (async () => {
  329. const blob = await file.getFile();
  330. const writable = await file.createWritable({ keepExistingData: true });
  331. await writable.write({
  332. type: 'write',
  333. data: buffer,
  334. position: blob.size,
  335. });
  336. await writable.close();
  337. })())
  338. .then(() => callback(null), error => callback(error));
  339. };
  340. this.readdir = (path, a, b) => {
  341. const [options, callback] = optHelpers.getReaddirOptsAndCb(a, b);
  342. const filename = util.pathToFilename(path);
  343. const [folder, name] = (0, util_1.pathToLocation)(filename);
  344. if (name)
  345. folder.push(name);
  346. this.getDir(folder, false, 'readdir')
  347. .then(dir => (async () => {
  348. var _a, e_1, _b, _c, _d, e_2, _e, _f;
  349. if (options.withFileTypes) {
  350. const list = [];
  351. try {
  352. for (var _g = true, _h = tslib_1.__asyncValues(dir.entries()), _j; _j = await _h.next(), _a = _j.done, !_a; _g = true) {
  353. _c = _j.value;
  354. _g = false;
  355. const [name, handle] = _c;
  356. const dirent = new FsaNodeDirent_1.FsaNodeDirent(name, handle.kind);
  357. list.push(dirent);
  358. }
  359. }
  360. catch (e_1_1) { e_1 = { error: e_1_1 }; }
  361. finally {
  362. try {
  363. if (!_g && !_a && (_b = _h.return)) await _b.call(_h);
  364. }
  365. finally { if (e_1) throw e_1.error; }
  366. }
  367. if (!util_2.isWin && options.encoding !== 'buffer')
  368. list.sort((a, b) => {
  369. if (a.name < b.name)
  370. return -1;
  371. if (a.name > b.name)
  372. return 1;
  373. return 0;
  374. });
  375. return list;
  376. }
  377. else {
  378. const list = [];
  379. try {
  380. for (var _k = true, _l = tslib_1.__asyncValues(dir.keys()), _m; _m = await _l.next(), _d = _m.done, !_d; _k = true) {
  381. _f = _m.value;
  382. _k = false;
  383. const key = _f;
  384. list.push(key);
  385. }
  386. }
  387. catch (e_2_1) { e_2 = { error: e_2_1 }; }
  388. finally {
  389. try {
  390. if (!_k && !_d && (_e = _l.return)) await _e.call(_l);
  391. }
  392. finally { if (e_2) throw e_2.error; }
  393. }
  394. if (!util_2.isWin && options.encoding !== 'buffer')
  395. list.sort();
  396. return list;
  397. }
  398. })())
  399. .then(res => callback(null, res), err => callback(err));
  400. };
  401. this.readlink = (path, a, b) => {
  402. const [opts, callback] = optHelpers.getDefaultOptsAndCb(a, b);
  403. const filename = util.pathToFilename(path);
  404. const buffer = buffer_1.Buffer.from(filename);
  405. callback(null, util.bufferToEncoding(buffer, opts.encoding));
  406. };
  407. /** @todo Could this use `FileSystemSyncAccessHandle.flush` through a Worker thread? */
  408. this.fsync = (fd, callback) => {
  409. callback(null);
  410. };
  411. this.fdatasync = (fd, callback) => {
  412. callback(null);
  413. };
  414. this.ftruncate = (fd, a, b) => {
  415. const len = typeof a === 'number' ? a : 0;
  416. const callback = util.validateCallback(typeof a === 'number' ? b : a);
  417. this.getFileByFdAsync(fd)
  418. .then(file => file.file.createWritable({ keepExistingData: true }))
  419. .then(writable => writable.truncate(len).then(() => writable.close()))
  420. .then(() => callback(null), error => callback(error));
  421. };
  422. this.truncate = (path, a, b) => {
  423. const len = typeof a === 'number' ? a : 0;
  424. const callback = util.validateCallback(typeof a === 'number' ? b : a);
  425. this.open(path, 'r+', (error, fd) => {
  426. if (error)
  427. callback(error);
  428. else {
  429. this.ftruncate(fd, len, error => {
  430. if (error)
  431. this.close(fd, () => callback(error));
  432. else
  433. this.close(fd, callback);
  434. });
  435. }
  436. });
  437. };
  438. this.futimes = (fd, atime, mtime, callback) => {
  439. callback(null);
  440. };
  441. this.utimes = (path, atime, mtime, callback) => {
  442. callback(null);
  443. };
  444. this.mkdir = (path, a, b) => {
  445. var _a;
  446. const opts = optHelpers.getMkdirOptions(a);
  447. const callback = util.validateCallback(typeof a === 'function' ? a : b);
  448. // const modeNum = modeToNumber(opts.mode, 0o777);
  449. const filename = util.pathToFilename(path);
  450. const [folder, name] = (0, util_1.pathToLocation)(filename);
  451. // TODO: need to throw if directory already exists
  452. this.getDir(folder, (_a = opts.recursive) !== null && _a !== void 0 ? _a : false)
  453. .then(dir => dir.getDirectoryHandle(name, { create: true }))
  454. .then(() => callback(null), error => {
  455. if (error && typeof error === 'object') {
  456. switch (error.name) {
  457. case 'NotFoundError': {
  458. const err = util.createError('ENOENT', 'mkdir', folder.join('/'));
  459. callback(err);
  460. return;
  461. }
  462. }
  463. }
  464. callback(error);
  465. });
  466. };
  467. this.mkdtemp = (prefix, a, b) => {
  468. const [{ encoding }, callback] = optHelpers.getDefaultOptsAndCb(a, b);
  469. if (!prefix || typeof prefix !== 'string')
  470. throw new TypeError('filename prefix is required');
  471. if (!util.nullCheck(prefix))
  472. return;
  473. const filename = prefix + util.genRndStr6();
  474. this.mkdir(filename, 511 /* MODE.DIR */, err => {
  475. if (err)
  476. callback(err);
  477. else
  478. callback(null, (0, encoding_1.strToEncoding)(filename, encoding));
  479. });
  480. };
  481. this.rmdir = (path, a, b) => {
  482. const options = optHelpers.getRmdirOptions(a);
  483. const callback = util.validateCallback(typeof a === 'function' ? a : b);
  484. const [folder, name] = (0, util_1.pathToLocation)(util.pathToFilename(path));
  485. if (!name && options.recursive)
  486. return this.rmAll(callback);
  487. this.getDir(folder, false, 'rmdir')
  488. .then(dir => dir.getDirectoryHandle(name).then(() => dir))
  489. .then(dir => { var _a; return dir.removeEntry(name, { recursive: (_a = options.recursive) !== null && _a !== void 0 ? _a : false }); })
  490. .then(() => callback(null), error => {
  491. if (error && typeof error === 'object') {
  492. switch (error.name) {
  493. case 'NotFoundError': {
  494. const err = util.createError('ENOENT', 'rmdir', folder.join('/'));
  495. callback(err);
  496. return;
  497. }
  498. case 'InvalidModificationError': {
  499. const err = util.createError('ENOTEMPTY', 'rmdir', folder.join('/'));
  500. callback(err);
  501. return;
  502. }
  503. }
  504. }
  505. callback(error);
  506. });
  507. };
  508. this.rm = (path, a, b) => {
  509. const [options, callback] = optHelpers.getRmOptsAndCb(a, b);
  510. const [folder, name] = (0, util_1.pathToLocation)(util.pathToFilename(path));
  511. if (!name && options.recursive)
  512. return this.rmAll(callback);
  513. this.getDir(folder, false, 'rmdir')
  514. .then(dir => { var _a; return dir.removeEntry(name, { recursive: (_a = options.recursive) !== null && _a !== void 0 ? _a : false }); })
  515. .then(() => callback(null), error => {
  516. if (options.force) {
  517. callback(null);
  518. return;
  519. }
  520. if (error && typeof error === 'object') {
  521. switch (error.name) {
  522. case 'NotFoundError': {
  523. const err = util.createError('ENOENT', 'rmdir', folder.join('/'));
  524. callback(err);
  525. return;
  526. }
  527. case 'InvalidModificationError': {
  528. const err = util.createError('ENOTEMPTY', 'rmdir', folder.join('/'));
  529. callback(err);
  530. return;
  531. }
  532. }
  533. }
  534. callback(error);
  535. });
  536. };
  537. this.fchmod = (fd, mode, callback) => {
  538. callback(null);
  539. };
  540. this.chmod = (path, mode, callback) => {
  541. callback(null);
  542. };
  543. this.lchmod = (path, mode, callback) => {
  544. callback(null);
  545. };
  546. this.fchown = (fd, uid, gid, callback) => {
  547. callback(null);
  548. };
  549. this.chown = (path, uid, gid, callback) => {
  550. callback(null);
  551. };
  552. this.lchown = (path, uid, gid, callback) => {
  553. callback(null);
  554. };
  555. this.createWriteStream = (path, options) => {
  556. var _a;
  557. const defaults = {
  558. encoding: 'utf8',
  559. flags: 'w',
  560. autoClose: true,
  561. emitClose: true,
  562. };
  563. const optionsObj = optHelpers.getOptions(defaults, options);
  564. const filename = util.pathToFilename(path);
  565. const flags = util.flagsToNumber((_a = optionsObj.flags) !== null && _a !== void 0 ? _a : 'w');
  566. const fd = optionsObj.fd ? (typeof optionsObj.fd === 'number' ? optionsObj.fd : optionsObj.fd.fd) : 0;
  567. const handle = fd ? this.getFileByFdAsync(fd) : this.__open(filename, flags, 0);
  568. const stream = new FsaNodeWriteStream_1.FsaNodeWriteStream(handle, filename, optionsObj);
  569. if (optionsObj.autoClose) {
  570. stream.once('finish', () => {
  571. handle.then(file => this.close(file.fd, () => { }));
  572. });
  573. stream.once('error', () => {
  574. handle.then(file => this.close(file.fd, () => { }));
  575. });
  576. }
  577. return stream;
  578. };
  579. this.createReadStream = (path, options) => {
  580. const defaults = {
  581. flags: 'r',
  582. fd: null,
  583. mode: 0o666,
  584. autoClose: true,
  585. emitClose: true,
  586. start: 0,
  587. end: Infinity,
  588. highWaterMark: 64 * 1024,
  589. fs: null,
  590. signal: null,
  591. };
  592. const optionsObj = optHelpers.getOptions(defaults, options);
  593. const filename = util.pathToFilename(path);
  594. const flags = util.flagsToNumber(optionsObj.flags);
  595. const fd = optionsObj.fd ? (typeof optionsObj.fd === 'number' ? optionsObj.fd : optionsObj.fd.fd) : 0;
  596. const handle = fd ? this.getFileByFdAsync(fd) : this.__open(filename, flags, 0);
  597. const stream = new FsaNodeReadStream_1.FsaNodeReadStream(this, handle, filename, optionsObj);
  598. return stream;
  599. };
  600. this.cp = notImplemented;
  601. this.lutimes = notImplemented;
  602. this.openAsBlob = notImplemented;
  603. this.opendir = notImplemented;
  604. this.readv = notImplemented;
  605. this.statfs = notImplemented;
  606. this.glob = notImplemented;
  607. /**
  608. * @todo Watchers could be implemented in the future on top of `FileSystemObserver`,
  609. * which is currently a proposal.
  610. * @see https://github.com/whatwg/fs/blob/main/proposals/FileSystemObserver.md
  611. */
  612. this.watchFile = notSupported;
  613. this.unwatchFile = notSupported;
  614. this.watch = notSupported;
  615. this.symlink = notSupported;
  616. this.link = notSupported;
  617. // --------------------------------------------------------- FsSynchronousApi
  618. this.statSync = (path, options) => {
  619. var _a;
  620. const { bigint = true, throwIfNoEntry = true } = optHelpers.getStatOptions(options);
  621. const filename = util.pathToFilename(path);
  622. const location = (0, util_1.pathToLocation)(filename);
  623. const adapter = this.getSyncAdapter();
  624. const res = adapter.call('stat', location);
  625. const stats = new FsaNodeStats_1.FsaNodeStats(bigint, (_a = res.size) !== null && _a !== void 0 ? _a : 0, res.kind);
  626. return stats;
  627. };
  628. this.lstatSync = this.statSync;
  629. this.fstatSync = (fd, options) => {
  630. const filename = this.getFileName(fd);
  631. return this.statSync(filename, options);
  632. };
  633. this.accessSync = (path, mode = 0 /* AMODE.F_OK */) => {
  634. const filename = util.pathToFilename(path);
  635. mode = mode | 0;
  636. const adapter = this.getSyncAdapter();
  637. adapter.call('access', [filename, mode]);
  638. };
  639. this.readFileSync = (id, options) => {
  640. const opts = optHelpers.getReadFileOptions(options);
  641. const flagsNum = util.flagsToNumber(opts.flag);
  642. const filename = this.getFileName(id);
  643. const adapter = this.getSyncAdapter();
  644. const uint8 = adapter.call('readFile', [filename, opts]);
  645. const buffer = buffer_1.Buffer.from(uint8.buffer, uint8.byteOffset, uint8.byteLength);
  646. return util.bufferToEncoding(buffer, opts.encoding);
  647. };
  648. this.writeFileSync = (id, data, options) => {
  649. const opts = optHelpers.getWriteFileOptions(options);
  650. const flagsNum = util.flagsToNumber(opts.flag);
  651. const modeNum = util.modeToNumber(opts.mode);
  652. const buf = (0, util_2.dataToBuffer)(data, opts.encoding);
  653. const filename = this.getFileName(id);
  654. const adapter = this.getSyncAdapter();
  655. adapter.call('writeFile', [filename, util.bufToUint8(buf), opts]);
  656. };
  657. this.appendFileSync = (id, data, options) => {
  658. const opts = optHelpers.getAppendFileOpts(options);
  659. if (!opts.flag || (0, util_2.isFd)(id))
  660. opts.flag = 'a';
  661. const filename = this.getFileName(id);
  662. const buf = (0, util_2.dataToBuffer)(data, opts.encoding);
  663. const adapter = this.getSyncAdapter();
  664. adapter.call('appendFile', [filename, util.bufToUint8(buf), opts]);
  665. };
  666. this.closeSync = (fd) => {
  667. (0, util_2.validateFd)(fd);
  668. const file = this.getFileByFd(fd, 'close');
  669. file.close().catch(() => { });
  670. this.fds.delete(fd);
  671. this.releasedFds.push(fd);
  672. };
  673. this.existsSync = (path) => {
  674. try {
  675. this.statSync(path);
  676. return true;
  677. }
  678. catch (_a) {
  679. return false;
  680. }
  681. };
  682. this.copyFileSync = (src, dest, flags) => {
  683. const srcFilename = util.pathToFilename(src);
  684. const destFilename = util.pathToFilename(dest);
  685. const adapter = this.getSyncAdapter();
  686. adapter.call('copy', [srcFilename, destFilename, flags]);
  687. };
  688. this.renameSync = (oldPath, newPath) => {
  689. const srcFilename = util.pathToFilename(oldPath);
  690. const destFilename = util.pathToFilename(newPath);
  691. const adapter = this.getSyncAdapter();
  692. adapter.call('move', [srcFilename, destFilename]);
  693. };
  694. this.rmdirSync = (path, opts) => {
  695. const filename = util.pathToFilename(path);
  696. const adapter = this.getSyncAdapter();
  697. adapter.call('rmdir', [filename, opts]);
  698. };
  699. this.rmSync = (path, options) => {
  700. const filename = util.pathToFilename(path);
  701. const adapter = this.getSyncAdapter();
  702. adapter.call('rm', [filename, options]);
  703. };
  704. this.mkdirSync = (path, options) => {
  705. const opts = optHelpers.getMkdirOptions(options);
  706. const modeNum = util.modeToNumber(opts.mode, 0o777);
  707. const filename = util.pathToFilename(path);
  708. return this.getSyncAdapter().call('mkdir', [filename, options]);
  709. };
  710. this.mkdtempSync = (prefix, options) => {
  711. const { encoding } = optHelpers.getDefaultOpts(options);
  712. if (!prefix || typeof prefix !== 'string')
  713. throw new TypeError('filename prefix is required');
  714. util.nullCheck(prefix);
  715. const result = this.getSyncAdapter().call('mkdtemp', [prefix, options]);
  716. return (0, encoding_1.strToEncoding)(result, encoding);
  717. };
  718. this.readlinkSync = (path, options) => {
  719. const opts = optHelpers.getDefaultOpts(options);
  720. const filename = util.pathToFilename(path);
  721. const buffer = buffer_1.Buffer.from(filename);
  722. return util.bufferToEncoding(buffer, opts.encoding);
  723. };
  724. this.truncateSync = (id, len) => {
  725. if ((0, util_2.isFd)(id))
  726. return this.ftruncateSync(id, len);
  727. const filename = util.pathToFilename(id);
  728. this.getSyncAdapter().call('trunc', [filename, Number(len) || 0]);
  729. };
  730. this.ftruncateSync = (fd, len) => {
  731. const filename = this.getFileName(fd);
  732. this.truncateSync(filename, len);
  733. };
  734. this.unlinkSync = (path) => {
  735. const filename = util.pathToFilename(path);
  736. this.getSyncAdapter().call('unlink', [filename]);
  737. };
  738. this.readdirSync = (path, options) => {
  739. const opts = optHelpers.getReaddirOptions(options);
  740. const filename = util.pathToFilename(path);
  741. const adapter = this.getSyncAdapter();
  742. const list = adapter.call('readdir', [filename]);
  743. if (opts.withFileTypes) {
  744. const res = [];
  745. for (const entry of list)
  746. res.push(new FsaNodeDirent_1.FsaNodeDirent(entry.name, entry.kind));
  747. return res;
  748. }
  749. else {
  750. const res = [];
  751. for (const entry of list) {
  752. const buffer = buffer_1.Buffer.from(entry.name);
  753. res.push(util.bufferToEncoding(buffer, opts.encoding));
  754. }
  755. return res;
  756. }
  757. };
  758. this.realpathSync = (path, options) => {
  759. let filename = util.pathToFilename(path);
  760. const { encoding } = optHelpers.getRealpathOptions(options);
  761. if (filename[0] !== "/" /* FsaToNodeConstants.Separator */)
  762. filename = "/" /* FsaToNodeConstants.Separator */ + filename;
  763. return (0, encoding_1.strToEncoding)(filename, encoding);
  764. };
  765. this.readSync = (fd, buffer, offset, length, position) => {
  766. (0, util_2.validateFd)(fd);
  767. const filename = this.getFileName(fd);
  768. const adapter = this.getSyncAdapter();
  769. const uint8 = adapter.call('read', [filename, position, length]);
  770. const dest = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
  771. dest.set(uint8, offset);
  772. return uint8.length;
  773. };
  774. this.writeSync = (fd, a, b, c, d) => {
  775. const [, buf, offset, length, position] = util.getWriteSyncArgs(fd, a, b, c, d);
  776. const filename = this.getFileName(fd);
  777. const data = new Uint8Array(buf.buffer, buf.byteOffset + offset, length);
  778. return this.getSyncAdapter().call('write', [filename, data, position || null]);
  779. };
  780. this.openSync = (path, flags, mode = 438 /* MODE.DEFAULT */) => {
  781. const modeNum = util.modeToNumber(mode);
  782. const filename = util.pathToFilename(path);
  783. const flagsNum = util.flagsToNumber(flags);
  784. const adapter = this.getSyncAdapter();
  785. const handle = adapter.call('open', [filename, flagsNum, modeNum]);
  786. const openFile = this.__open2(handle, filename, flagsNum, modeNum);
  787. return openFile.fd;
  788. };
  789. this.writevSync = (fd, buffers, position) => {
  790. if (buffers.length === 0)
  791. return 0;
  792. let bytesWritten = 0;
  793. bytesWritten += this.writeSync(fd, buffers[0], 0, buffers[0].byteLength, position);
  794. for (let i = 1; i < buffers.length; i++) {
  795. bytesWritten += this.writeSync(fd, buffers[i], 0, buffers[i].byteLength, null);
  796. }
  797. return bytesWritten;
  798. };
  799. this.fdatasyncSync = noop;
  800. this.fsyncSync = noop;
  801. this.chmodSync = noop;
  802. this.chownSync = noop;
  803. this.fchmodSync = noop;
  804. this.fchownSync = noop;
  805. this.futimesSync = noop;
  806. this.lchmodSync = noop;
  807. this.lchownSync = noop;
  808. this.utimesSync = noop;
  809. this.lutimesSync = noop;
  810. this.cpSync = notImplemented;
  811. this.opendirSync = notImplemented;
  812. this.statfsSync = notImplemented;
  813. this.readvSync = notImplemented;
  814. this.globSync = notImplemented;
  815. this.symlinkSync = notSupported;
  816. this.linkSync = notSupported;
  817. // ---------------------------------------------------------- FsCommonObjects
  818. this.F_OK = constants_2.constants.F_OK;
  819. this.R_OK = constants_2.constants.R_OK;
  820. this.W_OK = constants_2.constants.W_OK;
  821. this.X_OK = constants_2.constants.X_OK;
  822. this.constants = constants_2.constants;
  823. this.Dirent = FsaNodeDirent_1.FsaNodeDirent;
  824. this.Stats = (FsaNodeStats_1.FsaNodeStats);
  825. this.WriteStream = FsaNodeWriteStream_1.FsaNodeWriteStream;
  826. this.ReadStream = FsaNodeReadStream_1.FsaNodeReadStream;
  827. this.StatFs = 0;
  828. this.Dir = 0;
  829. this.StatsWatcher = 0;
  830. this.FSWatcher = 0;
  831. }
  832. async getHandleStats(bigint, handle) {
  833. let size = 0;
  834. if (handle.kind === 'file') {
  835. const file = handle;
  836. const fileData = await file.getFile();
  837. size = fileData.size;
  838. }
  839. const stats = new FsaNodeStats_1.FsaNodeStats(bigint, bigint ? BigInt(size) : size, handle.kind);
  840. return stats;
  841. }
  842. rmAll(callback) {
  843. (async () => {
  844. var _a, e_3, _b, _c;
  845. const root = await this.root;
  846. try {
  847. for (var _d = true, _e = tslib_1.__asyncValues(root.keys()), _f; _f = await _e.next(), _a = _f.done, !_a; _d = true) {
  848. _c = _f.value;
  849. _d = false;
  850. const name = _c;
  851. await root.removeEntry(name, { recursive: true });
  852. }
  853. }
  854. catch (e_3_1) { e_3 = { error: e_3_1 }; }
  855. finally {
  856. try {
  857. if (!_d && !_a && (_b = _e.return)) await _b.call(_e);
  858. }
  859. finally { if (e_3) throw e_3.error; }
  860. }
  861. })().then(() => callback(null), error => callback(error));
  862. }
  863. }
  864. exports.FsaNodeFs = FsaNodeFs;
  865. //# sourceMappingURL=FsaNodeFs.js.map