@@ -81,6 +81,16 @@ function throwOptionsError(options) {
8181 'but got ' + typeof options + ' instead' ) ;
8282}
8383
84+ function isFD ( fd ) {
85+ return Number . isInteger ( fd ) && fd >= 0 && fd <= 0xFFFFFFFF ;
86+ }
87+
88+ function sanitizeFD ( fd ) {
89+ if ( ! isFD ( fd ) )
90+ throw new TypeError ( 'file descriptor must be a unsigned 32-bit integer' ) ;
91+ return fd ;
92+ }
93+
8494// Ensure that callbacks run in the global context. Only use this function
8595// for callbacks that are passed to the binding layer, callbacks that are
8696// invoked from JS already run in the proper scope.
@@ -112,10 +122,6 @@ function nullCheck(path, callback) {
112122 return true ;
113123}
114124
115- function isFd ( path ) {
116- return ( path >>> 0 ) === path ;
117- }
118-
119125// Static method to set the stats properties on a Stats object.
120126fs . Stats = function (
121127 dev ,
@@ -257,7 +263,7 @@ fs.readFile = function(path, options, callback) {
257263 return ;
258264
259265 var context = new ReadFileContext ( callback , encoding ) ;
260- context . isUserFd = isFd ( path ) ; // file descriptor ownership
266+ context . isUserFd = isFD ( path ) ; // file descriptor ownership
261267 var req = new FSReqWrap ( ) ;
262268 req . context = context ;
263269 req . oncomplete = readFileAfterOpen ;
@@ -473,7 +479,7 @@ fs.readFileSync = function(path, options) {
473479 assertEncoding ( encoding ) ;
474480
475481 var flag = options . flag || 'r' ;
476- var isUserFd = isFd ( path ) ; // file descriptor ownership
482+ var isUserFd = isFD ( path ) ; // file descriptor ownership
477483 var fd = isUserFd ? path : fs . openSync ( path , flag , 0o666 ) ;
478484
479485 var st = tryStatSync ( fd , isUserFd ) ;
@@ -570,12 +576,12 @@ Object.defineProperty(exports, '_stringToFlags', {
570576
571577fs . close = function ( fd , callback ) {
572578 var req = new FSReqWrap ( ) ;
573- req . oncomplete = makeCallback ( arguments [ arguments . length - 1 ] ) ;
574- binding . close ( fd , req ) ;
579+ req . oncomplete = makeCallback ( callback ) ;
580+ binding . close ( sanitizeFD ( fd ) , req ) ;
575581} ;
576582
577583fs . closeSync = function ( fd ) {
578- return binding . close ( fd ) ;
584+ return binding . close ( sanitizeFD ( fd ) ) ;
579585} ;
580586
581587function modeNum ( m , def ) {
@@ -612,6 +618,7 @@ fs.openSync = function(path, flags, mode) {
612618var readWarned = false ;
613619fs . read = function ( fd , buffer , offset , length , position , callback ) {
614620 callback = makeCallback ( arguments [ arguments . length - 1 ] ) ;
621+ fd = sanitizeFD ( fd ) ;
615622 if ( ! ( buffer instanceof Buffer ) ) {
616623 // legacy string interface (fd, length, position, encoding, callback)
617624 readWarned = printDeprecation ( 'fs.read\'s legacy String interface ' +
@@ -672,6 +679,7 @@ fs.readSync = function(fd, buffer, offset, length, position) {
672679 var legacy = false ;
673680 var encoding ;
674681
682+ fd = sanitizeFD ( fd ) ;
675683 if ( ! ( buffer instanceof Buffer ) ) {
676684 // legacy string interface (fd, length, position, encoding, callback)
677685 readSyncWarned = printDeprecation ( 'fs.readSync\'s legacy String interface' +
@@ -713,6 +721,7 @@ fs.readSync = function(fd, buffer, offset, length, position) {
713721// fs.write(fd, string[, position[, encoding]], callback);
714722fs . write = function ( fd , buffer , offset , length , position , callback ) {
715723 callback = makeCallback ( arguments [ arguments . length - 1 ] ) ;
724+ fd = sanitizeFD ( fd ) ;
716725 function wrapper ( err , written ) {
717726 // Retain a reference to buffer so that it can't be GC'ed too soon.
718727 callback ( err , written || 0 , buffer ) ;
@@ -748,6 +757,7 @@ fs.write = function(fd, buffer, offset, length, position, callback) {
748757// OR
749758// fs.writeSync(fd, string[, position[, encoding]]);
750759fs . writeSync = function ( fd , buffer , offset , length , position ) {
760+ fd = sanitizeFD ( fd ) ;
751761 if ( buffer instanceof Buffer ) {
752762 if ( position === undefined )
753763 position = null ;
@@ -779,14 +789,18 @@ fs.renameSync = function(oldPath, newPath) {
779789} ;
780790
781791fs . truncate = function ( path , len , callback ) {
782- if ( typeof path === 'number' ) {
792+ callback = makeCallback ( arguments [ arguments . length - 1 ] ) ;
793+
794+ if ( isFD ( path ) )
783795 return fs . ftruncate ( path , len , callback ) ;
784- }
785796
786- callback = makeCallback ( arguments [ arguments . length - 1 ] ) ;
797+ if ( typeof path !== 'string' )
798+ throw new TypeError ( 'path must be a string' ) ;
787799
788- if ( typeof len === 'function' || len === undefined ) {
800+ if ( typeof len === 'function' || len == undefined ) {
789801 len = 0 ;
802+ } else if ( ! Number . isInteger ( len ) || len < 0 ) {
803+ throw new TypeError ( 'length must be a positive integer' ) ;
790804 }
791805
792806 fs . open ( path , 'r+' , function ( er , fd ) {
@@ -802,13 +816,18 @@ fs.truncate = function(path, len, callback) {
802816} ;
803817
804818fs . truncateSync = function ( path , len ) {
805- if ( typeof path === 'number' ) {
806- // legacy
819+ if ( isFD ( path ) )
807820 return fs . ftruncateSync ( path , len ) ;
808- }
809- if ( len === undefined ) {
821+
822+ if ( typeof path !== 'string' )
823+ throw new TypeError ( 'path must be a string' ) ;
824+
825+ if ( len === undefined || len === null ) {
810826 len = 0 ;
827+ } else if ( ! Number . isInteger ( len ) || len < 0 ) {
828+ throw new TypeError ( 'length must be a positive integer' ) ;
811829 }
830+
812831 // allow error to be thrown, but still close fd.
813832 var fd = fs . openSync ( path , 'r+' ) ;
814833 var ret ;
@@ -822,18 +841,30 @@ fs.truncateSync = function(path, len) {
822841} ;
823842
824843fs . ftruncate = function ( fd , len , callback ) {
825- if ( typeof len === 'function' || len === undefined ) {
844+ callback = makeCallback ( arguments [ arguments . length - 1 ] ) ;
845+
846+ fd = sanitizeFD ( fd ) ;
847+
848+ if ( typeof len === 'function' || len == undefined ) {
826849 len = 0 ;
850+ } else if ( ! Number . isInteger ( len ) || len < 0 ) {
851+ throw new TypeError ( 'length must be a positive integer' ) ;
827852 }
853+
828854 var req = new FSReqWrap ( ) ;
829- req . oncomplete = makeCallback ( arguments [ arguments . length - 1 ] ) ;
855+ req . oncomplete = callback ;
830856 binding . ftruncate ( fd , len , req ) ;
831857} ;
832858
833859fs . ftruncateSync = function ( fd , len ) {
834- if ( len === undefined ) {
860+ fd = sanitizeFD ( fd ) ;
861+
862+ if ( len === undefined || len === null ) {
835863 len = 0 ;
864+ } else if ( ! Number . isInteger ( len ) || len < 0 ) {
865+ throw new TypeError ( 'length must be a positive integer' ) ;
836866 }
867+
837868 return binding . ftruncate ( fd , len ) ;
838869} ;
839870
@@ -853,21 +884,21 @@ fs.rmdirSync = function(path) {
853884fs . fdatasync = function ( fd , callback ) {
854885 var req = new FSReqWrap ( ) ;
855886 req . oncomplete = makeCallback ( callback ) ;
856- binding . fdatasync ( fd , req ) ;
887+ binding . fdatasync ( sanitizeFD ( fd ) , req ) ;
857888} ;
858889
859890fs . fdatasyncSync = function ( fd ) {
860- return binding . fdatasync ( fd ) ;
891+ return binding . fdatasync ( sanitizeFD ( fd ) ) ;
861892} ;
862893
863894fs . fsync = function ( fd , callback ) {
864895 var req = new FSReqWrap ( ) ;
865- req . oncomplete = makeCallback ( arguments [ arguments . length - 1 ] ) ;
866- binding . fsync ( fd , req ) ;
896+ req . oncomplete = makeCallback ( callback ) ;
897+ binding . fsync ( sanitizeFD ( fd ) , req ) ;
867898} ;
868899
869900fs . fsyncSync = function ( fd ) {
870- return binding . fsync ( fd ) ;
901+ return binding . fsync ( sanitizeFD ( fd ) ) ;
871902} ;
872903
873904fs . mkdir = function ( path , mode , callback ) {
@@ -915,8 +946,8 @@ fs.readdirSync = function(path, options) {
915946
916947fs . fstat = function ( fd , callback ) {
917948 var req = new FSReqWrap ( ) ;
918- req . oncomplete = makeCallback ( arguments [ arguments . length - 1 ] ) ;
919- binding . fstat ( fd , req ) ;
949+ req . oncomplete = makeCallback ( callback ) ;
950+ binding . fstat ( sanitizeFD ( fd ) , req ) ;
920951} ;
921952
922953fs . lstat = function ( path , callback ) {
@@ -936,7 +967,7 @@ fs.stat = function(path, callback) {
936967} ;
937968
938969fs . fstatSync = function ( fd ) {
939- return binding . fstat ( fd ) ;
970+ return binding . fstat ( sanitizeFD ( fd ) ) ;
940971} ;
941972
942973fs . lstatSync = function ( path ) {
@@ -1053,11 +1084,11 @@ fs.unlinkSync = function(path) {
10531084fs . fchmod = function ( fd , mode , callback ) {
10541085 var req = new FSReqWrap ( ) ;
10551086 req . oncomplete = makeCallback ( arguments [ arguments . length - 1 ] ) ;
1056- binding . fchmod ( fd , modeNum ( mode ) , req ) ;
1087+ binding . fchmod ( sanitizeFD ( fd ) , modeNum ( mode ) , req ) ;
10571088} ;
10581089
10591090fs . fchmodSync = function ( fd , mode ) {
1060- return binding . fchmod ( fd , modeNum ( mode ) ) ;
1091+ return binding . fchmod ( sanitizeFD ( fd ) , modeNum ( mode ) ) ;
10611092} ;
10621093
10631094if ( constants . hasOwnProperty ( 'O_SYMLINK' ) ) {
@@ -1136,11 +1167,11 @@ if (constants.hasOwnProperty('O_SYMLINK')) {
11361167fs . fchown = function ( fd , uid , gid , callback ) {
11371168 var req = new FSReqWrap ( ) ;
11381169 req . oncomplete = makeCallback ( arguments [ arguments . length - 1 ] ) ;
1139- binding . fchown ( fd , uid , gid , req ) ;
1170+ binding . fchown ( sanitizeFD ( fd ) , uid , gid , req ) ;
11401171} ;
11411172
11421173fs . fchownSync = function ( fd , uid , gid ) {
1143- return binding . fchown ( fd , uid , gid ) ;
1174+ return binding . fchown ( sanitizeFD ( fd ) , uid , gid ) ;
11441175} ;
11451176
11461177fs . chown = function ( path , uid , gid , callback ) {
@@ -1197,6 +1228,7 @@ fs.utimesSync = function(path, atime, mtime) {
11971228
11981229fs . futimes = function ( fd , atime , mtime , callback ) {
11991230 callback = makeCallback ( arguments [ arguments . length - 1 ] ) ;
1231+ fd = sanitizeFD ( fd ) ;
12001232 atime = toUnixTimestamp ( atime ) ;
12011233 mtime = toUnixTimestamp ( mtime ) ;
12021234 var req = new FSReqWrap ( ) ;
@@ -1205,6 +1237,7 @@ fs.futimes = function(fd, atime, mtime, callback) {
12051237} ;
12061238
12071239fs . futimesSync = function ( fd , atime , mtime ) {
1240+ fd = sanitizeFD ( fd ) ;
12081241 atime = toUnixTimestamp ( atime ) ;
12091242 mtime = toUnixTimestamp ( mtime ) ;
12101243 binding . futimes ( fd , atime , mtime ) ;
@@ -1257,7 +1290,7 @@ fs.writeFile = function(path, data, options, callback) {
12571290
12581291 var flag = options . flag || 'w' ;
12591292
1260- if ( isFd ( path ) ) {
1293+ if ( isFD ( path ) ) {
12611294 writeFd ( path , true ) ;
12621295 return ;
12631296 }
@@ -1291,7 +1324,7 @@ fs.writeFileSync = function(path, data, options) {
12911324 assertEncoding ( options . encoding ) ;
12921325
12931326 var flag = options . flag || 'w' ;
1294- var isUserFd = isFd ( path ) ; // file descriptor ownership
1327+ var isUserFd = isFD ( path ) ; // file descriptor ownership
12951328 var fd = isUserFd ? path : fs . openSync ( path , flag , options . mode ) ;
12961329
12971330 if ( ! ( data instanceof Buffer ) ) {
@@ -1329,7 +1362,7 @@ fs.appendFile = function(path, data, options, callback) {
13291362 options = util . _extend ( { flag : 'a' } , options ) ;
13301363
13311364 // force append behavior when using a supplied file descriptor
1332- if ( isFd ( path ) )
1365+ if ( isFD ( path ) )
13331366 options . flag = 'a' ;
13341367
13351368 fs . writeFile ( path , data , options , callback ) ;
@@ -1348,7 +1381,7 @@ fs.appendFileSync = function(path, data, options) {
13481381 options = util . _extend ( { flag : 'a' } , options ) ;
13491382
13501383 // force append behavior when using a supplied file descriptor
1351- if ( isFd ( path ) )
1384+ if ( isFD ( path ) )
13521385 options . flag = 'a' ;
13531386
13541387 fs . writeFileSync ( path , data , options ) ;
@@ -1932,7 +1965,7 @@ function SyncWriteStream(fd, options) {
19321965
19331966 options = options || { } ;
19341967
1935- this . fd = fd ;
1968+ this . fd = sanitizeFD ( fd ) ;
19361969 this . writable = true ;
19371970 this . readable = false ;
19381971 this . autoClose = options . autoClose === undefined ? true : options . autoClose ;
0 commit comments