diff options
author | max99x <max99x@gmail.com> | 2011-07-22 21:36:14 +0300 |
---|---|---|
committer | max99x <max99x@gmail.com> | 2011-07-22 23:31:57 +0300 |
commit | 5f9646ca267736036e87afc965e665539eed3578 (patch) | |
tree | 29f7928e8e37fc7a968434b8fad87d25ce2b5e8f | |
parent | 4f25c5b69954137557da89973f10d121cdb4a980 (diff) |
Added FS.analyzePath() which will simplify some library functions.
-rw-r--r-- | src/library.js | 113 | ||||
-rw-r--r-- | tests/filesystem/output.txt | 208 | ||||
-rw-r--r-- | tests/filesystem/src.js | 46 | ||||
-rw-r--r-- | tests/runner.py | 11 |
4 files changed, 344 insertions, 34 deletions
diff --git a/src/library.js b/src/library.js index 1347eb67..edcfb425 100644 --- a/src/library.js +++ b/src/library.js @@ -50,7 +50,7 @@ LibraryManager.library = { absolutePath: function(relative, base) { if (typeof relative !== 'string') return null; if (base === undefined) base = FS.currentPath; - else if (relative[0] == '/') base = ''; + if (relative && relative[0] == '/') base = ''; var full = base + '/' + relative; var parts = full.split('/').reverse(); var absolute = ['']; @@ -66,45 +66,90 @@ LibraryManager.library = { } return absolute.length == 1 ? '/' : absolute.join('/'); }, + // Analyzes a relative or absolute path returning a description, containing: + // isRoot: Whether the path points to the root. + // exists: Whether the object at the path exists. + // error: If !exists, this will contain the errno code of the cause. + // name: The base name of the object (null if !parentExists). + // path: The absolute path to the object, with all links resolved. + // object: The filesystem record of the object referenced by the path. + // parentExists: Whether the parent of the object exist and is a folder. + // parentPath: The absolute path to the parent folder. + // parentObject: The filesystem record of the parent folder. + analyzePath: function(path, dontResolveLastLink, linksVisited) { + var ret = { + isRoot: false, + exists: false, + error: 0, + name: null, + path: null, + object: null, + parentExists: false, + parentPath: null, + parentObject: null + }; + path = FS.absolutePath(path); + if (path == '/') { + ret.isRoot = true; + ret.exists = ret.parentExists = true; + ret.name = '/'; + ret.path = ret.parentPath = '/'; + ret.object = ret.parentObject = FS.root; + } else if (path !== null) { + linksVisited = linksVisited || 0; + path = path.slice(1).split('/'); + var current = FS.root; + var traversed = ['']; + while (path.length) { + if (path.length == 1 && current.isFolder) { + ret.parentExists = true; + ret.parentPath = traversed.length == 1 ? '/' : traversed.join('/'); + ret.parentObject = current; + ret.name = path[0]; + } + var target = path.shift(); + if (!current.isFolder) { + ret.error = ERRNO_CODES.ENOTDIR; + break; + } else if (!current.read) { + ret.error = ERRNO_CODES.EACCES; + break; + } else if (!current.contents.hasOwnProperty(target)) { + ret.error = ERRNO_CODES.ENOENT; + break; + } + current = current.contents[target]; + if (current.link && !(dontResolveLastLink && path.length == 0)) { + if (linksVisited > 40) { // Usual Linux SYMLOOP_MAX. + ret.error = ERRNO_CODES.ELOOP; + break; + } + var link = FS.absolutePath(current.link, traversed.join('/')); + return FS.analyzePath([link].concat(path).join('/'), + dontResolveLastLink, linksVisited + 1); + } + traversed.push(target); + if (path.length == 0) { + ret.exists = true; + ret.path = traversed.join('/'); + ret.object = current; + } + } + return ret; + } + return ret; + }, // Finds the file system object at a given path. If dontResolveLastLink is // set to true and the object is a symbolic link, it will be returned as is // instead of being resolved. Links embedded in the path as still resolved. findObject: function(path, dontResolveLastLink) { - var linksVisited = 0; - path = FS.absolutePath(path); - if (path === null) { - ___setErrNo(ERRNO_CODES.ENOENT); + var ret = FS.analyzePath(path, dontResolveLastLink); + if (ret.exists) { + return ret.object; + } else { + ___setErrNo(ret.error); return null; } - if (path == '/') return FS.root; - path = path.split('/').reverse(); - path.pop(); - var current = FS.root; - var traversed = ['']; - while (path.length) { - var target = path.pop(); - if (!current.isFolder) { - ___setErrNo(ERRNO_CODES.ENOTDIR); - return null; - } else if (!current.read) { - ___setErrNo(ERRNO_CODES.EACCES); - return null; - } else if (!current.contents.hasOwnProperty(target)) { - ___setErrNo(ERRNO_CODES.ENOENT); - return null; - } - current = current.contents[target]; - if (current.link && !(dontResolveLastLink && path.length == 0)) { - var link = FS.absolutePath(current.link, traversed.join('/')); - current = FS.findObject(link, dontResolveLastLink); - if (++linksVisited > 40) { // Usual Linux SYMLOOP_MAX. - ___setErrNo(ERRNO_CODES.ELOOP); - return null; - } - } - traversed.push(target); - } - return current; }, // Creates a file system record: file, link, device or folder. createObject: function(parent, name, properties, canRead, canWrite) { diff --git a/tests/filesystem/output.txt b/tests/filesystem/output.txt new file mode 100644 index 00000000..dd58133c --- /dev/null +++ b/tests/filesystem/output.txt @@ -0,0 +1,208 @@ + + isRoot: false + exists: true + error: 0 + path: /abc + name: abc + object.contents: ["123","456","deviceA","localLink","rootLink","relativeLink"] + parentExists: true + parentPath: / + parentObject.contents: ["forbidden","abc","def"] + +/ + isRoot: true + exists: true + error: 0 + path: / + name: / + object.contents: ["forbidden","abc","def"] + parentExists: true + parentPath: / + parentObject.contents: ["forbidden","abc","def"] + +. + isRoot: false + exists: true + error: 0 + path: /abc + name: abc + object.contents: ["123","456","deviceA","localLink","rootLink","relativeLink"] + parentExists: true + parentPath: / + parentObject.contents: ["forbidden","abc","def"] + +.. + isRoot: true + exists: true + error: 0 + path: / + name: / + object.contents: ["forbidden","abc","def"] + parentExists: true + parentPath: / + parentObject.contents: ["forbidden","abc","def"] + +../.. + isRoot: true + exists: true + error: 0 + path: / + name: / + object.contents: ["forbidden","abc","def"] + parentExists: true + parentPath: / + parentObject.contents: ["forbidden","abc","def"] + +/abc + isRoot: false + exists: true + error: 0 + path: /abc + name: abc + object.contents: ["123","456","deviceA","localLink","rootLink","relativeLink"] + parentExists: true + parentPath: / + parentObject.contents: ["forbidden","abc","def"] + +/abc/123 + isRoot: false + exists: true + error: 0 + path: /abc/123 + name: 123 + object.contents: [] + parentExists: true + parentPath: /abc + parentObject.contents: ["123","456","deviceA","localLink","rootLink","relativeLink"] + +/abc/noexist + isRoot: false + exists: false + error: 2 + path: null + name: noexist + object.contents: null + parentExists: true + parentPath: /abc + parentObject.contents: ["123","456","deviceA","localLink","rootLink","relativeLink"] + +/abc/deviceA + isRoot: false + exists: true + error: 0 + path: /abc/deviceA + name: deviceA + object.contents: [] + parentExists: true + parentPath: /abc + parentObject.contents: ["123","456","deviceA","localLink","rootLink","relativeLink"] + +/abc/localLink + isRoot: false + exists: true + error: 0 + path: /abc/123 + name: 123 + object.contents: [] + parentExists: true + parentPath: /abc + parentObject.contents: ["123","456","deviceA","localLink","rootLink","relativeLink"] + +/abc/rootLink + isRoot: true + exists: true + error: 0 + path: / + name: / + object.contents: ["forbidden","abc","def"] + parentExists: true + parentPath: / + parentObject.contents: ["forbidden","abc","def"] + +/abc/relativeLink + isRoot: false + exists: true + error: 0 + path: /def + name: def + object.contents: ["789","deviceB"] + parentExists: true + parentPath: / + parentObject.contents: ["forbidden","abc","def"] + +/abc/relativeLink/deviceB + isRoot: false + exists: true + error: 0 + path: /def/deviceB + name: deviceB + object.contents: [] + parentExists: true + parentPath: /def + parentObject.contents: ["789","deviceB"] + +/abc/rootLink/noexist + isRoot: false + exists: false + error: 2 + path: null + name: noexist + object.contents: null + parentExists: true + parentPath: / + parentObject.contents: ["forbidden","abc","def"] + +/abc/rootLink/abc/noexist + isRoot: false + exists: false + error: 2 + path: null + name: noexist + object.contents: null + parentExists: true + parentPath: /abc + parentObject.contents: ["123","456","deviceA","localLink","rootLink","relativeLink"] + +/forbidden + isRoot: false + exists: true + error: 0 + path: /forbidden + name: forbidden + object.contents: ["test"] + parentExists: true + parentPath: / + parentObject.contents: ["forbidden","abc","def"] + +/forbidden/test + isRoot: false + exists: false + error: 13 + path: null + name: test + object.contents: null + parentExists: true + parentPath: /forbidden + parentObject.contents: ["test"] + +/forbidden/noexist + isRoot: false + exists: false + error: 13 + path: null + name: noexist + object.contents: null + parentExists: true + parentPath: /forbidden + parentObject.contents: ["test"] + +/noexist1/noexist2 + isRoot: false + exists: false + error: 2 + path: null + name: null + object.contents: null + parentExists: false + parentPath: null + parentObject.contents: null diff --git a/tests/filesystem/src.js b/tests/filesystem/src.js new file mode 100644 index 00000000..5fdef564 --- /dev/null +++ b/tests/filesystem/src.js @@ -0,0 +1,46 @@ +FS.createFolder('/', 'forbidden', false, false); +FS.createFolder('/forbidden', 'test', true, true); +FS.createPath('/', 'abc/123', true, true); +FS.createPath('/', 'abc/456', true, true); +FS.createPath('/', 'def/789', true, true); +FS.createDevice('/abc', 'deviceA', function() {}, function() {}); +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); + +function explore(path) { + print(path); + var ret = FS.analyzePath(path); + print(' isRoot: ' + ret.isRoot); + print(' exists: ' + ret.exists); + print(' error: ' + ret.error); + print(' path: ' + ret.path); + print(' name: ' + ret.name); + print(' object.contents: ' + (ret.object && JSON.stringify(Object.keys(ret.object.contents || {})))); + print(' parentExists: ' + ret.parentExists); + print(' parentPath: ' + ret.parentPath); + print(' parentObject.contents: ' + (ret.parentObject && JSON.stringify(Object.keys(ret.parentObject.contents)))); + print(''); +} + +FS.currentPath = '/abc'; +explore(''); +explore('/'); +explore('.'); +explore('..'); +explore('../..'); +explore('/abc'); +explore('/abc/123'); +explore('/abc/noexist'); +explore('/abc/deviceA'); +explore('/abc/localLink'); +explore('/abc/rootLink'); +explore('/abc/relativeLink'); +explore('/abc/relativeLink/deviceB'); +explore('/abc/rootLink/noexist'); +explore('/abc/rootLink/abc/noexist'); +explore('/forbidden'); +explore('/forbidden/test'); +explore('/forbidden/noexist'); +explore('/noexist1/noexist2'); diff --git a/tests/runner.py b/tests/runner.py index 99ab9974..b673b45c 100644 --- a/tests/runner.py +++ b/tests/runner.py @@ -2404,6 +2404,17 @@ if 'benchmark' not in sys.argv: ''' self.do_test(src, re.sub('(^|\n)\s+', '\\1', expected), post_build=addPreRunAndChecks) + def test_fs_base(self): + global INCLUDE_FULL_LIBRARY; INCLUDE_FULL_LIBRARY = 1 + def addJS(filename): + src = open(filename, 'r').read().replace( + '// {{PRE_RUN_ADDITIONS}}', + open(path_from_root('tests', 'filesystem', 'src.js'), 'r').read()) + open(filename, 'w').write(src) + src = 'int main() {return 0;}\n' + expected = open(path_from_root('tests', 'filesystem', 'output.txt'), 'r').read() + self.do_test(src, expected, post_build=addJS) + ### 'Big' tests def test_fannkuch(self): |