From 580dad53156c6c0e18db3a04f8fab21407c39f5b Mon Sep 17 00:00:00 2001 From: Alan Kligman Date: Fri, 31 May 2013 03:52:04 -0400 Subject: [PATCH] WIP --- build/wrap.end | 2 +- dist/idbfs.js | 300 ++++++++++++------ examples/Linq2IndexedDB.js | 58 ++-- examples/refactoring-test.html | 8 +- src/descriptor.js | 10 + src/directory.js | 59 +--- src/file-system.js | 21 +- src/file.js | 95 +++++- src/object-store.js | 65 ++++ tests/index.html | 52 +++ tests/spec/idbfs.spec.js | 15 + .../MIT.LICENSE | 0 .../jasmine-html.js | 2 +- .../jasmine.css | 0 .../jasmine.js | 4 +- 15 files changed, 504 insertions(+), 187 deletions(-) create mode 100644 src/descriptor.js create mode 100644 tests/index.html create mode 100644 tests/spec/idbfs.spec.js rename tools/{jasmine-1.3.0 => jasmine-1.3.1}/MIT.LICENSE (100%) rename tools/{jasmine-1.3.0 => jasmine-1.3.1}/jasmine-html.js (99%) rename tools/{jasmine-1.3.0 => jasmine-1.3.1}/jasmine.css (100%) rename tools/{jasmine-1.3.0 => jasmine-1.3.1}/jasmine.js (99%) diff --git a/build/wrap.end b/build/wrap.end index 785bbe5..0da7a67 100644 --- a/build/wrap.end +++ b/build/wrap.end @@ -1,5 +1,5 @@ - var IDBFS = require( "src/fs" ); + var IDBFS = require( "src/file-system" ); return IDBFS; diff --git a/dist/idbfs.js b/dist/idbfs.js index 4b61b08..a2add4e 100644 --- a/dist/idbfs.js +++ b/dist/idbfs.js @@ -5617,76 +5617,6 @@ define('src/constants',['require'],function(require) { FS_ERROR: 'ERROR', }; -}); -define('src/object-store',['require'],function(require) { - - function read_object(objectStore, id, callback) { - var getRequest = objectStore.get(id); - getRequest.onsuccess = function onsuccess(event) { - var result = event.target.result; - callback(undefined, result); - }; - getRequest.onerror = function onerror(error) { - callback(error); - }; - }; - - function write_object(objectStore, object, id, callback) { - var putRequest = objectStore.put(object, id); - putRequest.onsuccess = function onsuccess(event) { - var result = event.target.result; - callback(undefined, result); - }; - putRequest.onerror = function onerror(error) { - callback(error); - }; - }; - - function delete_object(objectStore, id, callback) { - var deleteRequest = objectStore.delete(id); - deleteRequest.onsuccess = function onsuccess(event) { - var result = event.target.result; - callback(undefined, result); - }; - deleteRequest.onerror = function(error) { - callback(error); - }; - }; - - return { - read_object: read_object, - write_object: write_object, - delete_object: delete_object, - }; - -}); -define('src/file',['require','src/constants','src/shared','src/shared'],function(require) { - - var MODE_FILE = require('src/constants').MODE_FILE; - - var guid = require('src/shared').guid; - var hash = require('src/shared').hash; - - function Node(id, mode, size, atime, ctime, mtime, flags, xattrs, links, version) { - var now = Date.now(); - - this.id = id || hash(guid()), - this.mode = mode || MODE_FILE; // node type (file, directory, etc) - this.size = size || 0; // size (bytes for files, entries for directories) - this.atime = atime || now; // access time - this.ctime = ctime || now; // creation time - this.mtime = mtime || now; // modified time - this.flags = flags || ''; // file flags - this.xattrs = xattrs || {}; // extended attributes - this.links = links || 0; // links count - this.version = version || 0; // node version - this.data = hash(id) // id for data object - }; - - return { - Node: Node, - }; - }); // Copyright Joyent, Inc. and other Node contributors. // @@ -5815,31 +5745,20 @@ define('src/path',['require'],function(require) { } }); -define('src/directory',['require','src/object-store','src/object-store','src/object-store','src/error','src/error','src/error','src/constants','src/constants','src/constants','src/constants','src/file','src/path','src/path','src/path'],function(require) { - - var read_object = require('src/object-store').read_object; - var write_object = require('src/object-store').write_object; - var delete_object = require('src/object-store').delete_object; +define('src/object-store',['require','src/error','src/error','src/error','src/path','src/path','src/path','src/constants','src/constants','src/constants'],function(require) { var ENoEntry = require('src/error').ENoEntry; var ENotDirectory = require('src/error').ENotDirectory; var EPathExists = require('src/error').EPathExists; - var MODE_FILE = require('src/constants').MODE_FILE; - var MODE_DIRECTORY = require('src/constants').MODE_DIRECTORY; - var ROOT_DIRECTORY_NAME = require('src/constants').ROOT_DIRECTORY_NAME; - var ROOT_NODE_ID = require('src/constants').ROOT_NODE_ID; - - var Node = require('src/file').Node; - var normalize = require('src/path').normalize; var dirname = require('src/path').dirname; var basename = require('src/path').basename; - function DirectoryEntry(id, type) { - this.id = id; - this.type = type || MODE_FILE; - }; + var ROOT_DIRECTORY_NAME = require('src/constants').ROOT_DIRECTORY_NAME; + var ROOT_NODE_ID = require('src/constants').ROOT_NODE_ID; + + var MODE_DIRECTORY = require('src/constants').MODE_DIRECTORY; // in: file or directory path // out: node structure, or error @@ -5892,6 +5811,189 @@ define('src/directory',['require','src/object-store','src/object-store','src/obj } }; + function read_object(objectStore, id, callback) { + var getRequest = objectStore.get(id); + getRequest.onsuccess = function onsuccess(event) { + var result = event.target.result; + callback(undefined, result); + }; + getRequest.onerror = function onerror(error) { + callback(error); + }; + }; + + function write_object(objectStore, object, id, callback) { + var putRequest = objectStore.put(object, id); + putRequest.onsuccess = function onsuccess(event) { + var result = event.target.result; + callback(undefined, result); + }; + putRequest.onerror = function onerror(error) { + callback(error); + }; + }; + + function delete_object(objectStore, id, callback) { + var deleteRequest = objectStore.delete(id); + deleteRequest.onsuccess = function onsuccess(event) { + var result = event.target.result; + callback(undefined, result); + }; + deleteRequest.onerror = function(error) { + callback(error); + }; + }; + + return { + read_object: read_object, + write_object: write_object, + delete_object: delete_object, + find_node: find_node + }; + +}); +define('src/file',['require','lodash','src/path','src/path','src/path','src/constants','src/shared','src/shared','src/object-store','src/object-store','src/object-store','src/object-store','src/constants'],function(require) { + + var _ = require('lodash'); + + var normalize = require('src/path').normalize; + var dirname = require('src/path').dirname; + var basename = require('src/path').basename; + + var MODE_FILE = require('src/constants').MODE_FILE; + + var guid = require('src/shared').guid; + var hash = require('src/shared').hash; + + var read_object = require('src/object-store').read_object; + var write_object = require('src/object-store').write_object; + var delete_object = require('src/object-store').delete_object; + var find_node = require('src/object-store').find_node; + + var O_CREATE = require('src/constants').O_CREATE; + + function DirectoryEntry(id, type) { + this.id = id; + this.type = type || MODE_FILE; + }; + + function Node(id, mode, size, atime, ctime, mtime, flags, xattrs, links, version) { + var now = Date.now(); + + this.id = id || hash(guid()), + this.mode = mode || MODE_FILE; // node type (file, directory, etc) + this.size = size || 0; // size (bytes for files, entries for directories) + this.atime = atime || now; // access time + this.ctime = ctime || now; // creation time + this.mtime = mtime || now; // modified time + this.flags = flags || []; // file flags + this.xattrs = xattrs || {}; // extended attributes + this.links = links || 0; // links count + this.version = version || 0; // node version + this.data = hash(this.id) // id for data object + }; + + function open_file(objectStore, path, flags, mode, callback) { + path = normalize(path); + var name = basename(path); + + var directoryNode; + var directoryData; + var fileNode; + var fileData; + + 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)) { + // file exists + } else { + if(_(flags).contains(O_CREATE)) { + write_file_node(); + } else { + callback(error); + } + } + } + }; + + function write_file_node() { + fileNode = new Node(undefined, MODE_FILE); + fileNode.links += 1; + write_object(objectStore, fileNode, fileNode.id, write_file_data); + }; + + function write_file_data(error) { + if(error) { + callback(error); + } else { + fileData = {}; + write_object(objectStore, fileData, fileNode.data, update_directory_data); + } + }; + + function update_directory_data(error) { + if(error) { + callback(error); + } else { + directoryData[name] = new DirectoryEntry(fileNode.id, MODE_FILE); + write_object(objectStore, directoryData, directoryNode.data, create_file_descriptor); + } + }; + + function create_file_descriptor(error) { + if(error) { + console.log(error); + } else { + callback(undefined, '!'); + } + }; + + var parentPath = dirname(path); + find_node(objectStore, parentPath, read_directory_data); + }; + + return { + Node: Node, + open_file: open_file, + DirectoryEntry: DirectoryEntry, + }; + +}); +define('src/directory',['require','src/object-store','src/object-store','src/object-store','src/object-store','src/error','src/error','src/error','src/constants','src/constants','src/constants','src/constants','src/file','src/file','src/path','src/path','src/path'],function(require) { + + var read_object = require('src/object-store').read_object; + var write_object = require('src/object-store').write_object; + var delete_object = require('src/object-store').delete_object; + var find_node = require('src/object-store').find_node; + + var ENoEntry = require('src/error').ENoEntry; + var ENotDirectory = require('src/error').ENotDirectory; + var EPathExists = require('src/error').EPathExists; + + var MODE_FILE = require('src/constants').MODE_FILE; + var MODE_DIRECTORY = require('src/constants').MODE_DIRECTORY; + var ROOT_DIRECTORY_NAME = require('src/constants').ROOT_DIRECTORY_NAME; + var ROOT_NODE_ID = require('src/constants').ROOT_NODE_ID; + + var Node = require('src/file').Node; + var DirectoryEntry = require('src/file').DirectoryEntry; + + var normalize = require('src/path').normalize; + var dirname = require('src/path').dirname; + var basename = require('src/path').basename; + // Note: this should only be invoked when formatting a new file system function make_root_directory(objectStore, callback) { var directoryNode; @@ -6058,11 +6160,10 @@ define('src/directory',['require','src/object-store','src/object-store','src/obj make_directory: make_directory, make_root_directory: make_root_directory, remove_directory: remove_directory, - find_node: find_node, }; }); -define('src/file-system',['require','lodash','when','src/shared','src/shared','src/shared','src/error','src/error','src/error','src/error','src/error','src/error','src/error','src/error','src/error','src/error','src/constants','src/constants','src/constants','src/constants','src/constants','src/constants','src/constants','src/directory','src/directory','src/directory'],function(require) { +define('src/file-system',['require','lodash','when','src/shared','src/shared','src/shared','src/error','src/error','src/error','src/error','src/error','src/error','src/error','src/error','src/error','src/error','src/constants','src/constants','src/constants','src/constants','src/constants','src/constants','src/constants','src/directory','src/directory','src/directory','src/file'],function(require) { var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; @@ -6097,6 +6198,8 @@ define('src/file-system',['require','lodash','when','src/shared','src/shared','s var make_directory = require('src/directory').make_directory; var remove_directory = require('src/directory').remove_directory; + var open_file = require('src/file').open_file; + /* * FileSystem */ @@ -6162,7 +6265,22 @@ define('src/file-system',['require','lodash','when','src/shared','src/shared','s this.db = null; }; FileSystem.prototype.open = function open(path, flags, mode) { + var deferred = when.defer(); + var transaction = this.db.transaction([FILE_STORE_NAME], IDB_RW); + var files = transaction.objectStore(FILE_STORE_NAME); + function check_result(error, fd) { + if(error) { + if(transaction.error) transaction.abort(); + deferred.reject(error); + } else { + deferred.resolve(); + } + }; + + open_file(files, path, flags, mode, check_result); + + return deferred.promise; }; FileSystem.prototype.opendir = function opendir(path) { @@ -6174,7 +6292,7 @@ define('src/file-system',['require','lodash','when','src/shared','src/shared','s function check_result(error) { if(error) { - transaction.abort(); + if(transaction.error) transaction.abort(); deferred.reject(error); } else { deferred.resolve(); @@ -6191,7 +6309,7 @@ define('src/file-system',['require','lodash','when','src/shared','src/shared','s function check_result(error) { if(error) { - transaction.abort(); + if(transaction.error) transaction.abort(); deferred.reject(error); } else { deferred.resolve(); @@ -6222,7 +6340,7 @@ define('src/file-system',['require','lodash','when','src/shared','src/shared','s }; }); - var IDBFS = require( "src/fs" ); + var IDBFS = require( "src/file-system" ); return IDBFS; diff --git a/examples/Linq2IndexedDB.js b/examples/Linq2IndexedDB.js index cfe4670..8df082c 100644 --- a/examples/Linq2IndexedDB.js +++ b/examples/Linq2IndexedDB.js @@ -93,11 +93,11 @@ var enableLogging = false; if (enableDebugging) { returnObject.viewer = viewer(dbConfig); linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.warning, "Debugging enabled: be carefull when using in production enviroment. Complex objects get written to the log and may cause memory leaks.") - + } else { returnObject.viewer = null; } - + return returnObject; }; @@ -507,7 +507,7 @@ var enableLogging = false; }); }); } - + function executeWhere(queryBuilder, pw, transaction) { linq2indexedDB.prototype.core.objectStore(transaction, queryBuilder.from).then(function (objArgs) { try { @@ -1187,7 +1187,7 @@ var enableLogging = false; for (var i = 1; i < arguments.length; i++) { args.push(arguments[i]); } - + switch (severity) { case linq2indexedDB.prototype.utilities.severity.exception: if (window.console.exception) { @@ -1333,7 +1333,7 @@ var enableLogging = false; })(typeof Windows !== "undefined"); if (typeof window !== "undefined") { - // UI Thread + // UI Thread // Namespace linq2indexedDB.prototype.core (function (window, isMetroApp) { @@ -1568,16 +1568,16 @@ if (typeof window !== "undefined") { function (args /*error, e*/) { // Database connection error or abort var err = internal.wrapError(args[1], "db"); - + // Fix for firefox & chrome if (args[1].target && args[1].target.errorCode == 12) { err.type = "VersionError"; } - + if (err.type == "VersionError") { err.message = "You are trying to open the database in a lower version (" + version + ") than the current version of the database"; } - + // Fix for firefox & chrome if (args[1].target && args[1].target.errorCode == 8) { err.type = "AbortError"; @@ -1618,7 +1618,7 @@ if (typeof window !== "undefined") { transactionType = transactionType || linq2indexedDB.prototype.core.transactionTypes.READ_ONLY; var nonExistingObjectStores = []; - + try { // Check for non-existing object stores for (var i = 0; i < objectStoreNames.length; i++) { @@ -1694,7 +1694,7 @@ if (typeof window !== "undefined") { err.severity = "abort"; err.message = "Transaction was aborted"; } - + // Fix for firefox & chrome if (args[1].target && args[1].target.errorCode == 4) { err.type = "ConstraintError"; @@ -1702,7 +1702,7 @@ if (typeof window !== "undefined") { if (err.type == "ConstraintError") { err.message = "A mutation operation in the transaction failed. For more details look at the error on the instert, update, remove or clear statement."; - } + } // txn error or abort linq2indexedDB.prototype.utilities.logError(err); pw.error(this, err); @@ -1982,7 +1982,7 @@ if (typeof window !== "undefined") { if (propertyName.indexOf(linq2indexedDB.prototype.core.indexSuffix) == -1) { indexName = indexName + linq2indexedDB.prototype.core.indexSuffix; } - + try { objectStore.deleteIndex(indexName); linq2indexedDB.prototype.core.dbStructureChanged.fire({ type: dbEvents.indexRemoved, data: indexName }); @@ -2011,9 +2011,9 @@ if (typeof window !== "undefined") { var keyRange; var returnData = []; var request; - + try { - + keyRange = range; if (!keyRange) { @@ -2166,7 +2166,7 @@ if (typeof window !== "undefined") { error.type = "TransactionInactiveError"; error.message = "You are trying to retrieve data on an inactieve transaction. (The transaction was already aborted or committed)"; } - + if (ex.name == "TypeError") { error.type = "TypeError"; error.message = "The provided directory parameter is invalid"; @@ -2391,7 +2391,7 @@ if (typeof window !== "undefined") { try { var req; - + if (key) { req = source.count(key); } @@ -2500,7 +2500,7 @@ if (typeof window !== "undefined") { if (args[1].target && args[1].target.errorCode == 4) { err.type = "ConstraintError"; } - + if (err.type == "ConstraintError") { var duplicateKey = key; if (!duplicateKey && objectStore.keyPath) { @@ -2532,22 +2532,22 @@ if (typeof window !== "undefined") { error.message = "The provided key isn't a valid key (must be an array, string, date or number)."; } } - + if ((ex.READ_ONLY_ERR && ex.code == ex.READ_ONLY_ERR) || ex.name == "ReadOnlyError") { error.type = "ReadOnlyError"; error.message = "You are trying to insert data in a readonly transaction."; } - + if (ex.name == "TransactionInactiveError") { error.type = "TransactionInactiveError"; error.message = "You are trying to insert data on an inactieve transaction. (The transaction was already aborted or committed)"; } - + if ((ex.DATA_CLONE_ERR && ex.code == ex.DATA_CLONE_ERR) || ex.name == "DataCloneError") { error.type = "DataCloneError"; error.message = "The data you are trying to insert could not be cloned. Your data probably contains a function which can not be cloned by default. Try using the serialize method to insert the data."; } - + if ((ex.INVALID_STATE_ERR && ex.code == ex.INVALID_STATE_ERR) || (ex.NOT_ALLOWED_ERR && ex.code == ex.NOT_ALLOWED_ERR) || ex.name == "InvalidStateError") { error.type = "InvalidStateError"; error.message = "You are trying to insert data on a removed object store."; @@ -2610,12 +2610,12 @@ if (typeof window !== "undefined") { error.type = "ReadOnlyError"; error.message = "You are trying to update data in a readonly transaction."; } - + if (ex.name == "TransactionInactiveError") { error.type = "TransactionInactiveError"; error.message = "You are trying to update data on an inactieve transaction. (The transaction was already aborted or committed)"; } - + if ((ex.DATA_CLONE_ERR && ex.code == ex.DATA_CLONE_ERR) || ex.name == "DataCloneError") { error.type = "DataCloneError"; error.message = "The data you are trying to update could not be cloned. Your data probably contains a function which can not be cloned by default. Try using the serialize method to update the data."; @@ -2625,7 +2625,7 @@ if (typeof window !== "undefined") { error.type = "InvalidStateError"; error.message = "You are trying to update data on a removed object store."; } - + linq2indexedDB.prototype.utilities.logError(error); linq2indexedDB.prototype.core.abortTransaction(objectStore.transaction); pw.error(this, error); @@ -3080,7 +3080,7 @@ if (typeof window !== "undefined") { db = target.transaction.db; } else if (target instanceof IDBIndex) { db = target.objectStore.transaction.db; - } + } linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Close database Connection: ", db); db.close(); @@ -3172,7 +3172,7 @@ if (typeof window !== "undefined") { linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "IE10+ Initialized", window.indexedDB); return implementations.MICROSOFT; } - + // Initialising the window.indexedDB Object for IE 8 & 9 else if (navigator.appName == 'Microsoft Internet Explorer') { try { @@ -3372,6 +3372,6 @@ if (typeof window !== "undefined") { } // Extend array for Opera -Array.prototype.contains = function (obj) { - return this.indexOf(obj) > -1; -}; \ No newline at end of file +//Array.prototype.contains = function (obj) { +// return this.indexOf(obj) > -1; +//}; \ No newline at end of file diff --git a/examples/refactoring-test.html b/examples/refactoring-test.html index 3f9c0c4..f4a5502 100644 --- a/examples/refactoring-test.html +++ b/examples/refactoring-test.html @@ -35,10 +35,14 @@ function remove_tmp_directory() { return fs.rmdir('/tmp'); }; +function create_tmp_file() { + return fs.open('/tmp/1', 'CREATE'); +}; + fs.promise.then(make_tmp_directory) - .then(remove_tmp_directory) + .then(create_tmp_file) .then(function() { console.log('done'); }) - .otherwise(function(error) { console.error(error.stack); }); + .otherwise(function(error) { console.error(error, error.stack); }); }); diff --git a/src/descriptor.js b/src/descriptor.js new file mode 100644 index 0000000..e4ee30b --- /dev/null +++ b/src/descriptor.js @@ -0,0 +1,10 @@ +define(function(require) { + + function Descriptor() { + }; + + return { + Descriptor: Descriptor, + }; + +}); \ No newline at end of file diff --git a/src/directory.js b/src/directory.js index b7aa039..164be9d 100644 --- a/src/directory.js +++ b/src/directory.js @@ -3,6 +3,7 @@ define(function(require) { var read_object = require('src/object-store').read_object; var write_object = require('src/object-store').write_object; var delete_object = require('src/object-store').delete_object; + var find_node = require('src/object-store').find_node; var ENoEntry = require('src/error').ENoEntry; var ENotDirectory = require('src/error').ENotDirectory; @@ -14,67 +15,12 @@ define(function(require) { var ROOT_NODE_ID = require('src/constants').ROOT_NODE_ID; var Node = require('src/file').Node; + var DirectoryEntry = require('src/file').DirectoryEntry; var normalize = require('src/path').normalize; var dirname = require('src/path').dirname; var basename = require('src/path').basename; - function DirectoryEntry(id, type) { - this.id = id; - this.type = type || MODE_FILE; - }; - - // in: file or directory path - // out: node structure, or error - function find_node(objectStore, path, callback) { - path = normalize(path); - var name = basename(path); - - if(ROOT_DIRECTORY_NAME == name) { - function check_root_directory_node(error, rootDirectoryNode) { - if(error) { - callback(error); - } else if(!rootDirectoryNode) { - callback(new ENoEntry()); - } else { - callback(undefined, rootDirectoryNode); - } - }; - - read_object(objectStore, ROOT_NODE_ID, check_root_directory_node); - } else { - // in: parent directory node - // out: parent directory data - function read_parent_directory_data(error, parentDirectoryNode) { - if(error) { - callback(error); - } else if(!_(parentDirectoryNode).has('data') || !parentDirectoryNode.type == MODE_DIRECTORY) { - callback(new ENotDirectory()); - } else { - read_object(objectStore, parentDirectoryNode.data, get_node_id_from_parent_directory_data); - } - }; - - // in: parent directory data - // out: searched node id - function get_node_id_from_parent_directory_data(error, parentDirectoryData) { - if(error) { - callback(error); - } else { - if(!_(parentDirectoryData).has(name)) { - callback(new ENoEntry()); - } else { - var nodeId = parentDirectoryData[name].id; - read_object(objectStore, nodeId, callback); - } - } - }; - - var parentPath = dirname(path); - find_node(objectStore, parentPath, read_parent_directory_data); - } - }; - // Note: this should only be invoked when formatting a new file system function make_root_directory(objectStore, callback) { var directoryNode; @@ -241,7 +187,6 @@ define(function(require) { make_directory: make_directory, make_root_directory: make_root_directory, remove_directory: remove_directory, - find_node: find_node, }; }); \ No newline at end of file diff --git a/src/file-system.js b/src/file-system.js index 1514f47..0c244c1 100644 --- a/src/file-system.js +++ b/src/file-system.js @@ -33,6 +33,8 @@ define(function(require) { var make_directory = require('src/directory').make_directory; var remove_directory = require('src/directory').remove_directory; + var open_file = require('src/file').open_file; + /* * FileSystem */ @@ -98,7 +100,22 @@ define(function(require) { this.db = null; }; FileSystem.prototype.open = function open(path, flags, mode) { + var deferred = when.defer(); + var transaction = this.db.transaction([FILE_STORE_NAME], IDB_RW); + var files = transaction.objectStore(FILE_STORE_NAME); + function check_result(error, fd) { + if(error) { + if(transaction.error) transaction.abort(); + deferred.reject(error); + } else { + deferred.resolve(); + } + }; + + open_file(files, path, flags, mode, check_result); + + return deferred.promise; }; FileSystem.prototype.opendir = function opendir(path) { @@ -110,7 +127,7 @@ define(function(require) { function check_result(error) { if(error) { - transaction.abort(); + if(transaction.error) transaction.abort(); deferred.reject(error); } else { deferred.resolve(); @@ -127,7 +144,7 @@ define(function(require) { function check_result(error) { if(error) { - transaction.abort(); + if(transaction.error) transaction.abort(); deferred.reject(error); } else { deferred.resolve(); diff --git a/src/file.js b/src/file.js index c6ee50c..803027c 100644 --- a/src/file.js +++ b/src/file.js @@ -1,10 +1,28 @@ define(function(require) { + var _ = require('lodash'); + + var normalize = require('src/path').normalize; + var dirname = require('src/path').dirname; + var basename = require('src/path').basename; + var MODE_FILE = require('src/constants').MODE_FILE; var guid = require('src/shared').guid; var hash = require('src/shared').hash; + var read_object = require('src/object-store').read_object; + var write_object = require('src/object-store').write_object; + var delete_object = require('src/object-store').delete_object; + var find_node = require('src/object-store').find_node; + + var O_CREATE = require('src/constants').O_CREATE; + + function DirectoryEntry(id, type) { + this.id = id; + this.type = type || MODE_FILE; + }; + function Node(id, mode, size, atime, ctime, mtime, flags, xattrs, links, version) { var now = Date.now(); @@ -14,15 +32,88 @@ define(function(require) { this.atime = atime || now; // access time this.ctime = ctime || now; // creation time this.mtime = mtime || now; // modified time - this.flags = flags || ''; // file flags + this.flags = flags || []; // file flags this.xattrs = xattrs || {}; // extended attributes this.links = links || 0; // links count this.version = version || 0; // node version - this.data = hash(id) // id for data object + this.data = hash(this.id) // id for data object + }; + + function open_file(objectStore, path, flags, mode, callback) { + path = normalize(path); + var name = basename(path); + + var directoryNode; + var directoryData; + var fileNode; + var fileData; + + 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)) { + // file exists + } else { + if(_(flags).contains(O_CREATE)) { + write_file_node(); + } else { + callback(error); + } + } + } + }; + + function write_file_node() { + fileNode = new Node(undefined, MODE_FILE); + fileNode.links += 1; + write_object(objectStore, fileNode, fileNode.id, write_file_data); + }; + + function write_file_data(error) { + if(error) { + callback(error); + } else { + fileData = {}; + write_object(objectStore, fileData, fileNode.data, update_directory_data); + } + }; + + function update_directory_data(error) { + if(error) { + callback(error); + } else { + directoryData[name] = new DirectoryEntry(fileNode.id, MODE_FILE); + write_object(objectStore, directoryData, directoryNode.data, create_file_descriptor); + } + }; + + function create_file_descriptor(error) { + if(error) { + console.log(error); + } else { + callback(undefined, '!'); + } + }; + + var parentPath = dirname(path); + find_node(objectStore, parentPath, read_directory_data); }; return { Node: Node, + open_file: open_file, + DirectoryEntry: DirectoryEntry, }; }); \ No newline at end of file diff --git a/src/object-store.js b/src/object-store.js index 5323e03..1022377 100644 --- a/src/object-store.js +++ b/src/object-store.js @@ -1,5 +1,69 @@ define(function(require) { + var ENoEntry = require('src/error').ENoEntry; + var ENotDirectory = require('src/error').ENotDirectory; + var EPathExists = require('src/error').EPathExists; + + var normalize = require('src/path').normalize; + var dirname = require('src/path').dirname; + var basename = require('src/path').basename; + + var ROOT_DIRECTORY_NAME = require('src/constants').ROOT_DIRECTORY_NAME; + var ROOT_NODE_ID = require('src/constants').ROOT_NODE_ID; + + var MODE_DIRECTORY = require('src/constants').MODE_DIRECTORY; + + // in: file or directory path + // out: node structure, or error + function find_node(objectStore, path, callback) { + path = normalize(path); + var name = basename(path); + + if(ROOT_DIRECTORY_NAME == name) { + function check_root_directory_node(error, rootDirectoryNode) { + if(error) { + callback(error); + } else if(!rootDirectoryNode) { + callback(new ENoEntry()); + } else { + callback(undefined, rootDirectoryNode); + } + }; + + read_object(objectStore, ROOT_NODE_ID, check_root_directory_node); + } else { + // in: parent directory node + // out: parent directory data + function read_parent_directory_data(error, parentDirectoryNode) { + if(error) { + callback(error); + } else if(!_(parentDirectoryNode).has('data') || !parentDirectoryNode.type == MODE_DIRECTORY) { + callback(new ENotDirectory()); + } else { + read_object(objectStore, parentDirectoryNode.data, get_node_id_from_parent_directory_data); + } + }; + + // in: parent directory data + // out: searched node id + function get_node_id_from_parent_directory_data(error, parentDirectoryData) { + if(error) { + callback(error); + } else { + if(!_(parentDirectoryData).has(name)) { + callback(new ENoEntry()); + } else { + var nodeId = parentDirectoryData[name].id; + read_object(objectStore, nodeId, callback); + } + } + }; + + var parentPath = dirname(path); + find_node(objectStore, parentPath, read_parent_directory_data); + } + }; + function read_object(objectStore, id, callback) { var getRequest = objectStore.get(id); getRequest.onsuccess = function onsuccess(event) { @@ -37,6 +101,7 @@ define(function(require) { read_object: read_object, write_object: write_object, delete_object: delete_object, + find_node: find_node }; }); \ No newline at end of file diff --git a/tests/index.html b/tests/index.html new file mode 100644 index 0000000..6bdc8bf --- /dev/null +++ b/tests/index.html @@ -0,0 +1,52 @@ + + + + Jasmine Spec Runner + + + + + + + + + + + + + + + + + + + + diff --git a/tests/spec/idbfs.spec.js b/tests/spec/idbfs.spec.js new file mode 100644 index 0000000..d72b472 --- /dev/null +++ b/tests/spec/idbfs.spec.js @@ -0,0 +1,15 @@ +var TEST_DATABASE_NAME = 'test'; + +describe("file system", function() { + beforeEach(function() { + this.fs = new IDBFS.FileSystem(TEST_DATABASE_NAME, 'FORMAT'); + }); + + afterEach(function() { + indexedDB.deleteDatabase(TEST_DATABASE_NAME); + }); + + it("is created", function() { + expect(typeof this.fs).toEqual('object'); + }); +}); \ No newline at end of file diff --git a/tools/jasmine-1.3.0/MIT.LICENSE b/tools/jasmine-1.3.1/MIT.LICENSE similarity index 100% rename from tools/jasmine-1.3.0/MIT.LICENSE rename to tools/jasmine-1.3.1/MIT.LICENSE diff --git a/tools/jasmine-1.3.0/jasmine-html.js b/tools/jasmine-1.3.1/jasmine-html.js similarity index 99% rename from tools/jasmine-1.3.0/jasmine-html.js rename to tools/jasmine-1.3.1/jasmine-html.js index 157f7e8..543d569 100644 --- a/tools/jasmine-1.3.0/jasmine-html.js +++ b/tools/jasmine-1.3.1/jasmine-html.js @@ -154,7 +154,7 @@ jasmine.HtmlReporter = function(_doc) { dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}), dom.alert = self.createDom('div', {className: 'alert'}, self.createDom('span', { className: 'exceptions' }, - self.createDom('label', { className: 'label', for: 'no_try_catch' }, 'No try/catch'), + self.createDom('label', { className: 'label', 'for': 'no_try_catch' }, 'No try/catch'), self.createDom('input', { id: 'no_try_catch', type: 'checkbox' }))), dom.results = self.createDom('div', {className: 'results'}, dom.summary = self.createDom('div', { className: 'summary' }), diff --git a/tools/jasmine-1.3.0/jasmine.css b/tools/jasmine-1.3.1/jasmine.css similarity index 100% rename from tools/jasmine-1.3.0/jasmine.css rename to tools/jasmine-1.3.1/jasmine.css diff --git a/tools/jasmine-1.3.0/jasmine.js b/tools/jasmine-1.3.1/jasmine.js similarity index 99% rename from tools/jasmine-1.3.0/jasmine.js rename to tools/jasmine-1.3.1/jasmine.js index 5964112..6b3459b 100644 --- a/tools/jasmine-1.3.0/jasmine.js +++ b/tools/jasmine-1.3.1/jasmine.js @@ -2595,6 +2595,6 @@ jasmine.WaitsForBlock.prototype.execute = function(onComplete) { jasmine.version_= { "major": 1, "minor": 3, - "build": 0, - "revision": 1354052693 + "build": 1, + "revision": 1354556913 };