Merge pull request #1458 from inolen/vfs

initial vfs work
This commit is contained in:
Alon Zakai 2013-08-06 10:32:57 -07:00
Родитель ca19fbd11b f739fc81c0
Коммит 8dfcd06d78
11 изменённых файлов: 2262 добавлений и 1282 удалений

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

@ -66,3 +66,29 @@ IN NO EVENT SHALL THE CONTRIBUTORS 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 WITH THE SOFTWARE.
==============================================================================
This program uses portions of Node.js source code located in src/library_path.js,
in accordance with the terms of the MIT license. Node's license follows:
"""
Copyright Joyent, Inc. and other Node contributors. All rights reserved.
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.
"""

Разница между файлами не показана из-за своего большого размера Загрузить разницу

133
src/library_path.js Normal file
Просмотреть файл

@ -0,0 +1,133 @@
mergeInto(LibraryManager.library, {
$PATH: {
// split a filename into [root, dir, basename, ext], unix version
// 'root' is just a slash, or nothing.
splitPath: function (filename) {
var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
return splitPathRe.exec(filename).slice(1);
},
normalizeArray: function (parts, allowAboveRoot) {
// if the path tries to go above the root, `up` ends up > 0
var up = 0;
for (var i = parts.length - 1; i >= 0; i--) {
var last = parts[i];
if (last === '.') {
parts.splice(i, 1);
} else if (last === '..') {
parts.splice(i, 1);
up++;
} else if (up) {
parts.splice(i, 1);
up--;
}
}
// if the path is allowed to go above the root, restore leading ..s
if (allowAboveRoot) {
for (; up--; up) {
parts.unshift('..');
}
}
return parts;
},
normalize: function (path) {
var isAbsolute = path.charAt(0) === '/',
trailingSlash = path.substr(-1) === '/';
// Normalize the path
path = PATH.normalizeArray(path.split('/').filter(function(p) {
return !!p;
}), !isAbsolute).join('/');
if (!path && !isAbsolute) {
path = '.';
}
if (path && trailingSlash) {
path += '/';
}
return (isAbsolute ? '/' : '') + path;
},
dirname: function (path) {
var result = PATH.splitPath(path),
root = result[0],
dir = result[1];
if (!root && !dir) {
// No dirname whatsoever
return '.';
}
if (dir) {
// It has a dirname, strip trailing slash
dir = dir.substr(0, dir.length - 1);
}
return root + dir;
},
basename: function (path, ext) {
// EMSCRIPTEN return '/'' for '/', not an empty string
if (path === '/') return '/';
var f = PATH.splitPath(path)[2];
if (ext && f.substr(-1 * ext.length) === ext) {
f = f.substr(0, f.length - ext.length);
}
return f;
},
join: function () {
var paths = Array.prototype.slice.call(arguments, 0);
return PATH.normalize(paths.filter(function(p, index) {
if (typeof p !== 'string') {
throw new TypeError('Arguments to path.join must be strings');
}
return p;
}).join('/'));
},
resolve: function () {
var resolvedPath = '',
resolvedAbsolute = false;
for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
var path = (i >= 0) ? arguments[i] : process.cwd();
// Skip empty and invalid entries
if (typeof path !== 'string') {
throw new TypeError('Arguments to path.resolve must be strings');
} else if (!path) {
continue;
}
resolvedPath = path + '/' + resolvedPath;
resolvedAbsolute = path.charAt(0) === '/';
}
// At this point the path should be resolved to a full absolute path, but
// handle relative paths to be safe (might happen when process.cwd() fails)
resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter(function(p) {
return !!p;
}), !resolvedAbsolute).join('/');
return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
},
relative: function(from, to) {
from = PATH.resolve(from).substr(1);
to = PATH.resolve(to).substr(1);
function trim(arr) {
var start = 0;
for (; start < arr.length; start++) {
if (arr[start] !== '') break;
}
var end = arr.length - 1;
for (; end >= 0; end--) {
if (arr[end] !== '') break;
}
if (start > end) return [];
return arr.slice(start, end - start + 1);
}
var fromParts = trim(from.split('/'));
var toParts = trim(to.split('/'));
var length = Math.min(fromParts.length, toParts.length);
var samePartsLength = length;
for (var i = 0; i < length; i++) {
if (fromParts[i] !== toParts[i]) {
samePartsLength = i;
break;
}
}
var outputParts = [];
for (var i = samePartsLength; i < fromParts.length; i++) {
outputParts.push('..');
}
outputParts = outputParts.concat(toParts.slice(samePartsLength));
return outputParts.join('/');
}
}
});

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

