static Persistent<String> errno_symbol;
static Persistent<String> syscall_symbol;
+static Persistent<String> errpath_symbol;
static Persistent<String> dev_symbol;
static Persistent<String> ino_symbol;
Local<Value> ErrnoException(int errorno,
const char *syscall,
- const char *msg) {
+ const char *msg,
+ const char *path) {
+ Local<Value> e;
Local<String> estring = String::NewSymbol(errno_string(errorno));
if (!msg[0]) msg = strerror(errorno);
Local<String> message = String::NewSymbol(msg);
Local<String> cons1 = String::Concat(estring, String::NewSymbol(", "));
Local<String> cons2 = String::Concat(cons1, message);
- Local<Value> e = Exception::Error(cons2);
-
- Local<Object> obj = e->ToObject();
-
if (errno_symbol.IsEmpty()) {
syscall_symbol = NODE_PSYMBOL("syscall");
errno_symbol = NODE_PSYMBOL("errno");
+ errpath_symbol = NODE_PSYMBOL("path");
+ }
+
+ if (path) {
+ Local<String> cons3 = String::Concat(cons2, String::NewSymbol(" '"));
+ Local<String> cons4 = String::Concat(cons3, String::New(path));
+ Local<String> cons5 = String::Concat(cons4, String::NewSymbol("'"));
+ e = Exception::Error(cons5);
+ } else {
+ e = Exception::Error(cons2);
}
+ Local<Object> obj = e->ToObject();
+
obj->Set(errno_symbol, Integer::New(errorno));
+ if (path) obj->Set(errpath_symbol, String::New(path));
if (syscall) obj->Set(syscall_symbol, String::NewSymbol(syscall));
return e;
}
v8::Local<v8::Value> ErrnoException(int errorno,
const char *syscall = NULL,
- const char *msg = "");
+ const char *msg = "",
+ const char *path = NULL);
const char *signo_string(int errorno);
} // namespace node
if (req->errorno != 0) {
argc = 1;
- argv[0] = ErrnoException(req->errorno);
+ switch (req->type) {
+ case EIO_STAT:
+ case EIO_LSTAT:
+ case EIO_LINK:
+ case EIO_UNLINK:
+ case EIO_RMDIR:
+ case EIO_RENAME:
+ case EIO_READLINK:
+ case EIO_OPEN:
+ case EIO_CHMOD:
+ case EIO_MKDIR:
+ argv[0] = ErrnoException(req->errorno, NULL, "", static_cast<const char*>(req->ptr1));
+ break;
+ default:
+ argv[0] = ErrnoException(req->errorno);
+ }
} else {
// Note: the error is always given the first argument of the callback.
// If there is no error then then the first argument is null.
argv[0] = Local<Value>::New(Null());
-
switch (req->type) {
case EIO_CLOSE:
case EIO_RENAME:
} else {
struct stat s;
int ret = stat(*path, &s);
- if (ret != 0) return ThrowException(ErrnoException(errno));
+ if (ret != 0) return ThrowException(ErrnoException(errno, NULL, "", *path));
return scope.Close(BuildStatsObject(&s));
}
}
} else {
struct stat s;
int ret = lstat(*path, &s);
- if (ret != 0) return ThrowException(ErrnoException(errno));
+ if (ret != 0) return ThrowException(ErrnoException(errno, NULL, "", *path));
return scope.Close(BuildStatsObject(&s));
}
}
ASYNC_CALL(link, args[2], *orig_path, *new_path)
} else {
int ret = link(*orig_path, *new_path);
- if (ret != 0) return ThrowException(ErrnoException(errno));
+ if (ret != 0) return ThrowException(ErrnoException(errno, NULL, "", *orig_path));
return Undefined();
}
}
} else {
char buf[PATH_MAX];
ssize_t bz = readlink(*path, buf, PATH_MAX);
- if (bz == -1) return ThrowException(ErrnoException(errno));
+ if (bz == -1) return ThrowException(ErrnoException(errno, NULL, "", *path));
return scope.Close(String::New(buf, bz));
}
}
ASYNC_CALL(rename, args[2], *old_path, *new_path)
} else {
int ret = rename(*old_path, *new_path);
- if (ret != 0) return ThrowException(ErrnoException(errno));
+ if (ret != 0) return ThrowException(ErrnoException(errno, NULL, "", *old_path));
return Undefined();
}
}
ASYNC_CALL(unlink, args[1], *path)
} else {
int ret = unlink(*path);
- if (ret != 0) return ThrowException(ErrnoException(errno));
+ if (ret != 0) return ThrowException(ErrnoException(errno, NULL, "", *path));
return Undefined();
}
}
ASYNC_CALL(rmdir, args[1], *path)
} else {
int ret = rmdir(*path);
- if (ret != 0) return ThrowException(ErrnoException(errno));
+ if (ret != 0) return ThrowException(ErrnoException(errno, NULL, "", *path));
return Undefined();
}
}
ASYNC_CALL(mkdir, args[2], *path, mode)
} else {
int ret = mkdir(*path, mode);
- if (ret != 0) return ThrowException(ErrnoException(errno));
+ if (ret != 0) return ThrowException(ErrnoException(errno, NULL, "", *path));
return Undefined();
}
}
ASYNC_CALL(readdir, args[1], *path, 0 /*flags*/)
} else {
DIR *dir = opendir(*path);
- if (!dir) return ThrowException(ErrnoException(errno));
+ if (!dir) return ThrowException(ErrnoException(errno, NULL, "", *path));
struct dirent *ent;
ASYNC_CALL(open, args[3], *path, flags, mode)
} else {
int fd = open(*path, flags, mode);
- if (fd < 0) return ThrowException(ErrnoException(errno));
+ if (fd < 0) return ThrowException(ErrnoException(errno, NULL, "", *path));
return scope.Close(Integer::New(fd));
}
}
ASYNC_CALL(chmod, args[2], *path, mode);
} else {
int ret = chmod(*path, mode);
- if (ret != 0) return ThrowException(ErrnoException(errno));
+ if (ret != 0) return ThrowException(ErrnoException(errno, NULL, "", *path));
return Undefined();
}
}
--- /dev/null
+require('../common');
+
+var path = require('path'),
+ fs = require('fs'),
+ fn = path.join(fixturesDir, 'non-existent'),
+ existingFile = path.join(fixturesDir, 'exit.js');
+
+// ASYNC_CALL
+
+fs.stat(fn, function(err) {
+ assert.equal(fn, err.path)
+ assert.ok(0 <= err.message.indexOf(fn));
+});
+
+fs.lstat(fn, function(err) {
+ assert.ok(0 <= err.message.indexOf(fn));
+});
+
+fs.readlink(fn, function(err) {
+ assert.ok(0 <= err.message.indexOf(fn));
+});
+
+fs.link(fn, 'foo', function(err) {
+ assert.ok(0 <= err.message.indexOf(fn));
+});
+
+fs.unlink(fn, function(err) {
+ assert.ok(0 <= err.message.indexOf(fn));
+});
+
+fs.rename(fn, 'foo', function(err) {
+ assert.ok(0 <= err.message.indexOf(fn));
+});
+
+fs.rmdir(fn, function(err) {
+ assert.ok(0 <= err.message.indexOf(fn));
+});
+
+fs.mkdir(existingFile, 0666, function(err) {
+ assert.ok(0 <= err.message.indexOf(existingFile));
+});
+
+fs.rmdir(existingFile, function(err) {
+ assert.ok(0 <= err.message.indexOf(existingFile));
+});
+
+fs.chmod(fn, 0666, function(err) {
+ assert.ok(0 <= err.message.indexOf(fn));
+});
+
+fs.open(fn, 'r', 0666, function(err) {
+ assert.ok(0 <= err.message.indexOf(fn));
+});
+
+fs.readFile(fn, function(err) {
+ assert.ok(0 <= err.message.indexOf(fn));
+});
+
+// Sync
+
+var errors = [],
+ expected = 0;
+
+try {
+ ++expected;
+ fs.statSync(fn);
+} catch (err) {
+ errors.push('stat');
+ assert.ok(0 <= err.message.indexOf(fn));
+}
+
+try {
+ ++expected;
+ fs.mkdirSync(existingFile, 0666);
+} catch (err) {
+ errors.push('mkdir');
+ assert.ok(0 <= err.message.indexOf(existingFile));
+}
+
+try {
+ ++expected;
+ fs.chmodSync(fn, 0666);
+} catch (err) {
+ errors.push('chmod');
+ assert.ok(0 <= err.message.indexOf(fn));
+}
+
+try {
+ ++expected;
+ fs.lstatSync(fn);
+} catch (err) {
+ errors.push('lstat');
+ assert.ok(0 <= err.message.indexOf(fn));
+}
+
+try {
+ ++expected;
+ fs.readlinkSync(fn);
+} catch (err) {
+ errors.push('readlink');
+ assert.ok(0 <= err.message.indexOf(fn));
+}
+
+try {
+ ++expected;
+ fs.linkSync(fn, 'foo');
+} catch (err) {
+ errors.push('link');
+ assert.ok(0 <= err.message.indexOf(fn));
+}
+
+try {
+ ++expected;
+ fs.unlinkSync(fn);
+} catch (err) {
+ errors.push('unlink');
+ assert.ok(0 <= err.message.indexOf(fn));
+}
+
+try {
+ ++expected;
+ fs.rmdirSync(fn);
+} catch (err) {
+ errors.push('rmdir');
+ assert.ok(0 <= err.message.indexOf(fn));
+}
+
+try {
+ ++expected;
+ fs.rmdirSync(existingFile);
+} catch (err) {
+ errors.push('rmdir');
+ assert.ok(0 <= err.message.indexOf(existingFile));
+}
+
+try {
+ ++expected;
+ fs.openSync(fn, 'r');
+} catch (err) {
+ errors.push('opens');
+ assert.ok(0 <= err.message.indexOf(fn));
+}
+
+try {
+ ++expected;
+ fs.renameSync(fn, 'foo');
+} catch (err) {
+ errors.push('rename');
+ assert.ok(0 <= err.message.indexOf(fn));
+}
+
+try {
+ ++expected;
+ fs.readdirSync(fn);
+} catch (err) {
+ errors.push('readdir');
+ assert.ok(0 <= err.message.indexOf(fn));
+}
+
+process.addListener('exit', function () {
+ assert.equal(expected, errors.length,
+ 'Test fs sync exceptions raised, got ' + errors.length + ' expected ' + expected);
+});