• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright Joyent, Inc. and other Node contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the
5// "Software"), to deal in the Software without restriction, including
6// without limitation the rights to use, copy, modify, merge, publish,
7// distribute, sublicense, and/or sell copies of the Software, and to permit
8// persons to whom the Software is furnished to do so, subject to the
9// following conditions:
10//
11// The above copyright notice and this permission notice shall be included
12// in all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22'use strict';
23const common = require('../common');
24const assert = require('assert');
25const path = require('path');
26const fs = require('fs');
27const tmpdir = require('../common/tmpdir');
28const tmp = tmpdir.path;
29const filename = path.resolve(tmp, 'truncate-file.txt');
30const data = Buffer.alloc(1024 * 16, 'x');
31
32tmpdir.refresh();
33
34let stat;
35
36const msg = 'Using fs.truncate with a file descriptor is deprecated.' +
37            ' Please use fs.ftruncate with a file descriptor instead.';
38
39// Check truncateSync
40fs.writeFileSync(filename, data);
41stat = fs.statSync(filename);
42assert.strictEqual(stat.size, 1024 * 16);
43
44fs.truncateSync(filename, 1024);
45stat = fs.statSync(filename);
46assert.strictEqual(stat.size, 1024);
47
48fs.truncateSync(filename);
49stat = fs.statSync(filename);
50assert.strictEqual(stat.size, 0);
51
52// Check ftruncateSync
53fs.writeFileSync(filename, data);
54const fd = fs.openSync(filename, 'r+');
55
56stat = fs.statSync(filename);
57assert.strictEqual(stat.size, 1024 * 16);
58
59fs.ftruncateSync(fd, 1024);
60stat = fs.statSync(filename);
61assert.strictEqual(stat.size, 1024);
62
63fs.ftruncateSync(fd);
64stat = fs.statSync(filename);
65assert.strictEqual(stat.size, 0);
66
67// truncateSync
68common.expectWarning('DeprecationWarning', msg, 'DEP0081');
69fs.truncateSync(fd);
70
71fs.closeSync(fd);
72
73// Async tests
74testTruncate(common.mustSucceed(() => {
75  testFtruncate(common.mustSucceed());
76}));
77
78function testTruncate(cb) {
79  fs.writeFile(filename, data, function(er) {
80    if (er) return cb(er);
81    fs.stat(filename, function(er, stat) {
82      if (er) return cb(er);
83      assert.strictEqual(stat.size, 1024 * 16);
84
85      fs.truncate(filename, 1024, function(er) {
86        if (er) return cb(er);
87        fs.stat(filename, function(er, stat) {
88          if (er) return cb(er);
89          assert.strictEqual(stat.size, 1024);
90
91          fs.truncate(filename, function(er) {
92            if (er) return cb(er);
93            fs.stat(filename, function(er, stat) {
94              if (er) return cb(er);
95              assert.strictEqual(stat.size, 0);
96              cb();
97            });
98          });
99        });
100      });
101    });
102  });
103}
104
105function testFtruncate(cb) {
106  fs.writeFile(filename, data, function(er) {
107    if (er) return cb(er);
108    fs.stat(filename, function(er, stat) {
109      if (er) return cb(er);
110      assert.strictEqual(stat.size, 1024 * 16);
111
112      fs.open(filename, 'w', function(er, fd) {
113        if (er) return cb(er);
114        fs.ftruncate(fd, 1024, function(er) {
115          if (er) return cb(er);
116          fs.stat(filename, function(er, stat) {
117            if (er) return cb(er);
118            assert.strictEqual(stat.size, 1024);
119
120            fs.ftruncate(fd, function(er) {
121              if (er) return cb(er);
122              fs.stat(filename, function(er, stat) {
123                if (er) return cb(er);
124                assert.strictEqual(stat.size, 0);
125                fs.close(fd, cb);
126              });
127            });
128          });
129        });
130      });
131    });
132  });
133}
134
135// Make sure if the size of the file is smaller than the length then it is
136// filled with zeroes.
137
138{
139  const file1 = path.resolve(tmp, 'truncate-file-1.txt');
140  fs.writeFileSync(file1, 'Hi');
141  fs.truncateSync(file1, 4);
142  assert(fs.readFileSync(file1).equals(Buffer.from('Hi\u0000\u0000')));
143}
144
145{
146  const file2 = path.resolve(tmp, 'truncate-file-2.txt');
147  fs.writeFileSync(file2, 'Hi');
148  const fd = fs.openSync(file2, 'r+');
149  process.on('beforeExit', () => fs.closeSync(fd));
150  fs.ftruncateSync(fd, 4);
151  assert(fs.readFileSync(file2).equals(Buffer.from('Hi\u0000\u0000')));
152}
153
154{
155  const file3 = path.resolve(tmp, 'truncate-file-3.txt');
156  fs.writeFileSync(file3, 'Hi');
157  fs.truncate(file3, 4, common.mustSucceed(() => {
158    assert(fs.readFileSync(file3).equals(Buffer.from('Hi\u0000\u0000')));
159  }));
160}
161
162{
163  const file4 = path.resolve(tmp, 'truncate-file-4.txt');
164  fs.writeFileSync(file4, 'Hi');
165  const fd = fs.openSync(file4, 'r+');
166  process.on('beforeExit', () => fs.closeSync(fd));
167  fs.ftruncate(fd, 4, common.mustSucceed(() => {
168    assert(fs.readFileSync(file4).equals(Buffer.from('Hi\u0000\u0000')));
169  }));
170}
171
172{
173  const file5 = path.resolve(tmp, 'truncate-file-5.txt');
174  fs.writeFileSync(file5, 'Hi');
175  const fd = fs.openSync(file5, 'r+');
176  process.on('beforeExit', () => fs.closeSync(fd));
177
178  ['', false, null, {}, []].forEach((input) => {
179    const received = common.invalidArgTypeHelper(input);
180    assert.throws(
181      () => fs.truncate(file5, input, common.mustNotCall()),
182      {
183        code: 'ERR_INVALID_ARG_TYPE',
184        name: 'TypeError',
185        message: `The "len" argument must be of type number.${received}`
186      }
187    );
188
189    assert.throws(
190      () => fs.ftruncate(fd, input),
191      {
192        code: 'ERR_INVALID_ARG_TYPE',
193        name: 'TypeError',
194        message: `The "len" argument must be of type number.${received}`
195      }
196    );
197  });
198
199  [-1.5, 1.5].forEach((input) => {
200    assert.throws(
201      () => fs.truncate(file5, input),
202      {
203        code: 'ERR_OUT_OF_RANGE',
204        name: 'RangeError',
205        message: 'The value of "len" is out of range. It must be ' +
206                  `an integer. Received ${input}`
207      }
208    );
209
210    assert.throws(
211      () => fs.ftruncate(fd, input),
212      {
213        code: 'ERR_OUT_OF_RANGE',
214        name: 'RangeError',
215        message: 'The value of "len" is out of range. It must be ' +
216                  `an integer. Received ${input}`
217      }
218    );
219  });
220
221  fs.ftruncate(fd, undefined, common.mustSucceed(() => {
222    assert(fs.readFileSync(file5).equals(Buffer.from('')));
223  }));
224}
225
226{
227  const file6 = path.resolve(tmp, 'truncate-file-6.txt');
228  fs.writeFileSync(file6, 'Hi');
229  const fd = fs.openSync(file6, 'r+');
230  process.on('beforeExit', () => fs.closeSync(fd));
231  fs.ftruncate(fd, -1, common.mustSucceed(() => {
232    assert(fs.readFileSync(file6).equals(Buffer.from('')));
233  }));
234}
235
236{
237  const file7 = path.resolve(tmp, 'truncate-file-7.txt');
238  fs.writeFileSync(file7, 'Hi');
239  fs.truncate(file7, undefined, common.mustSucceed(() => {
240    assert(fs.readFileSync(file7).equals(Buffer.from('')));
241  }));
242}
243
244{
245  const file8 = path.resolve(tmp, 'non-existent-truncate-file.txt');
246  const validateError = (err) => {
247    assert.strictEqual(file8, err.path);
248    assert.strictEqual(
249      err.message,
250      `ENOENT: no such file or directory, open '${file8}'`);
251    assert.strictEqual(err.code, 'ENOENT');
252    assert.strictEqual(err.syscall, 'open');
253    return true;
254  };
255  fs.truncate(file8, 0, common.mustCall(validateError));
256}
257
258['', false, null, {}, []].forEach((input) => {
259  assert.throws(
260    () => fs.truncate('/foo/bar', input),
261    {
262      code: 'ERR_INVALID_ARG_TYPE',
263      name: 'TypeError',
264      message: 'The "len" argument must be of type number.' +
265               common.invalidArgTypeHelper(input)
266    }
267  );
268});
269
270['', false, null, undefined, {}, []].forEach((input) => {
271  ['ftruncate', 'ftruncateSync'].forEach((fnName) => {
272    assert.throws(
273      () => fs[fnName](input),
274      {
275        code: 'ERR_INVALID_ARG_TYPE',
276        name: 'TypeError',
277        message: 'The "fd" argument must be of type number.' +
278                 common.invalidArgTypeHelper(input)
279      }
280    );
281  });
282});
283
284{
285  const file1 = path.resolve(tmp, 'truncate-file-1.txt');
286  fs.writeFileSync(file1, 'Hi');
287  fs.truncateSync(file1, -1);  // Negative coerced to 0, No error.
288  assert(fs.readFileSync(file1).equals(Buffer.alloc(0)));
289}
290
291{
292  const file1 = path.resolve(tmp, 'truncate-file-2.txt');
293  fs.writeFileSync(file1, 'Hi');
294  // Negative coerced to 0, No error.
295  fs.truncate(file1, -1, common.mustSucceed(() => {
296    assert(fs.readFileSync(file1).equals(Buffer.alloc(0)));
297  }));
298}
299