Added fs.realpath and fs.realpathSync (pure javascript versions)
This commit is contained in:
parent
7a251f3bdf
commit
20d5963fae
@ -622,6 +622,14 @@ The callback gets two arguments +(err, resolvedPath)+.
|
|||||||
Synchronous readlink(2). Returns the resolved path.
|
Synchronous readlink(2). Returns the resolved path.
|
||||||
|
|
||||||
|
|
||||||
|
+fs.realpath(path, callback)+ ::
|
||||||
|
Asynchronous realpath(2).
|
||||||
|
The callback gets two arguments +(err, resolvedPath)+.
|
||||||
|
|
||||||
|
+fs.realpathSync(path)+ ::
|
||||||
|
Synchronous realpath(2). Returns the resolved path.
|
||||||
|
|
||||||
|
|
||||||
+fs.unlink(path, callback)+ ::
|
+fs.unlink(path, callback)+ ::
|
||||||
Asynchronous unlink(2).
|
Asynchronous unlink(2).
|
||||||
No arguments other than a possible exception are given to the completion callback.
|
No arguments other than a possible exception are given to the completion callback.
|
||||||
|
85
lib/fs.js
85
lib/fs.js
@ -289,4 +289,89 @@ exports.unwatchFile = function (filename) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Realpath
|
||||||
|
|
||||||
|
var path = require('path');
|
||||||
|
var dirname = path.dirname,
|
||||||
|
basename = path.basename,
|
||||||
|
normalize = path.normalize;
|
||||||
|
|
||||||
|
function readlinkDeepSync(path, stats) {
|
||||||
|
var seen_links = {}, resolved_link, stats, file_id;
|
||||||
|
while (true) {
|
||||||
|
stats = stats || exports.lstatSync(path);
|
||||||
|
file_id = stats.dev.toString(32)+":"+stats.ino.toString(32);
|
||||||
|
if (file_id in seen_links) {
|
||||||
|
throw new Error("cyclic symbolic link at "+path);
|
||||||
|
} else {
|
||||||
|
seen_links[file_id] = 1;
|
||||||
|
if (stats.isSymbolicLink()) {
|
||||||
|
var newpath = exports.readlinkSync(path);
|
||||||
|
if (newpath.charAt(0) === '/') {
|
||||||
|
path = newpath;
|
||||||
|
} else {
|
||||||
|
var dir = dirname(path);
|
||||||
|
path = (dir !== '') ? dir + '/' + newpath : newpath;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return normalize(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stats = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function readlinkDeep(path, stats, callback) {
|
||||||
|
var seen_links = {}, resolved_link, file_id;
|
||||||
|
function next(stats) {
|
||||||
|
file_id = stats.dev.toString(32)+":"+stats.ino.toString(32);
|
||||||
|
if (file_id in seen_links) {
|
||||||
|
callback(new Error("cyclic symbolic link at "+path));
|
||||||
|
} else {
|
||||||
|
seen_links[file_id] = 1;
|
||||||
|
if (stats.isSymbolicLink()) {
|
||||||
|
exports.readlink(path, function(err, newpath) {
|
||||||
|
if (err) callback(err);
|
||||||
|
if (newpath.charAt(0) === '/') {
|
||||||
|
path = newpath;
|
||||||
|
} else {
|
||||||
|
var dir = dirname(path);
|
||||||
|
path = (dir !== '') ? dir + '/' + newpath : newpath;
|
||||||
|
}
|
||||||
|
_next();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
callback(null, normalize(path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function _next() {
|
||||||
|
exports.lstat(path, function(err, stats){
|
||||||
|
if (err) callback(err);
|
||||||
|
else next(stats);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (stats) next(stats);
|
||||||
|
else _next();
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.realpathSync = function(path) {
|
||||||
|
var stats = exports.lstatSync(path);
|
||||||
|
if (stats.isSymbolicLink())
|
||||||
|
return readlinkDeepSync(path, stats);
|
||||||
|
else
|
||||||
|
return normalize(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.realpath = function(path, callback) {
|
||||||
|
var resolved_path = path;
|
||||||
|
if (!callback) return;
|
||||||
|
exports.lstat(path, function(err, stats){
|
||||||
|
if (err)
|
||||||
|
callback(err);
|
||||||
|
else if (stats.isSymbolicLink())
|
||||||
|
readlinkDeep(path, stats, callback);
|
||||||
|
else
|
||||||
|
callback(null, normalize(path));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
56
test/simple/test-fs-realpath.js
Normal file
56
test/simple/test-fs-realpath.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
process.mixin(require("../common"));
|
||||||
|
|
||||||
|
var async_completed = 0, async_expected = 0;
|
||||||
|
|
||||||
|
// a. deep relative file symlink
|
||||||
|
var dstPath = path.join(fixturesDir, 'cycles', 'root.js');
|
||||||
|
var linkData1 = "../../cycles/root.js";
|
||||||
|
var linkPath1 = path.join(fixturesDir, "nested-index", 'one', 'symlink1.js');
|
||||||
|
try {fs.unlinkSync(linkPath1);}catch(e){}
|
||||||
|
fs.symlinkSync(linkData1, linkPath1);
|
||||||
|
|
||||||
|
var linkData2 = "../one/symlink1.js";
|
||||||
|
var linkPath2 = path.join(fixturesDir, "nested-index", 'two', 'symlink1-b.js');
|
||||||
|
try {fs.unlinkSync(linkPath2);}catch(e){}
|
||||||
|
fs.symlinkSync(linkData2, linkPath2);
|
||||||
|
|
||||||
|
// b. deep relative directory symlink
|
||||||
|
var dstPath_b = path.join(fixturesDir, 'cycles', 'folder');
|
||||||
|
var linkData1b = "../../cycles/folder";
|
||||||
|
var linkPath1b = path.join(fixturesDir, "nested-index", 'one', 'symlink1-dir');
|
||||||
|
try {fs.unlinkSync(linkPath1b);}catch(e){}
|
||||||
|
fs.symlinkSync(linkData1b, linkPath1b);
|
||||||
|
|
||||||
|
var linkData2b = "../one/symlink1-dir";
|
||||||
|
var linkPath2b = path.join(fixturesDir, "nested-index", 'two', 'symlink12-dir');
|
||||||
|
try {fs.unlinkSync(linkPath2b);}catch(e){}
|
||||||
|
fs.symlinkSync(linkData2b, linkPath2b);
|
||||||
|
|
||||||
|
assert.equal(fs.realpathSync(linkPath2), dstPath);
|
||||||
|
assert.equal(fs.realpathSync(linkPath2b), dstPath_b);
|
||||||
|
|
||||||
|
async_expected++;
|
||||||
|
fs.realpath(linkPath2, function(err, rpath) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.equal(rpath, dstPath);
|
||||||
|
async_completed++;
|
||||||
|
});
|
||||||
|
|
||||||
|
async_expected++;
|
||||||
|
fs.realpath(linkPath2b, function(err, rpath) {
|
||||||
|
if (err) throw err;
|
||||||
|
assert.equal(rpath, dstPath_b);
|
||||||
|
async_completed++;
|
||||||
|
});
|
||||||
|
|
||||||
|
// todo: test shallow symlinks (file & dir)
|
||||||
|
// todo: test non-symlinks (file & dir)
|
||||||
|
// todo: test error on cyclic symlinks
|
||||||
|
|
||||||
|
process.addListener("exit", function () {
|
||||||
|
try {fs.unlinkSync(linkPath1);}catch(e){}
|
||||||
|
try {fs.unlinkSync(linkPath2);}catch(e){}
|
||||||
|
try {fs.unlinkSync(linkPath1b);}catch(e){}
|
||||||
|
try {fs.unlinkSync(linkPath2b);}catch(e){}
|
||||||
|
assert.equal(async_completed, async_expected);
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user