diff --git a/examples/idbfs-test.html b/examples/idbfs-test.html index 19dd993..6141746 100644 --- a/examples/idbfs-test.html +++ b/examples/idbfs-test.html @@ -57,6 +57,28 @@ require(["src/fs"], function(IDBFS) { return console.error(error); } console.info("stat /tmp/0", result); + fs.link("/tmp/0", "/tmp/1", function(error) { + if(error) { + return console.error(error); + } + fs.stat("/tmp/1", function(error, result) { + if(error) { + return console.error(error); + } + console.info("stat /tmp/1", result); + fs.unlink("/tmp/0", function(error) { + if(error) { + return console.error(error); + } + fs.stat("/tmp/1", function(error, result) { + if(error) { + return console.error(error); + } + console.info("stat /tmp/1", result); + }); + }); + }); + }); }); }); }); diff --git a/src/error.js b/src/error.js index 330cf2e..29fec28 100644 --- a/src/error.js +++ b/src/error.js @@ -59,7 +59,10 @@ define(function(require) { ENotMounted.prototype.name = "ENotMounted"; ENotMounted.prototype.constructor = ENotMounted; - + function EFileExists(){ Error.apply(this, arguments); } + EFileExists.prototype = new Error(); + EFileExists.prototype.name = "EFileExists"; + EFileExists.prototype.constructor = EFileExists; return { EPathExists: EPathExists, @@ -70,7 +73,8 @@ define(function(require) { ENotDirectory: ENotDirectory, EBadFileDescriptor: EBadFileDescriptor, ENotImplemented: ENotImplemented, - ENotMounted: ENotMounted + ENotMounted: ENotMounted, + EFileExists: EFileExists }; }); \ No newline at end of file diff --git a/src/fs.js b/src/fs.js index 0c31831..d86b38f 100644 --- a/src/fs.js +++ b/src/fs.js @@ -166,6 +166,7 @@ define(function(require) { if(_(flags).contains(OF_CREATE)) { entry = new FileEntry(fullpath); file = new File(); + ++ file.links; var createFileRequest = files.put(file, entry.file); createFileRequest.onsuccess = function(e) { var createEntryRequest = metadata.put(entry, entry.name); @@ -207,7 +208,7 @@ define(function(require) { var fs = this; fullpath = Path.normalize(fullpath); - var transaction = optTransaction || fs.Transaction([METADATA_STORE_NAME], IDB_RW); + var transaction = optTransaction || new fs.Transaction([METADATA_STORE_NAME], IDB_RW); var metadata = transaction.objectStore(METADATA_STORE_NAME); @@ -235,7 +236,7 @@ define(function(require) { var fs = this; fullpath = Path.normalize(fullpath); - var transaction = optTransaction || fs.Transaction([METADATA_STORE_NAME], IDB_RW); + var transaction = optTransaction || new fs.Transaction([METADATA_STORE_NAME], IDB_RW); var metadata = transaction.objectStore(METADATA_STORE_NAME); var parentIndex = metadata.index(PARENT_INDEX); @@ -274,7 +275,7 @@ define(function(require) { var fs = this; fullpath = Path.normalize(fullpath); - var transaction = optTransaction || fs.Transaction([METADATA_STORE_NAME, FILE_STORE_NAME], IDB_RO); + var transaction = optTransaction || new fs.Transaction([METADATA_STORE_NAME, FILE_STORE_NAME], IDB_RO); var metadata = transaction.objectStore(METADATA_STORE_NAME); var files = transaction.objectStore(FILE_STORE_NAME); @@ -306,16 +307,118 @@ define(function(require) { runCallback(callback, e); }; }; - FileSystem.prototype.link = function link(oldpath, newpath, callback) { + FileSystem.prototype.link = function link(oldpath, newpath, callback, optTransaction) { + var fs = this; + oldpath = Path.normalize(oldpath); + newpath = Path.normalize(newpath); + + var transaction = optTransaction || new fs.Transaction([METADATA_STORE_NAME, FILE_STORE_NAME], IDB_RW); + + var metadata = transaction.objectStore(METADATA_STORE_NAME); + var files = transaction.objectStore(FILE_STORE_NAME); + + var getOldEntryRequest = metadata.get(oldpath); + getOldEntryRequest.onsuccess = function(e) { + var oldentry = e.target.result; + if(!oldentry) { + runCallback(callback, new error.ENoEntry()); + } else { + var getNewEntryRequest = metadata.get(newpath); + getNewEntryRequest.onsuccess = function(e) { + var newentry = e.target.result; + if(newentry) { + runCallback(callback, new error.EPathExists()); + } else { + newentry = new FileEntry(newpath, oldentry.file); + var putNewEntryRequest = metadata.put(newentry, newentry.name); + putNewEntryRequest.onsuccess = function(e) { + var getFileRequest = files.get(newentry.file); + getFileRequest.onsuccess = function(e) { + var file = e.target.result; + ++ file.links; + var putFileRequest = files.put(file, newentry.file); + putFileRequest.onsuccess = function(e) { + runCallback(callback); + }; + putFileRequest.onerror = function(e) { + runCallback(callback, e); + }; + }; + getFileRequest.onerror = function(e) { + runCallback(callback, e); + }; + }; + putNewEntryRequest.onerror = function(e) { + runCallback(callback, e); + }; + } + }; + getNewEntryRequest.onerror = function(e) { + runCallback(callback, e); + }; + } + }; + getOldEntryRequest.onerror = function(e) { + runCallback(callback, e); + } + }; + FileSystem.prototype.unlink = function unlink(fullpath, callback, optTransaction) { + var fs = this; + fullpath = Path.normalize(fullpath); + + var transaction = optTransaction || new fs.Transaction([METADATA_STORE_NAME, FILE_STORE_NAME], IDB_RW); + + var metadata = transaction.objectStore(METADATA_STORE_NAME); + var files = transaction.objectStore(FILE_STORE_NAME); + + var getEntryRequest = metadata.get(fullpath); + getEntryRequest.onsuccess = function(e) { + var entry = e.target.result; + if(!entry) { + runCallback(callback, new error.ENoEntry()); + } else if(DIRECTORY_ENTRY_MIME_TYPE === entry.type) { + runCallback(callback, new error.EIsDirectory()); + } else { + var deleteEntryRequest = metadata.delete(entry.name); + deleteEntryRequest.onsuccess = function(e) { + var getFileRequest = files.get(entry.file); + getFileRequest.onsuccess = function(e) { + var file = e.target.result; + -- file.links; + if(0 === files.links) { + var deleteFileRequest = files.delete(entry.file); + deleteFileRequest.onsuccess = complete; + deleteFileRequest.onerror = function(e) { + runCallback(callback, e); + }; + } else { + var putFileRequest = files.put(file, entry.file); + putFileRequest.onsuccess = complete; + putFileRequest.onerror = function(e) { + runCallback(callback, e); + }; + } + function complete() { + runCallback(callback); + } + }; + getFileRequest.onerror = function(e) { + runCallback(callback, e); + }; + }; + deleteEntryRequest.onerror = function(e) { + runCallback(callback, e); + }; + } + }; + getEntryRequest.onerror = function(e) { + runCallback(callback, e); + }; + }; + FileSystem.prototype.setxattr = function setxattr(fullpath, name, value, callback, optTransaction) { }; - FileSystem.prototype.unlink = function unlink(fullpath, callback) { - - }; - FileSystem.prototype.setxattr = function setxattr(fullpath, name, value, callback) { - - }; - FileSystem.prototype.getxattr = function getxattr(fullpath, name, callback) { + FileSystem.prototype.getxattr = function getxattr(fullpath, name, callback, optTransaction) { }; @@ -349,10 +452,10 @@ define(function(require) { this._fs.stat(Path.normalize(this._cwd + "/" + path), callback); }; FileSystemContext.prototype.link = function link(oldpath, newpath, callback) { - + this._fs.link(Path.normalize(this._cwd + "/" + oldpath), Path.normalize(this._cwd + "/" + newpath), callback); }; FileSystemContext.prototype.unlink = function unlink(path, callback) { - + this._fs.unlink(Path.normalize(this._cwd + "/" + path), callback); }; FileSystemContext.prototype.setxattr = function setxattr(path, name, value, callback) {