FsaNodeFs.js 39 KB

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