Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fs: adjust truncate mode from r+ to a #43315

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion doc/api/fs.md
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,7 @@ try {
```

If the file previously was shorter than `len` bytes, it is extended, and the
extended part is filled with null bytes (`'\0'`):
extended part is filled with null bytes (`'\0'`).

If `len` is negative then `0` will be used.

Expand Down Expand Up @@ -1481,6 +1481,10 @@ automatically be normalized to absolute path.

<!-- YAML
added: v10.0.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/43315
description: Creates a file if it didn't exist.
-->

* `path` {string|Buffer|URL}
Expand Down Expand Up @@ -4073,6 +4077,9 @@ $ tree .
<!-- YAML
added: v0.8.6
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/43315
description: Creates a file if it didn't exist.
- version: v18.0.0
pr-url: https://github.com/nodejs/node/pull/41678
description: Passing an invalid callback to the `callback` argument
Expand Down Expand Up @@ -5781,6 +5788,10 @@ this API: [`fs.symlink()`][].

<!-- YAML
added: v0.8.6
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/43315
description: Creates a file if it didn't exist.
-->

* `path` {string|Buffer|URL}
Expand Down
4 changes: 2 additions & 2 deletions lib/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -1060,7 +1060,7 @@ function truncate(path, len, callback) {
validateInteger(len, 'len');
len = MathMax(0, len);
callback = maybeCallback(callback);
fs.open(path, 'r+', (er, fd) => {
fs.open(path, 'a', (er, fd) => {
if (er) return callback(er);
const req = new FSReqCallback();
req.oncomplete = function oncomplete(er) {
Expand Down Expand Up @@ -1088,7 +1088,7 @@ function truncateSync(path, len) {
len = 0;
}
// Allow error to be thrown, but still close fd.
const fd = fs.openSync(path, 'r+');
const fd = fs.openSync(path, 'a');
let ret;

try {
Expand Down
2 changes: 1 addition & 1 deletion lib/internal/fs/promises.js
Original file line number Diff line number Diff line change
Expand Up @@ -635,7 +635,7 @@ async function rename(oldPath, newPath) {
}

async function truncate(path, len = 0) {
const fd = await open(path, 'r+');
const fd = await open(path, 'a');
return handleFdClose(ftruncate(fd, len), fd.close);
}

Expand Down
48 changes: 48 additions & 0 deletions test/parallel/test-fs-truncate-nonreadable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
'use strict';

const common = require('../common');

// This test ensures that truncate works on non-readable files

const assert = require('assert');
const fs = require('fs');
const fsPromises = fs.promises;
const path = require('path');
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();

const expected = Buffer.from('good');

function checkContents(filepath) {
fs.chmodSync(filepath, 0o400);
assert.deepStrictEqual(
fs.readFileSync(filepath),
expected
);
}

(async () => {
const MODE = 0o200;
{
const filepath = path.resolve(tmpdir.path, 'promises.txt');
fs.writeFileSync(filepath, 'good bad');
fs.chmodSync(filepath, MODE);
await fsPromises.truncate(filepath, 4);
checkContents(filepath);
}
{
const filepath = path.resolve(tmpdir.path, 'callback.txt');
fs.writeFileSync(filepath, 'good bad');
fs.chmodSync(filepath, MODE);
fs.truncate(filepath, 4, common.mustSucceed(() => {
checkContents(filepath);
}));
}
{
const filepath = path.resolve(tmpdir.path, 'synchronous.txt');
fs.writeFileSync(filepath, 'good bad');
fs.chmodSync(filepath, MODE);
fs.truncateSync(filepath, 4);
checkContents(filepath);
}
})().then(common.mustCall());
22 changes: 11 additions & 11 deletions test/parallel/test-fs-truncate.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,17 +242,17 @@ function testFtruncate(cb) {
}

{
const file8 = path.resolve(tmp, 'non-existent-truncate-file.txt');
const validateError = (err) => {
assert.strictEqual(file8, err.path);
assert.strictEqual(
err.message,
`ENOENT: no such file or directory, open '${file8}'`);
assert.strictEqual(err.code, 'ENOENT');
assert.strictEqual(err.syscall, 'open');
return true;
};
fs.truncate(file8, 0, common.mustCall(validateError));
const file8 = path.resolve(tmp, 'non-existent-truncate-file-1.txt');
fs.truncate(file8, 0, common.mustSucceed(() => {
assert(fs.readFileSync(file8).equals(Buffer.from('')));
}));
}

{
const file9 = path.resolve(tmp, 'non-existent-truncate-file-2.txt');
fs.truncate(file9, 2, common.mustSucceed(() => {
assert(fs.readFileSync(file9).equals(Buffer.from('\u0000\u0000')));
}));
}

['', false, null, {}, []].forEach((input) => {
Expand Down