From 2e97e8184ed383959cd0bb6865937ea2478b9f05 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Apr 2026 15:39:41 +0000 Subject: [PATCH 1/2] Add try/finally to utimesMillisSync to prevent fd leak Agent-Logs-Url: https://github.com/jprichardson/node-fs-extra/sessions/b96a4f0a-2672-406f-9c6a-bd78c8a7ab99 Co-authored-by: RyanZim <17342435+RyanZim@users.noreply.github.com> --- lib/util/utimes.js | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/util/utimes.js b/lib/util/utimes.js index 434b3cea..55ad9132 100644 --- a/lib/util/utimes.js +++ b/lib/util/utimes.js @@ -27,8 +27,24 @@ async function utimesMillis (path, atime, mtime) { function utimesMillisSync (path, atime, mtime) { const fd = fs.openSync(path, 'r+') - fs.futimesSync(fd, atime, mtime) - return fs.closeSync(fd) + + let error = null + + try { + fs.futimesSync(fd, atime, mtime) + } catch (futimesErr) { + error = futimesErr + } finally { + try { + fs.closeSync(fd) + } catch (closeErr) { + error = closeErr + } + } + + if (error) { + throw error + } } module.exports = { From 90cf44f4afa2a62d1f533df376ed551a9cebb749 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Apr 2026 07:34:21 +0000 Subject: [PATCH 2/2] Add test for fd leak fix in utimesMillisSync Agent-Logs-Url: https://github.com/jprichardson/node-fs-extra/sessions/685e7e26-4679-4fd1-bec5-820f5e2780e0 Co-authored-by: JPeer264 <10677263+JPeer264@users.noreply.github.com> --- lib/util/__tests__/utimes.test.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/lib/util/__tests__/utimes.test.js b/lib/util/__tests__/utimes.test.js index 02c65d1f..eaab1adb 100644 --- a/lib/util/__tests__/utimes.test.js +++ b/lib/util/__tests__/utimes.test.js @@ -97,4 +97,26 @@ describe('utimes', () => { }) }) }) + + describe('utimesMillisSync()', () => { + it('should close open file descriptors after encountering an error', () => { + const fakeFd = Math.random() + + gracefulFsStub.openSync = (pathIgnored, flagsIgnored) => fakeFd + + let closeCalled = false + gracefulFsStub.closeSync = (fd) => { + assert.strictEqual(fd, fakeFd) + closeCalled = true + } + + const testError = new Error('A test error') + gracefulFsStub.futimesSync = (fd, atimeIgnored, mtimeIgnored) => { + throw testError + } + + assert.throws(() => utimes.utimesMillisSync('ignored', 'ignored', 'ignored'), testError) + assert(closeCalled) + }) + }) })