From 85a804cc0c9ed5b80880a564c698a731c0ac6fa2 Mon Sep 17 00:00:00 2001 From: Abir Viqar Date: Sat, 23 Nov 2013 13:34:40 -0500 Subject: [PATCH] add symlink Also enable readlink's symbolic link test. --- README.md | 7 +++- src/fs.js | 80 +++++++++++++++++++++++++++++++++++++++- tests/spec/idbfs.spec.js | 79 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 163 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 20232fb..b0e9a49 100644 --- a/README.md +++ b/README.md @@ -161,7 +161,12 @@ Asynchronous lseek(2), where `whence` can be `SET`, `CUR`, or `END`. Callback ge 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. - diff --git a/src/fs.js b/src/fs.js index 94c9c93..081e6da 100644 --- a/src/fs.js +++ b/src/fs.js @@ -753,6 +753,61 @@ 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); @@ -1212,8 +1267,19 @@ define(function(require) { 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(context, path, callback) { var that = this; @@ -1527,6 +1593,18 @@ define(function(require) { ); 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); + }; // FIXME: WebSQL stuff, this needs implementation function WebSQLContext(transaction) { diff --git a/tests/spec/idbfs.spec.js b/tests/spec/idbfs.spec.js index 8f1a74d..8f0ca41 100644 --- a/tests/spec/idbfs.spec.js +++ b/tests/spec/idbfs.spec.js @@ -1351,6 +1351,83 @@ 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(); @@ -1406,7 +1483,7 @@ describe('fs.readlink', function() { }); }); - xit('should return the contents of a symbolic link', function() { + it('should return the contents of a symbolic link', function() { var complete = false; var _error, _result; var that = this;