Browse Source

added fs.link, fs.symlink, fs.readlink

including sync versions and complete tests
v0.7.4-release
Rasmus Andersson 15 years ago
committed by Ryan Dahl
parent
commit
b57d946184
  1. 24
      doc/api.txt
  2. 24
      src/node.js
  3. 75
      src/node_file.cc
  4. 38
      test/mjsunit/test-fs-symlink.js

24
doc/api.txt

@ -608,6 +608,30 @@ See the +fs.Stats+ section below for more information.
Synchronous stat(2) or lstat(2). Returns an instance of +fs.Stats+.
+fs.link(srcpath, dstpath, callback)+ ::
Asynchronous link(2).
No arguments other than a possible exception are given to the completion callback.
+fs.linkSync(dstpath, srcpath)+ ::
Synchronous link(2).
+fs.symlink(linkdata, path, callback)+ ::
Asynchronous symlink(2).
No arguments other than a possible exception are given to the completion callback.
+fs.symlinkSync(linkdata, path)+ ::
Synchronous symlink(2).
+fs.readlink(path, callback)+ ::
Asynchronous readlink(2).
The callback gets two arguments +(err, resolvedPath)+.
+fs.readlinkSync(path)+ ::
Synchronous readlink(2). Returns the resolved path.
+fs.unlink(path, callback)+ ::
Asynchronous unlink(2).
No arguments other than a possible exception are given to the completion callback.

24
src/node.js

@ -498,6 +498,30 @@ var fsModule = createInternalModule("fs", function (exports) {
return process.fs.stat(path);
};
exports.readlink = function (path, callback) {
process.fs.readlink(path, callback || noop);
};
exports.readlinkSync = function (path) {
return process.fs.readlink(path);
};
exports.symlink = function (destination, path, callback) {
process.fs.symlink(destination, path, callback || noop);
};
exports.symlinkSync = function (destination, path) {
return process.fs.symlink(destination, path);
};
exports.link = function (srcpath, dstpath, callback) {
process.fs.link(srcpath, dstpath, callback || noop);
};
exports.linkSync = function (srcpath, dstpath) {
return process.fs.link(srcpath, dstpath);
};
exports.unlink = function (path, callback) {
process.fs.unlink(path, callback || noop);
};

75
src/node_file.cc

@ -10,6 +10,12 @@
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
/* used for readlink, AIX doesn't provide it */
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
namespace node {
@ -55,6 +61,8 @@ static int After(eio_req *req) {
case EIO_RMDIR:
case EIO_MKDIR:
case EIO_FTRUNCATE:
case EIO_LINK:
case EIO_SYMLINK:
case EIO_CHMOD:
argc = 0;
break;
@ -78,6 +86,13 @@ static int After(eio_req *req) {
argv[1] = BuildStatsObject(s);
break;
}
case EIO_READLINK:
{
argc = 2;
argv[1] = String::New(static_cast<char*>(req->ptr2), req->result);
break;
}
case EIO_READ:
{
@ -207,6 +222,63 @@ static Handle<Value> LStat(const Arguments& args) {
}
}
static Handle<Value> Symlink(const Arguments& args) {
HandleScope scope;
if (args.Length() < 2 || !args[0]->IsString() || !args[1]->IsString()) {
return THROW_BAD_ARGS;
}
String::Utf8Value dest(args[0]->ToString());
String::Utf8Value path(args[1]->ToString());
if (args[2]->IsFunction()) {
ASYNC_CALL(symlink, args[2], *dest, *path)
} else {
int ret = symlink(*dest, *path);
if (ret != 0) return ThrowException(errno_exception(errno));
return Undefined();
}
}
static Handle<Value> Link(const Arguments& args) {
HandleScope scope;
if (args.Length() < 2 || !args[0]->IsString() || !args[1]->IsString()) {
return THROW_BAD_ARGS;
}
String::Utf8Value orig_path(args[0]->ToString());
String::Utf8Value new_path(args[1]->ToString());
if (args[2]->IsFunction()) {
ASYNC_CALL(link, args[2], *orig_path, *new_path)
} else {
int ret = link(*orig_path, *new_path);
if (ret != 0) return ThrowException(errno_exception(errno));
return Undefined();
}
}
static Handle<Value> ReadLink(const Arguments& args) {
HandleScope scope;
if (args.Length() < 1 || !args[0]->IsString()) {
return THROW_BAD_ARGS;
}
String::Utf8Value path(args[0]->ToString());
if (args[1]->IsFunction()) {
ASYNC_CALL(readlink, args[1], *path)
} else {
char buf[PATH_MAX];
ssize_t bz = readlink(*path, buf, PATH_MAX);
if (bz == -1) return ThrowException(errno_exception(errno));
return scope.Close(String::New(buf));
}
}
static Handle<Value> Rename(const Arguments& args) {
HandleScope scope;
@ -505,6 +577,9 @@ void File::Initialize(Handle<Object> target) {
NODE_SET_METHOD(target, "readdir", ReadDir);
NODE_SET_METHOD(target, "stat", Stat);
NODE_SET_METHOD(target, "lstat", LStat);
NODE_SET_METHOD(target, "link", Link);
NODE_SET_METHOD(target, "symlink", Symlink);
NODE_SET_METHOD(target, "readlink", ReadLink);
NODE_SET_METHOD(target, "unlink", Unlink);
NODE_SET_METHOD(target, "write", Write);

38
test/mjsunit/test-fs-symlink.js

@ -0,0 +1,38 @@
process.mixin(require("./common"));
var completed = 0;
// test creating and reading symbolic link
var linkData = "../../cycles/root.js";
var linkPath = path.join(fixturesDir, "nested-index", 'one', 'symlink1.js');
try {fs.unlinkSync(linkPath);}catch(e){}
fs.symlink(linkData, linkPath, function(err){
if (err) throw err;
puts('symlink done');
// todo: fs.lstat?
fs.readlink(linkPath, function(err, destination) {
if (err) throw err;
assert.equal(destination, linkData);
completed++;
})
});
// test creating and reading hard link
var srcPath = path.join(fixturesDir, "cycles", 'root.js');
var dstPath = path.join(fixturesDir, "nested-index", 'one', 'link1.js');
try {fs.unlinkSync(dstPath);}catch(e){}
fs.link(srcPath, dstPath, function(err){
if (err) throw err;
puts('hard link done');
var srcContent = fs.readFileSync(srcPath);
var dstContent = fs.readFileSync(dstPath);
assert.equal(srcContent, dstContent);
completed++;
});
process.addListener("exit", function () {
try {fs.unlinkSync(linkPath);}catch(e){}
try {fs.unlinkSync(dstPath);}catch(e){}
assert.equal(completed, 2);
});
Loading…
Cancel
Save