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