• 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.mustCall(function(er) {
75  assert.ifError(er);
76  testFtruncate(common.mustCall(assert.ifError));
77}));
78
79function testTruncate(cb) {
80  fs.writeFile(filename, data, function(er) {
81    if (er) return cb(er);
82    fs.stat(filename, function(er, stat) {
83      if (er) return cb(er);
84      assert.strictEqual(stat.size, 1024 * 16);
85
86      fs.truncate(filename, 1024, function(er) {
87        if (er) return cb(er);
88        fs.stat(filename, function(er, stat) {
89          if (er) return cb(er);
90          assert.strictEqual(stat.size, 1024);
91
92          fs.truncate(filename, function(er) {
93            if (er) return cb(er);
94            fs.stat(filename, function(er, stat) {
95              if (er) return cb(er);
96              assert.strictEqual(stat.size, 0);
97              cb();
98            });
99          });
100        });
101      });
102    });
103  });
104}
105
106function testFtruncate(cb) {
107  fs.writeFile(filename, data, function(er) {
108    if (er) return cb(er);
109    fs.stat(filename, function(er, stat) {
110      if (er) return cb(er);
111      assert.strictEqual(stat.size, 1024 * 16);
112
113      fs.open(filename, 'w', function(er, fd) {
114        if (er) return cb(er);
115        fs.ftruncate(fd, 1024, function(er) {
116          if (er) return cb(er);
117          fs.stat(filename, function(er, stat) {
118            if (er) return cb(er);
119            assert.strictEqual(stat.size, 1024);
120
121            fs.ftruncate(fd, function(er) {
122              if (er) return cb(er);
123              fs.stat(filename, function(er, stat) {
124                if (er) return cb(er);
125                assert.strictEqual(stat.size, 0);
126                fs.close(fd, cb);
127              });
128            });
129          });
130        });
131      });
132    });
133  });
134}
135
136// Make sure if the size of the file is smaller than the length then it is
137// filled with zeroes.
138
139{
140  const file1 = path.resolve(tmp, 'truncate-file-1.txt');
141  fs.writeFileSync(file1, 'Hi');
142  fs.truncateSync(file1, 4);
143  assert(fs.readFileSync(file1).equals(Buffer.from('Hi\u0000\u0000')));
144}
145
146{
147  const file2 = path.resolve(tmp, 'truncate-file-2.txt');
148  fs.writeFileSync(file2, 'Hi');
149  const fd = fs.openSync(file2, 'r+');
150  process.on('exit', () => fs.closeSync(fd));
151  fs.ftruncateSync(fd, 4);
152  assert(fs.readFileSync(file2).equals(Buffer.from('Hi\u0000\u0000')));
153}
154
155{
156  const file3 = path.resolve(tmp, 'truncate-file-3.txt');
157  fs.writeFileSync(file3, 'Hi');
158  fs.truncate(file3, 4, common.mustCall(function(err) {
159    assert.ifError(err);
160    assert(fs.readFileSync(file3).equals(Buffer.from('Hi\u0000\u0000')));
161  }));
162}
163
164{
165  const file4 = path.resolve(tmp, 'truncate-file-4.txt');
166  fs.writeFileSync(file4, 'Hi');
167  const fd = fs.openSync(file4, 'r+');
168  process.on('exit', () => fs.closeSync(fd));
169  fs.ftruncate(fd, 4, common.mustCall(function(err) {
170    assert.ifError(err);
171    assert(fs.readFileSync(file4).equals(Buffer.from('Hi\u0000\u0000')));
172  }));
173}
174
175{
176  const file5 = path.resolve(tmp, 'truncate-file-5.txt');
177  fs.writeFileSync(file5, 'Hi');
178  const fd = fs.openSync(file5, 'r+');
179  process.on('exit', () => fs.closeSync(fd));
180
181  ['', false, null, {}, []].forEach((input) => {
182    const received = common.invalidArgTypeHelper(input);
183    assert.throws(
184      () => fs.truncate(file5, input, common.mustNotCall()),
185      {
186        code: 'ERR_INVALID_ARG_TYPE',
187        name: 'TypeError',
188        message: `The "len" argument must be of type number.${received}`
189      }
190    );
191
192    assert.throws(
193      () => fs.ftruncate(fd, input),
194      {
195        code: 'ERR_INVALID_ARG_TYPE',
196        name: 'TypeError',
197        message: `The "len" argument must be of type number.${received}`
198      }
199    );
200  });
201
202  [-1.5, 1.5].forEach((input) => {
203    assert.throws(
204      () => fs.truncate(file5, input),
205      {
206        code: 'ERR_OUT_OF_RANGE',
207        name: 'RangeError',
208        message: 'The value of "len" is out of range. It must be ' +
209                  `an integer. Received ${input}`
210      }
211    );
212
213    assert.throws(
214      () => fs.ftruncate(fd, input),
215      {
216        code: 'ERR_OUT_OF_RANGE',
217        name: 'RangeError',
218        message: 'The value of "len" is out of range. It must be ' +
219                  `an integer. Received ${input}`
220      }
221    );
222  });
223
224  fs.ftruncate(fd, undefined, common.mustCall(function(err) {
225    assert.ifError(err);
226    assert(fs.readFileSync(file5).equals(Buffer.from('')));
227  }));
228}
229
230{
231  const file6 = path.resolve(tmp, 'truncate-file-6.txt');
232  fs.writeFileSync(file6, 'Hi');
233  const fd = fs.openSync(file6, 'r+');
234  process.on('exit', () => fs.closeSync(fd));
235  fs.ftruncate(fd, -1, common.mustCall(function(err) {
236    assert.ifError(err);
237    assert(fs.readFileSync(file6).equals(Buffer.from('')));
238  }));
239}
240
241{
242  const file7 = path.resolve(tmp, 'truncate-file-7.txt');
243  fs.writeFileSync(file7, 'Hi');
244  fs.truncate(file7, undefined, common.mustCall(function(err) {
245    assert.ifError(err);
246    assert(fs.readFileSync(file7).equals(Buffer.from('')));
247  }));
248}
249
250{
251  const file8 = path.resolve(tmp, 'non-existent-truncate-file.txt');
252  const validateError = (err) => {
253    assert.strictEqual(file8, err.path);
254    assert.strictEqual(
255      err.message,
256      `ENOENT: no such file or directory, open '${file8}'`);
257    assert.strictEqual(err.code, 'ENOENT');
258    assert.strictEqual(err.syscall, 'open');
259    return true;
260  };
261  fs.truncate(file8, 0, common.mustCall(validateError));
262}
263
264['', false, null, {}, []].forEach((input) => {
265  assert.throws(
266    () => fs.truncate('/foo/bar', input),
267    {
268      code: 'ERR_INVALID_ARG_TYPE',
269      name: 'TypeError',
270      message: 'The "len" argument must be of type number.' +
271               common.invalidArgTypeHelper(input)
272    }
273  );
274});
275
276['', false, null, undefined, {}, []].forEach((input) => {
277  ['ftruncate', 'ftruncateSync'].forEach((fnName) => {
278    assert.throws(
279      () => fs[fnName](input),
280      {
281        code: 'ERR_INVALID_ARG_TYPE',
282        name: 'TypeError',
283        message: 'The "fd" argument must be of type number.' +
284                 common.invalidArgTypeHelper(input)
285      }
286    );
287  });
288});
289