aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMichaël Zasso <targos@protonmail.com>2018-02-14 09:57:42 +0100
committerMichaël Zasso <targos@protonmail.com>2018-02-17 10:09:22 +0100
commit2620358624b6c0f6c7d02dc2e4333eae9e73b3ea (patch)
tree641d4b7e2a1202e78674e64f000a90e289817a12 /lib
parent6c9774fd94173ee29921f65d42880d1344ee027b (diff)
downloadandroid-node-v8-2620358624b6c0f6c7d02dc2e4333eae9e73b3ea.tar.gz
android-node-v8-2620358624b6c0f6c7d02dc2e4333eae9e73b3ea.tar.bz2
android-node-v8-2620358624b6c0f6c7d02dc2e4333eae9e73b3ea.zip
fs: move utility functions to internal/fs
PR-URL: https://github.com/nodejs/node/pull/18777 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/fs.js309
-rw-r--r--lib/internal/fs.js325
2 files changed, 340 insertions, 294 deletions
diff --git a/lib/fs.js b/lib/fs.js
index e762f90d96..f787037629 100644
--- a/lib/fs.js
+++ b/lib/fs.js
@@ -37,14 +37,29 @@ const { Buffer } = require('buffer');
const errors = require('internal/errors');
const { Readable, Writable } = require('stream');
const EventEmitter = require('events');
-const { FSReqWrap } = binding;
+const { FSReqWrap, statValues } = binding;
const { FSEvent } = process.binding('fs_event_wrap');
const internalFS = require('internal/fs');
const { getPathFromURL } = require('internal/url');
const internalUtil = require('internal/util');
const {
- assertEncoding,
- stringToFlags
+ copyObject,
+ getOptions,
+ isUint32,
+ modeNum,
+ nullCheck,
+ preprocessSymlinkDestination,
+ Stats,
+ statsFromValues,
+ stringToFlags,
+ stringToSymlinkType,
+ toUnixTimestamp,
+ validateBuffer,
+ validateLen,
+ validateOffsetLengthRead,
+ validateOffsetLengthWrite,
+ validatePath,
+ validateUint32
} = internalFS;
const {
CHAR_FORWARD_SLASH,
@@ -70,9 +85,6 @@ const errnoException = errors.errnoException;
let truncateWarn = true;
-function isInt32(n) { return n === (n | 0); }
-function isUint32(n) { return n === (n >>> 0); }
-
function showTruncateDeprecation() {
if (truncateWarn) {
process.emitWarning(
@@ -83,35 +95,6 @@ function showTruncateDeprecation() {
}
}
-function getOptions(options, defaultOptions) {
- if (options === null || options === undefined ||
- typeof options === 'function') {
- return defaultOptions;
- }
-
- if (typeof options === 'string') {
- defaultOptions = util._extend({}, defaultOptions);
- defaultOptions.encoding = options;
- options = defaultOptions;
- } else if (typeof options !== 'object') {
- throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
- 'options',
- ['string', 'Object'],
- options);
- }
-
- if (options.encoding !== 'buffer')
- assertEncoding(options.encoding);
- return options;
-}
-
-function copyObject(source) {
- var target = {};
- for (var key in source)
- target[key] = source[key];
- return target;
-}
-
function handleErrorFromBinding(ctx) {
if (ctx.errno !== undefined) { // libuv error numbers
const err = errors.uvException(ctx);
@@ -175,117 +158,6 @@ function makeCallback(cb) {
};
}
-function validateBuffer(buffer) {
- if (!isUint8Array(buffer)) {
- const err = new errors.TypeError('ERR_INVALID_ARG_TYPE', 'buffer',
- ['Buffer', 'Uint8Array']);
- Error.captureStackTrace(err, validateBuffer);
- throw err;
- }
-}
-
-function validateLen(len) {
- let err;
-
- if (!isInt32(len))
- err = new errors.TypeError('ERR_INVALID_ARG_TYPE', 'len', 'integer');
-
- if (err !== undefined) {
- Error.captureStackTrace(err, validateLen);
- throw err;
- }
-}
-
-function validateOffsetLengthRead(offset, length, bufferLength) {
- let err;
-
- if (offset < 0 || offset >= bufferLength) {
- err = new errors.RangeError('ERR_OUT_OF_RANGE', 'offset');
- } else if (length < 0 || offset + length > bufferLength) {
- err = new errors.RangeError('ERR_OUT_OF_RANGE', 'length');
- }
-
- if (err !== undefined) {
- Error.captureStackTrace(err, validateOffsetLengthRead);
- throw err;
- }
-}
-
-function validateOffsetLengthWrite(offset, length, byteLength) {
- let err;
-
- if (offset > byteLength) {
- err = new errors.RangeError('ERR_OUT_OF_RANGE', 'offset');
- } else if (offset + length > byteLength || offset + length > kMaxLength) {
- err = new errors.RangeError('ERR_OUT_OF_RANGE', 'length');
- }
-
- if (err !== undefined) {
- Error.captureStackTrace(err, validateOffsetLengthWrite);
- throw err;
- }
-}
-
-// Check if the path contains null types if it is a string nor Uint8Array,
-// otherwise return silently.
-function nullCheck(path, propName, throwError = true) {
- const pathIsString = typeof path === 'string';
- const pathIsUint8Array = isUint8Array(path);
-
- // We can only perform meaningful checks on strings and Uint8Arrays.
- if (!pathIsString && !pathIsUint8Array) {
- return;
- }
-
- if (pathIsString && path.indexOf('\u0000') === -1) {
- return;
- } else if (pathIsUint8Array && path.indexOf(0) === -1) {
- return;
- }
-
- const err = new errors.Error(
- 'ERR_INVALID_ARG_VALUE', propName, path,
- 'must be a string or Uint8Array without null bytes');
-
- if (throwError) {
- Error.captureStackTrace(err, nullCheck);
- throw err;
- }
- return err;
-}
-
-function validatePath(path, propName) {
- let err;
-
- if (propName === undefined) {
- propName = 'path';
- }
-
- if (typeof path !== 'string' && !isUint8Array(path)) {
- err = new errors.TypeError('ERR_INVALID_ARG_TYPE', propName,
- ['string', 'Buffer', 'URL']);
- } else {
- err = nullCheck(path, propName, false);
- }
-
- if (err !== undefined) {
- Error.captureStackTrace(err, validatePath);
- throw err;
- }
-}
-
-function validateUint32(value, propName) {
- let err;
-
- if (!isUint32(value))
- err = new errors.TypeError('ERR_INVALID_ARG_TYPE', propName, 'integer');
-
- if (err !== undefined) {
- Error.captureStackTrace(err, validateUint32);
- throw err;
- }
-}
-
// Special case of `makeCallback()` that is specific to async `*stat()` calls as
// an optimization, since the data passed back to the callback needs to be
// transformed anyway.
@@ -308,85 +180,8 @@ function isFd(path) {
return (path >>> 0) === path;
}
-// Constructor for file stats.
-function Stats(
- dev,
- mode,
- nlink,
- uid,
- gid,
- rdev,
- blksize,
- ino,
- size,
- blocks,
- atim_msec,
- mtim_msec,
- ctim_msec,
- birthtim_msec
-) {
- this.dev = dev;
- this.mode = mode;
- this.nlink = nlink;
- this.uid = uid;
- this.gid = gid;
- this.rdev = rdev;
- this.blksize = blksize;
- this.ino = ino;
- this.size = size;
- this.blocks = blocks;
- this.atimeMs = atim_msec;
- this.mtimeMs = mtim_msec;
- this.ctimeMs = ctim_msec;
- this.birthtimeMs = birthtim_msec;
- this.atime = new Date(atim_msec + 0.5);
- this.mtime = new Date(mtim_msec + 0.5);
- this.ctime = new Date(ctim_msec + 0.5);
- this.birthtime = new Date(birthtim_msec + 0.5);
-}
fs.Stats = Stats;
-Stats.prototype._checkModeProperty = function(property) {
- return ((this.mode & S_IFMT) === property);
-};
-
-Stats.prototype.isDirectory = function() {
- return this._checkModeProperty(constants.S_IFDIR);
-};
-
-Stats.prototype.isFile = function() {
- return this._checkModeProperty(S_IFREG);
-};
-
-Stats.prototype.isBlockDevice = function() {
- return this._checkModeProperty(constants.S_IFBLK);
-};
-
-Stats.prototype.isCharacterDevice = function() {
- return this._checkModeProperty(constants.S_IFCHR);
-};
-
-Stats.prototype.isSymbolicLink = function() {
- return this._checkModeProperty(S_IFLNK);
-};
-
-Stats.prototype.isFIFO = function() {
- return this._checkModeProperty(S_IFIFO);
-};
-
-Stats.prototype.isSocket = function() {
- return this._checkModeProperty(S_IFSOCK);
-};
-
-const statValues = binding.statValues;
-
-function statsFromValues(stats = statValues) {
- return new Stats(stats[0], stats[1], stats[2], stats[3], stats[4], stats[5],
- stats[6] < 0 ? undefined : stats[6], stats[7], stats[8],
- stats[9] < 0 ? undefined : stats[9], stats[10], stats[11],
- stats[12], stats[13]);
-}
-
// Don't allow mode to accidentally be overwritten.
Object.defineProperties(fs, {
F_OK: { enumerable: true, value: constants.F_OK || 0 },
@@ -760,16 +555,6 @@ fs.closeSync = function(fd) {
handleErrorFromBinding(ctx);
};
-function modeNum(m, def) {
- if (typeof m === 'number')
- return m;
- if (typeof m === 'string')
- return parseInt(m, 8);
- if (def)
- return modeNum(def);
- return undefined;
-}
-
fs.open = function(path, flags, mode, callback_) {
var callback = makeCallback(arguments[arguments.length - 1]);
mode = modeNum(mode, 0o666);
@@ -1162,42 +947,6 @@ fs.readlinkSync = function(path, options) {
return result;
};
-function preprocessSymlinkDestination(path, type, linkPath) {
- if (!isWindows) {
- // No preprocessing is needed on Unix.
- return path;
- } else if (type === 'junction') {
- // Junctions paths need to be absolute and \\?\-prefixed.
- // A relative target is relative to the link's parent directory.
- path = pathModule.resolve(linkPath, '..', path);
- return pathModule.toNamespacedPath(path);
- } else {
- // Windows symlinks don't tolerate forward slashes.
- return ('' + path).replace(/\//g, '\\');
- }
-}
-
-function stringToSymlinkType(type) {
- let flags = 0;
- if (typeof type === 'string') {
- switch (type) {
- case 'dir':
- flags |= constants.UV_FS_SYMLINK_DIR;
- break;
- case 'junction':
- flags |= constants.UV_FS_SYMLINK_JUNCTION;
- break;
- case 'file':
- break;
- default:
- const err = new errors.Error('ERR_FS_INVALID_SYMLINK_TYPE', type);
- Error.captureStackTrace(err, stringToSymlinkType);
- throw err;
- }
- }
- return flags;
-}
-
fs.symlink = function(target, path, type_, callback_) {
var type = (typeof type_ === 'string' ? type_ : null);
var callback = makeCallback(arguments[arguments.length - 1]);
@@ -1421,28 +1170,6 @@ fs.chownSync = function(path, uid, gid) {
return binding.chown(pathModule.toNamespacedPath(path), uid, gid);
};
-// converts Date or number to a fractional UNIX timestamp
-function toUnixTimestamp(time, name = 'time') {
- // eslint-disable-next-line eqeqeq
- if (typeof time === 'string' && +time == time) {
- return +time;
- }
- if (Number.isFinite(time)) {
- if (time < 0) {
- return Date.now() / 1000;
- }
- return time;
- }
- if (util.isDate(time)) {
- // convert to 123.456 UNIX timestamp
- return time.getTime() / 1000;
- }
- throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
- name,
- ['Date', 'Time in seconds'],
- time);
-}
-
// exported for unit tests, not for public consumption
fs._toUnixTimestamp = toUnixTimestamp;
diff --git a/lib/internal/fs.js b/lib/internal/fs.js
index 01c5ff4bfc..9c5c4d8ad7 100644
--- a/lib/internal/fs.js
+++ b/lib/internal/fs.js
@@ -1,9 +1,11 @@
'use strict';
-const { Buffer } = require('buffer');
+const { Buffer, kMaxLength } = require('buffer');
const { Writable } = require('stream');
const errors = require('internal/errors');
+const { isUint8Array } = require('internal/util/types');
const fs = require('fs');
+const pathModule = require('path');
const util = require('util');
const {
@@ -14,8 +16,21 @@ const {
O_RDWR,
O_SYNC,
O_TRUNC,
- O_WRONLY
+ O_WRONLY,
+ S_IFBLK,
+ S_IFCHR,
+ S_IFDIR,
+ S_IFIFO,
+ S_IFLNK,
+ S_IFMT,
+ S_IFREG,
+ S_IFSOCK,
+ UV_FS_SYMLINK_DIR,
+ UV_FS_SYMLINK_JUNCTION
} = process.binding('constants').fs;
+const { statValues } = process.binding('fs');
+
+const isWindows = process.platform === 'win32';
function assertEncoding(encoding) {
if (encoding && !Buffer.isEncoding(encoding)) {
@@ -23,6 +38,167 @@ function assertEncoding(encoding) {
}
}
+function copyObject(source) {
+ var target = {};
+ for (var key in source)
+ target[key] = source[key];
+ return target;
+}
+
+function getOptions(options, defaultOptions) {
+ if (options === null || options === undefined ||
+ typeof options === 'function') {
+ return defaultOptions;
+ }
+
+ if (typeof options === 'string') {
+ defaultOptions = util._extend({}, defaultOptions);
+ defaultOptions.encoding = options;
+ options = defaultOptions;
+ } else if (typeof options !== 'object') {
+ throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
+ 'options',
+ ['string', 'Object'],
+ options);
+ }
+
+ if (options.encoding !== 'buffer')
+ assertEncoding(options.encoding);
+ return options;
+}
+
+function isInt32(n) { return n === (n | 0); }
+function isUint32(n) { return n === (n >>> 0); }
+
+function modeNum(m, def) {
+ if (typeof m === 'number')
+ return m;
+ if (typeof m === 'string')
+ return parseInt(m, 8);
+ if (def)
+ return modeNum(def);
+ return undefined;
+}
+
+// Check if the path contains null types if it is a string nor Uint8Array,
+// otherwise return silently.
+function nullCheck(path, propName, throwError = true) {
+ const pathIsString = typeof path === 'string';
+ const pathIsUint8Array = isUint8Array(path);
+
+ // We can only perform meaningful checks on strings and Uint8Arrays.
+ if (!pathIsString && !pathIsUint8Array) {
+ return;
+ }
+
+ if (pathIsString && path.indexOf('\u0000') === -1) {
+ return;
+ } else if (pathIsUint8Array && path.indexOf(0) === -1) {
+ return;
+ }
+
+ const err = new errors.Error(
+ 'ERR_INVALID_ARG_VALUE', propName, path,
+ 'must be a string or Uint8Array without null bytes');
+
+ if (throwError) {
+ Error.captureStackTrace(err, nullCheck);
+ throw err;
+ }
+ return err;
+}
+
+function preprocessSymlinkDestination(path, type, linkPath) {
+ if (!isWindows) {
+ // No preprocessing is needed on Unix.
+ return path;
+ } else if (type === 'junction') {
+ // Junctions paths need to be absolute and \\?\-prefixed.
+ // A relative target is relative to the link's parent directory.
+ path = pathModule.resolve(linkPath, '..', path);
+ return pathModule.toNamespacedPath(path);
+ } else {
+ // Windows symlinks don't tolerate forward slashes.
+ return ('' + path).replace(/\//g, '\\');
+ }
+}
+
+// Constructor for file stats.
+function Stats(
+ dev,
+ mode,
+ nlink,
+ uid,
+ gid,
+ rdev,
+ blksize,
+ ino,
+ size,
+ blocks,
+ atim_msec,
+ mtim_msec,
+ ctim_msec,
+ birthtim_msec
+) {
+ this.dev = dev;
+ this.mode = mode;
+ this.nlink = nlink;
+ this.uid = uid;
+ this.gid = gid;
+ this.rdev = rdev;
+ this.blksize = blksize;
+ this.ino = ino;
+ this.size = size;
+ this.blocks = blocks;
+ this.atimeMs = atim_msec;
+ this.mtimeMs = mtim_msec;
+ this.ctimeMs = ctim_msec;
+ this.birthtimeMs = birthtim_msec;
+ this.atime = new Date(atim_msec + 0.5);
+ this.mtime = new Date(mtim_msec + 0.5);
+ this.ctime = new Date(ctim_msec + 0.5);
+ this.birthtime = new Date(birthtim_msec + 0.5);
+}
+
+Stats.prototype._checkModeProperty = function(property) {
+ return ((this.mode & S_IFMT) === property);
+};
+
+Stats.prototype.isDirectory = function() {
+ return this._checkModeProperty(S_IFDIR);
+};
+
+Stats.prototype.isFile = function() {
+ return this._checkModeProperty(S_IFREG);
+};
+
+Stats.prototype.isBlockDevice = function() {
+ return this._checkModeProperty(S_IFBLK);
+};
+
+Stats.prototype.isCharacterDevice = function() {
+ return this._checkModeProperty(S_IFCHR);
+};
+
+Stats.prototype.isSymbolicLink = function() {
+ return this._checkModeProperty(S_IFLNK);
+};
+
+Stats.prototype.isFIFO = function() {
+ return this._checkModeProperty(S_IFIFO);
+};
+
+Stats.prototype.isSocket = function() {
+ return this._checkModeProperty(S_IFSOCK);
+};
+
+function statsFromValues(stats = statValues) {
+ return new Stats(stats[0], stats[1], stats[2], stats[3], stats[4], stats[5],
+ stats[6] < 0 ? undefined : stats[6], stats[7], stats[8],
+ stats[9] < 0 ? undefined : stats[9], stats[10], stats[11],
+ stats[12], stats[13]);
+}
+
function stringToFlags(flags) {
if (typeof flags === 'number') {
return flags;
@@ -56,6 +232,27 @@ function stringToFlags(flags) {
throw new errors.TypeError('ERR_INVALID_OPT_VALUE', 'flags', flags);
}
+function stringToSymlinkType(type) {
+ let flags = 0;
+ if (typeof type === 'string') {
+ switch (type) {
+ case 'dir':
+ flags |= UV_FS_SYMLINK_DIR;
+ break;
+ case 'junction':
+ flags |= UV_FS_SYMLINK_JUNCTION;
+ break;
+ case 'file':
+ break;
+ default:
+ const err = new errors.Error('ERR_FS_INVALID_SYMLINK_TYPE', type);
+ Error.captureStackTrace(err, stringToSymlinkType);
+ throw err;
+ }
+ }
+ return flags;
+}
+
// Temporary hack for process.stdout and process.stderr when piped to files.
function SyncWriteStream(fd, options) {
Writable.call(this);
@@ -95,9 +292,131 @@ SyncWriteStream.prototype.destroy = function() {
return true;
};
+// converts Date or number to a fractional UNIX timestamp
+function toUnixTimestamp(time, name = 'time') {
+ // eslint-disable-next-line eqeqeq
+ if (typeof time === 'string' && +time == time) {
+ return +time;
+ }
+ if (Number.isFinite(time)) {
+ if (time < 0) {
+ return Date.now() / 1000;
+ }
+ return time;
+ }
+ if (util.isDate(time)) {
+ // convert to 123.456 UNIX timestamp
+ return time.getTime() / 1000;
+ }
+ throw new errors.TypeError('ERR_INVALID_ARG_TYPE',
+ name,
+ ['Date', 'Time in seconds'],
+ time);
+}
+
+function validateBuffer(buffer) {
+ if (!isUint8Array(buffer)) {
+ const err = new errors.TypeError('ERR_INVALID_ARG_TYPE', 'buffer',
+ ['Buffer', 'Uint8Array']);
+ Error.captureStackTrace(err, validateBuffer);
+ throw err;
+ }
+}
+
+function validateLen(len) {
+ let err;
+
+ if (!isInt32(len))
+ err = new errors.TypeError('ERR_INVALID_ARG_TYPE', 'len', 'integer');
+
+ if (err !== undefined) {
+ Error.captureStackTrace(err, validateLen);
+ throw err;
+ }
+}
+
+function validateOffsetLengthRead(offset, length, bufferLength) {
+ let err;
+
+ if (offset < 0 || offset >= bufferLength) {
+ err = new errors.RangeError('ERR_OUT_OF_RANGE', 'offset');
+ } else if (length < 0 || offset + length > bufferLength) {
+ err = new errors.RangeError('ERR_OUT_OF_RANGE', 'length');
+ }
+
+ if (err !== undefined) {
+ Error.captureStackTrace(err, validateOffsetLengthRead);
+ throw err;
+ }
+}
+
+function validateOffsetLengthWrite(offset, length, byteLength) {
+ let err;
+
+ if (offset > byteLength) {
+ err = new errors.RangeError('ERR_OUT_OF_RANGE', 'offset');
+ } else if (offset + length > byteLength || offset + length > kMaxLength) {
+ err = new errors.RangeError('ERR_OUT_OF_RANGE', 'length');
+ }
+
+ if (err !== undefined) {
+ Error.captureStackTrace(err, validateOffsetLengthWrite);
+ throw err;
+ }
+}
+
+function validatePath(path, propName) {
+ let err;
+
+ if (propName === undefined) {
+ propName = 'path';
+ }
+
+ if (typeof path !== 'string' && !isUint8Array(path)) {
+ err = new errors.TypeError('ERR_INVALID_ARG_TYPE', propName,
+ ['string', 'Buffer', 'URL']);
+ } else {
+ err = nullCheck(path, propName, false);
+ }
+
+ if (err !== undefined) {
+ Error.captureStackTrace(err, validatePath);
+ throw err;
+ }
+}
+
+function validateUint32(value, propName) {
+ let err;
+
+ if (!isUint32(value))
+ err = new errors.TypeError('ERR_INVALID_ARG_TYPE', propName, 'integer');
+
+ if (err !== undefined) {
+ Error.captureStackTrace(err, validateUint32);
+ throw err;
+ }
+}
+
module.exports = {
assertEncoding,
+ copyObject,
+ getOptions,
+ isInt32,
+ isUint32,
+ modeNum,
+ nullCheck,
+ preprocessSymlinkDestination,
+ realpathCacheKey: Symbol('realpathCacheKey'),
+ statsFromValues,
stringToFlags,
+ stringToSymlinkType,
+ Stats,
SyncWriteStream,
- realpathCacheKey: Symbol('realpathCacheKey')
+ toUnixTimestamp,
+ validateBuffer,
+ validateLen,
+ validateOffsetLengthRead,
+ validateOffsetLengthWrite,
+ validatePath,
+ validateUint32
};