add an optional node to FS.ErrnoError, and use it in stat to tell if an error is about the relevant file - if not, it occurred when looking up its parents, and we should emit ENOTDIR; fixes #2669

This commit is contained in:
Alon Zakai 2014-08-13 16:42:56 -07:00
Родитель 17d260c5cf
Коммит dcf835b803
3 изменённых файлов: 92 добавлений и 8 удалений

Просмотреть файл

@ -283,6 +283,10 @@ LibraryManager.library = {
{{{ makeSetValue('buf', C_STRUCTS.stat.st_ino, 'stat.ino', 'i32') }}};
return 0;
} catch (e) {
if (e.node && PATH.normalize(path) !== PATH.normalize(FS.getPath(e.node))) {
// an error occurred while trying to look up the path; we should just report ENOTDIR
e.setErrno(ERRNO_CODES.ENOTDIR);
}
FS.handleFSError(e);
return -1;
}

Просмотреть файл

@ -161,7 +161,7 @@ mergeInto(LibraryManager.library, {
lookupNode: function(parent, name) {
var err = FS.mayLookup(parent);
if (err) {
throw new FS.ErrnoError(err);
throw new FS.ErrnoError(err, parent);
}
var hash = FS.hashName(parent.id, name);
#if CASE_INSENSITIVE_FS
@ -1299,14 +1299,18 @@ mergeInto(LibraryManager.library, {
},
ensureErrnoError: function() {
if (FS.ErrnoError) return;
FS.ErrnoError = function ErrnoError(errno) {
this.errno = errno;
for (var key in ERRNO_CODES) {
if (ERRNO_CODES[key] === errno) {
this.code = key;
break;
FS.ErrnoError = function ErrnoError(errno, node) {
this.node = node;
this.setErrno = function(errno) {
this.errno = errno;
for (var key in ERRNO_CODES) {
if (ERRNO_CODES[key] === errno) {
this.code = key;
break;
}
}
}
};
this.setErrno(errno);
this.message = ERRNO_MESSAGES[errno];
#if ASSERTIONS
if (this.stack) this.stack = demangleAll(this.stack);

Просмотреть файл

@ -3983,3 +3983,79 @@ main(const int argc, const char * const * const argv)
test([])
test(['-O1'])
def test_stat_fail_alongtheway(self):
open('src.cpp', 'w').write(r'''
#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#define CHECK(expression) \
if(!(expression)) { \
error = errno; \
printf("FAIL: %s\n", #expression); fail = 1; \
} else { \
error = errno; \
printf("pass: %s\n", #expression); \
} \
int
main()
{
int error;
int fail = 0;
CHECK(mkdir("path", 0777) == 0);
CHECK(close(open("path/file", O_CREAT | O_WRONLY, 0644)) == 0);
{
struct stat st;
CHECK(stat("path", &st) == 0);
CHECK(st.st_mode = 0777);
}
{
struct stat st;
CHECK(stat("path/nosuchfile", &st) == -1);
printf("info: errno=%d %s\n", error, strerror(error));
CHECK(error == ENOENT);
}
{
struct stat st;
CHECK(stat("path/file", &st) == 0);
CHECK(st.st_mode = 0666);
}
{
struct stat st;
CHECK(stat("path/file/impossible", &st) == -1);
printf("info: errno=%d %s\n", error, strerror(error));
CHECK(error == ENOTDIR);
}
{
struct stat st;
CHECK(lstat("path/file/impossible", &st) == -1);
printf("info: errno=%d %s\n", error, strerror(error));
CHECK(error == ENOTDIR);
}
return fail;
}
''')
Popen([PYTHON, EMCC, 'src.cpp']).communicate()
self.assertContained(r'''pass: mkdir("path", 0777) == 0
pass: close(open("path/file", O_CREAT | O_WRONLY, 0644)) == 0
pass: stat("path", &st) == 0
pass: st.st_mode = 0777
pass: stat("path/nosuchfile", &st) == -1
info: errno=2 No such file or directory
pass: error == ENOENT
pass: stat("path/file", &st) == 0
pass: st.st_mode = 0666
pass: stat("path/file/impossible", &st) == -1
info: errno=20 Not a directory
pass: error == ENOTDIR
pass: lstat("path/file/impossible", &st) == -1
info: errno=20 Not a directory
pass: error == ENOTDIR
''', run_js('a.out.js'))