Skip to content

Commit 8f4b924

Browse files
thefourtheyeTrott
authored andcommitted
fs: make writeFile consistent with readFile wrt fd
As it is, `readFile` always reads from the current position of the file, if a file descriptor is used. But `writeFile` always writes from the beginning of the file. This patch fixes this inconsistency by making `writeFile` also to write from the current position of the file when used with a file descriptor. PR-URL: #23709 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Vse Mozhet Byt <[email protected]> Reviewed-By: Sam Roberts <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Daniel Bevenius <[email protected]> Reviewed-By: Rod Vagg <[email protected]> Reviewed-By: Anatoli Papirovski <[email protected]> Reviewed-By: Сковорода Никита Андреевич <[email protected]> Reviewed-By: Ruben Bridgewater <[email protected]>
1 parent 2c5dae5 commit 8f4b924

5 files changed

+180
-3
lines changed

lib/fs.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1229,7 +1229,7 @@ function writeFile(path, data, options, callback) {
12291229
function writeFd(fd, isUserFd) {
12301230
const buffer = isArrayBufferView(data) ?
12311231
data : Buffer.from('' + data, options.encoding || 'utf8');
1232-
const position = /a/.test(flag) ? null : 0;
1232+
const position = (/a/.test(flag) || isUserFd) ? null : 0;
12331233

12341234
writeAll(fd, isUserFd, buffer, 0, buffer.byteLength, position, callback);
12351235
}
@@ -1247,7 +1247,7 @@ function writeFileSync(path, data, options) {
12471247
}
12481248
let offset = 0;
12491249
let length = data.byteLength;
1250-
let position = /a/.test(flag) ? null : 0;
1250+
let position = (/a/.test(flag) || isUserFd) ? null : 0;
12511251
try {
12521252
while (length > 0) {
12531253
const written = fs.writeSync(fd, data, offset, length, position);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
'use strict';
2+
3+
/*
4+
* This test makes sure that `readFile()` always reads from the current
5+
* position of the file, instead of reading from the beginning of the file.
6+
*/
7+
8+
const common = require('../common');
9+
const assert = require('assert');
10+
const path = require('path');
11+
const { writeFileSync } = require('fs');
12+
const { open } = require('fs').promises;
13+
14+
const tmpdir = require('../common/tmpdir');
15+
tmpdir.refresh();
16+
17+
const fn = path.join(tmpdir.path, 'test.txt');
18+
writeFileSync(fn, 'Hello World');
19+
20+
async function readFileTest() {
21+
const handle = await open(fn, 'r');
22+
23+
/* Read only five bytes, so that the position moves to five. */
24+
const buf = Buffer.alloc(5);
25+
const { bytesRead } = await handle.read(buf, 0, 5, null);
26+
assert.strictEqual(bytesRead, 5);
27+
assert.deepStrictEqual(buf.toString(), 'Hello');
28+
29+
/* readFile() should read from position five, instead of zero. */
30+
assert.deepStrictEqual((await handle.readFile()).toString(), ' World');
31+
}
32+
33+
34+
readFileTest()
35+
.then(common.mustCall());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
'use strict';
2+
3+
/*
4+
* This test makes sure that `writeFile()` always writes from the current
5+
* position of the file, instead of truncating the file.
6+
*/
7+
8+
const common = require('../common');
9+
const assert = require('assert');
10+
const path = require('path');
11+
const { readFileSync } = require('fs');
12+
const { open } = require('fs').promises;
13+
14+
const tmpdir = require('../common/tmpdir');
15+
tmpdir.refresh();
16+
17+
const fn = path.join(tmpdir.path, 'test.txt');
18+
19+
async function writeFileTest() {
20+
const handle = await open(fn, 'w');
21+
22+
/* Write only five bytes, so that the position moves to five. */
23+
const buf = Buffer.from('Hello');
24+
const { bytesWritten } = await handle.write(buf, 0, 5, null);
25+
assert.strictEqual(bytesWritten, 5);
26+
27+
/* Write some more with writeFile(). */
28+
await handle.writeFile('World');
29+
30+
/* New content should be written at position five, instead of zero. */
31+
assert.deepStrictEqual(readFileSync(fn).toString(), 'HelloWorld');
32+
}
33+
34+
35+
writeFileTest()
36+
.then(common.mustCall());

test/parallel/test-fs-readfile-fd.js

+49-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
'use strict';
2-
require('../common');
2+
const common = require('../common');
33

44
// Test fs.readFile using a file descriptor.
55

66
const fixtures = require('../common/fixtures');
77
const assert = require('assert');
88
const fs = require('fs');
99
const fn = fixtures.path('empty.txt');
10+
const join = require('path').join;
11+
const tmpdir = require('../common/tmpdir');
12+
tmpdir.refresh();
1013

1114
tempFd(function(fd, close) {
1215
fs.readFile(fd, function(err, data) {
@@ -46,3 +49,48 @@ function tempFdSync(callback) {
4649
callback(fd);
4750
fs.closeSync(fd);
4851
}
52+
53+
{
54+
/*
55+
* This test makes sure that `readFile()` always reads from the current
56+
* position of the file, instead of reading from the beginning of the file,
57+
* when used with file descriptors.
58+
*/
59+
60+
const filename = join(tmpdir.path, 'test.txt');
61+
fs.writeFileSync(filename, 'Hello World');
62+
63+
{
64+
/* Tests the fs.readFileSync(). */
65+
const fd = fs.openSync(filename, 'r');
66+
67+
/* Read only five bytes, so that the position moves to five. */
68+
const buf = Buffer.alloc(5);
69+
assert.deepStrictEqual(fs.readSync(fd, buf, 0, 5), 5);
70+
assert.deepStrictEqual(buf.toString(), 'Hello');
71+
72+
/* readFileSync() should read from position five, instead of zero. */
73+
assert.deepStrictEqual(fs.readFileSync(fd).toString(), ' World');
74+
}
75+
76+
{
77+
/* Tests the fs.readFile(). */
78+
fs.open(filename, 'r', common.mustCall((err, fd) => {
79+
assert.ifError(err);
80+
const buf = Buffer.alloc(5);
81+
82+
/* Read only five bytes, so that the position moves to five. */
83+
fs.read(fd, buf, 0, 5, null, common.mustCall((err, bytes) => {
84+
assert.ifError(err);
85+
assert.strictEqual(bytes, 5);
86+
assert.deepStrictEqual(buf.toString(), 'Hello');
87+
88+
fs.readFile(fd, common.mustCall((err, data) => {
89+
assert.ifError(err);
90+
/* readFile() should read from position five, instead of zero. */
91+
assert.deepStrictEqual(data.toString(), ' World');
92+
}));
93+
}));
94+
}));
95+
}
96+
}
+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
'use strict';
2+
3+
/*
4+
* This test makes sure that `writeFile()` always writes from the current
5+
* position of the file, instead of truncating the file, when used with file
6+
* descriptors.
7+
*/
8+
9+
const common = require('../common');
10+
const assert = require('assert');
11+
const fs = require('fs');
12+
const join = require('path').join;
13+
14+
const tmpdir = require('../common/tmpdir');
15+
tmpdir.refresh();
16+
17+
{
18+
/* writeFileSync() test. */
19+
const filename = join(tmpdir.path, 'test.txt');
20+
21+
/* Open the file descriptor. */
22+
const fd = fs.openSync(filename, 'w');
23+
24+
/* Write only five characters, so that the position moves to five. */
25+
assert.deepStrictEqual(fs.writeSync(fd, 'Hello'), 5);
26+
assert.deepStrictEqual(fs.readFileSync(filename).toString(), 'Hello');
27+
28+
/* Write some more with writeFileSync(). */
29+
fs.writeFileSync(fd, 'World');
30+
31+
/* New content should be written at position five, instead of zero. */
32+
assert.deepStrictEqual(fs.readFileSync(filename).toString(), 'HelloWorld');
33+
}
34+
35+
{
36+
/* writeFile() test. */
37+
const file = join(tmpdir.path, 'test1.txt');
38+
39+
/* Open the file descriptor. */
40+
fs.open(file, 'w', common.mustCall((err, fd) => {
41+
assert.ifError(err);
42+
43+
/* Write only five characters, so that the position moves to five. */
44+
fs.write(fd, 'Hello', common.mustCall((err, bytes) => {
45+
assert.ifError(err);
46+
assert.strictEqual(bytes, 5);
47+
assert.deepStrictEqual(fs.readFileSync(file).toString(), 'Hello');
48+
49+
/* Write some more with writeFile(). */
50+
fs.writeFile(fd, 'World', common.mustCall((err) => {
51+
assert.ifError(err);
52+
53+
/* New content should be written at position five, instead of zero. */
54+
assert.deepStrictEqual(fs.readFileSync(file).toString(), 'HelloWorld');
55+
}));
56+
}));
57+
}));
58+
}

0 commit comments

Comments
 (0)