Коммит
8dfcd06d78
26
LICENSE
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.
|
||||
"""
|
3174
src/library.js
3174
src/library.js
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
Загрузка…
Ссылка в новой задаче