| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1542,6 +1542,10 @@ link(2) documentation for more detail. | |||
| 1542 | 1542 | <!-- YAML | |
| 1543 | 1543 | added: v10.0.0 | |
| 1544 | 1544 | changes: | |
| 1545 | + - version: REPLACEME | ||
| 1546 | + pr-url: https://github.com/nodejs/node/pull/63143 | ||
| 1547 | + description: Accepts an additional `signal` option to allow aborting the | ||
| 1548 | + operation. | ||
| 1545 | 1549 | - version: v10.5.0 | |
| 1546 | 1550 | pr-url: https://github.com/nodejs/node/pull/20220 | |
| 1547 | 1551 | description: Accepts an additional `options` object to specify whether | |
@@ -1552,6 +1556,8 @@ changes: | |||
| 1552 | 1556 | * `options` {Object} | |
| 1553 | 1557 | * `bigint` {boolean} Whether the numeric values in the returned | |
| 1554 | 1558 | {fs.Stats} object should be `bigint`. **Default:** `false`. | |
| 1559 | + * `signal` {AbortSignal} An AbortSignal to cancel the operation. | ||
| 1560 | + **Default:** `undefined`. | ||
| 1555 | 1561 | * Returns: {Promise} Fulfills with the {fs.Stats} object for the given | |
| 1556 | 1562 | symbolic link `path`. | |
| 1557 | 1563 | ||
@@ -2080,6 +2086,10 @@ Removes files and directories (modeled on the standard POSIX `rm` utility). | |||
| 2080 | 2086 | <!-- YAML | |
| 2081 | 2087 | added: v10.0.0 | |
| 2082 | 2088 | changes: | |
| 2089 | + - version: REPLACEME | ||
| 2090 | + pr-url: https://github.com/nodejs/node/pull/63143 | ||
| 2091 | + description: Accepts an additional `signal` option to allow aborting the | ||
| 2092 | + operation. | ||
| 2083 | 2093 | - version: v25.7.0 | |
| 2084 | 2094 | pr-url: https://github.com/nodejs/node/pull/61178 | |
| 2085 | 2095 | description: Accepts a `throwIfNoEntry` option to specify whether | |
@@ -2097,6 +2107,8 @@ changes: | |||
| 2097 | 2107 | * `throwIfNoEntry` {boolean} Whether an exception will be thrown | |
| 2098 | 2108 | if no file system entry exists, rather than returning `undefined`. | |
| 2099 | 2109 | **Default:** `true`. | |
| 2110 | + * `signal` {AbortSignal} An AbortSignal to cancel the operation. | ||
| 2111 | + **Default:** `undefined`. | ||
| 2100 | 2112 | * Returns: {Promise} Fulfills with the {fs.Stats} object for the | |
| 2101 | 2113 | given `path`. | |
| 2102 | 2114 | ||
@@ -3437,6 +3449,10 @@ exception are given to the completion callback. | |||
| 3437 | 3449 | <!-- YAML | |
| 3438 | 3450 | added: v0.1.95 | |
| 3439 | 3451 | changes: | |
| 3452 | + - version: REPLACEME | ||
| 3453 | + pr-url: https://github.com/nodejs/node/pull/63143 | ||
| 3454 | + description: Accepts an additional `signal` option to allow aborting the | ||
| 3455 | + operation. | ||
| 3440 | 3456 | - version: v18.0.0 | |
| 3441 | 3457 | pr-url: https://github.com/nodejs/node/pull/41678 | |
| 3442 | 3458 | description: Passing an invalid callback to the `callback` argument | |
@@ -3460,6 +3476,8 @@ changes: | |||
| 3460 | 3476 | * `options` {Object} | |
| 3461 | 3477 | * `bigint` {boolean} Whether the numeric values in the returned | |
| 3462 | 3478 | {fs.Stats} object should be `bigint`. **Default:** `false`. | |
| 3479 | + * `signal` {AbortSignal} An AbortSignal to cancel the operation. | ||
| 3480 | + **Default:** `undefined`. | ||
| 3463 | 3481 | * `callback` {Function} | |
| 3464 | 3482 | * `err` {Error} | |
| 3465 | 3483 | * `stats` {fs.Stats} | |
@@ -3802,6 +3820,10 @@ exception are given to the completion callback. | |||
| 3802 | 3820 | <!-- YAML | |
| 3803 | 3821 | added: v0.1.30 | |
| 3804 | 3822 | changes: | |
| 3823 | + - version: REPLACEME | ||
| 3824 | + pr-url: https://github.com/nodejs/node/pull/63143 | ||
| 3825 | + description: Accepts an additional `signal` option to allow aborting the | ||
| 3826 | + operation. | ||
| 3805 | 3827 | - version: v18.0.0 | |
| 3806 | 3828 | pr-url: https://github.com/nodejs/node/pull/41678 | |
| 3807 | 3829 | description: Passing an invalid callback to the `callback` argument | |
@@ -3829,6 +3851,8 @@ changes: | |||
| 3829 | 3851 | * `options` {Object} | |
| 3830 | 3852 | * `bigint` {boolean} Whether the numeric values in the returned | |
| 3831 | 3853 | {fs.Stats} object should be `bigint`. **Default:** `false`. | |
| 3854 | + * `signal` {AbortSignal} An AbortSignal to cancel the operation. | ||
| 3855 | + **Default:** `undefined`. | ||
| 3832 | 3856 | * `callback` {Function} | |
| 3833 | 3857 | * `err` {Error} | |
| 3834 | 3858 | * `stats` {fs.Stats} | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -139,6 +139,7 @@ const { | |||
| 139 | 139 | const { | |
| 140 | 140 | isInt32, | |
| 141 | 141 | parseFileMode, | |
| 142 | + validateAbortSignal, | ||
| 142 | 143 | validateBoolean, | |
| 143 | 144 | validateBuffer, | |
| 144 | 145 | validateEncoding, | |
@@ -383,6 +384,25 @@ function checkAborted(signal, callback) { | |||
| 383 | 384 | return false; | |
| 384 | 385 | } | |
| 385 | 386 | ||
| 387 | + function bindSignalToReq(req, signal, callback) { | ||
| 388 | + if (!signal) { | ||
| 389 | + req.oncomplete = callback; | ||
| 390 | + return; | ||
| 391 | + } | ||
| 392 | + let aborted = false; | ||
| 393 | + const onAbort = () => { | ||
| 394 | + aborted = true; | ||
| 395 | + callback(new AbortError(undefined, { cause: signal.reason })); | ||
| 396 | + }; | ||
| 397 | + kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation; | ||
| 398 | + signal.addEventListener('abort', onAbort, { __proto__: null, [kResistStopPropagation]: true }); | ||
| 399 | + req.oncomplete = function(err, result) { | ||
| 400 | + signal.removeEventListener('abort', onAbort); | ||
| 401 | + if (aborted) return; | ||
| 402 | + callback(err, result); | ||
| 403 | + }; | ||
| 404 | + } | ||
| 405 | + | ||
| 386 | 406 | /** | |
| 387 | 407 | * Asynchronously reads the entire contents of a file. | |
| 388 | 408 | * @param {string | Buffer | URL | number} path | |
@@ -1954,7 +1974,7 @@ function readdirSync(path, options) { | |||
| 1954 | 1974 | * Invokes the callback with the `fs.Stats` | |
| 1955 | 1975 | * for the file descriptor. | |
| 1956 | 1976 | * @param {number} fd | |
| 1957 | - * @param {{ bigint?: boolean; }} [options] | ||
| 1977 | + * @param {{ bigint?: boolean, signal?: AbortSignal }} [options] | ||
| 1958 | 1978 | * @param {( | |
| 1959 | 1979 | * err?: Error, | |
| 1960 | 1980 | * stats?: Stats | |
@@ -1965,23 +1985,28 @@ function fstat(fd, options = { __proto__: null, bigint: false }, callback) { | |||
| 1965 | 1985 | if (typeof options === 'function') { | |
| 1966 | 1986 | callback = options; | |
| 1967 | 1987 | options = kEmptyObject; | |
| 1988 | + } else if (options === null || typeof options !== 'object') { | ||
| 1989 | + options = kEmptyObject; | ||
| 1968 | 1990 | } | |
| 1969 | 1991 | ||
| 1970 | 1992 | const h = vfsState.handlers; | |
| 1971 | 1993 | if (h !== null && vfsResult(h.fstat(fd, options), callback)) return; | |
| 1972 | 1994 | ||
| 1973 | 1995 | callback = makeStatsCallback(callback); | |
| 1974 | 1996 | ||
| 1997 | + if (options.signal !== undefined) validateAbortSignal(options.signal, 'options.signal'); | ||
| 1998 | + if (checkAborted(options.signal, callback)) return; | ||
| 1999 | + | ||
| 1975 | 2000 | const req = new FSReqCallback(options.bigint); | |
| 1976 | - req.oncomplete = callback; | ||
| 2001 | + bindSignalToReq(req, options.signal, callback); | ||
| 1977 | 2002 | binding.fstat(fd, options.bigint, req); | |
| 1978 | 2003 | } | |
| 1979 | 2004 | ||
| 1980 | 2005 | /** | |
| 1981 | 2006 | * Retrieves the `fs.Stats` for the symbolic link | |
| 1982 | 2007 | * referred to by the `path`. | |
| 1983 | 2008 | * @param {string | Buffer | URL} path | |
| 1984 | - * @param {{ bigint?: boolean; }} [options] | ||
| 2009 | + * @param {{ bigint?: boolean, signal?: AbortSignal }} [options] | ||
| 1985 | 2010 | * @param {( | |
| 1986 | 2011 | * err?: Error, | |
| 1987 | 2012 | * stats?: Stats | |
@@ -1992,6 +2017,10 @@ function lstat(path, options = { __proto__: null, bigint: false }, callback) { | |||
| 1992 | 2017 | if (typeof options === 'function') { | |
| 1993 | 2018 | callback = options; | |
| 1994 | 2019 | options = kEmptyObject; | |
| 2020 | + } else if (options === null || typeof options !== 'object') { | ||
| 2021 | + options = kEmptyObject; | ||
| 2022 | + } else { | ||
| 2023 | + options = getOptions(options, { bigint: false }); | ||
| 1995 | 2024 | } | |
| 1996 | 2025 | ||
| 1997 | 2026 | const h = vfsState.handlers; | |
@@ -2005,8 +2034,11 @@ function lstat(path, options = { __proto__: null, bigint: false }, callback) { | |||
| 2005 | 2034 | return; | |
| 2006 | 2035 | } | |
| 2007 | 2036 | ||
| 2037 | + if (options.signal !== undefined) validateAbortSignal(options.signal, 'options.signal'); | ||
| 2038 | + if (checkAborted(options.signal, callback)) return; | ||
| 2039 | + | ||
| 2008 | 2040 | const req = new FSReqCallback(options.bigint); | |
| 2009 | - req.oncomplete = callback; | ||
| 2041 | + bindSignalToReq(req, options.signal, callback); | ||
| 2010 | 2042 | binding.lstat(path, options.bigint, req); | |
| 2011 | 2043 | } | |
| 2012 | 2044 | ||
@@ -2036,11 +2068,12 @@ function stat(path, options = { __proto__: null, bigint: false, throwIfNoEntry: | |||
| 2036 | 2068 | callback = makeStatsCallback(callback); | |
| 2037 | 2069 | path = getValidatedPath(path); | |
| 2038 | 2070 | ||
| 2071 | + if (options.signal !== undefined) validateAbortSignal(options.signal, 'options.signal'); | ||
| 2039 | 2072 | if (checkAborted(options.signal, callback)) return; | |
| 2040 | 2073 | ||
| 2041 | 2074 | const req = new FSReqCallback(options.bigint); | |
| 2042 | - req.oncomplete = callback; | ||
| 2043 | - binding.stat(getValidatedPath(path), options.bigint, req, options.throwIfNoEntry); | ||
| 2075 | + bindSignalToReq(req, options.signal, callback); | ||
| 2076 | + binding.stat(path, options.bigint, req, options.throwIfNoEntry); | ||
| 2044 | 2077 | } | |
| 2045 | 2078 | ||
| 2046 | 2079 | function statfs(path, options = { __proto__: null, bigint: false }, callback) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -12,8 +12,10 @@ const { | |||
| 12 | 12 | PromisePrototypeThen, | |
| 13 | 13 | PromiseReject, | |
| 14 | 14 | PromiseResolve, | |
| 15 | + PromiseWithResolvers, | ||
| 15 | 16 | SafeArrayIterator, | |
| 16 | 17 | SafePromisePrototypeFinally, | |
| 18 | + SafePromiseRace, | ||
| 17 | 19 | Symbol, | |
| 18 | 20 | SymbolAsyncDispose, | |
| 19 | 21 | SymbolAsyncIterator, | |
@@ -1126,6 +1128,21 @@ function checkAborted(signal) { | |||
| 1126 | 1128 | throw new AbortError(undefined, { cause: signal.reason }); | |
| 1127 | 1129 | } | |
| 1128 | 1130 | ||
| 1131 | + function rejectWithReason(signal, reject) { | ||
| 1132 | + return () => { | ||
| 1133 | + reject(new AbortError(undefined, { cause: signal.reason })); | ||
| 1134 | + }; | ||
| 1135 | + } | ||
| 1136 | + | ||
| 1137 | + async function raceWithSignal(opPromise, signal) { | ||
| 1138 | + if (!signal) return opPromise; | ||
| 1139 | + const { promise: abortPromise, reject } = PromiseWithResolvers(); | ||
| 1140 | + // eslint-disable-next-line no-unused-vars | ||
| 1141 | + using _ = EventEmitter.addAbortListener(signal, | ||
| 1142 | + rejectWithReason(signal, reject)); | ||
| 1143 | + return await SafePromiseRace([opPromise, abortPromise]); | ||
| 1144 | + } | ||
| 1145 | + | ||
| 1129 | 1146 | async function writeFileHandle(filehandle, data, signal, encoding) { | |
| 1130 | 1147 | checkAborted(signal); | |
| 1131 | 1148 | if (isCustomIterable(data)) { | |
@@ -1779,15 +1796,26 @@ async function symlink(target, path, type) { | |||
| 1779 | 1796 | } | |
| 1780 | 1797 | ||
| 1781 | 1798 | async function fstat(handle, options = { __proto__: null, bigint: false }) { | |
| 1782 | - const result = await PromisePrototypeThen( | ||
| 1783 | - binding.fstat(handle.fd, options.bigint, kUsePromises), | ||
| 1784 | - undefined, | ||
| 1785 | - handleErrorFromBinding, | ||
| 1799 | + validateObject(options, 'options'); | ||
| 1800 | + const { signal } = options; | ||
| 1801 | + if (signal !== undefined) validateAbortSignal(signal, 'options.signal'); | ||
| 1802 | + checkAborted(signal); | ||
| 1803 | + const result = await raceWithSignal( | ||
| 1804 | + PromisePrototypeThen( | ||
| 1805 | + binding.fstat(handle.fd, options.bigint, kUsePromises), | ||
| 1806 | + undefined, | ||
| 1807 | + handleErrorFromBinding, | ||
| 1808 | + ), | ||
| 1809 | + signal, | ||
| 1786 | 1810 | ); | |
| 1787 | 1811 | return getStatsFromBinding(result); | |
| 1788 | 1812 | } | |
| 1789 | 1813 | ||
| 1790 | 1814 | async function lstat(path, options = { __proto__: null, bigint: false }) { | |
| 1815 | + validateObject(options, 'options'); | ||
| 1816 | + const { signal } = options; | ||
| 1817 | + if (signal !== undefined) validateAbortSignal(signal, 'options.signal'); | ||
| 1818 | + checkAborted(signal); | ||
| 1791 | 1819 | const h = vfsState.handlers; | |
| 1792 | 1820 | if (h !== null) { | |
| 1793 | 1821 | const promise = h.lstat(path, options); | |
@@ -1798,24 +1826,34 @@ async function lstat(path, options = { __proto__: null, bigint: false }) { | |||
| 1798 | 1826 | const resource = pathModule.toNamespacedPath(BufferIsBuffer(path) ? BufferToString(path) : path); | |
| 1799 | 1827 | throw new ERR_ACCESS_DENIED('Access to this API has been restricted', 'FileSystemRead', resource); | |
| 1800 | 1828 | } | |
| 1801 | - const result = await PromisePrototypeThen( | ||
| 1802 | - binding.lstat(path, options.bigint, kUsePromises), | ||
| 1803 | - undefined, | ||
| 1804 | - handleErrorFromBinding, | ||
| 1829 | + const result = await raceWithSignal( | ||
| 1830 | + PromisePrototypeThen( | ||
| 1831 | + binding.lstat(path, options.bigint, kUsePromises), | ||
| 1832 | + undefined, | ||
| 1833 | + handleErrorFromBinding, | ||
| 1834 | + ), | ||
| 1835 | + signal, | ||
| 1805 | 1836 | ); | |
| 1806 | 1837 | return getStatsFromBinding(result); | |
| 1807 | 1838 | } | |
| 1808 | 1839 | ||
| 1809 | 1840 | async function stat(path, options = { __proto__: null, bigint: false, throwIfNoEntry: true }) { | |
| 1841 | + validateObject(options, 'options'); | ||
| 1842 | + const { signal } = options; | ||
| 1843 | + if (signal !== undefined) validateAbortSignal(signal, 'options.signal'); | ||
| 1844 | + checkAborted(signal); | ||
| 1810 | 1845 | const h = vfsState.handlers; | |
| 1811 | 1846 | if (h !== null) { | |
| 1812 | 1847 | const promise = h.stat(path, options); | |
| 1813 | 1848 | if (promise !== undefined) return await promise; | |
| 1814 | 1849 | } | |
| 1815 | - const result = await PromisePrototypeThen( | ||
| 1816 | - binding.stat(getValidatedPath(path), options.bigint, kUsePromises, options.throwIfNoEntry), | ||
| 1817 | - undefined, | ||
| 1818 | - handleErrorFromBinding, | ||
| 1850 | + const result = await raceWithSignal( | ||
| 1851 | + PromisePrototypeThen( | ||
| 1852 | + binding.stat(getValidatedPath(path), options.bigint, kUsePromises, options.throwIfNoEntry), | ||
| 1853 | + undefined, | ||
| 1854 | + handleErrorFromBinding, | ||
| 1855 | + ), | ||
| 1856 | + signal, | ||
| 1819 | 1857 | ); | |
| 1820 | 1858 | ||
| 1821 | 1859 | // Binding will resolve undefined if UV_ENOENT or UV_ENOTDIR and throwIfNoEntry is false | |
| Back | FazBrowse Home | New Git URL |
0 commit comments