2017-01-03 22:16:48 +01:00
|
|
|
// Copyright Joyent, Inc. and other Node contributors.
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
// copy of this software and associated documentation files (the
|
|
|
|
// "Software"), to deal in the Software without restriction, including
|
|
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
|
|
|
// persons to whom the Software is furnished to do so, subject to the
|
|
|
|
// following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included
|
|
|
|
// in all copies or substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
|
|
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
|
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
|
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
|
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
2015-01-10 21:12:37 +01:00
|
|
|
// Maintainers, keep in mind that ES1-style octal literals (`0666`) are not
|
|
|
|
// allowed in strict mode. Use ES6-style octal literals instead (`0o666`).
|
2011-11-04 13:10:07 +01:00
|
|
|
|
2014-11-22 16:59:48 +01:00
|
|
|
'use strict';
|
|
|
|
|
2018-05-15 01:36:37 +02:00
|
|
|
const { fs: constants } = process.binding('constants');
|
|
|
|
const {
|
|
|
|
S_IFIFO,
|
|
|
|
S_IFLNK,
|
|
|
|
S_IFMT,
|
|
|
|
S_IFREG,
|
|
|
|
S_IFSOCK,
|
|
|
|
F_OK,
|
|
|
|
R_OK,
|
|
|
|
W_OK,
|
|
|
|
X_OK,
|
|
|
|
O_WRONLY,
|
|
|
|
O_SYMLINK,
|
|
|
|
UV_FS_COPYFILE_EXCL,
|
|
|
|
UV_FS_COPYFILE_FICLONE,
|
|
|
|
UV_FS_COPYFILE_FICLONE_FORCE
|
|
|
|
} = constants;
|
2015-01-21 17:36:59 +01:00
|
|
|
const util = require('util');
|
|
|
|
const pathModule = require('path');
|
2017-09-28 09:16:41 +02:00
|
|
|
const { isUint8Array } = require('internal/util/types');
|
2010-03-05 19:24:20 +01:00
|
|
|
|
2015-01-21 17:36:59 +01:00
|
|
|
const binding = process.binding('fs');
|
|
|
|
const fs = exports;
|
2018-05-15 01:36:37 +02:00
|
|
|
const { Buffer, kMaxLength } = require('buffer');
|
2017-08-26 13:46:47 +02:00
|
|
|
const errors = require('internal/errors');
|
2018-02-27 14:55:32 +01:00
|
|
|
const {
|
2018-03-15 14:22:36 +01:00
|
|
|
ERR_FS_FILE_TOO_LARGE,
|
2018-02-27 14:55:32 +01:00
|
|
|
ERR_INVALID_ARG_TYPE,
|
|
|
|
ERR_INVALID_CALLBACK,
|
|
|
|
ERR_OUT_OF_RANGE
|
|
|
|
} = errors.codes;
|
2017-10-07 16:50:42 +02:00
|
|
|
const { Readable, Writable } = require('stream');
|
2015-09-17 00:45:29 +02:00
|
|
|
const EventEmitter = require('events');
|
2018-03-30 22:02:57 +02:00
|
|
|
const { FSReqWrap, statValues, kFsStatsFieldsLength } = binding;
|
2017-10-07 16:50:42 +02:00
|
|
|
const { FSEvent } = process.binding('fs_event_wrap');
|
2018-05-03 20:40:48 +02:00
|
|
|
const internalFS = require('internal/fs/utils');
|
2017-10-07 16:50:42 +02:00
|
|
|
const { getPathFromURL } = require('internal/url');
|
2016-12-27 03:38:05 +01:00
|
|
|
const internalUtil = require('internal/util');
|
2017-10-07 16:50:42 +02:00
|
|
|
const {
|
2018-02-14 09:57:42 +01:00
|
|
|
copyObject,
|
|
|
|
getOptions,
|
|
|
|
nullCheck,
|
|
|
|
preprocessSymlinkDestination,
|
|
|
|
Stats,
|
2018-03-30 22:02:57 +02:00
|
|
|
getStatsFromBinding,
|
2018-05-15 01:36:37 +02:00
|
|
|
realpathCacheKey,
|
2018-02-14 09:57:42 +01:00
|
|
|
stringToFlags,
|
|
|
|
stringToSymlinkType,
|
|
|
|
toUnixTimestamp,
|
|
|
|
validateBuffer,
|
|
|
|
validateOffsetLengthRead,
|
|
|
|
validateOffsetLengthWrite,
|
2018-04-15 11:16:50 +02:00
|
|
|
validatePath
|
2017-10-07 16:50:42 +02:00
|
|
|
} = internalFS;
|
2018-02-13 12:49:53 +01:00
|
|
|
const {
|
|
|
|
CHAR_FORWARD_SLASH,
|
|
|
|
CHAR_BACKWARD_SLASH,
|
|
|
|
} = require('internal/constants');
|
2018-04-15 11:16:50 +02:00
|
|
|
const {
|
|
|
|
isUint32,
|
2018-05-09 16:44:44 +02:00
|
|
|
validateAndMaskMode,
|
2018-04-15 11:16:50 +02:00
|
|
|
validateInt32,
|
|
|
|
validateUint32
|
|
|
|
} = require('internal/validators');
|
2010-03-11 23:32:10 +01:00
|
|
|
|
2018-05-15 01:25:27 +02:00
|
|
|
// Lazy loaded
|
|
|
|
let promises;
|
|
|
|
|
|
|
|
let promisesWarn = true;
|
2018-05-03 20:40:48 +02:00
|
|
|
|
|
|
|
Object.defineProperty(fs, 'promises', {
|
|
|
|
configurable: true,
|
2018-05-09 18:36:59 +02:00
|
|
|
enumerable: false,
|
2018-05-03 20:40:48 +02:00
|
|
|
get() {
|
2018-05-15 01:25:27 +02:00
|
|
|
if (promisesWarn) {
|
|
|
|
promises = require('internal/fs/promises');
|
|
|
|
promisesWarn = false;
|
2018-05-03 20:40:48 +02:00
|
|
|
process.emitWarning('The fs.promises API is experimental',
|
|
|
|
'ExperimentalWarning');
|
|
|
|
}
|
|
|
|
return promises;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2016-05-02 19:27:12 +02:00
|
|
|
Object.defineProperty(exports, 'constants', {
|
|
|
|
configurable: false,
|
|
|
|
enumerable: true,
|
|
|
|
value: constants
|
|
|
|
});
|
|
|
|
|
2018-03-02 17:28:05 +01:00
|
|
|
let assert_ = null;
|
|
|
|
function lazyAssert() {
|
|
|
|
if (assert_ === null) {
|
|
|
|
assert_ = require('assert');
|
|
|
|
}
|
|
|
|
return assert_;
|
|
|
|
}
|
|
|
|
|
2015-01-20 05:01:42 +01:00
|
|
|
const kMinPoolSpace = 128;
|
2010-05-25 00:47:40 +02:00
|
|
|
|
2015-01-21 17:36:59 +01:00
|
|
|
const isWindows = process.platform === 'win32';
|
2012-05-23 01:02:10 +02:00
|
|
|
|
2017-10-06 20:06:35 +02:00
|
|
|
let truncateWarn = true;
|
|
|
|
|
|
|
|
function showTruncateDeprecation() {
|
|
|
|
if (truncateWarn) {
|
|
|
|
process.emitWarning(
|
|
|
|
'Using fs.truncate with a file descriptor is deprecated. Please use ' +
|
|
|
|
'fs.ftruncate with a file descriptor instead.',
|
|
|
|
'DeprecationWarning', 'DEP0081');
|
|
|
|
truncateWarn = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-08 15:24:08 +01:00
|
|
|
function handleErrorFromBinding(ctx) {
|
|
|
|
if (ctx.errno !== undefined) { // libuv error numbers
|
|
|
|
const err = errors.uvException(ctx);
|
|
|
|
Error.captureStackTrace(err, handleErrorFromBinding);
|
|
|
|
throw err;
|
|
|
|
} else if (ctx.error !== undefined) { // errors created in C++ land.
|
|
|
|
// TODO(joyeecheung): currently, ctx.error are encoding errors
|
|
|
|
// usually caused by memory problems. We need to figure out proper error
|
|
|
|
// code(s) for this.
|
|
|
|
Error.captureStackTrace(ctx.error, handleErrorFromBinding);
|
|
|
|
throw ctx.error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-23 01:38:36 +02:00
|
|
|
function maybeCallback(cb) {
|
2018-02-09 00:54:31 +01:00
|
|
|
if (typeof cb === 'function')
|
|
|
|
return cb;
|
|
|
|
|
2018-02-27 14:55:32 +01:00
|
|
|
throw new ERR_INVALID_CALLBACK();
|
2016-07-23 01:38:36 +02:00
|
|
|
}
|
|
|
|
|
2012-12-04 03:17:52 +01:00
|
|
|
// Ensure that callbacks run in the global context. Only use this function
|
|
|
|
// for callbacks that are passed to the binding layer, callbacks that are
|
|
|
|
// invoked from JS already run in the proper scope.
|
|
|
|
function makeCallback(cb) {
|
2017-05-11 17:52:20 +02:00
|
|
|
if (typeof cb !== 'function') {
|
2018-02-27 14:55:32 +01:00
|
|
|
throw new ERR_INVALID_CALLBACK();
|
2017-05-11 17:52:20 +02:00
|
|
|
}
|
2015-02-18 18:55:13 +01:00
|
|
|
|
2017-12-06 18:45:34 +01:00
|
|
|
return function(...args) {
|
|
|
|
return Reflect.apply(cb, undefined, args);
|
2012-12-04 03:17:52 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2017-03-12 01:41:20 +01:00
|
|
|
// 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.
|
|
|
|
function makeStatsCallback(cb) {
|
2017-05-11 17:52:20 +02:00
|
|
|
if (typeof cb !== 'function') {
|
2018-02-27 14:55:32 +01:00
|
|
|
throw new ERR_INVALID_CALLBACK();
|
2017-05-11 17:52:20 +02:00
|
|
|
}
|
2017-03-12 01:41:20 +01:00
|
|
|
|
2018-03-30 22:02:57 +02:00
|
|
|
return function(err, stats) {
|
2017-03-12 01:41:20 +01:00
|
|
|
if (err) return cb(err);
|
2018-03-30 22:02:57 +02:00
|
|
|
cb(err, getStatsFromBinding(stats));
|
2017-03-12 01:41:20 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-04-26 13:22:14 +02:00
|
|
|
const isFd = isUint32;
|
2016-07-23 01:37:54 +02:00
|
|
|
|
2017-02-23 18:45:10 +01:00
|
|
|
fs.Stats = Stats;
|
2014-02-27 21:45:18 +01:00
|
|
|
|
2018-04-07 10:57:22 +02:00
|
|
|
function isFileType(stats, fileType) {
|
2018-02-11 19:29:19 +01:00
|
|
|
// Use stats array directly to avoid creating an fs.Stats instance just for
|
|
|
|
// our internal use.
|
2018-04-07 10:57:22 +02:00
|
|
|
return (stats[1/* mode */] & S_IFMT) === fileType;
|
2018-02-11 19:29:19 +01:00
|
|
|
}
|
|
|
|
|
2015-01-19 11:12:16 +01:00
|
|
|
// Don't allow mode to accidentally be overwritten.
|
2017-02-26 07:52:16 +01:00
|
|
|
Object.defineProperties(fs, {
|
2018-05-15 01:36:37 +02:00
|
|
|
F_OK: { enumerable: true, value: F_OK || 0 },
|
|
|
|
R_OK: { enumerable: true, value: R_OK || 0 },
|
|
|
|
W_OK: { enumerable: true, value: W_OK || 0 },
|
|
|
|
X_OK: { enumerable: true, value: X_OK || 0 },
|
2015-01-19 11:12:16 +01:00
|
|
|
});
|
2014-12-15 16:44:46 +01:00
|
|
|
|
|
|
|
fs.access = function(path, mode, callback) {
|
|
|
|
if (typeof mode === 'function') {
|
2016-07-23 01:38:36 +02:00
|
|
|
callback = mode;
|
2018-05-15 01:36:37 +02:00
|
|
|
mode = F_OK;
|
2014-12-15 16:44:46 +01:00
|
|
|
}
|
|
|
|
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(path);
|
2017-11-20 21:47:57 +01:00
|
|
|
|
2014-12-15 16:44:46 +01:00
|
|
|
mode = mode | 0;
|
|
|
|
var req = new FSReqWrap();
|
2017-05-11 17:52:20 +02:00
|
|
|
req.oncomplete = makeCallback(callback);
|
2017-08-21 07:44:47 +02:00
|
|
|
binding.access(pathModule.toNamespacedPath(path), mode, req);
|
2014-12-15 16:44:46 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
fs.accessSync = function(path, mode) {
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(path);
|
2014-12-15 16:44:46 +01:00
|
|
|
|
|
|
|
if (mode === undefined)
|
2018-05-15 01:36:37 +02:00
|
|
|
mode = F_OK;
|
2014-12-15 16:44:46 +01:00
|
|
|
else
|
|
|
|
mode = mode | 0;
|
|
|
|
|
2017-11-27 05:08:05 +01:00
|
|
|
const ctx = { path };
|
2017-11-20 21:47:57 +01:00
|
|
|
binding.access(pathModule.toNamespacedPath(path), mode, undefined, ctx);
|
2018-02-08 15:24:08 +01:00
|
|
|
handleErrorFromBinding(ctx);
|
2014-12-15 16:44:46 +01:00
|
|
|
};
|
|
|
|
|
2015-01-12 15:24:30 +01:00
|
|
|
fs.exists = function(path, callback) {
|
2018-02-09 00:54:31 +01:00
|
|
|
maybeCallback(callback);
|
2018-01-23 03:23:46 +01:00
|
|
|
|
|
|
|
function suppressedCallback(err) {
|
|
|
|
callback(err ? false : true);
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
2018-05-15 01:36:37 +02:00
|
|
|
fs.access(path, F_OK, suppressedCallback);
|
2018-01-23 03:23:46 +01:00
|
|
|
} catch (err) {
|
|
|
|
return callback(false);
|
|
|
|
}
|
2015-01-12 15:24:30 +01:00
|
|
|
};
|
2012-01-21 02:37:57 +01:00
|
|
|
|
2017-05-30 23:34:27 +02:00
|
|
|
Object.defineProperty(fs.exists, internalUtil.promisify.custom, {
|
|
|
|
value: (path) => {
|
2018-05-15 01:39:54 +02:00
|
|
|
const { createPromise, promiseResolve } = process.binding('util');
|
2017-05-30 23:34:27 +02:00
|
|
|
const promise = createPromise();
|
|
|
|
fs.exists(path, (exists) => promiseResolve(promise, exists));
|
|
|
|
return promise;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2018-01-23 03:23:46 +01:00
|
|
|
// fs.existsSync never throws, it only returns true or false.
|
|
|
|
// Since fs.existsSync never throws, users have established
|
|
|
|
// the expectation that passing invalid arguments to it, even like
|
|
|
|
// fs.existsSync(), would only get a false in return, so we cannot signal
|
|
|
|
// validation errors to users properly out of compatibility concerns.
|
|
|
|
// TODO(joyeecheung): deprecate the never-throw-on-invalid-arguments behavior
|
2015-01-12 15:24:30 +01:00
|
|
|
fs.existsSync = function(path) {
|
2012-01-21 02:37:57 +01:00
|
|
|
try {
|
2018-05-15 01:36:37 +02:00
|
|
|
fs.accessSync(path, F_OK);
|
2012-01-21 02:37:57 +01:00
|
|
|
return true;
|
|
|
|
} catch (e) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-01-12 15:24:30 +01:00
|
|
|
};
|
2012-01-21 02:37:57 +01:00
|
|
|
|
2016-06-25 20:33:05 +02:00
|
|
|
fs.readFile = function(path, options, callback) {
|
2017-04-24 08:20:45 +02:00
|
|
|
callback = maybeCallback(callback || options);
|
2016-06-25 20:33:05 +02:00
|
|
|
options = getOptions(options, { flag: 'r' });
|
|
|
|
var context = new ReadFileContext(callback, options.encoding);
|
2016-07-23 01:37:54 +02:00
|
|
|
context.isUserFd = isFd(path); // file descriptor ownership
|
2015-02-03 20:07:02 +01:00
|
|
|
var req = new FSReqWrap();
|
|
|
|
req.context = context;
|
|
|
|
req.oncomplete = readFileAfterOpen;
|
2010-12-02 02:43:30 +01:00
|
|
|
|
2015-10-03 02:06:42 +02:00
|
|
|
if (context.isUserFd) {
|
2018-04-30 09:08:20 +02:00
|
|
|
process.nextTick(function tick() {
|
2015-10-03 02:06:42 +02:00
|
|
|
req.oncomplete(null, path);
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(path);
|
2017-08-21 07:44:47 +02:00
|
|
|
binding.open(pathModule.toNamespacedPath(path),
|
2016-06-25 20:33:05 +02:00
|
|
|
stringToFlags(options.flag || 'r'),
|
2015-02-03 20:07:02 +01:00
|
|
|
0o666,
|
|
|
|
req);
|
|
|
|
};
|
|
|
|
|
|
|
|
const kReadFileBufferLength = 8 * 1024;
|
|
|
|
|
|
|
|
function ReadFileContext(callback, encoding) {
|
|
|
|
this.fd = undefined;
|
2015-10-03 02:06:42 +02:00
|
|
|
this.isUserFd = undefined;
|
2015-02-03 20:07:02 +01:00
|
|
|
this.size = undefined;
|
|
|
|
this.callback = callback;
|
|
|
|
this.buffers = null;
|
|
|
|
this.buffer = null;
|
|
|
|
this.pos = 0;
|
|
|
|
this.encoding = encoding;
|
|
|
|
this.err = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReadFileContext.prototype.read = function() {
|
|
|
|
var buffer;
|
|
|
|
var offset;
|
|
|
|
var length;
|
|
|
|
|
2015-06-03 00:11:04 +02:00
|
|
|
if (this.size === 0) {
|
2016-03-21 20:38:08 +01:00
|
|
|
buffer = this.buffer = Buffer.allocUnsafeSlow(kReadFileBufferLength);
|
2015-02-03 20:07:02 +01:00
|
|
|
offset = 0;
|
|
|
|
length = kReadFileBufferLength;
|
|
|
|
} else {
|
|
|
|
buffer = this.buffer;
|
|
|
|
offset = this.pos;
|
fs: partition readFile against pool exhaustion
Problem:
Node implements fs.readFile as:
- a call to stat, then
- a C++ -> libuv request to read the entire file using the stat size
Why is this bad?
The effect is to place on the libuv threadpool a potentially-large
read request, occupying the libuv thread until it completes.
While readFile certainly requires buffering the entire file contents,
it can partition the read into smaller buffers
(as is done on other read paths)
along the way to avoid threadpool exhaustion.
If the file is relatively large or stored on a slow medium, reading
the entire file in one shot seems particularly harmful,
and presents a possible DoS vector.
Solution:
Partition the read into multiple smaller requests.
Considerations:
1. Correctness
I don't think partitioning the read like this raises
any additional risk of read-write races on the FS.
If the application is concurrently readFile'ing and modifying the file,
it will already see funny behavior. Though libuv uses preadv where
available, this doesn't guarantee read atomicity in the presence of
concurrent writes.
2. Performance
Downside: Partitioning means that a single large readFile will
require into many "out and back" requests to libuv,
introducing overhead.
Upside: In between each "out and back", other work pending on the
threadpool can take a turn.
In short, although partitioning will slow down a large request,
it will lead to better throughput if the threadpool is handling
more than one type of request.
Fixes: https://github.com/nodejs/node/issues/17047
PR-URL: https://github.com/nodejs/node/pull/17054
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
2017-11-15 18:28:04 +01:00
|
|
|
length = Math.min(kReadFileBufferLength, this.size - this.pos);
|
2012-05-16 02:35:42 +02:00
|
|
|
}
|
2012-04-06 02:54:33 +02:00
|
|
|
|
2015-02-03 20:07:02 +01:00
|
|
|
var req = new FSReqWrap();
|
|
|
|
req.oncomplete = readFileAfterRead;
|
|
|
|
req.context = this;
|
2012-05-16 02:35:42 +02:00
|
|
|
|
2017-01-14 20:14:19 +01:00
|
|
|
binding.read(this.fd, buffer, offset, length, -1, req);
|
2015-02-03 20:07:02 +01:00
|
|
|
};
|
2012-06-12 15:32:40 +02:00
|
|
|
|
2015-02-03 20:07:02 +01:00
|
|
|
ReadFileContext.prototype.close = function(err) {
|
|
|
|
var req = new FSReqWrap();
|
|
|
|
req.oncomplete = readFileAfterClose;
|
|
|
|
req.context = this;
|
|
|
|
this.err = err;
|
2015-10-03 02:06:42 +02:00
|
|
|
|
|
|
|
if (this.isUserFd) {
|
2018-04-30 09:08:20 +02:00
|
|
|
process.nextTick(function tick() {
|
2015-10-03 02:06:42 +02:00
|
|
|
req.oncomplete(null);
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-02-03 20:07:02 +01:00
|
|
|
binding.close(this.fd, req);
|
|
|
|
};
|
|
|
|
|
|
|
|
function readFileAfterOpen(err, fd) {
|
|
|
|
var context = this.context;
|
|
|
|
|
|
|
|
if (err) {
|
2015-06-03 00:11:04 +02:00
|
|
|
context.callback(err);
|
2015-02-03 20:07:02 +01:00
|
|
|
return;
|
2012-05-16 02:35:42 +02:00
|
|
|
}
|
|
|
|
|
2015-02-03 20:07:02 +01:00
|
|
|
context.fd = fd;
|
2012-06-11 23:49:31 +02:00
|
|
|
|
2015-02-03 20:07:02 +01:00
|
|
|
var req = new FSReqWrap();
|
|
|
|
req.oncomplete = readFileAfterStat;
|
|
|
|
req.context = context;
|
|
|
|
binding.fstat(fd, req);
|
|
|
|
}
|
|
|
|
|
2018-04-07 10:57:22 +02:00
|
|
|
function readFileAfterStat(err, stats) {
|
2015-02-03 20:07:02 +01:00
|
|
|
var context = this.context;
|
|
|
|
|
|
|
|
if (err)
|
|
|
|
return context.close(err);
|
|
|
|
|
2017-03-12 01:41:20 +01:00
|
|
|
var size;
|
2018-04-07 10:57:22 +02:00
|
|
|
if (isFileType(stats, S_IFREG))
|
|
|
|
size = context.size = stats[8];
|
2017-03-12 01:41:20 +01:00
|
|
|
else
|
|
|
|
size = context.size = 0;
|
2015-02-03 20:07:02 +01:00
|
|
|
|
|
|
|
if (size === 0) {
|
|
|
|
context.buffers = [];
|
|
|
|
context.read();
|
|
|
|
return;
|
2012-05-16 02:35:42 +02:00
|
|
|
}
|
2015-02-03 20:07:02 +01:00
|
|
|
|
|
|
|
if (size > kMaxLength) {
|
2018-03-15 14:22:36 +01:00
|
|
|
err = new ERR_FS_FILE_TOO_LARGE(size);
|
2015-02-03 20:07:02 +01:00
|
|
|
return context.close(err);
|
|
|
|
}
|
|
|
|
|
2017-10-15 13:18:09 +02:00
|
|
|
try {
|
|
|
|
context.buffer = Buffer.allocUnsafeSlow(size);
|
|
|
|
} catch (err) {
|
|
|
|
return context.close(err);
|
|
|
|
}
|
2015-02-03 20:07:02 +01:00
|
|
|
context.read();
|
|
|
|
}
|
|
|
|
|
|
|
|
function readFileAfterRead(err, bytesRead) {
|
|
|
|
var context = this.context;
|
|
|
|
|
|
|
|
if (err)
|
|
|
|
return context.close(err);
|
|
|
|
|
|
|
|
if (bytesRead === 0)
|
|
|
|
return context.close();
|
|
|
|
|
|
|
|
context.pos += bytesRead;
|
|
|
|
|
|
|
|
if (context.size !== 0) {
|
|
|
|
if (context.pos === context.size)
|
|
|
|
context.close();
|
|
|
|
else
|
|
|
|
context.read();
|
|
|
|
} else {
|
|
|
|
// unknown size, just read until we don't get bytes.
|
|
|
|
context.buffers.push(context.buffer.slice(0, bytesRead));
|
|
|
|
context.read();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function readFileAfterClose(err) {
|
|
|
|
var context = this.context;
|
|
|
|
var buffer = null;
|
|
|
|
var callback = context.callback;
|
|
|
|
|
2016-11-18 04:03:39 +01:00
|
|
|
if (context.err || err)
|
|
|
|
return callback(context.err || err);
|
2015-02-03 20:07:02 +01:00
|
|
|
|
2015-10-22 13:58:26 +02:00
|
|
|
try {
|
2017-10-15 13:18:09 +02:00
|
|
|
if (context.size === 0)
|
|
|
|
buffer = Buffer.concat(context.buffers, context.pos);
|
|
|
|
else if (context.pos < context.size)
|
|
|
|
buffer = context.buffer.slice(0, context.pos);
|
|
|
|
else
|
|
|
|
buffer = context.buffer;
|
|
|
|
|
|
|
|
if (context.encoding)
|
|
|
|
buffer = buffer.toString(context.encoding);
|
2015-10-22 13:58:26 +02:00
|
|
|
} catch (err) {
|
2016-11-18 04:03:39 +01:00
|
|
|
return callback(err);
|
2015-10-22 13:58:26 +02:00
|
|
|
}
|
2017-10-15 13:18:09 +02:00
|
|
|
|
|
|
|
callback(null, buffer);
|
2015-10-22 13:58:26 +02:00
|
|
|
}
|
2010-03-15 18:41:58 +01:00
|
|
|
|
2016-04-07 16:04:47 +02:00
|
|
|
function tryStatSync(fd, isUserFd) {
|
2017-12-28 16:16:33 +01:00
|
|
|
const ctx = {};
|
2018-04-07 10:57:22 +02:00
|
|
|
const stats = binding.fstat(fd, undefined, ctx);
|
2017-12-28 16:16:33 +01:00
|
|
|
if (ctx.errno !== undefined && !isUserFd) {
|
|
|
|
fs.closeSync(fd);
|
2018-02-03 10:35:04 +01:00
|
|
|
throw errors.uvException(ctx);
|
2016-04-07 16:04:47 +02:00
|
|
|
}
|
2018-04-07 10:57:22 +02:00
|
|
|
return stats;
|
2016-04-07 16:04:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function tryCreateBuffer(size, fd, isUserFd) {
|
|
|
|
var threw = true;
|
|
|
|
var buffer;
|
|
|
|
try {
|
2018-03-15 14:22:36 +01:00
|
|
|
if (size > kMaxLength) {
|
|
|
|
throw new ERR_FS_FILE_TOO_LARGE(size);
|
|
|
|
}
|
2016-04-07 16:04:47 +02:00
|
|
|
buffer = Buffer.allocUnsafe(size);
|
|
|
|
threw = false;
|
|
|
|
} finally {
|
|
|
|
if (threw && !isUserFd) fs.closeSync(fd);
|
|
|
|
}
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2017-01-14 20:14:19 +01:00
|
|
|
function tryReadSync(fd, isUserFd, buffer, pos, len) {
|
2016-04-07 16:04:47 +02:00
|
|
|
var threw = true;
|
|
|
|
var bytesRead;
|
|
|
|
try {
|
2017-01-14 20:14:19 +01:00
|
|
|
bytesRead = fs.readSync(fd, buffer, pos, len);
|
2016-04-07 16:04:47 +02:00
|
|
|
threw = false;
|
|
|
|
} finally {
|
|
|
|
if (threw && !isUserFd) fs.closeSync(fd);
|
|
|
|
}
|
|
|
|
return bytesRead;
|
|
|
|
}
|
|
|
|
|
2013-03-01 18:10:26 +01:00
|
|
|
fs.readFileSync = function(path, options) {
|
2016-06-25 20:33:05 +02:00
|
|
|
options = getOptions(options, { flag: 'r' });
|
2016-07-23 01:37:54 +02:00
|
|
|
var isUserFd = isFd(path); // file descriptor ownership
|
2016-06-25 20:33:05 +02:00
|
|
|
var fd = isUserFd ? path : fs.openSync(path, options.flag || 'r', 0o666);
|
2010-09-23 02:58:08 +02:00
|
|
|
|
2018-04-07 10:57:22 +02:00
|
|
|
const stats = tryStatSync(fd, isUserFd);
|
2017-03-12 01:41:20 +01:00
|
|
|
var size;
|
2018-04-07 10:57:22 +02:00
|
|
|
if (isFileType(stats, S_IFREG))
|
|
|
|
size = stats[8];
|
2017-03-12 01:41:20 +01:00
|
|
|
else
|
|
|
|
size = 0;
|
2012-06-11 23:49:31 +02:00
|
|
|
var pos = 0;
|
|
|
|
var buffer; // single buffer with file data
|
|
|
|
var buffers; // list for when size is unknown
|
|
|
|
|
2012-05-16 02:35:42 +02:00
|
|
|
if (size === 0) {
|
2012-06-11 23:49:31 +02:00
|
|
|
buffers = [];
|
|
|
|
} else {
|
2016-04-07 16:04:47 +02:00
|
|
|
buffer = tryCreateBuffer(size, fd, isUserFd);
|
2012-05-03 01:03:08 +02:00
|
|
|
}
|
2010-03-15 18:41:58 +01:00
|
|
|
|
2015-06-03 00:11:04 +02:00
|
|
|
var bytesRead;
|
|
|
|
|
2016-04-07 16:04:47 +02:00
|
|
|
if (size !== 0) {
|
|
|
|
do {
|
2017-01-14 20:14:19 +01:00
|
|
|
bytesRead = tryReadSync(fd, isUserFd, buffer, pos, size - pos);
|
2016-04-07 16:04:47 +02:00
|
|
|
pos += bytesRead;
|
|
|
|
} while (bytesRead !== 0 && pos < size);
|
|
|
|
} else {
|
|
|
|
do {
|
|
|
|
// the kernel lies about many files.
|
|
|
|
// Go ahead and try to read some bytes.
|
|
|
|
buffer = Buffer.allocUnsafe(8192);
|
2017-01-14 20:14:19 +01:00
|
|
|
bytesRead = tryReadSync(fd, isUserFd, buffer, 0, 8192);
|
2016-04-07 16:04:47 +02:00
|
|
|
if (bytesRead !== 0) {
|
|
|
|
buffers.push(buffer.slice(0, bytesRead));
|
2012-06-11 23:49:31 +02:00
|
|
|
}
|
2016-04-07 16:04:47 +02:00
|
|
|
pos += bytesRead;
|
|
|
|
} while (bytesRead !== 0);
|
2010-05-29 22:38:00 +02:00
|
|
|
}
|
2010-09-23 02:58:08 +02:00
|
|
|
|
2015-10-03 02:06:42 +02:00
|
|
|
if (!isUserFd)
|
|
|
|
fs.closeSync(fd);
|
2012-05-16 02:35:42 +02:00
|
|
|
|
2012-06-11 23:49:31 +02:00
|
|
|
if (size === 0) {
|
|
|
|
// data was collected into the buffers list.
|
|
|
|
buffer = Buffer.concat(buffers, pos);
|
2012-06-12 16:04:56 +02:00
|
|
|
} else if (pos < size) {
|
|
|
|
buffer = buffer.slice(0, pos);
|
2012-06-11 23:49:31 +02:00
|
|
|
}
|
|
|
|
|
2016-06-25 20:33:05 +02:00
|
|
|
if (options.encoding) buffer = buffer.toString(options.encoding);
|
2010-09-23 02:58:08 +02:00
|
|
|
return buffer;
|
2010-03-15 18:41:58 +01:00
|
|
|
};
|
2010-03-01 19:14:49 +01:00
|
|
|
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.close = function(fd, callback) {
|
2017-12-23 01:19:33 +01:00
|
|
|
validateUint32(fd, 'fd');
|
2017-11-26 21:44:20 +01:00
|
|
|
const req = new FSReqWrap();
|
2016-07-23 01:38:36 +02:00
|
|
|
req.oncomplete = makeCallback(callback);
|
2016-07-23 01:37:54 +02:00
|
|
|
binding.close(fd, req);
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.closeSync = function(fd) {
|
2017-12-23 01:19:33 +01:00
|
|
|
validateUint32(fd, 'fd');
|
2017-11-26 21:44:20 +01:00
|
|
|
|
2017-11-29 05:52:16 +01:00
|
|
|
const ctx = {};
|
|
|
|
binding.close(fd, undefined, ctx);
|
2018-02-08 15:24:08 +01:00
|
|
|
handleErrorFromBinding(ctx);
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2018-05-09 16:44:44 +02:00
|
|
|
fs.open = function(path, flags, mode, callback) {
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(path);
|
2018-05-09 16:44:44 +02:00
|
|
|
const flagsNumber = stringToFlags(flags);
|
|
|
|
if (arguments.length < 4) {
|
|
|
|
callback = makeCallback(mode);
|
|
|
|
mode = 0o666;
|
|
|
|
} else {
|
|
|
|
mode = validateAndMaskMode(mode, 'mode', 0o666);
|
|
|
|
callback = makeCallback(callback);
|
|
|
|
}
|
2017-12-13 23:24:34 +01:00
|
|
|
|
|
|
|
const req = new FSReqWrap();
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = callback;
|
|
|
|
|
2017-08-21 07:44:47 +02:00
|
|
|
binding.open(pathModule.toNamespacedPath(path),
|
2018-05-09 16:44:44 +02:00
|
|
|
flagsNumber,
|
2012-02-19 00:01:35 +01:00
|
|
|
mode,
|
2014-12-09 05:29:47 +01:00
|
|
|
req);
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.openSync = function(path, flags, mode) {
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(path);
|
2018-05-09 16:44:44 +02:00
|
|
|
const flagsNumber = stringToFlags(flags);
|
|
|
|
mode = validateAndMaskMode(mode, 'mode', 0o666);
|
2017-12-13 23:24:34 +01:00
|
|
|
|
2018-02-14 20:08:52 +01:00
|
|
|
const ctx = { path };
|
|
|
|
const result = binding.open(pathModule.toNamespacedPath(path),
|
2018-05-09 16:44:44 +02:00
|
|
|
flagsNumber, mode,
|
2018-02-14 20:08:52 +01:00
|
|
|
undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
|
|
|
return result;
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.read = function(fd, buffer, offset, length, position, callback) {
|
2017-12-23 01:19:33 +01:00
|
|
|
validateUint32(fd, 'fd');
|
2017-12-14 01:54:09 +01:00
|
|
|
validateBuffer(buffer);
|
2017-11-27 05:51:01 +01:00
|
|
|
|
|
|
|
offset |= 0;
|
|
|
|
length |= 0;
|
|
|
|
|
2016-01-06 17:39:03 +01:00
|
|
|
if (length === 0) {
|
2018-04-30 09:08:20 +02:00
|
|
|
return process.nextTick(function tick() {
|
2016-07-23 01:38:36 +02:00
|
|
|
callback && callback(null, 0, buffer);
|
2016-01-06 17:39:03 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-12-13 23:29:03 +01:00
|
|
|
validateOffsetLengthRead(offset, length, buffer.length);
|
2017-11-27 05:51:01 +01:00
|
|
|
|
2017-12-13 23:24:34 +01:00
|
|
|
if (!isUint32(position))
|
2017-11-27 05:51:01 +01:00
|
|
|
position = -1;
|
|
|
|
|
2011-03-23 12:29:49 +01:00
|
|
|
function wrapper(err, bytesRead) {
|
|
|
|
// Retain a reference to buffer so that it can't be GC'ed too soon.
|
2016-07-23 01:38:36 +02:00
|
|
|
callback && callback(err, bytesRead || 0, buffer);
|
2011-03-23 12:29:49 +01:00
|
|
|
}
|
|
|
|
|
2017-11-27 05:51:01 +01:00
|
|
|
const req = new FSReqWrap();
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = wrapper;
|
|
|
|
|
|
|
|
binding.read(fd, buffer, offset, length, position, req);
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2017-04-16 21:19:36 +02:00
|
|
|
Object.defineProperty(fs.read, internalUtil.customPromisifyArgs,
|
|
|
|
{ value: ['bytesRead', 'buffer'], enumerable: false });
|
|
|
|
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.readSync = function(fd, buffer, offset, length, position) {
|
2017-12-23 01:19:33 +01:00
|
|
|
validateUint32(fd, 'fd');
|
2017-12-14 01:54:09 +01:00
|
|
|
validateBuffer(buffer);
|
2017-11-27 05:51:01 +01:00
|
|
|
|
|
|
|
offset |= 0;
|
|
|
|
length |= 0;
|
|
|
|
|
2016-01-06 17:39:03 +01:00
|
|
|
if (length === 0) {
|
2017-01-10 13:26:23 +01:00
|
|
|
return 0;
|
2010-05-21 00:13:22 +02:00
|
|
|
}
|
|
|
|
|
2017-12-13 23:29:03 +01:00
|
|
|
validateOffsetLengthRead(offset, length, buffer.length);
|
2017-11-27 05:51:01 +01:00
|
|
|
|
2017-12-13 23:24:34 +01:00
|
|
|
if (!isUint32(position))
|
2017-11-27 05:51:01 +01:00
|
|
|
position = -1;
|
|
|
|
|
2018-02-27 18:21:19 +01:00
|
|
|
const ctx = {};
|
|
|
|
const result = binding.read(fd, buffer, offset, length, position,
|
|
|
|
undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
|
|
|
return result;
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2013-07-02 09:27:26 +02:00
|
|
|
// usage:
|
2016-07-23 22:43:41 +02:00
|
|
|
// fs.write(fd, buffer[, offset[, length[, position]]], callback);
|
2013-07-02 09:27:26 +02:00
|
|
|
// OR
|
|
|
|
// fs.write(fd, string[, position[, encoding]], callback);
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.write = function(fd, buffer, offset, length, position, callback) {
|
2015-09-18 10:36:57 +02:00
|
|
|
function wrapper(err, written) {
|
2014-12-09 05:29:47 +01:00
|
|
|
// Retain a reference to buffer so that it can't be GC'ed too soon.
|
|
|
|
callback(err, written || 0, buffer);
|
|
|
|
}
|
|
|
|
|
2017-12-23 01:19:33 +01:00
|
|
|
validateUint32(fd, 'fd');
|
2017-12-13 23:24:34 +01:00
|
|
|
|
|
|
|
const req = new FSReqWrap();
|
2015-09-18 10:36:57 +02:00
|
|
|
req.oncomplete = wrapper;
|
|
|
|
|
2016-12-21 08:27:34 +01:00
|
|
|
if (isUint8Array(buffer)) {
|
2016-07-23 22:43:41 +02:00
|
|
|
callback = maybeCallback(callback || position || length || offset);
|
2017-12-13 23:24:34 +01:00
|
|
|
if (typeof offset !== 'number')
|
2016-07-23 22:43:41 +02:00
|
|
|
offset = 0;
|
2017-12-13 23:24:34 +01:00
|
|
|
if (typeof length !== 'number')
|
2016-07-23 22:43:41 +02:00
|
|
|
length = buffer.length - offset;
|
2017-12-13 23:24:34 +01:00
|
|
|
if (typeof position !== 'number')
|
2013-07-02 09:27:26 +02:00
|
|
|
position = null;
|
2017-12-23 00:33:31 +01:00
|
|
|
validateOffsetLengthWrite(offset, length, buffer.byteLength);
|
2014-12-09 05:29:47 +01:00
|
|
|
return binding.writeBuffer(fd, buffer, offset, length, position, req);
|
2010-05-19 20:17:50 +02:00
|
|
|
}
|
2010-08-25 05:46:37 +02:00
|
|
|
|
2015-03-08 21:19:56 +01:00
|
|
|
if (typeof buffer !== 'string')
|
2013-07-02 09:27:26 +02:00
|
|
|
buffer += '';
|
2015-01-29 02:05:53 +01:00
|
|
|
if (typeof position !== 'function') {
|
|
|
|
if (typeof offset === 'function') {
|
2013-07-02 09:27:26 +02:00
|
|
|
position = offset;
|
|
|
|
offset = null;
|
|
|
|
} else {
|
|
|
|
position = length;
|
2010-08-25 05:46:37 +02:00
|
|
|
}
|
2013-07-02 09:27:26 +02:00
|
|
|
length = 'utf8';
|
2010-08-25 05:46:37 +02:00
|
|
|
}
|
2016-07-23 01:38:36 +02:00
|
|
|
callback = maybeCallback(position);
|
2014-12-09 05:29:47 +01:00
|
|
|
return binding.writeString(fd, buffer, offset, length, req);
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2017-04-16 21:19:36 +02:00
|
|
|
Object.defineProperty(fs.write, internalUtil.customPromisifyArgs,
|
|
|
|
{ value: ['bytesWritten', 'buffer'], enumerable: false });
|
|
|
|
|
2013-07-02 09:27:26 +02:00
|
|
|
// usage:
|
2016-07-23 22:43:41 +02:00
|
|
|
// fs.writeSync(fd, buffer[, offset[, length[, position]]]);
|
2013-07-02 09:27:26 +02:00
|
|
|
// OR
|
|
|
|
// fs.writeSync(fd, string[, position[, encoding]]);
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.writeSync = function(fd, buffer, offset, length, position) {
|
2017-12-23 01:19:33 +01:00
|
|
|
validateUint32(fd, 'fd');
|
2018-02-27 19:17:12 +01:00
|
|
|
const ctx = {};
|
|
|
|
let result;
|
2016-12-21 08:27:34 +01:00
|
|
|
if (isUint8Array(buffer)) {
|
2015-01-29 02:05:53 +01:00
|
|
|
if (position === undefined)
|
2013-07-02 09:27:26 +02:00
|
|
|
position = null;
|
2016-07-23 22:43:41 +02:00
|
|
|
if (typeof offset !== 'number')
|
|
|
|
offset = 0;
|
|
|
|
if (typeof length !== 'number')
|
|
|
|
length = buffer.length - offset;
|
2017-12-23 00:33:31 +01:00
|
|
|
validateOffsetLengthWrite(offset, length, buffer.byteLength);
|
2018-02-27 19:17:12 +01:00
|
|
|
result = binding.writeBuffer(fd, buffer, offset, length, position,
|
|
|
|
undefined, ctx);
|
|
|
|
} else {
|
|
|
|
if (typeof buffer !== 'string')
|
|
|
|
buffer += '';
|
|
|
|
if (offset === undefined)
|
|
|
|
offset = null;
|
|
|
|
result = binding.writeString(fd, buffer, offset, length,
|
|
|
|
undefined, ctx);
|
2010-05-19 20:17:50 +02:00
|
|
|
}
|
2018-02-27 19:17:12 +01:00
|
|
|
handleErrorFromBinding(ctx);
|
|
|
|
return result;
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.rename = function(oldPath, newPath, callback) {
|
2016-07-23 01:38:36 +02:00
|
|
|
callback = makeCallback(callback);
|
2018-01-23 03:23:46 +01:00
|
|
|
oldPath = getPathFromURL(oldPath);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(oldPath, 'oldPath');
|
2018-01-23 03:23:46 +01:00
|
|
|
newPath = getPathFromURL(newPath);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(newPath, 'newPath');
|
2017-12-13 23:24:34 +01:00
|
|
|
const req = new FSReqWrap();
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = callback;
|
2017-08-21 07:44:47 +02:00
|
|
|
binding.rename(pathModule.toNamespacedPath(oldPath),
|
|
|
|
pathModule.toNamespacedPath(newPath),
|
2014-12-09 05:29:47 +01:00
|
|
|
req);
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.renameSync = function(oldPath, newPath) {
|
2018-01-23 03:23:46 +01:00
|
|
|
oldPath = getPathFromURL(oldPath);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(oldPath, 'oldPath');
|
2018-01-23 03:23:46 +01:00
|
|
|
newPath = getPathFromURL(newPath);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(newPath, 'newPath');
|
2018-01-24 02:03:45 +01:00
|
|
|
const ctx = { path: oldPath, dest: newPath };
|
|
|
|
binding.rename(pathModule.toNamespacedPath(oldPath),
|
|
|
|
pathModule.toNamespacedPath(newPath), undefined, ctx);
|
2018-02-08 15:24:08 +01:00
|
|
|
handleErrorFromBinding(ctx);
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2012-08-04 21:39:11 +02:00
|
|
|
fs.truncate = function(path, len, callback) {
|
2016-07-23 01:37:54 +02:00
|
|
|
if (typeof path === 'number') {
|
2017-10-06 20:06:35 +02:00
|
|
|
showTruncateDeprecation();
|
2015-02-07 19:27:20 +01:00
|
|
|
return fs.ftruncate(path, len, callback);
|
2016-07-23 01:37:54 +02:00
|
|
|
}
|
2016-07-23 01:38:36 +02:00
|
|
|
if (typeof len === 'function') {
|
|
|
|
callback = len;
|
|
|
|
len = 0;
|
|
|
|
} else if (len === undefined) {
|
2012-08-04 21:39:11 +02:00
|
|
|
len = 0;
|
|
|
|
}
|
2014-12-09 05:29:47 +01:00
|
|
|
|
2016-07-23 01:38:36 +02:00
|
|
|
callback = maybeCallback(callback);
|
2013-10-08 11:25:22 +02:00
|
|
|
fs.open(path, 'r+', function(er, fd) {
|
2012-08-04 21:39:11 +02:00
|
|
|
if (er) return callback(er);
|
2014-12-09 05:29:47 +01:00
|
|
|
var req = new FSReqWrap();
|
2016-10-16 00:02:43 +02:00
|
|
|
req.oncomplete = function oncomplete(er) {
|
2012-08-04 21:39:11 +02:00
|
|
|
fs.close(fd, function(er2) {
|
|
|
|
callback(er || er2);
|
|
|
|
});
|
2014-12-09 05:29:47 +01:00
|
|
|
};
|
|
|
|
binding.ftruncate(fd, len, req);
|
2012-08-04 21:39:11 +02:00
|
|
|
});
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2012-08-04 21:39:11 +02:00
|
|
|
fs.truncateSync = function(path, len) {
|
2016-07-23 01:37:54 +02:00
|
|
|
if (typeof path === 'number') {
|
|
|
|
// legacy
|
2017-10-06 20:06:35 +02:00
|
|
|
showTruncateDeprecation();
|
2012-08-08 23:07:18 +02:00
|
|
|
return fs.ftruncateSync(path, len);
|
2016-07-23 01:37:54 +02:00
|
|
|
}
|
|
|
|
if (len === undefined) {
|
2012-08-04 21:39:11 +02:00
|
|
|
len = 0;
|
|
|
|
}
|
|
|
|
// allow error to be thrown, but still close fd.
|
2013-10-08 11:25:22 +02:00
|
|
|
var fd = fs.openSync(path, 'r+');
|
2015-06-03 00:11:04 +02:00
|
|
|
var ret;
|
|
|
|
|
2012-08-04 21:39:11 +02:00
|
|
|
try {
|
2015-06-03 00:11:04 +02:00
|
|
|
ret = fs.ftruncateSync(fd, len);
|
2012-08-04 21:39:11 +02:00
|
|
|
} finally {
|
|
|
|
fs.closeSync(fd);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
};
|
|
|
|
|
2017-12-13 23:24:34 +01:00
|
|
|
fs.ftruncate = function(fd, len = 0, callback) {
|
2016-07-23 01:38:36 +02:00
|
|
|
if (typeof len === 'function') {
|
|
|
|
callback = len;
|
|
|
|
len = 0;
|
2012-08-04 21:39:11 +02:00
|
|
|
}
|
2017-12-23 01:19:33 +01:00
|
|
|
validateUint32(fd, 'fd');
|
2018-03-19 13:43:24 +01:00
|
|
|
// TODO(BridgeAR): This does not seem right.
|
|
|
|
// There does not seem to be any validation before and if there is any, it
|
|
|
|
// should work similar to validateUint32 or not have a upper cap at all.
|
2018-04-15 11:16:50 +02:00
|
|
|
// This applies to all usage of `validateInt32(len, 'len')`.
|
|
|
|
validateInt32(len, 'len');
|
2017-11-26 21:44:20 +01:00
|
|
|
len = Math.max(0, len);
|
|
|
|
const req = new FSReqWrap();
|
2016-07-23 01:38:36 +02:00
|
|
|
req.oncomplete = makeCallback(callback);
|
2014-12-09 05:29:47 +01:00
|
|
|
binding.ftruncate(fd, len, req);
|
2012-08-04 21:39:11 +02:00
|
|
|
};
|
|
|
|
|
2017-12-13 23:24:34 +01:00
|
|
|
fs.ftruncateSync = function(fd, len = 0) {
|
2017-12-23 01:19:33 +01:00
|
|
|
validateUint32(fd, 'fd');
|
2018-04-15 11:16:50 +02:00
|
|
|
validateInt32(len, 'len');
|
2017-11-26 21:44:20 +01:00
|
|
|
len = Math.max(0, len);
|
2018-01-24 02:20:30 +01:00
|
|
|
const ctx = {};
|
|
|
|
binding.ftruncate(fd, len, undefined, ctx);
|
2018-02-08 15:24:08 +01:00
|
|
|
handleErrorFromBinding(ctx);
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.rmdir = function(path, callback) {
|
2018-02-09 16:31:26 +01:00
|
|
|
callback = makeCallback(callback);
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(path);
|
2017-12-13 23:24:34 +01:00
|
|
|
const req = new FSReqWrap();
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = callback;
|
2017-08-21 07:44:47 +02:00
|
|
|
binding.rmdir(pathModule.toNamespacedPath(path), req);
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.rmdirSync = function(path) {
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(path);
|
2018-02-03 14:39:43 +01:00
|
|
|
const ctx = { path };
|
|
|
|
binding.rmdir(pathModule.toNamespacedPath(path), undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.fdatasync = function(fd, callback) {
|
2017-12-23 01:19:33 +01:00
|
|
|
validateUint32(fd, 'fd');
|
2017-11-26 21:44:20 +01:00
|
|
|
const req = new FSReqWrap();
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = makeCallback(callback);
|
2016-07-23 01:37:54 +02:00
|
|
|
binding.fdatasync(fd, req);
|
2010-03-22 08:25:24 +01:00
|
|
|
};
|
|
|
|
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.fdatasyncSync = function(fd) {
|
2017-12-23 01:19:33 +01:00
|
|
|
validateUint32(fd, 'fd');
|
2018-01-24 02:37:52 +01:00
|
|
|
const ctx = {};
|
|
|
|
binding.fdatasync(fd, undefined, ctx);
|
2018-02-08 15:24:08 +01:00
|
|
|
handleErrorFromBinding(ctx);
|
2010-03-22 08:25:24 +01:00
|
|
|
};
|
|
|
|
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.fsync = function(fd, callback) {
|
2017-12-23 01:19:33 +01:00
|
|
|
validateUint32(fd, 'fd');
|
2017-11-26 21:44:20 +01:00
|
|
|
const req = new FSReqWrap();
|
2016-07-23 01:38:36 +02:00
|
|
|
req.oncomplete = makeCallback(callback);
|
2016-07-23 01:37:54 +02:00
|
|
|
binding.fsync(fd, req);
|
2010-03-22 08:25:24 +01:00
|
|
|
};
|
|
|
|
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.fsyncSync = function(fd) {
|
2017-12-23 01:19:33 +01:00
|
|
|
validateUint32(fd, 'fd');
|
2018-01-24 11:39:35 +01:00
|
|
|
const ctx = {};
|
|
|
|
binding.fsync(fd, undefined, ctx);
|
2018-02-08 15:24:08 +01:00
|
|
|
handleErrorFromBinding(ctx);
|
2010-03-22 08:25:24 +01:00
|
|
|
};
|
|
|
|
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.mkdir = function(path, mode, callback) {
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(path);
|
2018-05-09 16:44:44 +02:00
|
|
|
|
|
|
|
if (arguments.length < 3) {
|
|
|
|
callback = makeCallback(mode);
|
|
|
|
mode = 0o777;
|
|
|
|
} else {
|
|
|
|
callback = makeCallback(callback);
|
|
|
|
mode = validateAndMaskMode(mode, 'mode', 0o777);
|
|
|
|
}
|
2017-12-13 23:24:34 +01:00
|
|
|
|
|
|
|
const req = new FSReqWrap();
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = callback;
|
2017-12-13 23:24:34 +01:00
|
|
|
binding.mkdir(pathModule.toNamespacedPath(path), mode, req);
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.mkdirSync = function(path, mode) {
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(path);
|
2018-05-09 16:44:44 +02:00
|
|
|
mode = validateAndMaskMode(mode, 'mode', 0o777);
|
2018-02-03 14:49:32 +01:00
|
|
|
const ctx = { path };
|
|
|
|
binding.mkdir(pathModule.toNamespacedPath(path), mode, undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
fs: Buffer and encoding enhancements to fs API
This makes several changes:
1. Allow path/filename to be passed in as a Buffer on fs methods
2. Add `options.encoding` to fs.readdir, fs.readdirSync, fs.readlink,
fs.readlinkSync and fs.watch.
3. Documentation updates
For 1... it's now possible to do:
```js
fs.open(Buffer('/fs/foo/bar'), 'w+', (err, fd) => { });
```
For 2...
```js
fs.readdir('/fs/foo/bar', {encoding:'hex'}, (err,list) => { });
fs.readdir('/fs/foo/bar', {encoding:'buffer'}, (err, list) => { });
```
encoding can also be passed as a string
```js
fs.readdir('/fs/foo/bar', 'hex', (err,list) => { });
```
The default encoding is set to UTF8 so this addresses the
discrepency that existed previously between fs.readdir and
fs.watch handling filenames differently.
Fixes: https://github.com/nodejs/node/issues/2088
Refs: https://github.com/nodejs/node/issues/3519
PR-URL: https://github.com/nodejs/node/pull/5616
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
2016-03-09 05:58:45 +01:00
|
|
|
fs.readdir = function(path, options, callback) {
|
2016-06-25 20:33:05 +02:00
|
|
|
callback = makeCallback(typeof options === 'function' ? options : callback);
|
|
|
|
options = getOptions(options, {});
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(path);
|
2017-12-13 23:24:34 +01:00
|
|
|
|
|
|
|
const req = new FSReqWrap();
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = callback;
|
2017-08-21 07:44:47 +02:00
|
|
|
binding.readdir(pathModule.toNamespacedPath(path), options.encoding, req);
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
fs: Buffer and encoding enhancements to fs API
This makes several changes:
1. Allow path/filename to be passed in as a Buffer on fs methods
2. Add `options.encoding` to fs.readdir, fs.readdirSync, fs.readlink,
fs.readlinkSync and fs.watch.
3. Documentation updates
For 1... it's now possible to do:
```js
fs.open(Buffer('/fs/foo/bar'), 'w+', (err, fd) => { });
```
For 2...
```js
fs.readdir('/fs/foo/bar', {encoding:'hex'}, (err,list) => { });
fs.readdir('/fs/foo/bar', {encoding:'buffer'}, (err, list) => { });
```
encoding can also be passed as a string
```js
fs.readdir('/fs/foo/bar', 'hex', (err,list) => { });
```
The default encoding is set to UTF8 so this addresses the
discrepency that existed previously between fs.readdir and
fs.watch handling filenames differently.
Fixes: https://github.com/nodejs/node/issues/2088
Refs: https://github.com/nodejs/node/issues/3519
PR-URL: https://github.com/nodejs/node/pull/5616
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
2016-03-09 05:58:45 +01:00
|
|
|
fs.readdirSync = function(path, options) {
|
2016-06-25 20:33:05 +02:00
|
|
|
options = getOptions(options, {});
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(path);
|
2018-02-03 15:45:30 +01:00
|
|
|
const ctx = { path };
|
|
|
|
const result = binding.readdir(pathModule.toNamespacedPath(path),
|
|
|
|
options.encoding, undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
|
|
|
return result;
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.fstat = function(fd, callback) {
|
2017-12-23 01:19:33 +01:00
|
|
|
validateUint32(fd, 'fd');
|
2017-11-26 21:44:20 +01:00
|
|
|
const req = new FSReqWrap();
|
2017-03-12 01:41:20 +01:00
|
|
|
req.oncomplete = makeStatsCallback(callback);
|
2016-07-23 01:37:54 +02:00
|
|
|
binding.fstat(fd, req);
|
2010-05-12 22:35:33 +02:00
|
|
|
};
|
|
|
|
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.lstat = function(path, callback) {
|
2017-03-12 01:41:20 +01:00
|
|
|
callback = makeStatsCallback(callback);
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(path);
|
2017-12-13 23:24:34 +01:00
|
|
|
const req = new FSReqWrap();
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = callback;
|
2017-08-21 07:44:47 +02:00
|
|
|
binding.lstat(pathModule.toNamespacedPath(path), req);
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.stat = function(path, callback) {
|
2017-03-12 01:41:20 +01:00
|
|
|
callback = makeStatsCallback(callback);
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(path);
|
2017-12-13 23:24:34 +01:00
|
|
|
const req = new FSReqWrap();
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = callback;
|
2017-08-21 07:44:47 +02:00
|
|
|
binding.stat(pathModule.toNamespacedPath(path), req);
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.fstatSync = function(fd) {
|
2017-12-23 01:19:33 +01:00
|
|
|
validateUint32(fd, 'fd');
|
2017-12-28 16:16:33 +01:00
|
|
|
const ctx = { fd };
|
2018-04-07 10:57:22 +02:00
|
|
|
const stats = binding.fstat(fd, undefined, ctx);
|
2018-02-08 15:24:08 +01:00
|
|
|
handleErrorFromBinding(ctx);
|
2018-04-07 10:57:22 +02:00
|
|
|
return getStatsFromBinding(stats);
|
2010-05-12 22:35:33 +02:00
|
|
|
};
|
|
|
|
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.lstatSync = function(path) {
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(path);
|
2017-12-28 07:51:05 +01:00
|
|
|
const ctx = { path };
|
2018-04-07 10:57:22 +02:00
|
|
|
const stats = binding.lstat(pathModule.toNamespacedPath(path),
|
|
|
|
undefined, ctx);
|
2018-02-08 15:24:08 +01:00
|
|
|
handleErrorFromBinding(ctx);
|
2018-04-07 10:57:22 +02:00
|
|
|
return getStatsFromBinding(stats);
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.statSync = function(path) {
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(path);
|
2017-12-27 21:01:45 +01:00
|
|
|
const ctx = { path };
|
2018-04-07 10:57:22 +02:00
|
|
|
const stats = binding.stat(pathModule.toNamespacedPath(path),
|
|
|
|
undefined, ctx);
|
2018-02-08 15:24:08 +01:00
|
|
|
handleErrorFromBinding(ctx);
|
2018-04-07 10:57:22 +02:00
|
|
|
return getStatsFromBinding(stats);
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
fs: Buffer and encoding enhancements to fs API
This makes several changes:
1. Allow path/filename to be passed in as a Buffer on fs methods
2. Add `options.encoding` to fs.readdir, fs.readdirSync, fs.readlink,
fs.readlinkSync and fs.watch.
3. Documentation updates
For 1... it's now possible to do:
```js
fs.open(Buffer('/fs/foo/bar'), 'w+', (err, fd) => { });
```
For 2...
```js
fs.readdir('/fs/foo/bar', {encoding:'hex'}, (err,list) => { });
fs.readdir('/fs/foo/bar', {encoding:'buffer'}, (err, list) => { });
```
encoding can also be passed as a string
```js
fs.readdir('/fs/foo/bar', 'hex', (err,list) => { });
```
The default encoding is set to UTF8 so this addresses the
discrepency that existed previously between fs.readdir and
fs.watch handling filenames differently.
Fixes: https://github.com/nodejs/node/issues/2088
Refs: https://github.com/nodejs/node/issues/3519
PR-URL: https://github.com/nodejs/node/pull/5616
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
2016-03-09 05:58:45 +01:00
|
|
|
fs.readlink = function(path, options, callback) {
|
2016-06-25 20:33:05 +02:00
|
|
|
callback = makeCallback(typeof options === 'function' ? options : callback);
|
|
|
|
options = getOptions(options, {});
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(path, 'oldPath');
|
2017-12-13 23:24:34 +01:00
|
|
|
const req = new FSReqWrap();
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = callback;
|
2017-08-21 07:44:47 +02:00
|
|
|
binding.readlink(pathModule.toNamespacedPath(path), options.encoding, req);
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
fs: Buffer and encoding enhancements to fs API
This makes several changes:
1. Allow path/filename to be passed in as a Buffer on fs methods
2. Add `options.encoding` to fs.readdir, fs.readdirSync, fs.readlink,
fs.readlinkSync and fs.watch.
3. Documentation updates
For 1... it's now possible to do:
```js
fs.open(Buffer('/fs/foo/bar'), 'w+', (err, fd) => { });
```
For 2...
```js
fs.readdir('/fs/foo/bar', {encoding:'hex'}, (err,list) => { });
fs.readdir('/fs/foo/bar', {encoding:'buffer'}, (err, list) => { });
```
encoding can also be passed as a string
```js
fs.readdir('/fs/foo/bar', 'hex', (err,list) => { });
```
The default encoding is set to UTF8 so this addresses the
discrepency that existed previously between fs.readdir and
fs.watch handling filenames differently.
Fixes: https://github.com/nodejs/node/issues/2088
Refs: https://github.com/nodejs/node/issues/3519
PR-URL: https://github.com/nodejs/node/pull/5616
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
2016-03-09 05:58:45 +01:00
|
|
|
fs.readlinkSync = function(path, options) {
|
2016-06-25 20:33:05 +02:00
|
|
|
options = getOptions(options, {});
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(path, 'oldPath');
|
2018-01-24 00:51:08 +01:00
|
|
|
const ctx = { path };
|
|
|
|
const result = binding.readlink(pathModule.toNamespacedPath(path),
|
|
|
|
options.encoding, undefined, ctx);
|
2018-02-08 15:24:08 +01:00
|
|
|
handleErrorFromBinding(ctx);
|
2018-01-24 00:51:08 +01:00
|
|
|
return result;
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2015-11-25 05:40:42 +01:00
|
|
|
fs.symlink = function(target, path, type_, callback_) {
|
2015-01-29 02:05:53 +01:00
|
|
|
var type = (typeof type_ === 'string' ? type_ : null);
|
2012-06-06 21:33:29 +02:00
|
|
|
var callback = makeCallback(arguments[arguments.length - 1]);
|
2012-05-23 01:02:10 +02:00
|
|
|
|
2018-01-23 03:23:46 +01:00
|
|
|
target = getPathFromURL(target);
|
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(target, 'target');
|
|
|
|
validatePath(path);
|
2014-12-09 05:29:47 +01:00
|
|
|
|
2017-12-13 23:24:34 +01:00
|
|
|
const flags = stringToSymlinkType(type);
|
|
|
|
const req = new FSReqWrap();
|
|
|
|
req.oncomplete = callback;
|
2018-01-23 23:53:47 +01:00
|
|
|
|
2015-11-25 05:40:42 +01:00
|
|
|
binding.symlink(preprocessSymlinkDestination(target, type, path),
|
2017-12-13 23:24:34 +01:00
|
|
|
pathModule.toNamespacedPath(path), flags, req);
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2015-11-25 05:40:42 +01:00
|
|
|
fs.symlinkSync = function(target, path, type) {
|
2015-01-29 02:05:53 +01:00
|
|
|
type = (typeof type === 'string' ? type : null);
|
2018-01-23 03:23:46 +01:00
|
|
|
target = getPathFromURL(target);
|
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(target, 'target');
|
|
|
|
validatePath(path);
|
2017-12-13 23:24:34 +01:00
|
|
|
const flags = stringToSymlinkType(type);
|
2018-01-23 23:53:47 +01:00
|
|
|
|
|
|
|
const ctx = { path: target, dest: path };
|
|
|
|
binding.symlink(preprocessSymlinkDestination(target, type, path),
|
|
|
|
pathModule.toNamespacedPath(path), flags, undefined, ctx);
|
|
|
|
|
2018-02-08 15:24:08 +01:00
|
|
|
handleErrorFromBinding(ctx);
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2016-10-19 22:42:34 +02:00
|
|
|
fs.link = function(existingPath, newPath, callback) {
|
2016-07-23 01:38:36 +02:00
|
|
|
callback = makeCallback(callback);
|
2017-01-11 16:02:40 +01:00
|
|
|
|
2018-01-23 03:23:46 +01:00
|
|
|
existingPath = getPathFromURL(existingPath);
|
|
|
|
newPath = getPathFromURL(newPath);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(existingPath, 'existingPath');
|
|
|
|
validatePath(newPath, 'newPath');
|
2017-12-13 23:24:34 +01:00
|
|
|
|
|
|
|
const req = new FSReqWrap();
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = callback;
|
|
|
|
|
2017-08-21 07:44:47 +02:00
|
|
|
binding.link(pathModule.toNamespacedPath(existingPath),
|
|
|
|
pathModule.toNamespacedPath(newPath),
|
2014-12-09 05:29:47 +01:00
|
|
|
req);
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2016-10-19 22:42:34 +02:00
|
|
|
fs.linkSync = function(existingPath, newPath) {
|
2018-01-23 03:23:46 +01:00
|
|
|
existingPath = getPathFromURL(existingPath);
|
|
|
|
newPath = getPathFromURL(newPath);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(existingPath, 'existingPath');
|
|
|
|
validatePath(newPath, 'newPath');
|
2018-01-24 00:03:11 +01:00
|
|
|
|
|
|
|
const ctx = { path: existingPath, dest: newPath };
|
|
|
|
const result = binding.link(pathModule.toNamespacedPath(existingPath),
|
|
|
|
pathModule.toNamespacedPath(newPath),
|
|
|
|
undefined, ctx);
|
2018-02-08 15:24:08 +01:00
|
|
|
handleErrorFromBinding(ctx);
|
2018-01-24 00:03:11 +01:00
|
|
|
return result;
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.unlink = function(path, callback) {
|
2016-07-23 01:38:36 +02:00
|
|
|
callback = makeCallback(callback);
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(path);
|
2017-12-13 23:24:34 +01:00
|
|
|
const req = new FSReqWrap();
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = callback;
|
2017-08-21 07:44:47 +02:00
|
|
|
binding.unlink(pathModule.toNamespacedPath(path), req);
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.unlinkSync = function(path) {
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(path);
|
2018-01-24 15:18:37 +01:00
|
|
|
const ctx = { path };
|
|
|
|
binding.unlink(pathModule.toNamespacedPath(path), undefined, ctx);
|
2018-02-08 15:24:08 +01:00
|
|
|
handleErrorFromBinding(ctx);
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2011-03-30 00:31:41 +02:00
|
|
|
fs.fchmod = function(fd, mode, callback) {
|
2017-12-23 01:19:33 +01:00
|
|
|
validateUint32(fd, 'fd');
|
2018-05-09 16:44:44 +02:00
|
|
|
mode = validateAndMaskMode(mode, 'mode');
|
|
|
|
callback = makeCallback(callback);
|
2017-11-26 21:44:20 +01:00
|
|
|
|
|
|
|
const req = new FSReqWrap();
|
2018-05-09 16:44:44 +02:00
|
|
|
req.oncomplete = callback;
|
2017-11-26 21:44:20 +01:00
|
|
|
binding.fchmod(fd, mode, req);
|
2011-03-30 00:31:41 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
fs.fchmodSync = function(fd, mode) {
|
2017-12-23 01:19:33 +01:00
|
|
|
validateUint32(fd, 'fd');
|
2018-05-09 16:44:44 +02:00
|
|
|
mode = validateAndMaskMode(mode, 'mode');
|
2018-02-27 18:33:31 +01:00
|
|
|
const ctx = {};
|
|
|
|
binding.fchmod(fd, mode, undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
2011-03-30 00:31:41 +02:00
|
|
|
};
|
|
|
|
|
2018-05-15 01:36:37 +02:00
|
|
|
if (O_SYMLINK !== undefined) {
|
2011-03-30 01:34:05 +02:00
|
|
|
fs.lchmod = function(path, mode, callback) {
|
2016-07-23 01:38:36 +02:00
|
|
|
callback = maybeCallback(callback);
|
2018-05-15 01:36:37 +02:00
|
|
|
fs.open(path, O_WRONLY | O_SYMLINK, function(err, fd) {
|
2011-03-30 01:34:05 +02:00
|
|
|
if (err) {
|
|
|
|
callback(err);
|
|
|
|
return;
|
|
|
|
}
|
2017-07-03 15:20:32 +02:00
|
|
|
// Prefer to return the chmod error, if one occurs,
|
2011-11-22 22:10:57 +01:00
|
|
|
// but still try to close, and report closing errors if they occur.
|
|
|
|
fs.fchmod(fd, mode, function(err) {
|
|
|
|
fs.close(fd, function(err2) {
|
|
|
|
callback(err || err2);
|
|
|
|
});
|
|
|
|
});
|
2011-03-30 01:34:05 +02:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
fs.lchmodSync = function(path, mode) {
|
2018-05-15 01:36:37 +02:00
|
|
|
const fd = fs.openSync(path, O_WRONLY | O_SYMLINK);
|
2011-11-22 22:10:57 +01:00
|
|
|
|
2017-07-03 15:20:32 +02:00
|
|
|
// Prefer to return the chmod error, if one occurs,
|
2011-11-22 22:10:57 +01:00
|
|
|
// but still try to close, and report closing errors if they occur.
|
2018-01-24 00:07:42 +01:00
|
|
|
let ret;
|
2011-11-22 22:10:57 +01:00
|
|
|
try {
|
2015-06-03 00:11:04 +02:00
|
|
|
ret = fs.fchmodSync(fd, mode);
|
2018-01-24 00:07:42 +01:00
|
|
|
} finally {
|
|
|
|
fs.closeSync(fd);
|
2011-11-22 22:10:57 +01:00
|
|
|
}
|
|
|
|
return ret;
|
2011-03-30 01:34:05 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.chmod = function(path, mode, callback) {
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(path);
|
2018-05-09 16:44:44 +02:00
|
|
|
mode = validateAndMaskMode(mode, 'mode');
|
|
|
|
callback = makeCallback(callback);
|
2017-12-13 23:24:34 +01:00
|
|
|
|
|
|
|
const req = new FSReqWrap();
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = callback;
|
2017-12-13 23:24:34 +01:00
|
|
|
binding.chmod(pathModule.toNamespacedPath(path), mode, req);
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2010-12-02 02:43:30 +01:00
|
|
|
fs.chmodSync = function(path, mode) {
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(path);
|
2018-05-09 16:44:44 +02:00
|
|
|
mode = validateAndMaskMode(mode, 'mode');
|
|
|
|
|
2018-02-19 10:09:41 +01:00
|
|
|
const ctx = { path };
|
|
|
|
binding.chmod(pathModule.toNamespacedPath(path), mode, undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2018-05-15 01:36:37 +02:00
|
|
|
if (O_SYMLINK !== undefined) {
|
2011-03-30 01:34:05 +02:00
|
|
|
fs.lchown = function(path, uid, gid, callback) {
|
2016-07-23 01:38:36 +02:00
|
|
|
callback = maybeCallback(callback);
|
2018-05-15 01:36:37 +02:00
|
|
|
fs.open(path, O_WRONLY | O_SYMLINK, function(err, fd) {
|
2011-03-30 01:34:05 +02:00
|
|
|
if (err) {
|
|
|
|
callback(err);
|
|
|
|
return;
|
|
|
|
}
|
2018-01-24 00:07:42 +01:00
|
|
|
// Prefer to return the chown error, if one occurs,
|
|
|
|
// but still try to close, and report closing errors if they occur.
|
|
|
|
fs.fchown(fd, uid, gid, function(err) {
|
|
|
|
fs.close(fd, function(err2) {
|
|
|
|
callback(err || err2);
|
|
|
|
});
|
|
|
|
});
|
2011-03-30 01:34:05 +02:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
fs.lchownSync = function(path, uid, gid) {
|
2018-05-15 01:36:37 +02:00
|
|
|
const fd = fs.openSync(path, O_WRONLY | O_SYMLINK);
|
2018-01-24 00:07:42 +01:00
|
|
|
let ret;
|
|
|
|
try {
|
|
|
|
ret = fs.fchownSync(fd, uid, gid);
|
|
|
|
} finally {
|
|
|
|
fs.closeSync(fd);
|
|
|
|
}
|
|
|
|
return ret;
|
2011-03-30 01:34:05 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2011-03-30 00:31:41 +02:00
|
|
|
fs.fchown = function(fd, uid, gid, callback) {
|
2017-12-23 01:19:33 +01:00
|
|
|
validateUint32(fd, 'fd');
|
|
|
|
validateUint32(uid, 'uid');
|
|
|
|
validateUint32(gid, 'gid');
|
2017-11-27 01:53:33 +01:00
|
|
|
|
|
|
|
const req = new FSReqWrap();
|
2016-07-23 01:38:36 +02:00
|
|
|
req.oncomplete = makeCallback(callback);
|
2016-07-23 01:37:54 +02:00
|
|
|
binding.fchown(fd, uid, gid, req);
|
2011-03-30 00:31:41 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
fs.fchownSync = function(fd, uid, gid) {
|
2017-12-23 01:19:33 +01:00
|
|
|
validateUint32(fd, 'fd');
|
|
|
|
validateUint32(uid, 'uid');
|
|
|
|
validateUint32(gid, 'gid');
|
2017-11-27 01:53:33 +01:00
|
|
|
|
2018-02-27 18:45:17 +01:00
|
|
|
const ctx = {};
|
|
|
|
binding.fchown(fd, uid, gid, undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
2011-03-30 00:31:41 +02:00
|
|
|
};
|
|
|
|
|
2010-05-26 19:49:01 +02:00
|
|
|
fs.chown = function(path, uid, gid, callback) {
|
2016-07-23 01:38:36 +02:00
|
|
|
callback = makeCallback(callback);
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(path);
|
2017-12-23 01:19:33 +01:00
|
|
|
validateUint32(uid, 'uid');
|
|
|
|
validateUint32(gid, 'gid');
|
2017-12-13 23:24:34 +01:00
|
|
|
|
|
|
|
const req = new FSReqWrap();
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = callback;
|
2017-08-21 07:44:47 +02:00
|
|
|
binding.chown(pathModule.toNamespacedPath(path), uid, gid, req);
|
2010-05-26 19:49:01 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
fs.chownSync = function(path, uid, gid) {
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(path);
|
2017-12-23 01:19:33 +01:00
|
|
|
validateUint32(uid, 'uid');
|
|
|
|
validateUint32(gid, 'gid');
|
2018-02-19 20:35:39 +01:00
|
|
|
const ctx = { path };
|
|
|
|
binding.chown(pathModule.toNamespacedPath(path), uid, gid, undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
2010-05-26 19:49:01 +02:00
|
|
|
};
|
|
|
|
|
2010-10-29 12:38:13 +02:00
|
|
|
// exported for unit tests, not for public consumption
|
|
|
|
fs._toUnixTimestamp = toUnixTimestamp;
|
|
|
|
|
|
|
|
fs.utimes = function(path, atime, mtime, callback) {
|
2016-07-23 01:38:36 +02:00
|
|
|
callback = makeCallback(callback);
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(path);
|
2017-12-13 23:24:34 +01:00
|
|
|
|
|
|
|
const req = new FSReqWrap();
|
2014-12-09 05:29:47 +01:00
|
|
|
req.oncomplete = callback;
|
2017-08-21 07:44:47 +02:00
|
|
|
binding.utimes(pathModule.toNamespacedPath(path),
|
2012-06-06 21:33:29 +02:00
|
|
|
toUnixTimestamp(atime),
|
|
|
|
toUnixTimestamp(mtime),
|
2014-12-09 05:29:47 +01:00
|
|
|
req);
|
2010-10-29 12:38:13 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
fs.utimesSync = function(path, atime, mtime) {
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(path);
|
2018-02-19 21:23:47 +01:00
|
|
|
const ctx = { path };
|
2017-12-13 23:24:34 +01:00
|
|
|
binding.utimes(pathModule.toNamespacedPath(path),
|
2018-02-19 21:23:47 +01:00
|
|
|
toUnixTimestamp(atime), toUnixTimestamp(mtime),
|
|
|
|
undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
2010-10-29 12:38:13 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
fs.futimes = function(fd, atime, mtime, callback) {
|
2017-12-23 01:19:33 +01:00
|
|
|
validateUint32(fd, 'fd');
|
2017-11-27 02:05:26 +01:00
|
|
|
atime = toUnixTimestamp(atime, 'atime');
|
|
|
|
mtime = toUnixTimestamp(mtime, 'mtime');
|
|
|
|
const req = new FSReqWrap();
|
2016-07-23 01:38:36 +02:00
|
|
|
req.oncomplete = makeCallback(callback);
|
2014-12-09 05:29:47 +01:00
|
|
|
binding.futimes(fd, atime, mtime, req);
|
2010-10-29 12:38:13 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
fs.futimesSync = function(fd, atime, mtime) {
|
2017-12-23 01:19:33 +01:00
|
|
|
validateUint32(fd, 'fd');
|
2017-11-27 02:05:26 +01:00
|
|
|
atime = toUnixTimestamp(atime, 'atime');
|
|
|
|
mtime = toUnixTimestamp(mtime, 'mtime');
|
2018-02-27 19:25:02 +01:00
|
|
|
const ctx = {};
|
|
|
|
binding.futimes(fd, atime, mtime, undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
2010-10-29 12:38:13 +02:00
|
|
|
};
|
|
|
|
|
2017-04-24 08:20:45 +02:00
|
|
|
function writeAll(fd, isUserFd, buffer, offset, length, position, callback) {
|
2010-11-14 05:12:47 +01:00
|
|
|
// write(fd, buffer, offset, length, position, callback)
|
2011-11-02 19:06:16 +01:00
|
|
|
fs.write(fd, buffer, offset, length, position, function(writeErr, written) {
|
2010-03-01 19:14:49 +01:00
|
|
|
if (writeErr) {
|
2015-10-03 02:06:42 +02:00
|
|
|
if (isUserFd) {
|
2016-01-21 16:35:10 +01:00
|
|
|
callback(writeErr);
|
2015-10-03 02:06:42 +02:00
|
|
|
} else {
|
2018-04-30 09:08:20 +02:00
|
|
|
fs.close(fd, function close() {
|
2016-01-21 16:35:10 +01:00
|
|
|
callback(writeErr);
|
2015-10-03 02:06:42 +02:00
|
|
|
});
|
|
|
|
}
|
2017-10-17 00:37:14 +02:00
|
|
|
} else if (written === length) {
|
|
|
|
if (isUserFd) {
|
|
|
|
callback(null);
|
2010-03-01 19:14:49 +01:00
|
|
|
} else {
|
2017-10-17 00:37:14 +02:00
|
|
|
fs.close(fd, callback);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
offset += written;
|
|
|
|
length -= written;
|
|
|
|
if (position !== null) {
|
|
|
|
position += written;
|
2010-03-01 19:14:49 +01:00
|
|
|
}
|
2017-10-17 00:37:14 +02:00
|
|
|
writeAll(fd, isUserFd, buffer, offset, length, position, callback);
|
2010-03-01 19:14:49 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-06-25 20:33:05 +02:00
|
|
|
fs.writeFile = function(path, data, options, callback) {
|
2017-04-24 08:20:45 +02:00
|
|
|
callback = maybeCallback(callback || options);
|
2016-06-25 20:33:05 +02:00
|
|
|
options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'w' });
|
|
|
|
const flag = options.flag || 'w';
|
2015-10-03 02:06:42 +02:00
|
|
|
|
2016-07-23 01:37:54 +02:00
|
|
|
if (isFd(path)) {
|
2015-10-03 02:06:42 +02:00
|
|
|
writeFd(path, true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-06-07 17:53:23 +02:00
|
|
|
fs.open(path, flag, options.mode, function(openErr, fd) {
|
2010-03-01 19:14:49 +01:00
|
|
|
if (openErr) {
|
2016-01-21 16:35:10 +01:00
|
|
|
callback(openErr);
|
2010-03-01 19:14:49 +01:00
|
|
|
} else {
|
2015-10-03 02:06:42 +02:00
|
|
|
writeFd(fd, false);
|
2010-03-01 19:14:49 +01:00
|
|
|
}
|
|
|
|
});
|
2015-10-03 02:06:42 +02:00
|
|
|
|
|
|
|
function writeFd(fd, isUserFd) {
|
2016-12-21 08:27:34 +01:00
|
|
|
var buffer = isUint8Array(data) ?
|
2017-07-05 18:21:40 +02:00
|
|
|
data : Buffer.from('' + data, options.encoding || 'utf8');
|
2015-10-03 02:06:42 +02:00
|
|
|
var position = /a/.test(flag) ? null : 0;
|
|
|
|
|
|
|
|
writeAll(fd, isUserFd, buffer, 0, buffer.length, position, callback);
|
|
|
|
}
|
2010-03-01 19:14:49 +01:00
|
|
|
};
|
|
|
|
|
2013-03-01 18:10:26 +01:00
|
|
|
fs.writeFileSync = function(path, data, options) {
|
2016-06-25 20:33:05 +02:00
|
|
|
options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'w' });
|
|
|
|
const flag = options.flag || 'w';
|
2013-03-01 18:10:26 +01:00
|
|
|
|
2016-07-23 01:37:54 +02:00
|
|
|
var isUserFd = isFd(path); // file descriptor ownership
|
2015-10-03 02:06:42 +02:00
|
|
|
var fd = isUserFd ? path : fs.openSync(path, flag, options.mode);
|
|
|
|
|
2016-12-21 08:27:34 +01:00
|
|
|
if (!isUint8Array(data)) {
|
2016-01-26 00:00:06 +01:00
|
|
|
data = Buffer.from('' + data, options.encoding || 'utf8');
|
2010-11-14 05:12:47 +01:00
|
|
|
}
|
2015-03-05 01:03:34 +01:00
|
|
|
var offset = 0;
|
2010-11-14 05:12:47 +01:00
|
|
|
var length = data.length;
|
2013-03-01 18:10:26 +01:00
|
|
|
var position = /a/.test(flag) ? null : 0;
|
2012-05-03 01:03:08 +02:00
|
|
|
try {
|
2015-03-05 01:03:34 +01:00
|
|
|
while (length > 0) {
|
|
|
|
var written = fs.writeSync(fd, data, offset, length, position);
|
|
|
|
offset += written;
|
|
|
|
length -= written;
|
|
|
|
if (position !== null) {
|
|
|
|
position += written;
|
|
|
|
}
|
2012-05-03 01:03:08 +02:00
|
|
|
}
|
|
|
|
} finally {
|
2015-10-03 02:06:42 +02:00
|
|
|
if (!isUserFd) fs.closeSync(fd);
|
2010-03-01 19:14:49 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-06-25 20:33:05 +02:00
|
|
|
fs.appendFile = function(path, data, options, callback) {
|
2017-02-28 15:13:49 +01:00
|
|
|
callback = maybeCallback(callback || options);
|
2016-06-25 20:33:05 +02:00
|
|
|
options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'a' });
|
2011-11-02 19:06:16 +01:00
|
|
|
|
2016-10-09 16:07:59 +02:00
|
|
|
// Don't make changes directly on options object
|
|
|
|
options = copyObject(options);
|
2015-10-03 02:06:42 +02:00
|
|
|
|
|
|
|
// force append behavior when using a supplied file descriptor
|
2016-10-09 16:07:59 +02:00
|
|
|
if (!options.flag || isFd(path))
|
2015-10-03 02:06:42 +02:00
|
|
|
options.flag = 'a';
|
|
|
|
|
2013-03-01 18:10:26 +01:00
|
|
|
fs.writeFile(path, data, options, callback);
|
2011-11-02 19:06:16 +01:00
|
|
|
};
|
|
|
|
|
2013-03-01 18:10:26 +01:00
|
|
|
fs.appendFileSync = function(path, data, options) {
|
2016-06-25 20:33:05 +02:00
|
|
|
options = getOptions(options, { encoding: 'utf8', mode: 0o666, flag: 'a' });
|
2015-10-03 02:06:42 +02:00
|
|
|
|
2016-10-09 16:07:59 +02:00
|
|
|
// Don't make changes directly on options object
|
|
|
|
options = copyObject(options);
|
2011-11-02 19:06:16 +01:00
|
|
|
|
2015-10-03 02:06:42 +02:00
|
|
|
// force append behavior when using a supplied file descriptor
|
2016-10-09 16:07:59 +02:00
|
|
|
if (!options.flag || isFd(path))
|
2015-10-03 02:06:42 +02:00
|
|
|
options.flag = 'a';
|
|
|
|
|
2013-03-01 18:10:26 +01:00
|
|
|
fs.writeFileSync(path, data, options);
|
2011-11-02 19:06:16 +01:00
|
|
|
};
|
2011-09-23 01:18:08 +02:00
|
|
|
|
2011-09-23 09:45:41 +02:00
|
|
|
function FSWatcher() {
|
2012-06-12 21:53:08 +02:00
|
|
|
EventEmitter.call(this);
|
|
|
|
|
2011-09-23 01:18:08 +02:00
|
|
|
var self = this;
|
|
|
|
this._handle = new FSEvent();
|
2012-04-27 04:39:05 +02:00
|
|
|
this._handle.owner = this;
|
2011-09-23 01:18:08 +02:00
|
|
|
|
2016-07-01 10:33:20 +02:00
|
|
|
this._handle.onchange = function(status, eventType, filename) {
|
2018-03-02 17:28:05 +01:00
|
|
|
// TODO(joyeecheung): we may check self._handle.initialized here
|
|
|
|
// and return if that is false. This allows us to avoid firing the event
|
|
|
|
// after the handle is closed, and to fire both UV_RENAME and UV_CHANGE
|
|
|
|
// if they are set by libuv at the same time.
|
2013-07-18 23:18:50 +02:00
|
|
|
if (status < 0) {
|
2012-05-12 19:37:33 +02:00
|
|
|
self._handle.close();
|
2018-03-02 17:28:05 +01:00
|
|
|
const error = errors.uvException({
|
|
|
|
errno: status,
|
|
|
|
syscall: 'watch',
|
|
|
|
path: filename
|
|
|
|
});
|
2015-09-30 07:03:27 +02:00
|
|
|
error.filename = filename;
|
|
|
|
self.emit('error', error);
|
2011-09-23 01:18:08 +02:00
|
|
|
} else {
|
2016-07-01 10:33:20 +02:00
|
|
|
self.emit('change', eventType, filename);
|
2011-09-23 01:18:08 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
2011-09-23 09:45:41 +02:00
|
|
|
util.inherits(FSWatcher, EventEmitter);
|
2011-09-23 01:18:08 +02:00
|
|
|
|
2018-01-23 03:23:46 +01:00
|
|
|
// FIXME(joyeecheung): this method is not documented.
|
|
|
|
// At the moment if filename is undefined, we
|
2018-03-14 11:55:43 +01:00
|
|
|
// 1. Throw an Error if it's the first time .start() is called
|
|
|
|
// 2. Return silently if .start() has already been called
|
2018-01-23 03:23:46 +01:00
|
|
|
// on a valid filename and the wrap has been initialized
|
2018-03-14 11:55:43 +01:00
|
|
|
// This method is a noop if the watcher has already been started.
|
fs: Buffer and encoding enhancements to fs API
This makes several changes:
1. Allow path/filename to be passed in as a Buffer on fs methods
2. Add `options.encoding` to fs.readdir, fs.readdirSync, fs.readlink,
fs.readlinkSync and fs.watch.
3. Documentation updates
For 1... it's now possible to do:
```js
fs.open(Buffer('/fs/foo/bar'), 'w+', (err, fd) => { });
```
For 2...
```js
fs.readdir('/fs/foo/bar', {encoding:'hex'}, (err,list) => { });
fs.readdir('/fs/foo/bar', {encoding:'buffer'}, (err, list) => { });
```
encoding can also be passed as a string
```js
fs.readdir('/fs/foo/bar', 'hex', (err,list) => { });
```
The default encoding is set to UTF8 so this addresses the
discrepency that existed previously between fs.readdir and
fs.watch handling filenames differently.
Fixes: https://github.com/nodejs/node/issues/2088
Refs: https://github.com/nodejs/node/issues/3519
PR-URL: https://github.com/nodejs/node/pull/5616
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
2016-03-09 05:58:45 +01:00
|
|
|
FSWatcher.prototype.start = function(filename,
|
|
|
|
persistent,
|
|
|
|
recursive,
|
|
|
|
encoding) {
|
2018-03-02 17:28:05 +01:00
|
|
|
lazyAssert()(this._handle instanceof FSEvent, 'handle must be a FSEvent');
|
|
|
|
if (this._handle.initialized) {
|
2018-03-14 11:55:43 +01:00
|
|
|
return;
|
2018-03-02 17:28:05 +01:00
|
|
|
}
|
|
|
|
|
2018-01-23 03:23:46 +01:00
|
|
|
filename = getPathFromURL(filename);
|
2018-03-02 17:28:05 +01:00
|
|
|
validatePath(filename, 'filename');
|
|
|
|
|
2018-03-14 11:55:43 +01:00
|
|
|
const err = this._handle.start(pathModule.toNamespacedPath(filename),
|
|
|
|
persistent,
|
|
|
|
recursive,
|
|
|
|
encoding);
|
2013-07-18 23:18:50 +02:00
|
|
|
if (err) {
|
2018-03-02 17:28:05 +01:00
|
|
|
const error = errors.uvException({
|
|
|
|
errno: err,
|
|
|
|
syscall: 'watch',
|
|
|
|
path: filename
|
|
|
|
});
|
2015-09-30 07:03:27 +02:00
|
|
|
error.filename = filename;
|
|
|
|
throw error;
|
2011-09-23 01:18:08 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-03-14 11:55:43 +01:00
|
|
|
// This method is a noop if the watcher has not been started.
|
2011-09-23 09:45:41 +02:00
|
|
|
FSWatcher.prototype.close = function() {
|
2018-03-02 17:28:05 +01:00
|
|
|
lazyAssert()(this._handle instanceof FSEvent, 'handle must be a FSEvent');
|
|
|
|
if (!this._handle.initialized) {
|
2018-03-14 11:55:43 +01:00
|
|
|
return;
|
2018-03-02 17:28:05 +01:00
|
|
|
}
|
2011-09-23 01:18:08 +02:00
|
|
|
this._handle.close();
|
2018-04-09 21:00:18 +02:00
|
|
|
process.nextTick(emitCloseNT, this);
|
2011-09-23 01:18:08 +02:00
|
|
|
};
|
|
|
|
|
2018-04-09 21:00:18 +02:00
|
|
|
function emitCloseNT(self) {
|
|
|
|
self.emit('close');
|
|
|
|
}
|
|
|
|
|
fs: Buffer and encoding enhancements to fs API
This makes several changes:
1. Allow path/filename to be passed in as a Buffer on fs methods
2. Add `options.encoding` to fs.readdir, fs.readdirSync, fs.readlink,
fs.readlinkSync and fs.watch.
3. Documentation updates
For 1... it's now possible to do:
```js
fs.open(Buffer('/fs/foo/bar'), 'w+', (err, fd) => { });
```
For 2...
```js
fs.readdir('/fs/foo/bar', {encoding:'hex'}, (err,list) => { });
fs.readdir('/fs/foo/bar', {encoding:'buffer'}, (err, list) => { });
```
encoding can also be passed as a string
```js
fs.readdir('/fs/foo/bar', 'hex', (err,list) => { });
```
The default encoding is set to UTF8 so this addresses the
discrepency that existed previously between fs.readdir and
fs.watch handling filenames differently.
Fixes: https://github.com/nodejs/node/issues/2088
Refs: https://github.com/nodejs/node/issues/3519
PR-URL: https://github.com/nodejs/node/pull/5616
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
2016-03-09 05:58:45 +01:00
|
|
|
fs.watch = function(filename, options, listener) {
|
|
|
|
if (typeof options === 'function') {
|
|
|
|
listener = options;
|
2011-09-23 01:18:08 +02:00
|
|
|
}
|
2016-06-25 20:33:05 +02:00
|
|
|
options = getOptions(options, {});
|
2011-09-23 01:18:08 +02:00
|
|
|
|
2016-10-09 16:07:59 +02:00
|
|
|
// Don't make changes directly on options object
|
|
|
|
options = copyObject(options);
|
|
|
|
|
2015-01-29 02:05:53 +01:00
|
|
|
if (options.persistent === undefined) options.persistent = true;
|
|
|
|
if (options.recursive === undefined) options.recursive = false;
|
2011-09-23 01:18:08 +02:00
|
|
|
|
fs: Buffer and encoding enhancements to fs API
This makes several changes:
1. Allow path/filename to be passed in as a Buffer on fs methods
2. Add `options.encoding` to fs.readdir, fs.readdirSync, fs.readlink,
fs.readlinkSync and fs.watch.
3. Documentation updates
For 1... it's now possible to do:
```js
fs.open(Buffer('/fs/foo/bar'), 'w+', (err, fd) => { });
```
For 2...
```js
fs.readdir('/fs/foo/bar', {encoding:'hex'}, (err,list) => { });
fs.readdir('/fs/foo/bar', {encoding:'buffer'}, (err, list) => { });
```
encoding can also be passed as a string
```js
fs.readdir('/fs/foo/bar', 'hex', (err,list) => { });
```
The default encoding is set to UTF8 so this addresses the
discrepency that existed previously between fs.readdir and
fs.watch handling filenames differently.
Fixes: https://github.com/nodejs/node/issues/2088
Refs: https://github.com/nodejs/node/issues/3519
PR-URL: https://github.com/nodejs/node/pull/5616
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
2016-03-09 05:58:45 +01:00
|
|
|
const watcher = new FSWatcher();
|
|
|
|
watcher.start(filename,
|
|
|
|
options.persistent,
|
|
|
|
options.recursive,
|
|
|
|
options.encoding);
|
2011-09-23 01:18:08 +02:00
|
|
|
|
2012-05-19 23:05:43 +02:00
|
|
|
if (listener) {
|
|
|
|
watcher.addListener('change', listener);
|
|
|
|
}
|
|
|
|
|
2011-09-23 01:18:08 +02:00
|
|
|
return watcher;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2010-03-01 19:42:37 +01:00
|
|
|
// Stat Change Watchers
|
|
|
|
|
2016-09-06 18:34:18 +02:00
|
|
|
function emitStop(self) {
|
|
|
|
self.emit('stop');
|
|
|
|
}
|
|
|
|
|
2011-07-19 10:23:50 +02:00
|
|
|
function StatWatcher() {
|
2012-06-12 21:53:08 +02:00
|
|
|
EventEmitter.call(this);
|
|
|
|
|
2011-07-19 10:23:50 +02:00
|
|
|
var self = this;
|
|
|
|
this._handle = new binding.StatWatcher();
|
|
|
|
|
2012-06-16 22:41:37 +02:00
|
|
|
// uv_fs_poll is a little more powerful than ev_stat but we curb it for
|
|
|
|
// the sake of backwards compatibility
|
|
|
|
var oldStatus = -1;
|
|
|
|
|
2018-03-30 22:02:57 +02:00
|
|
|
this._handle.onchange = function(newStatus, stats) {
|
2012-09-17 17:40:23 +02:00
|
|
|
if (oldStatus === -1 &&
|
|
|
|
newStatus === -1 &&
|
2018-04-07 10:57:22 +02:00
|
|
|
stats[2/* new nlink */] === stats[16/* old nlink */]) return;
|
2012-09-17 17:40:23 +02:00
|
|
|
|
2012-06-16 22:41:37 +02:00
|
|
|
oldStatus = newStatus;
|
2018-03-30 22:02:57 +02:00
|
|
|
self.emit('change', getStatsFromBinding(stats),
|
|
|
|
getStatsFromBinding(stats, kFsStatsFieldsLength));
|
2011-07-19 10:23:50 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
this._handle.onstop = function() {
|
2016-09-06 18:34:18 +02:00
|
|
|
process.nextTick(emitStop, self);
|
2011-07-19 10:23:50 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
util.inherits(StatWatcher, EventEmitter);
|
|
|
|
|
|
|
|
|
2018-01-23 03:23:46 +01:00
|
|
|
// FIXME(joyeecheung): this method is not documented.
|
|
|
|
// At the moment if filename is undefined, we
|
2018-03-14 13:11:55 +01:00
|
|
|
// 1. Throw an Error if it's the first time .start() is called
|
|
|
|
// 2. Return silently if .start() has already been called
|
2018-01-23 03:23:46 +01:00
|
|
|
// on a valid filename and the wrap has been initialized
|
2018-03-14 13:11:55 +01:00
|
|
|
// This method is a noop if the watcher has already been started.
|
2011-07-19 10:23:50 +02:00
|
|
|
StatWatcher.prototype.start = function(filename, persistent, interval) {
|
2018-03-14 13:11:55 +01:00
|
|
|
lazyAssert()(this._handle instanceof binding.StatWatcher,
|
|
|
|
'handle must be a StatWatcher');
|
|
|
|
if (this._handle.isActive) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-01-23 03:23:46 +01:00
|
|
|
filename = getPathFromURL(filename);
|
2018-03-14 13:11:55 +01:00
|
|
|
validatePath(filename, 'filename');
|
|
|
|
validateUint32(interval, 'interval');
|
|
|
|
const err = this._handle.start(pathModule.toNamespacedPath(filename),
|
|
|
|
persistent, interval);
|
|
|
|
if (err) {
|
|
|
|
const error = errors.uvException({
|
|
|
|
errno: err,
|
|
|
|
syscall: 'watch',
|
|
|
|
path: filename
|
|
|
|
});
|
|
|
|
error.filename = filename;
|
|
|
|
throw error;
|
|
|
|
}
|
2011-07-19 10:23:50 +02:00
|
|
|
};
|
|
|
|
|
2018-03-14 13:11:55 +01:00
|
|
|
// FIXME(joyeecheung): this method is not documented while there is
|
|
|
|
// another documented fs.unwatchFile(). The counterpart in
|
|
|
|
// FSWatcher is .close()
|
|
|
|
// This method is a noop if the watcher has not been started.
|
2011-07-19 10:23:50 +02:00
|
|
|
StatWatcher.prototype.stop = function() {
|
2018-03-14 13:11:55 +01:00
|
|
|
lazyAssert()(this._handle instanceof binding.StatWatcher,
|
|
|
|
'handle must be a StatWatcher');
|
|
|
|
if (!this._handle.isActive) {
|
|
|
|
return;
|
|
|
|
}
|
2011-07-19 10:23:50 +02:00
|
|
|
this._handle.stop();
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-06-02 19:02:15 +02:00
|
|
|
const statWatchers = new Map();
|
2011-07-19 10:23:50 +02:00
|
|
|
|
2015-07-01 17:14:52 +02:00
|
|
|
fs.watchFile = function(filename, options, listener) {
|
2018-01-23 03:23:46 +01:00
|
|
|
filename = getPathFromURL(filename);
|
|
|
|
validatePath(filename);
|
2014-02-06 07:29:58 +01:00
|
|
|
filename = pathModule.resolve(filename);
|
2010-03-01 19:42:37 +01:00
|
|
|
var stat;
|
|
|
|
|
2015-07-01 17:14:52 +02:00
|
|
|
var defaults = {
|
2012-06-21 15:03:21 +02:00
|
|
|
// Poll interval in milliseconds. 5007 is what libev used to use. It's
|
|
|
|
// a little on the slow side but let's stick with it for now to keep
|
|
|
|
// behavioral changes to a minimum.
|
|
|
|
interval: 5007,
|
2012-06-21 20:42:33 +02:00
|
|
|
persistent: true
|
2012-06-21 15:03:21 +02:00
|
|
|
};
|
|
|
|
|
2015-07-01 17:14:52 +02:00
|
|
|
if (options !== null && typeof options === 'object') {
|
|
|
|
options = util._extend(defaults, options);
|
2010-03-01 19:42:37 +01:00
|
|
|
} else {
|
2016-07-23 01:38:36 +02:00
|
|
|
listener = options;
|
2015-07-01 17:14:52 +02:00
|
|
|
options = defaults;
|
2010-03-01 19:42:37 +01:00
|
|
|
}
|
|
|
|
|
2016-07-23 01:38:36 +02:00
|
|
|
if (typeof listener !== 'function') {
|
2018-02-27 14:55:32 +01:00
|
|
|
throw new ERR_INVALID_ARG_TYPE('listener', 'Function', listener);
|
2016-07-23 01:38:36 +02:00
|
|
|
}
|
|
|
|
|
2015-06-02 19:02:15 +02:00
|
|
|
stat = statWatchers.get(filename);
|
|
|
|
|
|
|
|
if (stat === undefined) {
|
|
|
|
stat = new StatWatcher();
|
2010-03-01 19:42:37 +01:00
|
|
|
stat.start(filename, options.persistent, options.interval);
|
2015-06-02 19:02:15 +02:00
|
|
|
statWatchers.set(filename, stat);
|
2010-03-01 19:42:37 +01:00
|
|
|
}
|
2015-06-02 19:02:15 +02:00
|
|
|
|
2010-12-02 02:43:30 +01:00
|
|
|
stat.addListener('change', listener);
|
2010-03-01 19:42:37 +01:00
|
|
|
return stat;
|
|
|
|
};
|
|
|
|
|
2012-07-08 16:31:07 +02:00
|
|
|
fs.unwatchFile = function(filename, listener) {
|
2018-01-23 03:23:46 +01:00
|
|
|
filename = getPathFromURL(filename);
|
|
|
|
validatePath(filename);
|
2014-02-06 07:29:58 +01:00
|
|
|
filename = pathModule.resolve(filename);
|
2015-06-02 19:02:15 +02:00
|
|
|
var stat = statWatchers.get(filename);
|
2012-07-08 16:31:07 +02:00
|
|
|
|
2015-06-02 19:02:15 +02:00
|
|
|
if (stat === undefined) return;
|
2012-07-08 16:31:07 +02:00
|
|
|
|
2015-01-29 02:05:53 +01:00
|
|
|
if (typeof listener === 'function') {
|
2012-07-08 16:31:07 +02:00
|
|
|
stat.removeListener('change', listener);
|
|
|
|
} else {
|
|
|
|
stat.removeAllListeners('change');
|
|
|
|
}
|
|
|
|
|
2015-08-11 20:31:50 +02:00
|
|
|
if (stat.listenerCount('change') === 0) {
|
2010-03-01 19:42:37 +01:00
|
|
|
stat.stop();
|
2015-06-02 19:02:15 +02:00
|
|
|
statWatchers.delete(filename);
|
2010-03-01 19:42:37 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2010-09-10 03:49:28 +02:00
|
|
|
|
2017-03-12 05:59:37 +01:00
|
|
|
var splitRoot;
|
|
|
|
if (isWindows) {
|
|
|
|
// Regex to find the device root on Windows (e.g. 'c:\\'), including trailing
|
|
|
|
// slash.
|
|
|
|
const splitRootRe = /^(?:[a-zA-Z]:|[\\/]{2}[^\\/]+[\\/][^\\/]+)?[\\/]*/;
|
|
|
|
splitRoot = function splitRoot(str) {
|
|
|
|
return splitRootRe.exec(str)[0];
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
splitRoot = function splitRoot(str) {
|
|
|
|
for (var i = 0; i < str.length; ++i) {
|
2018-02-13 12:49:53 +01:00
|
|
|
if (str.charCodeAt(i) !== CHAR_FORWARD_SLASH)
|
2017-03-12 05:59:37 +01:00
|
|
|
return str.slice(0, i);
|
|
|
|
}
|
|
|
|
return str;
|
|
|
|
};
|
|
|
|
}
|
2016-07-27 00:18:35 +02:00
|
|
|
|
2017-01-18 04:50:33 +01:00
|
|
|
function encodeRealpathResult(result, options) {
|
|
|
|
if (!options || !options.encoding || options.encoding === 'utf8')
|
2016-07-27 00:18:35 +02:00
|
|
|
return result;
|
|
|
|
const asBuffer = Buffer.from(result);
|
|
|
|
if (options.encoding === 'buffer') {
|
|
|
|
return asBuffer;
|
|
|
|
} else {
|
|
|
|
return asBuffer.toString(options.encoding);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-13 11:09:52 +01:00
|
|
|
// Finds the next portion of a (partial) path, up to the next path delimiter
|
|
|
|
var nextPart;
|
|
|
|
if (isWindows) {
|
|
|
|
nextPart = function nextPart(p, i) {
|
|
|
|
for (; i < p.length; ++i) {
|
|
|
|
const ch = p.charCodeAt(i);
|
2018-02-13 12:49:53 +01:00
|
|
|
|
|
|
|
// Check for a separator character
|
|
|
|
if (ch === CHAR_BACKWARD_SLASH || ch === CHAR_FORWARD_SLASH)
|
2017-01-13 11:09:52 +01:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
nextPart = function nextPart(p, i) { return p.indexOf('/', i); };
|
|
|
|
}
|
|
|
|
|
2017-03-20 00:11:10 +01:00
|
|
|
const emptyObj = Object.create(null);
|
2016-07-27 00:18:35 +02:00
|
|
|
fs.realpathSync = function realpathSync(p, options) {
|
2017-03-12 05:59:37 +01:00
|
|
|
if (!options)
|
|
|
|
options = emptyObj;
|
|
|
|
else
|
|
|
|
options = getOptions(options, emptyObj);
|
2018-01-23 03:23:46 +01:00
|
|
|
p = getPathFromURL(p);
|
2017-03-12 05:59:37 +01:00
|
|
|
if (typeof p !== 'string') {
|
2018-01-23 03:23:46 +01:00
|
|
|
p += '';
|
2017-03-12 05:59:37 +01:00
|
|
|
}
|
2018-01-23 03:23:46 +01:00
|
|
|
validatePath(p);
|
2016-07-27 00:18:35 +02:00
|
|
|
p = pathModule.resolve(p);
|
|
|
|
|
2018-05-15 01:36:37 +02:00
|
|
|
const cache = options[realpathCacheKey];
|
2016-08-14 18:41:28 +02:00
|
|
|
const maybeCachedResult = cache && cache.get(p);
|
|
|
|
if (maybeCachedResult) {
|
|
|
|
return maybeCachedResult;
|
|
|
|
}
|
2016-07-27 00:18:35 +02:00
|
|
|
|
2017-03-20 00:11:10 +01:00
|
|
|
const seenLinks = Object.create(null);
|
|
|
|
const knownHard = Object.create(null);
|
2017-01-13 11:07:18 +01:00
|
|
|
const original = p;
|
|
|
|
|
2016-07-27 00:18:35 +02:00
|
|
|
// current character position in p
|
|
|
|
var pos;
|
|
|
|
// the partial path so far, including a trailing slash if any
|
|
|
|
var current;
|
|
|
|
// the partial path without a trailing slash (except when pointing at a root)
|
|
|
|
var base;
|
|
|
|
// the partial path scanned in the previous round, with slash
|
|
|
|
var previous;
|
|
|
|
|
2017-01-13 11:04:18 +01:00
|
|
|
// Skip over roots
|
2017-03-12 05:59:37 +01:00
|
|
|
current = base = splitRoot(p);
|
|
|
|
pos = current.length;
|
2016-07-27 00:18:35 +02:00
|
|
|
|
2017-01-13 11:04:18 +01:00
|
|
|
// On windows, check that the root exists. On unix there is no need.
|
|
|
|
if (isWindows && !knownHard[base]) {
|
2017-12-28 07:51:05 +01:00
|
|
|
const ctx = { path: base };
|
|
|
|
binding.lstat(pathModule.toNamespacedPath(base), undefined, ctx);
|
2018-02-08 15:24:08 +01:00
|
|
|
handleErrorFromBinding(ctx);
|
2017-01-13 11:04:18 +01:00
|
|
|
knownHard[base] = true;
|
2016-07-27 00:18:35 +02:00
|
|
|
}
|
|
|
|
|
2017-06-17 15:11:45 +02:00
|
|
|
// walk down the path, swapping out linked path parts for their real
|
2016-07-27 00:18:35 +02:00
|
|
|
// values
|
|
|
|
// NB: p.length changes.
|
|
|
|
while (pos < p.length) {
|
|
|
|
// find the next part
|
2017-01-13 11:09:52 +01:00
|
|
|
var result = nextPart(p, pos);
|
2016-07-27 00:18:35 +02:00
|
|
|
previous = current;
|
2017-01-13 11:09:52 +01:00
|
|
|
if (result === -1) {
|
|
|
|
var last = p.slice(pos);
|
|
|
|
current += last;
|
|
|
|
base = previous + last;
|
|
|
|
pos = p.length;
|
|
|
|
} else {
|
|
|
|
current += p.slice(pos, result + 1);
|
|
|
|
base = previous + p.slice(pos, result);
|
|
|
|
pos = result + 1;
|
|
|
|
}
|
2016-07-27 00:18:35 +02:00
|
|
|
|
2017-05-15 00:57:54 +02:00
|
|
|
// continue if not a symlink, break if a pipe/socket
|
2016-08-14 18:41:28 +02:00
|
|
|
if (knownHard[base] || (cache && cache.get(base) === base)) {
|
2018-04-07 10:57:22 +02:00
|
|
|
if (isFileType(statValues, S_IFIFO) ||
|
|
|
|
isFileType(statValues, S_IFSOCK)) {
|
2017-05-15 00:57:54 +02:00
|
|
|
break;
|
|
|
|
}
|
2016-07-27 00:18:35 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
var resolvedLink;
|
2017-01-13 11:11:11 +01:00
|
|
|
var maybeCachedResolved = cache && cache.get(base);
|
2016-08-14 18:41:28 +02:00
|
|
|
if (maybeCachedResolved) {
|
|
|
|
resolvedLink = maybeCachedResolved;
|
|
|
|
} else {
|
2017-03-12 01:41:20 +01:00
|
|
|
// Use stats array directly to avoid creating an fs.Stats instance just
|
|
|
|
// for our internal use.
|
|
|
|
|
2017-08-21 07:44:47 +02:00
|
|
|
var baseLong = pathModule.toNamespacedPath(base);
|
2017-12-28 07:51:05 +01:00
|
|
|
const ctx = { path: base };
|
2018-04-07 10:57:22 +02:00
|
|
|
const stats = binding.lstat(baseLong, undefined, ctx);
|
2018-02-08 15:24:08 +01:00
|
|
|
handleErrorFromBinding(ctx);
|
2017-03-12 01:41:20 +01:00
|
|
|
|
2018-04-07 10:57:22 +02:00
|
|
|
if (!isFileType(stats, S_IFLNK)) {
|
2016-08-14 18:41:28 +02:00
|
|
|
knownHard[base] = true;
|
2016-12-12 16:56:36 +01:00
|
|
|
if (cache) cache.set(base, base);
|
2016-08-14 18:41:28 +02:00
|
|
|
continue;
|
|
|
|
}
|
2016-07-27 00:18:35 +02:00
|
|
|
|
2016-08-14 18:41:28 +02:00
|
|
|
// read the link if it wasn't read before
|
|
|
|
// dev/ino always return 0 on windows, so skip the check.
|
2017-01-13 11:11:11 +01:00
|
|
|
var linkTarget = null;
|
|
|
|
var id;
|
2016-08-14 18:41:28 +02:00
|
|
|
if (!isWindows) {
|
2018-04-07 10:57:22 +02:00
|
|
|
var dev = stats[0].toString(32);
|
|
|
|
var ino = stats[7].toString(32);
|
2017-03-12 01:41:20 +01:00
|
|
|
id = `${dev}:${ino}`;
|
2017-03-12 05:59:37 +01:00
|
|
|
if (seenLinks[id]) {
|
2016-08-14 18:41:28 +02:00
|
|
|
linkTarget = seenLinks[id];
|
|
|
|
}
|
2016-07-27 00:18:35 +02:00
|
|
|
}
|
2016-08-14 18:41:28 +02:00
|
|
|
if (linkTarget === null) {
|
2017-12-27 21:01:45 +01:00
|
|
|
const ctx = { path: base };
|
|
|
|
binding.stat(baseLong, undefined, ctx);
|
2018-02-08 15:24:08 +01:00
|
|
|
handleErrorFromBinding(ctx);
|
2018-01-24 00:51:08 +01:00
|
|
|
linkTarget = binding.readlink(baseLong, undefined, undefined, ctx);
|
2018-02-08 15:24:08 +01:00
|
|
|
handleErrorFromBinding(ctx);
|
2016-08-14 18:41:28 +02:00
|
|
|
}
|
|
|
|
resolvedLink = pathModule.resolve(previous, linkTarget);
|
2016-07-27 00:18:35 +02:00
|
|
|
|
2016-08-14 18:41:28 +02:00
|
|
|
if (cache) cache.set(base, resolvedLink);
|
|
|
|
if (!isWindows) seenLinks[id] = linkTarget;
|
|
|
|
}
|
2016-07-27 00:18:35 +02:00
|
|
|
|
|
|
|
// resolve the link, then start over
|
|
|
|
p = pathModule.resolve(resolvedLink, p.slice(pos));
|
2017-01-13 11:04:18 +01:00
|
|
|
|
|
|
|
// Skip over roots
|
2017-03-12 05:59:37 +01:00
|
|
|
current = base = splitRoot(p);
|
|
|
|
pos = current.length;
|
2017-01-13 11:04:18 +01:00
|
|
|
|
|
|
|
// On windows, check that the root exists. On unix there is no need.
|
|
|
|
if (isWindows && !knownHard[base]) {
|
2017-12-28 07:51:05 +01:00
|
|
|
const ctx = { path: base };
|
|
|
|
binding.lstat(pathModule.toNamespacedPath(base), undefined, ctx);
|
2018-02-08 15:24:08 +01:00
|
|
|
handleErrorFromBinding(ctx);
|
2017-01-13 11:04:18 +01:00
|
|
|
knownHard[base] = true;
|
|
|
|
}
|
2016-07-27 00:18:35 +02:00
|
|
|
}
|
|
|
|
|
2016-08-14 18:41:28 +02:00
|
|
|
if (cache) cache.set(original, p);
|
2016-07-27 00:18:35 +02:00
|
|
|
return encodeRealpathResult(p, options);
|
2012-06-09 00:26:04 +02:00
|
|
|
};
|
2010-09-10 03:49:28 +02:00
|
|
|
|
2011-02-09 01:54:25 +01:00
|
|
|
|
2017-10-05 13:10:03 +02:00
|
|
|
fs.realpathSync.native = function(path, options) {
|
|
|
|
options = getOptions(options, {});
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
|
|
|
validatePath(path);
|
2018-02-03 15:22:05 +01:00
|
|
|
const ctx = { path };
|
|
|
|
const result = binding.realpath(path, options.encoding, undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
|
|
|
return result;
|
2017-10-05 13:10:03 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2016-07-27 00:18:35 +02:00
|
|
|
fs.realpath = function realpath(p, options, callback) {
|
2016-06-25 20:33:05 +02:00
|
|
|
callback = maybeCallback(typeof options === 'function' ? options : callback);
|
2017-03-12 05:59:37 +01:00
|
|
|
if (!options)
|
|
|
|
options = emptyObj;
|
|
|
|
else
|
|
|
|
options = getOptions(options, emptyObj);
|
2018-01-23 03:23:46 +01:00
|
|
|
p = getPathFromURL(p);
|
2017-03-12 05:59:37 +01:00
|
|
|
if (typeof p !== 'string') {
|
2018-01-23 03:23:46 +01:00
|
|
|
p += '';
|
2017-03-12 05:59:37 +01:00
|
|
|
}
|
2018-01-23 03:23:46 +01:00
|
|
|
validatePath(p);
|
2016-07-27 00:18:35 +02:00
|
|
|
p = pathModule.resolve(p);
|
|
|
|
|
2017-03-20 00:11:10 +01:00
|
|
|
const seenLinks = Object.create(null);
|
|
|
|
const knownHard = Object.create(null);
|
2016-07-27 00:18:35 +02:00
|
|
|
|
|
|
|
// current character position in p
|
|
|
|
var pos;
|
|
|
|
// the partial path so far, including a trailing slash if any
|
|
|
|
var current;
|
|
|
|
// the partial path without a trailing slash (except when pointing at a root)
|
|
|
|
var base;
|
|
|
|
// the partial path scanned in the previous round, with slash
|
|
|
|
var previous;
|
|
|
|
|
2017-03-12 05:59:37 +01:00
|
|
|
current = base = splitRoot(p);
|
|
|
|
pos = current.length;
|
2016-07-27 00:18:35 +02:00
|
|
|
|
2017-01-13 11:04:18 +01:00
|
|
|
// On windows, check that the root exists. On unix there is no need.
|
|
|
|
if (isWindows && !knownHard[base]) {
|
2018-04-07 10:57:22 +02:00
|
|
|
fs.lstat(base, function(err, stats) {
|
2017-01-13 11:04:18 +01:00
|
|
|
if (err) return callback(err);
|
|
|
|
knownHard[base] = true;
|
|
|
|
LOOP();
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
process.nextTick(LOOP);
|
2016-07-27 00:18:35 +02:00
|
|
|
}
|
|
|
|
|
2017-06-17 15:11:45 +02:00
|
|
|
// walk down the path, swapping out linked path parts for their real
|
2016-07-27 00:18:35 +02:00
|
|
|
// values
|
|
|
|
function LOOP() {
|
|
|
|
// stop if scanned past end of path
|
|
|
|
if (pos >= p.length) {
|
|
|
|
return callback(null, encodeRealpathResult(p, options));
|
|
|
|
}
|
|
|
|
|
|
|
|
// find the next part
|
2017-01-13 11:09:52 +01:00
|
|
|
var result = nextPart(p, pos);
|
2016-07-27 00:18:35 +02:00
|
|
|
previous = current;
|
2017-01-13 11:09:52 +01:00
|
|
|
if (result === -1) {
|
|
|
|
var last = p.slice(pos);
|
|
|
|
current += last;
|
|
|
|
base = previous + last;
|
|
|
|
pos = p.length;
|
|
|
|
} else {
|
|
|
|
current += p.slice(pos, result + 1);
|
|
|
|
base = previous + p.slice(pos, result);
|
|
|
|
pos = result + 1;
|
|
|
|
}
|
2016-07-27 00:18:35 +02:00
|
|
|
|
2017-05-15 00:57:54 +02:00
|
|
|
// continue if not a symlink, break if a pipe/socket
|
2016-07-27 00:18:35 +02:00
|
|
|
if (knownHard[base]) {
|
2018-04-07 10:57:22 +02:00
|
|
|
if (isFileType(statValues, S_IFIFO) ||
|
|
|
|
isFileType(statValues, S_IFSOCK)) {
|
2017-05-15 00:57:54 +02:00
|
|
|
return callback(null, encodeRealpathResult(p, options));
|
|
|
|
}
|
2016-07-27 00:18:35 +02:00
|
|
|
return process.nextTick(LOOP);
|
|
|
|
}
|
|
|
|
|
|
|
|
return fs.lstat(base, gotStat);
|
|
|
|
}
|
|
|
|
|
2018-04-07 10:57:22 +02:00
|
|
|
function gotStat(err, stats) {
|
2016-07-27 00:18:35 +02:00
|
|
|
if (err) return callback(err);
|
|
|
|
|
|
|
|
// if not a symlink, skip to the next path part
|
2018-04-07 10:57:22 +02:00
|
|
|
if (!stats.isSymbolicLink()) {
|
2016-07-27 00:18:35 +02:00
|
|
|
knownHard[base] = true;
|
|
|
|
return process.nextTick(LOOP);
|
|
|
|
}
|
|
|
|
|
|
|
|
// stat & read the link if not read before
|
|
|
|
// call gotTarget as soon as the link target is known
|
|
|
|
// dev/ino always return 0 on windows, so skip the check.
|
2016-08-14 18:41:28 +02:00
|
|
|
let id;
|
2016-07-27 00:18:35 +02:00
|
|
|
if (!isWindows) {
|
2018-04-07 10:57:22 +02:00
|
|
|
var dev = stats.dev.toString(32);
|
|
|
|
var ino = stats.ino.toString(32);
|
2017-03-12 01:41:20 +01:00
|
|
|
id = `${dev}:${ino}`;
|
2017-03-12 05:59:37 +01:00
|
|
|
if (seenLinks[id]) {
|
2016-07-27 00:18:35 +02:00
|
|
|
return gotTarget(null, seenLinks[id], base);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fs.stat(base, function(err) {
|
|
|
|
if (err) return callback(err);
|
|
|
|
|
|
|
|
fs.readlink(base, function(err, target) {
|
|
|
|
if (!isWindows) seenLinks[id] = target;
|
|
|
|
gotTarget(err, target);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function gotTarget(err, target, base) {
|
|
|
|
if (err) return callback(err);
|
|
|
|
|
|
|
|
var resolvedLink = pathModule.resolve(previous, target);
|
|
|
|
gotResolvedLink(resolvedLink);
|
|
|
|
}
|
|
|
|
|
|
|
|
function gotResolvedLink(resolvedLink) {
|
|
|
|
// resolve the link, then start over
|
|
|
|
p = pathModule.resolve(resolvedLink, p.slice(pos));
|
2017-03-12 05:59:37 +01:00
|
|
|
current = base = splitRoot(p);
|
|
|
|
pos = current.length;
|
2017-01-13 11:04:18 +01:00
|
|
|
|
|
|
|
// On windows, check that the root exists. On unix there is no need.
|
|
|
|
if (isWindows && !knownHard[base]) {
|
|
|
|
fs.lstat(base, function(err) {
|
|
|
|
if (err) return callback(err);
|
|
|
|
knownHard[base] = true;
|
|
|
|
LOOP();
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
process.nextTick(LOOP);
|
|
|
|
}
|
2016-07-27 00:18:35 +02:00
|
|
|
}
|
|
|
|
};
|
2010-05-25 00:47:40 +02:00
|
|
|
|
2017-10-05 13:10:03 +02:00
|
|
|
|
|
|
|
fs.realpath.native = function(path, options, callback) {
|
2018-02-09 16:31:26 +01:00
|
|
|
callback = makeCallback(callback || options);
|
2017-10-05 13:10:03 +02:00
|
|
|
options = getOptions(options, {});
|
2018-01-23 03:23:46 +01:00
|
|
|
path = getPathFromURL(path);
|
|
|
|
validatePath(path);
|
2017-10-05 13:10:03 +02:00
|
|
|
const req = new FSReqWrap();
|
|
|
|
req.oncomplete = callback;
|
|
|
|
return binding.realpath(path, options.encoding, req);
|
|
|
|
};
|
|
|
|
|
2016-05-30 19:45:01 +02:00
|
|
|
fs.mkdtemp = function(prefix, options, callback) {
|
2016-06-25 20:33:05 +02:00
|
|
|
callback = makeCallback(typeof options === 'function' ? options : callback);
|
|
|
|
options = getOptions(options, {});
|
2017-08-26 13:46:47 +02:00
|
|
|
if (!prefix || typeof prefix !== 'string') {
|
2018-02-27 14:55:32 +01:00
|
|
|
throw new ERR_INVALID_ARG_TYPE('prefix', 'string', prefix);
|
2017-08-26 13:46:47 +02:00
|
|
|
}
|
2018-01-23 03:23:46 +01:00
|
|
|
nullCheck(prefix, 'prefix');
|
2016-05-18 14:17:07 +02:00
|
|
|
var req = new FSReqWrap();
|
|
|
|
req.oncomplete = callback;
|
2017-11-10 13:47:17 +01:00
|
|
|
binding.mkdtemp(`${prefix}XXXXXX`, options.encoding, req);
|
2016-05-18 14:17:07 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
fs.mkdtempSync = function(prefix, options) {
|
2018-01-23 03:23:46 +01:00
|
|
|
options = getOptions(options, {});
|
2017-08-26 13:46:47 +02:00
|
|
|
if (!prefix || typeof prefix !== 'string') {
|
2018-02-27 14:55:32 +01:00
|
|
|
throw new ERR_INVALID_ARG_TYPE('prefix', 'string', prefix);
|
2017-08-26 13:46:47 +02:00
|
|
|
}
|
2018-01-23 03:23:46 +01:00
|
|
|
nullCheck(prefix, 'prefix');
|
2018-02-19 21:54:19 +01:00
|
|
|
const path = `${prefix}XXXXXX`;
|
|
|
|
const ctx = { path };
|
|
|
|
const result = binding.mkdtemp(path, options.encoding,
|
|
|
|
undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
|
|
|
return result;
|
2016-05-18 14:17:07 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2017-09-06 18:54:29 +02:00
|
|
|
// Define copyFile() flags.
|
|
|
|
Object.defineProperties(fs.constants, {
|
2018-05-15 01:36:37 +02:00
|
|
|
COPYFILE_EXCL: { enumerable: true, value: UV_FS_COPYFILE_EXCL },
|
2018-04-02 21:12:57 +02:00
|
|
|
COPYFILE_FICLONE: {
|
|
|
|
enumerable: true,
|
2018-05-15 01:36:37 +02:00
|
|
|
value: UV_FS_COPYFILE_FICLONE
|
2018-04-02 21:12:57 +02:00
|
|
|
},
|
|
|
|
COPYFILE_FICLONE_FORCE: {
|
|
|
|
enumerable: true,
|
2018-05-15 01:36:37 +02:00
|
|
|
value: UV_FS_COPYFILE_FICLONE_FORCE
|
2018-04-02 21:12:57 +02:00
|
|
|
}
|
2017-09-06 18:54:29 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
fs.copyFile = function(src, dest, flags, callback) {
|
|
|
|
if (typeof flags === 'function') {
|
|
|
|
callback = flags;
|
|
|
|
flags = 0;
|
|
|
|
} else if (typeof callback !== 'function') {
|
2018-02-27 14:55:32 +01:00
|
|
|
throw new ERR_INVALID_CALLBACK();
|
2017-09-06 18:54:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
src = getPathFromURL(src);
|
|
|
|
dest = getPathFromURL(dest);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(src, 'src');
|
|
|
|
validatePath(dest, 'dest');
|
2017-12-13 23:24:34 +01:00
|
|
|
|
2017-09-06 18:54:29 +02:00
|
|
|
src = pathModule._makeLong(src);
|
|
|
|
dest = pathModule._makeLong(dest);
|
|
|
|
flags = flags | 0;
|
|
|
|
const req = new FSReqWrap();
|
|
|
|
req.oncomplete = makeCallback(callback);
|
|
|
|
binding.copyFile(src, dest, flags, req);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
fs.copyFileSync = function(src, dest, flags) {
|
|
|
|
src = getPathFromURL(src);
|
|
|
|
dest = getPathFromURL(dest);
|
2017-12-23 00:42:21 +01:00
|
|
|
validatePath(src, 'src');
|
|
|
|
validatePath(dest, 'dest');
|
2017-12-13 23:24:34 +01:00
|
|
|
|
2018-02-16 06:25:21 +01:00
|
|
|
const ctx = { path: src, dest }; // non-prefixed
|
|
|
|
|
2017-09-06 18:54:29 +02:00
|
|
|
src = pathModule._makeLong(src);
|
|
|
|
dest = pathModule._makeLong(dest);
|
|
|
|
flags = flags | 0;
|
2018-02-16 06:25:21 +01:00
|
|
|
binding.copyFile(src, dest, flags, undefined, ctx);
|
|
|
|
handleErrorFromBinding(ctx);
|
2017-09-06 18:54:29 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2010-05-25 00:47:40 +02:00
|
|
|
var pool;
|
2010-12-02 02:43:30 +01:00
|
|
|
|
2013-01-04 17:05:27 +01:00
|
|
|
function allocNewPool(poolSize) {
|
2016-01-26 00:00:06 +01:00
|
|
|
pool = Buffer.allocUnsafe(poolSize);
|
2010-05-25 00:47:40 +02:00
|
|
|
pool.used = 0;
|
2010-03-02 03:01:44 +01:00
|
|
|
}
|
2010-03-02 23:12:52 +01:00
|
|
|
|
2010-05-25 00:47:40 +02:00
|
|
|
|
2010-04-08 19:22:55 +02:00
|
|
|
fs.createReadStream = function(path, options) {
|
2010-04-28 03:51:41 +02:00
|
|
|
return new ReadStream(path, options);
|
2010-03-03 12:39:41 +01:00
|
|
|
};
|
|
|
|
|
2012-10-05 02:44:48 +02:00
|
|
|
util.inherits(ReadStream, Readable);
|
|
|
|
fs.ReadStream = ReadStream;
|
2010-03-03 12:39:41 +01:00
|
|
|
|
2012-10-05 02:44:48 +02:00
|
|
|
function ReadStream(path, options) {
|
|
|
|
if (!(this instanceof ReadStream))
|
|
|
|
return new ReadStream(path, options);
|
2010-03-03 12:39:41 +01:00
|
|
|
|
2012-10-05 02:44:48 +02:00
|
|
|
// a little bit bigger buffer and water marks by default
|
2016-10-09 16:07:59 +02:00
|
|
|
options = copyObject(getOptions(options, {}));
|
2015-01-28 05:18:08 +01:00
|
|
|
if (options.highWaterMark === undefined)
|
|
|
|
options.highWaterMark = 64 * 1024;
|
2010-04-12 18:57:24 +02:00
|
|
|
|
2018-01-29 19:32:34 +01:00
|
|
|
// for backwards compat do not emit close on destroy.
|
|
|
|
options.emitClose = false;
|
|
|
|
|
2012-10-05 02:44:48 +02:00
|
|
|
Readable.call(this, options);
|
2010-03-03 12:39:41 +01:00
|
|
|
|
2018-01-23 03:23:46 +01:00
|
|
|
// path will be ignored when fd is specified, so it can be falsy
|
|
|
|
this.path = getPathFromURL(path);
|
2015-01-28 05:18:08 +01:00
|
|
|
this.fd = options.fd === undefined ? null : options.fd;
|
|
|
|
this.flags = options.flags === undefined ? 'r' : options.flags;
|
|
|
|
this.mode = options.mode === undefined ? 0o666 : options.mode;
|
|
|
|
|
2018-03-13 20:42:33 +01:00
|
|
|
this.start = options.start;
|
2015-06-03 00:11:04 +02:00
|
|
|
this.end = options.end;
|
2015-01-28 05:18:08 +01:00
|
|
|
this.autoClose = options.autoClose === undefined ? true : options.autoClose;
|
2012-10-05 02:44:48 +02:00
|
|
|
this.pos = undefined;
|
2016-08-01 21:31:16 +02:00
|
|
|
this.bytesRead = 0;
|
2018-01-05 10:41:14 +01:00
|
|
|
this.closed = false;
|
2010-09-27 19:34:16 +02:00
|
|
|
|
2015-01-29 02:05:53 +01:00
|
|
|
if (this.start !== undefined) {
|
2018-04-09 19:32:08 +02:00
|
|
|
if (!Number.isSafeInteger(this.start)) {
|
|
|
|
if (typeof this.start !== 'number')
|
|
|
|
throw new ERR_INVALID_ARG_TYPE('start', 'number', this.start);
|
|
|
|
if (!Number.isInteger(this.start))
|
|
|
|
throw new ERR_OUT_OF_RANGE('start', 'an integer', this.start);
|
|
|
|
throw new ERR_OUT_OF_RANGE(
|
|
|
|
'start',
|
|
|
|
'>= 0 and <= 2 ** 53 - 1',
|
|
|
|
this.start
|
|
|
|
);
|
2012-02-18 02:53:57 +01:00
|
|
|
}
|
2018-04-09 19:32:08 +02:00
|
|
|
if (this.start < 0) {
|
|
|
|
throw new ERR_OUT_OF_RANGE(
|
|
|
|
'start',
|
|
|
|
'>= 0 and <= 2 ** 53 - 1',
|
|
|
|
this.start
|
|
|
|
);
|
2010-07-20 14:46:27 +02:00
|
|
|
}
|
2011-09-09 01:19:28 +02:00
|
|
|
|
|
|
|
this.pos = this.start;
|
2010-07-20 14:46:27 +02:00
|
|
|
}
|
|
|
|
|
2018-04-09 19:32:08 +02:00
|
|
|
if (this.end === undefined) {
|
2018-03-13 20:42:33 +01:00
|
|
|
this.end = Infinity;
|
2018-04-09 19:32:08 +02:00
|
|
|
} else if (this.end !== Infinity) {
|
|
|
|
if (!Number.isSafeInteger(this.end)) {
|
|
|
|
if (typeof this.end !== 'number')
|
|
|
|
throw new ERR_INVALID_ARG_TYPE('end', 'number', this.end);
|
|
|
|
if (!Number.isInteger(this.end))
|
|
|
|
throw new ERR_OUT_OF_RANGE('end', 'an integer', this.end);
|
|
|
|
throw new ERR_OUT_OF_RANGE('end', '>= 0 and <= 2 ** 53 - 1', this.end);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.end < 0) {
|
|
|
|
throw new ERR_OUT_OF_RANGE('end', '>= 0 and <= 2 ** 53 - 1', this.end);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.start !== undefined && this.start > this.end) {
|
|
|
|
throw new ERR_OUT_OF_RANGE(
|
|
|
|
'start',
|
|
|
|
`<= "end" (here: ${this.end})`,
|
|
|
|
this.start
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2018-03-13 20:42:33 +01:00
|
|
|
|
2015-01-29 02:05:53 +01:00
|
|
|
if (typeof this.fd !== 'number')
|
2012-10-05 02:44:48 +02:00
|
|
|
this.open();
|
2010-03-03 12:39:41 +01:00
|
|
|
|
2012-10-05 02:44:48 +02:00
|
|
|
this.on('end', function() {
|
2012-12-17 16:03:19 +01:00
|
|
|
if (this.autoClose) {
|
|
|
|
this.destroy();
|
|
|
|
}
|
2012-10-05 02:44:48 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
fs.FileReadStream = fs.ReadStream; // support the legacy name
|
|
|
|
|
|
|
|
ReadStream.prototype.open = function() {
|
|
|
|
var self = this;
|
|
|
|
fs.open(this.path, this.flags, this.mode, function(er, fd) {
|
|
|
|
if (er) {
|
2013-08-20 15:53:54 +02:00
|
|
|
if (self.autoClose) {
|
2012-12-17 16:03:19 +01:00
|
|
|
self.destroy();
|
|
|
|
}
|
2012-10-05 02:44:48 +02:00
|
|
|
self.emit('error', er);
|
2010-03-03 12:39:41 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-04-08 19:37:10 +02:00
|
|
|
self.fd = fd;
|
|
|
|
self.emit('open', fd);
|
2018-03-17 11:54:46 +01:00
|
|
|
self.emit('ready');
|
2012-10-05 02:44:48 +02:00
|
|
|
// start the flow of data.
|
|
|
|
self.read();
|
2010-04-08 19:37:10 +02:00
|
|
|
});
|
|
|
|
};
|
2010-03-04 22:06:06 +01:00
|
|
|
|
stream: There is no _read cb, there is only push
This makes it so that `stream.push(chunk)` is the only way to signal the
end of reading, removing the confusing disparity between the
callback-style _read method, and the fact that most real-world streams
do not have a 1:1 corollation between the "please give me data" event,
and the actual arrival of a chunk of data.
It is still possible, of course, to implement a `CallbackReadable` on
top of this. Simply provide a method like this as the callback:
function readCallback(er, chunk) {
if (er)
stream.emit('error', er);
else
stream.push(chunk);
}
However, *only* fs streams actually would behave in this way, so it
makes not a lot of sense to make TCP, TLS, HTTP, and all the rest have
to bend into this uncomfortable paradigm.
2013-03-01 00:32:32 +01:00
|
|
|
ReadStream.prototype._read = function(n) {
|
2017-06-20 23:37:00 +02:00
|
|
|
if (typeof this.fd !== 'number') {
|
2012-10-05 02:44:48 +02:00
|
|
|
return this.once('open', function() {
|
stream: There is no _read cb, there is only push
This makes it so that `stream.push(chunk)` is the only way to signal the
end of reading, removing the confusing disparity between the
callback-style _read method, and the fact that most real-world streams
do not have a 1:1 corollation between the "please give me data" event,
and the actual arrival of a chunk of data.
It is still possible, of course, to implement a `CallbackReadable` on
top of this. Simply provide a method like this as the callback:
function readCallback(er, chunk) {
if (er)
stream.emit('error', er);
else
stream.push(chunk);
}
However, *only* fs streams actually would behave in this way, so it
makes not a lot of sense to make TCP, TLS, HTTP, and all the rest have
to bend into this uncomfortable paradigm.
2013-03-01 00:32:32 +01:00
|
|
|
this._read(n);
|
2012-10-05 02:44:48 +02:00
|
|
|
});
|
2017-06-20 23:37:00 +02:00
|
|
|
}
|
2010-05-25 00:47:40 +02:00
|
|
|
|
2012-10-05 02:44:48 +02:00
|
|
|
if (this.destroyed)
|
|
|
|
return;
|
2010-03-03 12:39:41 +01:00
|
|
|
|
2010-05-25 00:47:40 +02:00
|
|
|
if (!pool || pool.length - pool.used < kMinPoolSpace) {
|
2013-03-06 07:57:15 +01:00
|
|
|
// discard the old pool.
|
2017-05-05 15:57:57 +02:00
|
|
|
allocNewPool(this.readableHighWaterMark);
|
2010-05-25 00:47:40 +02:00
|
|
|
}
|
|
|
|
|
2012-10-05 02:44:48 +02:00
|
|
|
// Grab another reference to the pool in the case that while we're
|
|
|
|
// in the thread pool another read() finishes up the pool, and
|
|
|
|
// allocates a new one.
|
2010-05-25 00:47:40 +02:00
|
|
|
var thisPool = pool;
|
2012-10-05 02:44:48 +02:00
|
|
|
var toRead = Math.min(pool.length - pool.used, n);
|
2010-05-25 00:47:40 +02:00
|
|
|
var start = pool.used;
|
|
|
|
|
2015-01-29 02:05:53 +01:00
|
|
|
if (this.pos !== undefined)
|
2010-07-20 14:46:27 +02:00
|
|
|
toRead = Math.min(this.end - this.pos + 1, toRead);
|
2018-03-13 20:42:33 +01:00
|
|
|
else
|
|
|
|
toRead = Math.min(this.end - this.bytesRead + 1, toRead);
|
2010-07-20 14:46:27 +02:00
|
|
|
|
2012-10-05 02:44:48 +02:00
|
|
|
// already read everything we were supposed to read!
|
|
|
|
// treat as EOF.
|
|
|
|
if (toRead <= 0)
|
stream: There is no _read cb, there is only push
This makes it so that `stream.push(chunk)` is the only way to signal the
end of reading, removing the confusing disparity between the
callback-style _read method, and the fact that most real-world streams
do not have a 1:1 corollation between the "please give me data" event,
and the actual arrival of a chunk of data.
It is still possible, of course, to implement a `CallbackReadable` on
top of this. Simply provide a method like this as the callback:
function readCallback(er, chunk) {
if (er)
stream.emit('error', er);
else
stream.push(chunk);
}
However, *only* fs streams actually would behave in this way, so it
makes not a lot of sense to make TCP, TLS, HTTP, and all the rest have
to bend into this uncomfortable paradigm.
2013-03-01 00:32:32 +01:00
|
|
|
return this.push(null);
|
2010-03-03 12:39:41 +01:00
|
|
|
|
2012-10-05 02:44:48 +02:00
|
|
|
// the actual read.
|
2017-11-19 17:11:24 +01:00
|
|
|
fs.read(this.fd, pool, pool.used, toRead, this.pos, (er, bytesRead) => {
|
2012-10-05 02:44:48 +02:00
|
|
|
if (er) {
|
2017-11-19 17:11:24 +01:00
|
|
|
if (this.autoClose) {
|
|
|
|
this.destroy();
|
2012-12-17 16:03:19 +01:00
|
|
|
}
|
2017-11-19 17:11:24 +01:00
|
|
|
this.emit('error', er);
|
stream: There is no _read cb, there is only push
This makes it so that `stream.push(chunk)` is the only way to signal the
end of reading, removing the confusing disparity between the
callback-style _read method, and the fact that most real-world streams
do not have a 1:1 corollation between the "please give me data" event,
and the actual arrival of a chunk of data.
It is still possible, of course, to implement a `CallbackReadable` on
top of this. Simply provide a method like this as the callback:
function readCallback(er, chunk) {
if (er)
stream.emit('error', er);
else
stream.push(chunk);
}
However, *only* fs streams actually would behave in this way, so it
makes not a lot of sense to make TCP, TLS, HTTP, and all the rest have
to bend into this uncomfortable paradigm.
2013-03-01 00:32:32 +01:00
|
|
|
} else {
|
|
|
|
var b = null;
|
2016-08-01 21:31:16 +02:00
|
|
|
if (bytesRead > 0) {
|
2017-11-19 17:11:24 +01:00
|
|
|
this.bytesRead += bytesRead;
|
stream: There is no _read cb, there is only push
This makes it so that `stream.push(chunk)` is the only way to signal the
end of reading, removing the confusing disparity between the
callback-style _read method, and the fact that most real-world streams
do not have a 1:1 corollation between the "please give me data" event,
and the actual arrival of a chunk of data.
It is still possible, of course, to implement a `CallbackReadable` on
top of this. Simply provide a method like this as the callback:
function readCallback(er, chunk) {
if (er)
stream.emit('error', er);
else
stream.push(chunk);
}
However, *only* fs streams actually would behave in this way, so it
makes not a lot of sense to make TCP, TLS, HTTP, and all the rest have
to bend into this uncomfortable paradigm.
2013-03-01 00:32:32 +01:00
|
|
|
b = thisPool.slice(start, start + bytesRead);
|
2016-08-01 21:31:16 +02:00
|
|
|
}
|
2010-04-08 19:37:10 +02:00
|
|
|
|
2017-11-19 17:11:24 +01:00
|
|
|
this.push(b);
|
stream: There is no _read cb, there is only push
This makes it so that `stream.push(chunk)` is the only way to signal the
end of reading, removing the confusing disparity between the
callback-style _read method, and the fact that most real-world streams
do not have a 1:1 corollation between the "please give me data" event,
and the actual arrival of a chunk of data.
It is still possible, of course, to implement a `CallbackReadable` on
top of this. Simply provide a method like this as the callback:
function readCallback(er, chunk) {
if (er)
stream.emit('error', er);
else
stream.push(chunk);
}
However, *only* fs streams actually would behave in this way, so it
makes not a lot of sense to make TCP, TLS, HTTP, and all the rest have
to bend into this uncomfortable paradigm.
2013-03-01 00:32:32 +01:00
|
|
|
}
|
2017-11-19 17:11:24 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
// move the pool positions, and internal position for reading.
|
|
|
|
if (this.pos !== undefined)
|
|
|
|
this.pos += toRead;
|
|
|
|
pool.used += toRead;
|
2010-05-25 00:47:40 +02:00
|
|
|
};
|
|
|
|
|
2017-05-06 14:20:52 +02:00
|
|
|
ReadStream.prototype._destroy = function(err, cb) {
|
2018-01-05 10:41:14 +01:00
|
|
|
const isOpen = typeof this.fd !== 'number';
|
|
|
|
if (isOpen) {
|
|
|
|
this.once('open', closeFsStream.bind(null, this, cb, err));
|
|
|
|
return;
|
2012-10-05 02:44:48 +02:00
|
|
|
}
|
2017-02-07 19:38:33 +01:00
|
|
|
|
2018-04-01 18:58:16 +02:00
|
|
|
closeFsStream(this, cb, err);
|
2017-02-07 19:38:33 +01:00
|
|
|
this.fd = null;
|
2010-04-08 19:37:10 +02:00
|
|
|
};
|
2010-03-03 12:39:41 +01:00
|
|
|
|
2017-09-14 13:46:02 +02:00
|
|
|
function closeFsStream(stream, cb, err) {
|
|
|
|
fs.close(stream.fd, (er) => {
|
|
|
|
er = er || err;
|
|
|
|
cb(er);
|
2018-01-05 10:41:14 +01:00
|
|
|
stream.closed = true;
|
2017-09-14 13:46:02 +02:00
|
|
|
if (!er)
|
|
|
|
stream.emit('close');
|
|
|
|
});
|
2017-06-05 16:46:55 +02:00
|
|
|
}
|
2010-03-03 12:39:41 +01:00
|
|
|
|
2017-09-14 13:46:02 +02:00
|
|
|
ReadStream.prototype.close = function(cb) {
|
|
|
|
this.destroy(null, cb);
|
|
|
|
};
|
|
|
|
|
2010-04-08 19:22:55 +02:00
|
|
|
fs.createWriteStream = function(path, options) {
|
2010-04-28 03:51:41 +02:00
|
|
|
return new WriteStream(path, options);
|
2010-03-02 23:12:52 +01:00
|
|
|
};
|
|
|
|
|
2012-10-05 02:44:48 +02:00
|
|
|
util.inherits(WriteStream, Writable);
|
|
|
|
fs.WriteStream = WriteStream;
|
|
|
|
function WriteStream(path, options) {
|
|
|
|
if (!(this instanceof WriteStream))
|
|
|
|
return new WriteStream(path, options);
|
2010-09-17 04:04:09 +02:00
|
|
|
|
2016-10-09 16:07:59 +02:00
|
|
|
options = copyObject(getOptions(options, {}));
|
2012-10-05 02:44:48 +02:00
|
|
|
|
2018-01-29 19:32:34 +01:00
|
|
|
// for backwards compat do not emit close on destroy.
|
|
|
|
options.emitClose = false;
|
|
|
|
|
2012-10-05 02:44:48 +02:00
|
|
|
Writable.call(this, options);
|
2010-03-05 19:24:20 +01:00
|
|
|
|
2018-01-23 03:23:46 +01:00
|
|
|
// path will be ignored when fd is specified, so it can be falsy
|
|
|
|
this.path = getPathFromURL(path);
|
2015-01-28 05:18:08 +01:00
|
|
|
this.fd = options.fd === undefined ? null : options.fd;
|
|
|
|
this.flags = options.flags === undefined ? 'w' : options.flags;
|
|
|
|
this.mode = options.mode === undefined ? 0o666 : options.mode;
|
2010-04-12 18:57:24 +02:00
|
|
|
|
2015-06-03 00:11:04 +02:00
|
|
|
this.start = options.start;
|
2015-11-29 16:11:19 +01:00
|
|
|
this.autoClose = options.autoClose === undefined ? true : !!options.autoClose;
|
2012-10-05 02:44:48 +02:00
|
|
|
this.pos = undefined;
|
|
|
|
this.bytesWritten = 0;
|
2018-01-05 10:41:14 +01:00
|
|
|
this.closed = false;
|
2010-03-02 23:12:52 +01:00
|
|
|
|
2015-01-29 02:05:53 +01:00
|
|
|
if (this.start !== undefined) {
|
|
|
|
if (typeof this.start !== 'number') {
|
2018-02-27 14:55:32 +01:00
|
|
|
throw new ERR_INVALID_ARG_TYPE('start', 'number', this.start);
|
2012-02-18 02:53:57 +01:00
|
|
|
}
|
2011-09-11 22:30:01 +02:00
|
|
|
if (this.start < 0) {
|
2017-08-26 13:46:47 +02:00
|
|
|
const errVal = `{start: ${this.start}}`;
|
2018-02-27 14:55:32 +01:00
|
|
|
throw new ERR_OUT_OF_RANGE('start', '>= 0', errVal);
|
2011-09-11 22:30:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
this.pos = this.start;
|
|
|
|
}
|
|
|
|
|
2015-05-30 19:12:07 +02:00
|
|
|
if (options.encoding)
|
|
|
|
this.setDefaultEncoding(options.encoding);
|
|
|
|
|
2015-01-29 02:05:53 +01:00
|
|
|
if (typeof this.fd !== 'number')
|
2012-10-05 02:44:48 +02:00
|
|
|
this.open();
|
|
|
|
}
|
2010-03-02 23:12:52 +01:00
|
|
|
|
2010-04-28 03:51:41 +02:00
|
|
|
fs.FileWriteStream = fs.WriteStream; // support the legacy name
|
2010-03-02 23:12:52 +01:00
|
|
|
|
2018-05-06 19:16:09 +02:00
|
|
|
WriteStream.prototype._final = function(callback) {
|
|
|
|
if (this.autoClose) {
|
|
|
|
this.destroy();
|
|
|
|
}
|
|
|
|
|
|
|
|
callback();
|
|
|
|
};
|
2010-03-07 16:33:21 +01:00
|
|
|
|
2012-10-05 02:44:48 +02:00
|
|
|
WriteStream.prototype.open = function() {
|
2017-11-19 17:11:24 +01:00
|
|
|
fs.open(this.path, this.flags, this.mode, (er, fd) => {
|
2012-10-05 02:44:48 +02:00
|
|
|
if (er) {
|
2015-11-29 16:11:19 +01:00
|
|
|
if (this.autoClose) {
|
|
|
|
this.destroy();
|
|
|
|
}
|
2012-10-05 02:44:48 +02:00
|
|
|
this.emit('error', er);
|
2010-04-08 19:37:10 +02:00
|
|
|
return;
|
|
|
|
}
|
2010-03-02 23:12:52 +01:00
|
|
|
|
2012-10-05 02:44:48 +02:00
|
|
|
this.fd = fd;
|
|
|
|
this.emit('open', fd);
|
2018-03-17 11:54:46 +01:00
|
|
|
this.emit('ready');
|
2017-11-19 17:11:24 +01:00
|
|
|
});
|
2010-04-08 19:37:10 +02:00
|
|
|
};
|
2010-03-02 23:12:52 +01:00
|
|
|
|
2010-03-07 16:33:21 +01:00
|
|
|
|
2013-03-04 04:14:06 +01:00
|
|
|
WriteStream.prototype._write = function(data, encoding, cb) {
|
2017-12-17 20:55:22 +01:00
|
|
|
if (!(data instanceof Buffer)) {
|
2018-02-27 14:55:32 +01:00
|
|
|
const err = new ERR_INVALID_ARG_TYPE('data', 'Buffer', data);
|
2017-12-17 20:55:22 +01:00
|
|
|
return this.emit('error', err);
|
|
|
|
}
|
2010-05-18 00:22:09 +02:00
|
|
|
|
2017-06-20 23:37:00 +02:00
|
|
|
if (typeof this.fd !== 'number') {
|
2013-03-04 04:14:06 +01:00
|
|
|
return this.once('open', function() {
|
|
|
|
this._write(data, encoding, cb);
|
|
|
|
});
|
2017-06-20 23:37:00 +02:00
|
|
|
}
|
2010-05-18 00:22:09 +02:00
|
|
|
|
2017-11-19 17:11:24 +01:00
|
|
|
fs.write(this.fd, data, 0, data.length, this.pos, (er, bytes) => {
|
2012-10-05 02:44:48 +02:00
|
|
|
if (er) {
|
2017-11-19 17:11:24 +01:00
|
|
|
if (this.autoClose) {
|
|
|
|
this.destroy();
|
2015-11-29 16:11:19 +01:00
|
|
|
}
|
2012-10-05 02:44:48 +02:00
|
|
|
return cb(er);
|
|
|
|
}
|
2017-11-19 17:11:24 +01:00
|
|
|
this.bytesWritten += bytes;
|
2012-10-05 02:44:48 +02:00
|
|
|
cb();
|
|
|
|
});
|
2011-09-11 22:30:01 +02:00
|
|
|
|
2015-01-29 02:05:53 +01:00
|
|
|
if (this.pos !== undefined)
|
2011-09-11 22:30:01 +02:00
|
|
|
this.pos += data.length;
|
2010-04-08 19:37:10 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-07-28 07:59:35 +02:00
|
|
|
function writev(fd, chunks, position, callback) {
|
|
|
|
function wrapper(err, written) {
|
|
|
|
// Retain a reference to chunks so that they can't be GC'ed too soon.
|
|
|
|
callback(err, written || 0, chunks);
|
|
|
|
}
|
|
|
|
|
|
|
|
const req = new FSReqWrap();
|
|
|
|
req.oncomplete = wrapper;
|
|
|
|
binding.writeBuffers(fd, chunks, position, req);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
WriteStream.prototype._writev = function(data, cb) {
|
2017-06-20 23:37:00 +02:00
|
|
|
if (typeof this.fd !== 'number') {
|
2015-07-28 07:59:35 +02:00
|
|
|
return this.once('open', function() {
|
|
|
|
this._writev(data, cb);
|
|
|
|
});
|
2017-06-20 23:37:00 +02:00
|
|
|
}
|
2015-07-28 07:59:35 +02:00
|
|
|
|
|
|
|
const self = this;
|
|
|
|
const len = data.length;
|
|
|
|
const chunks = new Array(len);
|
|
|
|
var size = 0;
|
|
|
|
|
|
|
|
for (var i = 0; i < len; i++) {
|
|
|
|
var chunk = data[i].chunk;
|
|
|
|
|
|
|
|
chunks[i] = chunk;
|
|
|
|
size += chunk.length;
|
|
|
|
}
|
|
|
|
|
|
|
|
writev(this.fd, chunks, this.pos, function(er, bytes) {
|
|
|
|
if (er) {
|
|
|
|
self.destroy();
|
|
|
|
return cb(er);
|
|
|
|
}
|
|
|
|
self.bytesWritten += bytes;
|
|
|
|
cb();
|
|
|
|
});
|
|
|
|
|
|
|
|
if (this.pos !== undefined)
|
|
|
|
this.pos += size;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2017-05-06 14:20:52 +02:00
|
|
|
WriteStream.prototype._destroy = ReadStream.prototype._destroy;
|
2017-09-14 13:46:02 +02:00
|
|
|
WriteStream.prototype.close = function(cb) {
|
2018-01-05 10:41:14 +01:00
|
|
|
if (cb) {
|
|
|
|
if (this.closed) {
|
|
|
|
process.nextTick(cb);
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
this.on('close', cb);
|
|
|
|
}
|
2017-09-14 13:46:02 +02:00
|
|
|
}
|
|
|
|
|
2018-01-05 10:41:14 +01:00
|
|
|
// If we are not autoClosing, we should call
|
|
|
|
// destroy on 'finish'.
|
|
|
|
if (!this.autoClose) {
|
|
|
|
this.on('finish', this.destroy.bind(this));
|
2017-09-14 13:46:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// we use end() instead of destroy() because of
|
|
|
|
// https://github.com/nodejs/node/issues/2006
|
2018-01-05 10:41:14 +01:00
|
|
|
this.end();
|
2017-09-14 13:46:02 +02:00
|
|
|
};
|
2010-04-08 19:37:10 +02:00
|
|
|
|
2011-01-04 20:39:12 +01:00
|
|
|
// There is no shutdown() for files.
|
|
|
|
WriteStream.prototype.destroySoon = WriteStream.prototype.end;
|