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