diff --git a/lib/fs.js b/lib/fs.js index 618e48a2b892be..b226eb95af5594 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -2381,19 +2381,30 @@ function writeFileSync(path, data, options) { validateBoolean(flush, 'options.flush'); const flag = options.flag || 'w'; + const isUserFd = isFd(path); // File descriptor ownership // C++ fast path for string data and UTF8 encoding - if (typeof data === 'string' && (options.encoding === 'utf8' || options.encoding === 'utf-8')) { + if ( + typeof data === 'string' && + (options.encoding === 'utf8' || options.encoding === 'utf-8') && + !(flush && !isUserFd) + ) { if (!isInt32(path)) { path = getValidatedPath(path); } - return binding.writeFileUtf8( + binding.writeFileUtf8( path, data, stringToFlags(flag), parseFileMode(options.mode, 'mode', 0o666), ); + + if (flush && isUserFd) { + fs.fsyncSync(path); + } + + return; } if (!isArrayBufferView(data)) { @@ -2401,7 +2412,6 @@ function writeFileSync(path, data, options) { data = Buffer.from(data, options.encoding || 'utf8'); } - const isUserFd = isFd(path); // File descriptor ownership const fd = isUserFd ? path : fs.openSync(path, flag, options.mode); let offset = 0; diff --git a/test/parallel/test-fs-append-file-flush.js b/test/parallel/test-fs-append-file-flush.js index 69deeb4e8f9d14..8250b449fa8ee5 100644 --- a/test/parallel/test-fs-append-file-flush.js +++ b/test/parallel/test-fs-append-file-flush.js @@ -6,6 +6,7 @@ const fs = require('node:fs'); const fsp = require('node:fs/promises'); const test = require('node:test'); const data = 'foo'; +const data2 = 'bar'; let cnt = 0; function nextFile() { @@ -25,15 +26,27 @@ test('synchronous version', async (t) => { await t.test('performs flush', (t) => { const spy = t.mock.method(fs, 'fsyncSync'); + const checkCalls = (expected) => { + const calls = spy.mock.calls; + assert.strictEqual(calls.length, expected); + if (expected === 0) return; + assert.strictEqual(calls.at(-1).result, undefined); + assert.strictEqual(calls.at(-1).error, undefined); + assert.strictEqual(calls.at(-1).arguments.length, 1); + assert.strictEqual(typeof calls.at(-1).arguments[0], 'number'); + }; + const file = nextFile(); + + checkCalls(0); fs.appendFileSync(file, data, { flush: true }); - const calls = spy.mock.calls; - assert.strictEqual(calls.length, 1); - assert.strictEqual(calls[0].result, undefined); - assert.strictEqual(calls[0].error, undefined); - assert.strictEqual(calls[0].arguments.length, 1); - assert.strictEqual(typeof calls[0].arguments[0], 'number'); + checkCalls(1); assert.strictEqual(fs.readFileSync(file, 'utf8'), data); + + checkCalls(1); + fs.appendFileSync(file, data2, { flush: true }); + checkCalls(2); + assert.strictEqual(fs.readFileSync(file, 'utf8'), data + data2); }); await t.test('does not perform flush', (t) => { diff --git a/test/parallel/test-fs-write-file-flush.js b/test/parallel/test-fs-write-file-flush.js index 98a8d637c5fa28..96c76e63fe22ca 100644 --- a/test/parallel/test-fs-write-file-flush.js +++ b/test/parallel/test-fs-write-file-flush.js @@ -6,6 +6,7 @@ const fs = require('node:fs'); const fsp = require('node:fs/promises'); const test = require('node:test'); const data = 'foo'; +const data2 = 'bar'; let cnt = 0; function nextFile() { @@ -25,15 +26,27 @@ test('synchronous version', async (t) => { await t.test('performs flush', (t) => { const spy = t.mock.method(fs, 'fsyncSync'); + const checkCalls = (expected) => { + const calls = spy.mock.calls; + assert.strictEqual(calls.length, expected); + if (expected === 0) return; + assert.strictEqual(calls.at(-1).result, undefined); + assert.strictEqual(calls.at(-1).error, undefined); + assert.strictEqual(calls.at(-1).arguments.length, 1); + assert.strictEqual(typeof calls.at(-1).arguments[0], 'number'); + }; + const file = nextFile(); + + checkCalls(0); fs.writeFileSync(file, data, { flush: true }); - const calls = spy.mock.calls; - assert.strictEqual(calls.length, 1); - assert.strictEqual(calls[0].result, undefined); - assert.strictEqual(calls[0].error, undefined); - assert.strictEqual(calls[0].arguments.length, 1); - assert.strictEqual(typeof calls[0].arguments[0], 'number'); + checkCalls(1); assert.strictEqual(fs.readFileSync(file, 'utf8'), data); + + checkCalls(1); + fs.writeFileSync(file, data2, { flush: true, encoding: 'utf8' }); + checkCalls(2); + assert.strictEqual(fs.readFileSync(file, 'utf8'), data2); }); await t.test('does not perform flush', (t) => {