Merge pull request #38 from ispedals/symbolic-link
Initial Implementation of Symbolic link
This commit is contained in:
commit
6cc4226b45
1
AUTHORS
1
AUTHORS
|
@ -1,2 +1,3 @@
|
||||||
Alan K <ack@modeswitch.org> (blog.modeswitch.org)
|
Alan K <ack@modeswitch.org> (blog.modeswitch.org)
|
||||||
David Humphrey <david.humphrey@senecacollege.ca> (@humphd)
|
David Humphrey <david.humphrey@senecacollege.ca> (@humphd)
|
||||||
|
Abir Viqar <abiviq@hushmail.com>
|
||||||
|
|
14
README.md
14
README.md
|
@ -160,3 +160,17 @@ Asynchronous lseek(2), where `whence` can be `SET`, `CUR`, or `END`. Callback ge
|
||||||
#### fs.readdir(path, callback)
|
#### fs.readdir(path, callback)
|
||||||
|
|
||||||
Asynchronous readdir(3). Reads the contents of a directory. Callback gets `(error, files)`, where `files` is an array containing the names of each file in the directory, excluding `.` and `..`.
|
Asynchronous readdir(3). Reads the contents of a directory. Callback gets `(error, files)`, where `files` is an array containing the names of each file in the directory, excluding `.` and `..`.
|
||||||
|
|
||||||
|
#### fs.symlink(srcPath, dstPath, callback)
|
||||||
|
|
||||||
|
Asynchronous symlink(2). Callback gets no additional arguments.
|
||||||
|
|
||||||
|
Unlike node.js, IDBFS does not accept the optional `type` parameter.
|
||||||
|
|
||||||
|
#### fs.readlink(path, callback)
|
||||||
|
|
||||||
|
Asynchronous readlink(2). Callback gets `(error, linkContents)`, where `linkContents` is a string containing the path to which the symbolic link links to.
|
||||||
|
|
||||||
|
#### fs.lstat(path, callback)
|
||||||
|
|
||||||
|
Asynchronous lstat(2). Callback gets `(error, stats)`, See `fs.stat`.
|
||||||
|
|
|
@ -18,6 +18,8 @@ define(function(require) {
|
||||||
MODE_DIRECTORY: 'DIRECTORY',
|
MODE_DIRECTORY: 'DIRECTORY',
|
||||||
MODE_SYMBOLIC_LINK: 'SYMLINK',
|
MODE_SYMBOLIC_LINK: 'SYMLINK',
|
||||||
|
|
||||||
|
SYMLOOP_MAX: 10,
|
||||||
|
|
||||||
BINARY_MIME_TYPE: 'application/octet-stream',
|
BINARY_MIME_TYPE: 'application/octet-stream',
|
||||||
JSON_MIME_TYPE: 'application/json',
|
JSON_MIME_TYPE: 'application/json',
|
||||||
|
|
||||||
|
|
10
src/error.js
10
src/error.js
|
@ -91,6 +91,13 @@ define(function(require) {
|
||||||
EIO.prototype.name = "EIO";
|
EIO.prototype.name = "EIO";
|
||||||
EIO.prototype.constructor = EIO;
|
EIO.prototype.constructor = EIO;
|
||||||
|
|
||||||
|
function ELoop(message){
|
||||||
|
this.message = message || '';
|
||||||
|
}
|
||||||
|
ELoop.prototype = new Error();
|
||||||
|
ELoop.prototype.name = "ELoop";
|
||||||
|
ELoop.prototype.constructor = ELoop;
|
||||||
|
|
||||||
function EFileSystemError(message){
|
function EFileSystemError(message){
|
||||||
this.message = message || '';
|
this.message = message || '';
|
||||||
}
|
}
|
||||||
|
@ -109,7 +116,8 @@ define(function(require) {
|
||||||
ENotImplemented: ENotImplemented,
|
ENotImplemented: ENotImplemented,
|
||||||
ENotMounted: ENotMounted,
|
ENotMounted: ENotMounted,
|
||||||
EInvalid: EInvalid,
|
EInvalid: EInvalid,
|
||||||
EIO: EIO
|
EIO: EIO,
|
||||||
|
ELoop: ELoop
|
||||||
};
|
};
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
346
src/fs.js
346
src/fs.js
|
@ -28,17 +28,20 @@ define(function(require) {
|
||||||
var ENotMounted = require('src/error').ENotMounted;
|
var ENotMounted = require('src/error').ENotMounted;
|
||||||
var EInvalid = require('src/error').EInvalid;
|
var EInvalid = require('src/error').EInvalid;
|
||||||
var EIO = require('src/error').EIO;
|
var EIO = require('src/error').EIO;
|
||||||
|
var ELoop = require('src/error').ELoop;
|
||||||
var EFileSystemError = require('src/error').EFileSystemError;
|
var EFileSystemError = require('src/error').EFileSystemError;
|
||||||
|
|
||||||
var FS_FORMAT = require('src/constants').FS_FORMAT;
|
var FS_FORMAT = require('src/constants').FS_FORMAT;
|
||||||
var MODE_FILE = require('src/constants').MODE_FILE;
|
var MODE_FILE = require('src/constants').MODE_FILE;
|
||||||
var MODE_DIRECTORY = require('src/constants').MODE_DIRECTORY;
|
var MODE_DIRECTORY = require('src/constants').MODE_DIRECTORY;
|
||||||
|
var MODE_SYMBOLIC_LINK = require('src/constants').MODE_SYMBOLIC_LINK;
|
||||||
var ROOT_DIRECTORY_NAME = require('src/constants').ROOT_DIRECTORY_NAME;
|
var ROOT_DIRECTORY_NAME = require('src/constants').ROOT_DIRECTORY_NAME;
|
||||||
var ROOT_NODE_ID = require('src/constants').ROOT_NODE_ID;
|
var ROOT_NODE_ID = require('src/constants').ROOT_NODE_ID;
|
||||||
var IDB_RW = require('src/constants').IDB_RW;
|
var IDB_RW = require('src/constants').IDB_RW;
|
||||||
var IDB_RO = require('src/constants').IDB_RO;
|
var IDB_RO = require('src/constants').IDB_RO;
|
||||||
var FILE_STORE_NAME = require('src/constants').FILE_STORE_NAME;
|
var FILE_STORE_NAME = require('src/constants').FILE_STORE_NAME;
|
||||||
var METADATA_STORE_NAME = require('src/constants').METADATA_STORE_NAME;
|
var METADATA_STORE_NAME = require('src/constants').METADATA_STORE_NAME;
|
||||||
|
var SYMLOOP_MAX = require('src/constants').SYMLOOP_MAX;
|
||||||
var FS_READY = require('src/constants').FS_READY;
|
var FS_READY = require('src/constants').FS_READY;
|
||||||
var FS_PENDING = require('src/constants').FS_PENDING;
|
var FS_PENDING = require('src/constants').FS_PENDING;
|
||||||
var FS_ERROR = require('src/constants').FS_ERROR;
|
var FS_ERROR = require('src/constants').FS_ERROR;
|
||||||
|
@ -119,6 +122,7 @@ define(function(require) {
|
||||||
}
|
}
|
||||||
var name = basename(path);
|
var name = basename(path);
|
||||||
var parentPath = dirname(path);
|
var parentPath = dirname(path);
|
||||||
|
var followedCount = 0;
|
||||||
|
|
||||||
function check_root_directory_node(error, rootDirectoryNode) {
|
function check_root_directory_node(error, rootDirectoryNode) {
|
||||||
if(error) {
|
if(error) {
|
||||||
|
@ -138,13 +142,13 @@ define(function(require) {
|
||||||
} else if(parentDirectoryNode.mode !== MODE_DIRECTORY || !parentDirectoryNode.data) {
|
} else if(parentDirectoryNode.mode !== MODE_DIRECTORY || !parentDirectoryNode.data) {
|
||||||
callback(new ENotDirectory('a component of the path prefix is not a directory'));
|
callback(new ENotDirectory('a component of the path prefix is not a directory'));
|
||||||
} else {
|
} else {
|
||||||
read_object(objectStore, parentDirectoryNode.data, get_node_id_from_parent_directory_data);
|
read_object(objectStore, parentDirectoryNode.data, get_node_from_parent_directory_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// in: parent directory data
|
// in: parent directory data
|
||||||
// out: searched node id
|
// out: searched node
|
||||||
function get_node_id_from_parent_directory_data(error, parentDirectoryData) {
|
function get_node_from_parent_directory_data(error, parentDirectoryData) {
|
||||||
if(error) {
|
if(error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
} else {
|
} else {
|
||||||
|
@ -152,11 +156,39 @@ define(function(require) {
|
||||||
callback(new ENoEntry('path does not exist'));
|
callback(new ENoEntry('path does not exist'));
|
||||||
} else {
|
} else {
|
||||||
var nodeId = parentDirectoryData[name].id;
|
var nodeId = parentDirectoryData[name].id;
|
||||||
read_object(objectStore, nodeId, callback);
|
read_object(objectStore, nodeId, is_symbolic_link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function is_symbolic_link(error, node) {
|
||||||
|
if(error) {
|
||||||
|
callback(error);
|
||||||
|
} else {
|
||||||
|
if(node.mode == MODE_SYMBOLIC_LINK) {
|
||||||
|
followedCount++;
|
||||||
|
if(followedCount > SYMLOOP_MAX){
|
||||||
|
callback(new ELoop('too many symbolic links were encountered'));
|
||||||
|
} else {
|
||||||
|
follow_symbolic_link(node.data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
callback(undefined, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function follow_symbolic_link(data) {
|
||||||
|
data = normalize(data);
|
||||||
|
parentPath = dirname(data);
|
||||||
|
name = basename(data);
|
||||||
|
if(ROOT_DIRECTORY_NAME == name) {
|
||||||
|
read_object(objectStore, ROOT_NODE_ID, check_root_directory_node);
|
||||||
|
} else {
|
||||||
|
find_node(objectStore, parentPath, read_parent_directory_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(ROOT_DIRECTORY_NAME == name) {
|
if(ROOT_DIRECTORY_NAME == name) {
|
||||||
read_object(objectStore, ROOT_NODE_ID, check_root_directory_node);
|
read_object(objectStore, ROOT_NODE_ID, check_root_directory_node);
|
||||||
} else {
|
} else {
|
||||||
|
@ -300,13 +332,34 @@ define(function(require) {
|
||||||
var parentDirectoryNode;
|
var parentDirectoryNode;
|
||||||
var parentDirectoryData;
|
var parentDirectoryData;
|
||||||
|
|
||||||
function check_if_directory_exists(error, result) {
|
function read_parent_directory_data(error, result) {
|
||||||
|
if(error) {
|
||||||
|
callback(error);
|
||||||
|
} else {
|
||||||
|
parentDirectoryNode = result;
|
||||||
|
read_object(objectStore, parentDirectoryNode.data, check_if_node_exists);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_if_node_exists(error, result) {
|
||||||
if(error) {
|
if(error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
} else if(ROOT_DIRECTORY_NAME == name) {
|
} else if(ROOT_DIRECTORY_NAME == name) {
|
||||||
callback(new EBusy());
|
callback(new EBusy());
|
||||||
} else if(!result) {
|
} else if(!_(result).has(name)) {
|
||||||
callback(new ENoEntry());
|
callback(new ENoEntry());
|
||||||
|
} else {
|
||||||
|
parentDirectoryData = result;
|
||||||
|
directoryNode = parentDirectoryData[name].id;
|
||||||
|
read_object(objectStore, directoryNode, check_if_node_is_directory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_if_node_is_directory(error, result) {
|
||||||
|
if(error) {
|
||||||
|
callback(error);
|
||||||
|
} else if(result.mode != MODE_DIRECTORY) {
|
||||||
|
callback(new ENotDirectory());
|
||||||
} else {
|
} else {
|
||||||
directoryNode = result;
|
directoryNode = result;
|
||||||
read_object(objectStore, directoryNode.data, check_if_directory_is_empty);
|
read_object(objectStore, directoryNode.data, check_if_directory_is_empty);
|
||||||
|
@ -321,29 +374,15 @@ define(function(require) {
|
||||||
if(_(directoryData).size() > 0) {
|
if(_(directoryData).size() > 0) {
|
||||||
callback(new ENotEmpty());
|
callback(new ENotEmpty());
|
||||||
} else {
|
} else {
|
||||||
find_node(objectStore, parentPath, read_parent_directory_data);
|
remove_directory_entry_from_parent_directory_node();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function read_parent_directory_data(error, result) {
|
function remove_directory_entry_from_parent_directory_node() {
|
||||||
if(error) {
|
|
||||||
callback(error);
|
|
||||||
} else {
|
|
||||||
parentDirectoryNode = result;
|
|
||||||
read_object(objectStore, parentDirectoryNode.data, remove_directory_entry_from_parent_directory_node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function remove_directory_entry_from_parent_directory_node(error, result) {
|
|
||||||
if(error) {
|
|
||||||
callback(error);
|
|
||||||
} else {
|
|
||||||
parentDirectoryData = result;
|
|
||||||
delete parentDirectoryData[name];
|
delete parentDirectoryData[name];
|
||||||
write_object(objectStore, parentDirectoryData, parentDirectoryNode.data, remove_directory_node);
|
write_object(objectStore, parentDirectoryData, parentDirectoryNode.data, remove_directory_node);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function remove_directory_node(error) {
|
function remove_directory_node(error) {
|
||||||
if(error) {
|
if(error) {
|
||||||
|
@ -361,7 +400,7 @@ define(function(require) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
find_node(objectStore, path, check_if_directory_exists);
|
find_node(objectStore, parentPath, read_parent_directory_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function open_file(fs, objectStore, path, flags, callback) {
|
function open_file(fs, objectStore, path, flags, callback) {
|
||||||
|
@ -375,6 +414,8 @@ define(function(require) {
|
||||||
var fileNode;
|
var fileNode;
|
||||||
var fileData;
|
var fileData;
|
||||||
|
|
||||||
|
var followedCount = 0;
|
||||||
|
|
||||||
if(ROOT_DIRECTORY_NAME == name) {
|
if(ROOT_DIRECTORY_NAME == name) {
|
||||||
if(_(flags).contains(O_WRITE)) {
|
if(_(flags).contains(O_WRITE)) {
|
||||||
callback(new EIsDirectory('the named file is a directory and O_WRITE is set'));
|
callback(new EIsDirectory('the named file is a directory and O_WRITE is set'));
|
||||||
|
@ -407,7 +448,7 @@ define(function(require) {
|
||||||
if(directoryEntry.type == MODE_DIRECTORY && _(flags).contains(O_WRITE)) {
|
if(directoryEntry.type == MODE_DIRECTORY && _(flags).contains(O_WRITE)) {
|
||||||
callback(new EIsDirectory('the named file is a directory and O_WRITE is set'));
|
callback(new EIsDirectory('the named file is a directory and O_WRITE is set'));
|
||||||
} else {
|
} else {
|
||||||
read_object(objectStore, directoryEntry.id, set_file_node);
|
read_object(objectStore, directoryEntry.id, check_if_symbolic_link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -420,6 +461,38 @@ define(function(require) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function check_if_symbolic_link(error, result) {
|
||||||
|
if(error) {
|
||||||
|
callback(error);
|
||||||
|
} else {
|
||||||
|
var node = result;
|
||||||
|
if(node.mode == MODE_SYMBOLIC_LINK) {
|
||||||
|
followedCount++;
|
||||||
|
if(followedCount > SYMLOOP_MAX){
|
||||||
|
callback(new ELoop('too many symbolic links were encountered'));
|
||||||
|
} else {
|
||||||
|
follow_symbolic_link(node.data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
set_file_node(undefined, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function follow_symbolic_link(data) {
|
||||||
|
data = normalize(data);
|
||||||
|
parentPath = dirname(data);
|
||||||
|
name = basename(data);
|
||||||
|
if(ROOT_DIRECTORY_NAME == name) {
|
||||||
|
if(_(flags).contains(O_WRITE)) {
|
||||||
|
callback(new EIsDirectory('the named file is a directory and O_WRITE is set'));
|
||||||
|
} else {
|
||||||
|
find_node(objectStore, path, set_file_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
find_node(objectStore, parentPath, read_directory_data);
|
||||||
|
}
|
||||||
|
|
||||||
function set_file_node(error, result) {
|
function set_file_node(error, result) {
|
||||||
if(error) {
|
if(error) {
|
||||||
callback(error);
|
callback(error);
|
||||||
|
@ -577,6 +650,51 @@ define(function(require) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function lstat_file(objectStore, path, callback) {
|
||||||
|
path = normalize(path);
|
||||||
|
var name = basename(path);
|
||||||
|
var parentPath = dirname(path);
|
||||||
|
|
||||||
|
var directoryNode;
|
||||||
|
var directoryData;
|
||||||
|
|
||||||
|
if(ROOT_DIRECTORY_NAME == name) {
|
||||||
|
read_object(objectStore, ROOT_NODE_ID, check_file);
|
||||||
|
} else {
|
||||||
|
find_node(objectStore, parentPath, read_directory_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function read_directory_data(error, result) {
|
||||||
|
if(error) {
|
||||||
|
callback(error);
|
||||||
|
} else {
|
||||||
|
directoryNode = result;
|
||||||
|
read_object(objectStore, directoryNode.data, check_if_file_exists);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_if_file_exists(error, result) {
|
||||||
|
if(error) {
|
||||||
|
callback(error);
|
||||||
|
} else {
|
||||||
|
directoryData = result;
|
||||||
|
if(!_(directoryData).has(name)) {
|
||||||
|
callback(new ENoEntry('a component of the path does not name an existing file'));
|
||||||
|
} else {
|
||||||
|
read_object(objectStore, directoryData[name].id, check_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_file(error, result) {
|
||||||
|
if(error) {
|
||||||
|
callback(error);
|
||||||
|
} else {
|
||||||
|
callback(undefined, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function link_node(objectStore, oldpath, newpath, callback) {
|
function link_node(objectStore, oldpath, newpath, callback) {
|
||||||
oldpath = normalize(oldpath);
|
oldpath = normalize(oldpath);
|
||||||
var oldname = basename(oldpath);
|
var oldname = basename(oldpath);
|
||||||
|
@ -660,8 +778,8 @@ define(function(require) {
|
||||||
|
|
||||||
function unlink_node(objectStore, path, callback) {
|
function unlink_node(objectStore, path, callback) {
|
||||||
path = normalize(path);
|
path = normalize(path);
|
||||||
name = basename(path);
|
var name = basename(path);
|
||||||
parentPath = dirname(path);
|
var parentPath = dirname(path);
|
||||||
|
|
||||||
var directoryNode;
|
var directoryNode;
|
||||||
var directoryData;
|
var directoryData;
|
||||||
|
@ -752,6 +870,106 @@ define(function(require) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function make_symbolic_link(objectStore, srcpath, dstpath, callback) {
|
||||||
|
dstpath = normalize(dstpath);
|
||||||
|
var name = basename(dstpath);
|
||||||
|
var parentPath = dirname(dstpath);
|
||||||
|
|
||||||
|
var directoryNode;
|
||||||
|
var directoryData;
|
||||||
|
var fileNode;
|
||||||
|
|
||||||
|
if(ROOT_DIRECTORY_NAME == name) {
|
||||||
|
callback(new EExists('the destination path already exists'));
|
||||||
|
} else {
|
||||||
|
find_node(objectStore, parentPath, read_directory_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function read_directory_data(error, result) {
|
||||||
|
if(error) {
|
||||||
|
callback(error);
|
||||||
|
} else {
|
||||||
|
directoryNode = result;
|
||||||
|
read_object(objectStore, directoryNode.data, check_if_file_exists);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_if_file_exists(error, result) {
|
||||||
|
if(error) {
|
||||||
|
callback(error);
|
||||||
|
} else {
|
||||||
|
directoryData = result;
|
||||||
|
if(_(directoryData).has(name)) {
|
||||||
|
callback(new EExists('the destination path already exists'));
|
||||||
|
} else {
|
||||||
|
write_file_node();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function write_file_node() {
|
||||||
|
fileNode = new Node(undefined, MODE_SYMBOLIC_LINK);
|
||||||
|
fileNode.nlinks += 1;
|
||||||
|
fileNode.size = srcpath.length;
|
||||||
|
fileNode.data = srcpath;
|
||||||
|
write_object(objectStore, fileNode, fileNode.id, update_directory_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function update_directory_data(error) {
|
||||||
|
if(error) {
|
||||||
|
callback(error);
|
||||||
|
} else {
|
||||||
|
directoryData[name] = new DirectoryEntry(fileNode.id, MODE_SYMBOLIC_LINK);
|
||||||
|
write_object(objectStore, directoryData, directoryNode.data, callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function read_link(objectStore, path, callback) {
|
||||||
|
path = normalize(path);
|
||||||
|
var name = basename(path);
|
||||||
|
var parentPath = dirname(path);
|
||||||
|
|
||||||
|
var directoryNode;
|
||||||
|
var directoryData;
|
||||||
|
|
||||||
|
find_node(objectStore, parentPath, read_directory_data);
|
||||||
|
|
||||||
|
function read_directory_data(error, result) {
|
||||||
|
if(error) {
|
||||||
|
callback(error);
|
||||||
|
} else {
|
||||||
|
directoryNode = result;
|
||||||
|
read_object(objectStore, directoryNode.data, check_if_file_exists);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_if_file_exists(error, result) {
|
||||||
|
if(error) {
|
||||||
|
callback(error);
|
||||||
|
} else {
|
||||||
|
directoryData = result;
|
||||||
|
if(!_(directoryData).has(name)) {
|
||||||
|
callback(new ENoEntry('a component of the path does not name an existing file'));
|
||||||
|
} else {
|
||||||
|
read_object(objectStore, directoryData[name].id, check_if_symbolic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_if_symbolic(error, result) {
|
||||||
|
if(error) {
|
||||||
|
callback(error);
|
||||||
|
} else {
|
||||||
|
if(result.mode != MODE_SYMBOLIC_LINK) {
|
||||||
|
callback(new EInvalid("path not a symbolic link"));
|
||||||
|
} else {
|
||||||
|
callback(undefined, result.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function validate_flags(flags) {
|
function validate_flags(flags) {
|
||||||
if(!_(O_FLAGS).has(flags)) {
|
if(!_(O_FLAGS).has(flags)) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -1166,17 +1384,51 @@ define(function(require) {
|
||||||
FileSystem.prototype._ftruncate = function _ftruncate(fd, length, callback) {
|
FileSystem.prototype._ftruncate = function _ftruncate(fd, length, callback) {
|
||||||
|
|
||||||
};
|
};
|
||||||
FileSystem.prototype._symlink = function _symlink(fd, length, callback) {
|
FileSystem.prototype._symlink = function _symlink(context, srcpath, dstpath, callback) {
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
function check_result(error) {
|
||||||
|
if(error) {
|
||||||
|
// if(transaction.error) transaction.abort();
|
||||||
|
callback(error);
|
||||||
|
} else {
|
||||||
|
callback(undefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
make_symbolic_link(context, srcpath, dstpath, check_result);
|
||||||
};
|
};
|
||||||
FileSystem.prototype._readlink = function _readlink(fd, length, callback) {
|
FileSystem.prototype._readlink = function _readlink(context, path, callback) {
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
function check_result(error, result) {
|
||||||
|
if(error) {
|
||||||
|
// if(transaction.error) transaction.abort();
|
||||||
|
callback(error);
|
||||||
|
} else {
|
||||||
|
callback(undefined, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
read_link(context, path, check_result);
|
||||||
};
|
};
|
||||||
FileSystem.prototype._realpath = function _realpath(fd, length, callback) {
|
FileSystem.prototype._realpath = function _realpath(fd, length, callback) {
|
||||||
|
|
||||||
};
|
};
|
||||||
FileSystem.prototype._lstat = function _lstat(fd, length, callback) {
|
FileSystem.prototype._lstat = function _lstat(context, path, callback) {
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
function check_result(error, result) {
|
||||||
|
if(error) {
|
||||||
|
// if(transaction.error) transaction.abort();
|
||||||
|
callback(error);
|
||||||
|
} else {
|
||||||
|
var stats = new Stats(result, that.name);
|
||||||
|
callback(undefined, stats);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lstat_file(context, path, check_result);
|
||||||
};
|
};
|
||||||
|
|
||||||
function IndexedDBContext(objectStore) {
|
function IndexedDBContext(objectStore) {
|
||||||
|
@ -1458,6 +1710,42 @@ define(function(require) {
|
||||||
);
|
);
|
||||||
if(error) callback(error);
|
if(error) callback(error);
|
||||||
};
|
};
|
||||||
|
IndexedDBFileSystem.prototype.readlink = function readlink(path, callback) {
|
||||||
|
var fs = this;
|
||||||
|
var error = this._queueOrRun(
|
||||||
|
function() {
|
||||||
|
var transaction = fs.db.transaction([FILE_STORE_NAME], IDB_RW);
|
||||||
|
var files = transaction.objectStore(FILE_STORE_NAME);
|
||||||
|
var context = new IndexedDBContext(files);
|
||||||
|
fs._readlink(context, path, callback);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if(error) callback(error);
|
||||||
|
};
|
||||||
|
IndexedDBFileSystem.prototype.symlink = function symlink(srcpath, dstpath, callback) {
|
||||||
|
var fs = this;
|
||||||
|
var error = this._queueOrRun(
|
||||||
|
function() {
|
||||||
|
var transaction = fs.db.transaction([FILE_STORE_NAME], IDB_RW);
|
||||||
|
var files = transaction.objectStore(FILE_STORE_NAME);
|
||||||
|
var context = new IndexedDBContext(files);
|
||||||
|
fs._symlink(context, srcpath, dstpath, callback);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if(error) callback(error);
|
||||||
|
};
|
||||||
|
IndexedDBFileSystem.prototype.lstat = function lstat(path, callback) {
|
||||||
|
var fs = this;
|
||||||
|
var error = this._queueOrRun(
|
||||||
|
function() {
|
||||||
|
var transaction = fs.db.transaction([FILE_STORE_NAME], IDB_RW);
|
||||||
|
var files = transaction.objectStore(FILE_STORE_NAME);
|
||||||
|
var context = new IndexedDBContext(files);
|
||||||
|
fs._lstat(context, path, callback);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if(error) callback(error);
|
||||||
|
};
|
||||||
|
|
||||||
// FIXME: WebSQL stuff, this needs implementation
|
// FIXME: WebSQL stuff, this needs implementation
|
||||||
function WebSQLContext(transaction) {
|
function WebSQLContext(transaction) {
|
||||||
|
|
|
@ -148,6 +148,45 @@ describe('fs.stat', function() {
|
||||||
expect(_result['type']).toBeDefined();
|
expect(_result['type']).toBeDefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should follow symbolic links and return a stat object for the resulting path', function() {
|
||||||
|
var complete = false;
|
||||||
|
var _error, _node, _result;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
that.fs.open('/myfile', 'w', function(error, result) {
|
||||||
|
if(error) throw error;
|
||||||
|
var fd = result;
|
||||||
|
that.fs.close(fd, function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
that.fs.stat('/myfile', function(error, result) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
_node = result['node'];
|
||||||
|
that.fs.symlink('/myfile', '/myfilelink', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
that.fs.stat('/myfilelink', function(error, result) {
|
||||||
|
_error = error;
|
||||||
|
_result = result;
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(_result).toBeDefined();
|
||||||
|
expect(_node).toBeDefined();
|
||||||
|
expect(_error).not.toBeDefined();
|
||||||
|
expect(_result['node']).toEqual(_node);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('fs.fstat', function() {
|
describe('fs.fstat', function() {
|
||||||
|
@ -201,6 +240,92 @@ describe('fs.fstat', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('fs.lstat', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
this.db_name = mk_db_name();
|
||||||
|
this.fs = new IDBFS.FileSystem(this.db_name, 'FORMAT');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
indexedDB.deleteDatabase(this.db_name);
|
||||||
|
delete this.fs;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be a function', function() {
|
||||||
|
expect(typeof this.fs.lstat).toEqual('function');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an error if path does not exist', function() {
|
||||||
|
var complete = false;
|
||||||
|
var _error, _result;
|
||||||
|
|
||||||
|
this.fs.lstat('/tmp', function(error, result) {
|
||||||
|
_error = error;
|
||||||
|
_result = result;
|
||||||
|
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(_error).toBeDefined();
|
||||||
|
expect(_result).not.toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a stat object if path is not a symbolic link', function() {
|
||||||
|
var complete = false;
|
||||||
|
var _error, _result;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
that.fs.lstat('/', function(error, result) {
|
||||||
|
_error = error;
|
||||||
|
_result = result;
|
||||||
|
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(_error).not.toBeDefined();
|
||||||
|
expect(_result).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should return a stat object if path is a symbolic link', function() {
|
||||||
|
var complete = false;
|
||||||
|
var _error, _result;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
that.fs.symlink('/', '/mylink', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
that.fs.lstat('/mylink', function(error, result) {
|
||||||
|
_error = error;
|
||||||
|
_result = result;
|
||||||
|
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(_error).not.toBeDefined();
|
||||||
|
expect(_result).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('fs.mkdir', function() {
|
describe('fs.mkdir', function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
this.db_name = mk_db_name();
|
this.db_name = mk_db_name();
|
||||||
|
@ -343,6 +468,35 @@ describe('fs.readdir', function() {
|
||||||
expect(_files[0]).toEqual('tmp');
|
expect(_files[0]).toEqual('tmp');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should follow symbolic links', function() {
|
||||||
|
var complete = false;
|
||||||
|
var _error, _files;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
that.fs.mkdir('/tmp', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
that.fs.symlink('/', '/tmp/dirLink', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
that.fs.readdir('/tmp/dirLink', function(error, result) {
|
||||||
|
_error = error;
|
||||||
|
_files = result;
|
||||||
|
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(_error).not.toBeDefined();
|
||||||
|
expect(_files.length).toEqual(1);
|
||||||
|
expect(_files[0]).toEqual('tmp');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('fs.rmdir', function() {
|
describe('fs.rmdir', function() {
|
||||||
|
@ -424,6 +578,56 @@ describe('fs.rmdir', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should return an error if the path is not a directory', function() {
|
||||||
|
var complete = false;
|
||||||
|
var _error;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
that.fs.mkdir('/tmp', function(error) {
|
||||||
|
that.fs.open('/tmp/myfile', 'w', function(error, fd) {
|
||||||
|
that.fs.close(fd, function(error) {
|
||||||
|
that.fs.rmdir('/tmp/myfile', function(error) {
|
||||||
|
_error = error;
|
||||||
|
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(_error).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an error if the path is a symbolic link', function () {
|
||||||
|
var complete = false;
|
||||||
|
var _error;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
that.fs.mkdir('/tmp', function (error) {
|
||||||
|
that.fs.symlink('/tmp', '/tmp/myfile', function (error) {
|
||||||
|
that.fs.rmdir('/tmp/myfile', function (error) {
|
||||||
|
_error = error;
|
||||||
|
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function () {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function () {
|
||||||
|
expect(_error).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should remove an existing directory', function() {
|
it('should remove an existing directory', function() {
|
||||||
var complete = false;
|
var complete = false;
|
||||||
var _error, _stat;
|
var _error, _stat;
|
||||||
|
@ -859,6 +1063,36 @@ describe('fs.writeFile, fs.readFile', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should follow symbolic links', function () {
|
||||||
|
var complete = false;
|
||||||
|
var _result;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
var contents = "This is a file.";
|
||||||
|
|
||||||
|
that.fs.writeFile('/myfile', '', { encoding: 'utf8' }, function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
that.fs.symlink('/myfile', '/myFileLink', function (error) {
|
||||||
|
if (error) throw error;
|
||||||
|
that.fs.writeFile('/myFileLink', contents, 'utf8', function (error) {
|
||||||
|
if (error) throw error;
|
||||||
|
that.fs.readFile('/myFileLink', 'utf8', function(error, data) {
|
||||||
|
if(error) throw error;
|
||||||
|
_result = data;
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(_result).toEqual(contents);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('fs.read', function() {
|
describe('fs.read', function() {
|
||||||
|
@ -1054,6 +1288,44 @@ describe('fs.link', function() {
|
||||||
expect(_newstats).toEqual(_oldstats);
|
expect(_newstats).toEqual(_oldstats);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not follow symbolic links', function () {
|
||||||
|
var complete = false;
|
||||||
|
var _error, _oldstats, _linkstats, _newstats;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
that.fs.stat('/', function (error, result) {
|
||||||
|
if (error) throw error;
|
||||||
|
_oldstats = result;
|
||||||
|
that.fs.symlink('/', '/myfileLink', function (error) {
|
||||||
|
if (error) throw error;
|
||||||
|
that.fs.link('/myfileLink', '/myotherfile', function (error) {
|
||||||
|
if (error) throw error;
|
||||||
|
that.fs.lstat('/myfileLink', function (error, result) {
|
||||||
|
if (error) throw error;
|
||||||
|
_linkstats = result;
|
||||||
|
that.fs.lstat('/myotherfile', function (error, result) {
|
||||||
|
if (error) throw error;
|
||||||
|
_newstats = result;
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function () {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function () {
|
||||||
|
expect(_error).not.toBeDefined();
|
||||||
|
expect(_newstats.node).toEqual(_linkstats.node);
|
||||||
|
expect(_newstats.node).toNotEqual(_oldstats.node);
|
||||||
|
expect(_newstats.nlinks).toEqual(2);
|
||||||
|
expect(_newstats).toEqual(_linkstats);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('fs.unlink', function() {
|
describe('fs.unlink', function() {
|
||||||
|
@ -1115,6 +1387,49 @@ describe('fs.unlink', function() {
|
||||||
expect(_stats.nlinks).toEqual(1);
|
expect(_stats.nlinks).toEqual(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not follow symbolic links', function () {
|
||||||
|
var complete = false;
|
||||||
|
var _error, _stats1, _stats2;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
that.fs.symlink('/', '/myFileLink', function (error) {
|
||||||
|
if (error) throw error;
|
||||||
|
|
||||||
|
that.fs.link('/myFileLink', '/myotherfile', function (error) {
|
||||||
|
if (error) throw error;
|
||||||
|
|
||||||
|
that.fs.unlink('/myFileLink', function (error) {
|
||||||
|
if (error) throw error;
|
||||||
|
|
||||||
|
that.fs.lstat('/myFileLink', function (error, result) {
|
||||||
|
_error = error;
|
||||||
|
|
||||||
|
that.fs.lstat('/myotherfile', function (error, result) {
|
||||||
|
if (error) throw error;
|
||||||
|
_stats1 = result;
|
||||||
|
|
||||||
|
that.fs.stat('/', function (error, result) {
|
||||||
|
if (error) throw error;
|
||||||
|
_stats2 = result;
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function () {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function () {
|
||||||
|
expect(_error).toBeDefined();
|
||||||
|
expect(_stats1.nlinks).toEqual(1);
|
||||||
|
expect(_stats2.nlinks).toEqual(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('fs.rename', function() {
|
describe('fs.rename', function() {
|
||||||
|
@ -1172,6 +1487,54 @@ describe('fs.rename', function() {
|
||||||
expect(_stats.nlinks).toEqual(1);
|
expect(_stats.nlinks).toEqual(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not follow symbolic links', function () {
|
||||||
|
var complete = false;
|
||||||
|
var _error, _stats;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
that.fs.open('/myfile', 'w', function (error, result) {
|
||||||
|
if (error) throw error;
|
||||||
|
|
||||||
|
var fd = result;
|
||||||
|
that.fs.close(fd, function (error) {
|
||||||
|
if (error) throw error;
|
||||||
|
|
||||||
|
that.fs.symlink('/myfile', '/myFileLink', function (error) {
|
||||||
|
if (error) throw error;
|
||||||
|
|
||||||
|
that.fs.rename('/myFileLink', '/myOtherFileLink', function (error) {
|
||||||
|
if (error) throw error;
|
||||||
|
|
||||||
|
that.fs.stat('/myfile', function (error, result) {
|
||||||
|
_error1 = error;
|
||||||
|
|
||||||
|
that.fs.lstat('/myFileLink', function (error, result) {
|
||||||
|
_error2 = error;
|
||||||
|
|
||||||
|
that.fs.stat('/myOtherFileLink', function (error, result) {
|
||||||
|
if (error) throw error;
|
||||||
|
|
||||||
|
_stats = result;
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function () {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function () {
|
||||||
|
expect(_error1).not.toBeDefined();
|
||||||
|
expect(_error2).toBeDefined();
|
||||||
|
expect(_stats.nlinks).toEqual(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('fs.lseek', function() {
|
describe('fs.lseek', function() {
|
||||||
|
@ -1350,3 +1713,506 @@ describe('fs.lseek', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('fs.symlink', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
this.db_name = mk_db_name();
|
||||||
|
this.fs = new IDBFS.FileSystem(this.db_name, 'FORMAT');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
indexedDB.deleteDatabase(this.db_name);
|
||||||
|
delete this.fs;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be a function', function() {
|
||||||
|
expect(typeof this.fs.symlink).toEqual('function');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an error if part of the parent destination path does not exist', function() {
|
||||||
|
var complete = false;
|
||||||
|
var _error;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
that.fs.symlink('/', '/tmp/mydir', function(error) {
|
||||||
|
_error = error;
|
||||||
|
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(_error).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an error if the destination path already exists', function() {
|
||||||
|
var complete = false;
|
||||||
|
var _error;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
that.fs.symlink('/tmp', '/', function(error) {
|
||||||
|
_error = error;
|
||||||
|
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(_error).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create a symlink', function() {
|
||||||
|
var complete = false;
|
||||||
|
var _error, _result;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
that.fs.symlink('/', '/myfile', function(error, result) {
|
||||||
|
_error = error;
|
||||||
|
_result = result;
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(_error).not.toBeDefined();
|
||||||
|
expect(_result).not.toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('fs.readlink', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
this.db_name = mk_db_name();
|
||||||
|
this.fs = new IDBFS.FileSystem(this.db_name, 'FORMAT');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
indexedDB.deleteDatabase(this.db_name);
|
||||||
|
delete this.fs;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be a function', function() {
|
||||||
|
expect(typeof this.fs.readlink).toEqual('function');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an error if part of the parent destination path does not exist', function() {
|
||||||
|
var complete = false;
|
||||||
|
var _error;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
that.fs.readlink('/tmp/mydir', function(error) {
|
||||||
|
_error = error;
|
||||||
|
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(_error).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an error if the path is not a symbolic link', function() {
|
||||||
|
var complete = false;
|
||||||
|
var _error;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
that.fs.readlink('/', function(error) {
|
||||||
|
_error = error;
|
||||||
|
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(_error).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the contents of a symbolic link', function() {
|
||||||
|
var complete = false;
|
||||||
|
var _error, _result;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
that.fs.symlink('/', '/myfile', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
that.fs.readlink('/myfile', function(error, result) {
|
||||||
|
_error = error;
|
||||||
|
_result = result;
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(_error).not.toBeDefined();
|
||||||
|
expect(_result).toEqual('/');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('path resolution', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
this.db_name = mk_db_name();
|
||||||
|
this.fs = new IDBFS.FileSystem(this.db_name, 'FORMAT');
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
indexedDB.deleteDatabase(this.db_name);
|
||||||
|
delete this.fs;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should follow a symbolic link to the root directory', function() {
|
||||||
|
var complete = false;
|
||||||
|
var _error, _node, _result;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
that.fs.symlink('/', '/mydirectorylink', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
that.fs.stat('/', function(error, result) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
_node = result['node'];
|
||||||
|
that.fs.stat('/mydirectorylink', function(error, result) {
|
||||||
|
_error = error;
|
||||||
|
_result = result;
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(_result).toBeDefined();
|
||||||
|
expect(_node).toBeDefined();
|
||||||
|
expect(_error).not.toBeDefined();
|
||||||
|
expect(_result['node']).toEqual(_node);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should follow a symbolic link to a directory', function() {
|
||||||
|
var complete = false;
|
||||||
|
var _error, _node, _result;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
that.fs.mkdir('/mydir', function(error) {
|
||||||
|
that.fs.symlink('/mydir', '/mydirectorylink', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
that.fs.stat('/mydir', function(error, result) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
_node = result['node'];
|
||||||
|
that.fs.stat('/mydirectorylink', function(error, result) {
|
||||||
|
_error = error;
|
||||||
|
_result = result;
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(_result).toBeDefined();
|
||||||
|
expect(_node).toBeDefined();
|
||||||
|
expect(_error).not.toBeDefined();
|
||||||
|
expect(_result['node']).toEqual(_node);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should follow a symbolic link to a file', function() {
|
||||||
|
var complete = false;
|
||||||
|
var _error, _node, _result;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
that.fs.open('/myfile', 'w', function(error, result) {
|
||||||
|
if(error) throw error;
|
||||||
|
var fd = result;
|
||||||
|
that.fs.close(fd, function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
that.fs.stat('/myfile', function(error, result) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
_node = result['node'];
|
||||||
|
that.fs.symlink('/myfile', '/myfilelink', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
that.fs.stat('/myfilelink', function(error, result) {
|
||||||
|
_error = error;
|
||||||
|
_result = result;
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(_result).toBeDefined();
|
||||||
|
expect(_node).toBeDefined();
|
||||||
|
expect(_error).not.toBeDefined();
|
||||||
|
expect(_result['node']).toEqual(_node);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should follow multiple symbolic links to a file', function() {
|
||||||
|
var complete = false;
|
||||||
|
var _error, _node, _result;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
that.fs.open('/myfile', 'w', function(error, result) {
|
||||||
|
if(error) throw error;
|
||||||
|
var fd = result;
|
||||||
|
that.fs.close(fd, function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
that.fs.stat('/myfile', function(error, result) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
_node = result['node'];
|
||||||
|
that.fs.symlink('/myfile', '/myfilelink1', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
that.fs.symlink('/myfilelink1', '/myfilelink2', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
that.fs.stat('/myfilelink2', function(error, result) {
|
||||||
|
_error = error;
|
||||||
|
_result = result;
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(_result).toBeDefined();
|
||||||
|
expect(_node).toBeDefined();
|
||||||
|
expect(_error).not.toBeDefined();
|
||||||
|
expect(_result['node']).toEqual(_node);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should error if symbolic link leads to itself', function() {
|
||||||
|
var complete = false;
|
||||||
|
var _error, _node, _result;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
that.fs.symlink('/mylink1', '/mylink2', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
that.fs.symlink('/mylink2', '/mylink1', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
that.fs.stat('/myfilelink1', function(error, result) {
|
||||||
|
_error = error;
|
||||||
|
_result = result;
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(_error).toBeDefined();
|
||||||
|
expect(_result).not.toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should error if it follows more than 10 symbolic links', function() {
|
||||||
|
var complete = false;
|
||||||
|
var _error, _result;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
that.fs.open('/myfile', 'w', function(error, result) {
|
||||||
|
if(error) throw error;
|
||||||
|
var fd = result;
|
||||||
|
that.fs.close(fd, function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
that.fs.stat('/myfile', function(error, result) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
that.fs.symlink('/myfile', '/myfilelink1', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
that.fs.symlink('/myfilelink1', '/myfilelink2', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
that.fs.symlink('/myfilelink2', '/myfilelink3', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
that.fs.symlink('/myfilelink3', '/myfilelink4', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
that.fs.symlink('/myfilelink4', '/myfilelink5', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
that.fs.symlink('/myfilelink5', '/myfilelink6', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
that.fs.symlink('/myfilelink6', '/myfilelink7', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
that.fs.symlink('/myfilelink7', '/myfilelink8', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
that.fs.symlink('/myfilelink8', '/myfilelink9', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
that.fs.symlink('/myfilelink9', '/myfilelink10', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
that.fs.symlink('/myfilelink10', '/myfilelink11', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
that.fs.stat('/myfilelink11', function(error, result) {
|
||||||
|
_error = error;
|
||||||
|
_result = result;
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(_result).not.toBeDefined();
|
||||||
|
expect(_error).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should follow a symbolic link in the path to a file', function() {
|
||||||
|
var complete = false;
|
||||||
|
var _error, _node, _result;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
that.fs.open('/myfile', 'w', function(error, result) {
|
||||||
|
if(error) throw error;
|
||||||
|
var fd = result;
|
||||||
|
that.fs.close(fd, function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
that.fs.stat('/myfile', function(error, result) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
_node = result['node'];
|
||||||
|
that.fs.symlink('/', '/mydirlink', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
that.fs.stat('/mydirlink/myfile', function(error, result) {
|
||||||
|
_error = error;
|
||||||
|
_result = result;
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(_result).toBeDefined();
|
||||||
|
expect(_node).toBeDefined();
|
||||||
|
expect(_error).not.toBeDefined();
|
||||||
|
expect(_result['node']).toEqual(_node);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should error if a symbolic link in the path to a file is itself a file', function() {
|
||||||
|
var complete = false;
|
||||||
|
var _error, _result;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
that.fs.open('/myfile', 'w', function(error, result) {
|
||||||
|
if(error) throw error;
|
||||||
|
var fd = result;
|
||||||
|
that.fs.close(fd, function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
that.fs.stat('/myfile', function(error, result) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
that.fs.open('/myfile2', 'w', function(error, result) {
|
||||||
|
if(error) throw error;
|
||||||
|
var fd = result;
|
||||||
|
that.fs.close(fd, function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
that.fs.symlink('/myfile2', '/mynotdirlink', function(error) {
|
||||||
|
if(error) throw error;
|
||||||
|
|
||||||
|
that.fs.stat('/mynotdirlink/myfile', function(error, result) {
|
||||||
|
_error = error;
|
||||||
|
_result = result;
|
||||||
|
complete = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
waitsFor(function() {
|
||||||
|
return complete;
|
||||||
|
}, 'test to complete', DEFAULT_TIMEOUT);
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(_error).toBeDefined();
|
||||||
|
expect(_result).not.toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
Loading…
Reference in New Issue