@ -422,7 +422,7 @@ var LibraryManager = {
load: function() {
if (this.library) return;
var libraries = ['library.js', 'library_browser.js', 'library_sdl.js', 'library_gl.js', 'library_glut.js', 'library_xlib.js', 'library_egl.js', 'library_gc.js', 'library_jansson.js', 'library_openal.js', 'library_glfw.js'].concat(additionalLibraries);
var libraries = ['library.js', 'library_path.js', 'library_browser.js', 'library_sdl.js', 'library_gl.js', 'library_glut.js', 'library_xlib.js', 'library_egl.js', 'library_gc.js', 'library_jansson.js', 'library_openal.js', 'library_glfw.js'].concat(additionalLibraries);
for (var i = 0; i < libraries.length; i++) {
eval(processMacros(preprocess(read(libraries[i]))));
}

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

@ -249,8 +249,6 @@ var FS_LOG = 0; // Log all FS operations. This is especially helpful when you'r
// a new project and want to see a list of file system operations happening
// so that you can create a virtual file system with all of the required files.
var USE_OLD_FS = 1; // Switch to toggle the new / old FS code. Currently only used for testing purposes.
var USE_BSS = 1; // https://en.wikipedia.org/wiki/.bss
// When enabled, 0-initialized globals are sorted to the end of the globals list,
// enabling us to not explicitly store the initialization value for each 0 byte.
@ -880,9 +878,9 @@ var C_DEFINES = {
'S_IRGRP': '0000040',
'S_IROTH': '0000004',
'S_IRUSR': '0000400',
'S_IRWXG': '0000040',
'S_IRWXO': '0000004',
'S_IRWXU': '0000400',
'S_IRWXG': '0000070',
'S_IRWXO': '0000007',
'S_IRWXU': '0000700',
'S_ISGID': '0002000',
'S_ISUID': '0004000',
'S_ISVTX': '0001000',
@ -1297,6 +1295,33 @@ var C_DEFINES = {
'___int8_t_defined': '1',
'___int_least16_t_defined': '1',
'___int_least32_t_defined': '1',
'___int_least8_t_defined': '1'
'___int_least8_t_defined': '1',
'FMODE_READ': '0x1',
'FMODE_WRITE': '0x2',
'FMODE_LSEEK': '0x4',
'FMODE_PREAD': '0x8',
'FMODE_PWRITE': '0x10',
'FMODE_EXEC': '0x20',
'FMODE_NDELAY': '0x40',
'FMODE_EXCL': '0x80',
'FMODE_NOCMTIME': '0x800',
'FMODE_RANDOM': '0x1000',
'FMODE_UNSIGNED_OFFSET': '0x2000',
'FMODE_PATH': '0x4000',
'FMODE_NONOTIFY': '0x1000000',
'S_IRWXUGO': '511',
'S_IALLUGO': '4095',
'S_IRUGO': '292',
'S_IWUGO': '146',
'S_IXUGO': '73',
'LOOKUP_FOLLOW': '0x0001',
'LOOKUP_DIRECTORY': '0x0002',
'LOOKUP_PARENT': '0x0010',
'MAP_SHARED': '0x01',
'MAP_PRIVATE': '0x02',
'MAP_TYPE': '0x0f',
'MAP_FIXED': '0x100',
'MAP_ANONYMOUS': '0x10',
'O_NOFOLLOW': '0200000'
};

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

@ -8,6 +8,7 @@ FS.createDevice('/def', 'deviceB', function() {}, function() {});
FS.createLink('/abc', 'localLink', '123', true, true);
FS.createLink('/abc', 'rootLink', '/', true, true);
FS.createLink('/abc', 'relativeLink', '../def', true, true);
FS.ignorePermissions = false;
function explore(path) {
Module.print(path);

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

@ -3591,33 +3591,8 @@ Exiting setjmp function, level: 0, prev_jmp: -1
self.do_run(src, 'z:1*', force_c=True)
def test_rename(self):
src = '''
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
int main() {
int err;
FILE* fid;
err = mkdir("/foo", 0777);
err = mkdir("/bar", 0777);
fid = fopen("/foo/bar", "w+");
fclose(fid);
err = rename("/foo/bar", "/foo/bar2");
printf("%d\\n", err);
err = rename("/foo", "/foo/foo");
printf("%d\\n", err);
err = rename("/foo", "/bar/foo");
printf("%d\\n", err);
return 0;
}
'''
self.do_run(src, '0\n-1\n0\n', force_c=True)
src = open(path_from_root('tests', 'stdio', 'test_rename.c'), 'r').read()
self.do_run(src, 'success', force_c=True)
def test_alloca_stack(self):
if self.emcc_args is None: return # too slow in other modes
@ -7244,17 +7219,14 @@ def process(filename):
self.do_run(src, 'success', force_c=True)
def test_stat(self):
Building.COMPILER_TEST_OPTS += ['-DUSE_OLD_FS='+str(Settings.USE_OLD_FS)]
src = open(path_from_root('tests', 'stat', 'test_stat.c'), 'r').read()
self.do_run(src, 'success', force_c=True)
def test_stat_chmod(self):
Building.COMPILER_TEST_OPTS += ['-DUSE_OLD_FS='+str(Settings.USE_OLD_FS)]
src = open(path_from_root('tests', 'stat', 'test_chmod.c'), 'r').read()
self.do_run(src, 'success', force_c=True)
def test_stat_mknod(self):
Building.COMPILER_TEST_OPTS += ['-DUSE_OLD_FS='+str(Settings.USE_OLD_FS)]
src = open(path_from_root('tests', 'stat', 'test_mknod.c'), 'r').read()
self.do_run(src, 'success', force_c=True)

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

@ -56,11 +56,7 @@ void test() {
memset(&s, 0, sizeof s);
stat("file", &s);
#if USE_OLD_FS
assert(s.st_mode == (0222 | S_IFREG));
#else
assert(s.st_mode == (0200 | S_IFREG));
#endif
assert(s.st_ctime != lastctime);
//
@ -74,11 +70,7 @@ void test() {
memset(&s, 0, sizeof s);
stat("file", &s);
#if USE_OLD_FS
assert(s.st_mode == (0000 | S_IFREG));
#else
assert(s.st_mode == (0100 | S_IFREG));
#endif
assert(s.st_ctime != lastctime);
//
@ -95,11 +87,7 @@ void test() {
assert(!err);
memset(&s, 0, sizeof s);
stat("folder", &s);
#if USE_OLD_FS
assert(s.st_mode == (0222 | S_IFDIR));
#else
assert(s.st_mode == (0300 | S_IFDIR));
#endif
assert(s.st_ctime != lastctime);
//
@ -110,11 +98,7 @@ void test() {
// make sure the file it references changed
stat("file-link", &s);
#if USE_OLD_FS
assert(s.st_mode == (0555 | S_IFREG));
#else
assert(s.st_mode == (0400 | S_IFREG));
#endif
// but the link didn't
lstat("file-link", &s);
@ -128,19 +112,11 @@ void test() {
// make sure the file it references didn't change
stat("file-link", &s);
#if USE_OLD_FS
assert(s.st_mode == (0555 | S_IFREG));
#else
assert(s.st_mode == (0400 | S_IFREG));
#endif
// but the link did
lstat("file-link", &s);
#if USE_OLD_FS
assert(s.st_mode == (0555 | S_IFLNK));
#else
assert(s.st_mode == (0500 | S_IFLNK));
#endif
puts("success");
}

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

@ -53,15 +53,10 @@ void test() {
// mknod a character device
err = mknod("mknod-device", S_IFCHR | 0777, 123);
#if USE_OLD_FS
assert(err);
assert(errno == EPERM);
#else
assert(!err);
memset(&s, 0, sizeof s);
stat("mknod-device", &s);
assert(S_ISCHR(s.st_mode));
#endif
#endif

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

@ -104,12 +104,9 @@ void test() {
assert(s.st_ino);
assert(S_ISCHR(s.st_mode));
assert(s.st_nlink);
#if !USE_OLD_FS
// old FS doesn't store proper device ids
#ifndef __APPLE__
// mac uses makedev(3, 2) for /dev/null
assert(s.st_rdev == makedev(1, 3));
#endif
#endif
assert(!s.st_size);
assert(s.st_atime);

107
tests/stdio/test_rename.c Normal file
Просмотреть файл

@ -0,0 +1,107 @@
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
void create_file(const char *path, const char *buffer, int mode) {
int fd = open(path, O_WRONLY | O_CREAT | O_EXCL, mode);
assert(fd >= 0);
int err = write(fd, buffer, sizeof(char) * strlen(buffer));
assert(err == (sizeof(char) * strlen(buffer)));
close(fd);
}
void setup() {
create_file("file", "abcdef", 0777);
mkdir("dir", 0777);
create_file("dir/file", "abcdef", 0777);
mkdir("dir/subdir", 0777);
mkdir("dir-readonly", 0555);
mkdir("dir-nonempty", 0777);
create_file("dir-nonempty/file", "abcdef", 0777);
}
void cleanup() {
// we're hulk-smashing and removing original + renamed files to
// make sure we get it all regardless of anything failing
unlink("file");
unlink("dir/file");
unlink("dir/file1");
unlink("dir/file2");
rmdir("dir/subdir");
rmdir("dir/subdir1");
rmdir("dir/subdir2");
rmdir("dir");
rmdir("dir-readonly");
unlink("dir-nonempty/file");
rmdir("dir-nonempty");
}
void test() {
int err;
// can't rename something that doesn't exist
err = rename("noexist", "dir");
assert(err == -1);
assert(errno == ENOENT);
// can't overwrite a folder with a file
err = rename("file", "dir");
assert(err == -1);
assert(errno == EISDIR);
// can't overwrite a file with a folder
err = rename("dir", "file");
assert(err == -1);
assert(errno == ENOTDIR);
// can't overwrite a non-empty folder
err = rename("dir", "dir-nonempty");
assert(err == -1);
assert(errno == ENOTEMPTY);
// can't create anything in a read-only directory
err = rename("dir", "dir-readonly/dir");
assert(err == -1);
assert(errno == EACCES);
// source should not be ancestor of target
err = rename("dir", "dir/somename");
assert(err == -1);
assert(errno == EINVAL);
// target should not be an ancestor of source
err = rename("dir/subdir", "dir");
assert(err == -1);
assert(errno == ENOTEMPTY);
// do some valid renaming
err = rename("dir/file", "dir/file1");
assert(!err);
err = rename("dir/file1", "dir/file2");
assert(!err);
err = access("dir/file2", F_OK);
assert(!err);
err = rename("dir/subdir", "dir/subdir1");
assert(!err);
err = rename("dir/subdir1", "dir/subdir2");
assert(!err);
err = access("dir/subdir2", F_OK);
assert(!err);
puts("success");
}
int main() {
atexit(cleanup);
signal(SIGABRT, cleanup);
setup();
test();
return EXIT_SUCCESS;
}