You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by sg...@apache.org on 2016/01/26 14:19:29 UTC

[2/2] cordova-plugin-file git commit: CB-10419 cordova-plugin-file 4.0.0 error with browserify workflow

CB-10419 cordova-plugin-file 4.0.0 error with browserify workflow

github close #157


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/commit/79956e4c
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/tree/79956e4c
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/diff/79956e4c

Branch: refs/heads/master
Commit: 79956e4c3c8a90abe3bfa237ce59dd6d1e482311
Parents: 563dcaf
Author: sgrebnov <v-...@microsoft.com>
Authored: Tue Jan 26 13:11:01 2016 +0300
Committer: sgrebnov <v-...@microsoft.com>
Committed: Tue Jan 26 16:19:41 2016 +0300

----------------------------------------------------------------------
 plugin.xml                       |   10 +-
 src/browser/FileProxy.js         | 1533 +++++++++++++++++----------------
 www/browser/Preparing.js         |  286 +++---
 www/requestFileSystem.js         |  105 +--
 www/resolveLocalFileSystemURI.js |  127 +--
 5 files changed, 1034 insertions(+), 1027 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/79956e4c/plugin.xml
----------------------------------------------------------------------
diff --git a/plugin.xml b/plugin.xml
index 6820120..16d8112 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -102,6 +102,12 @@ xmlns:android="http://schemas.android.com/apk/res/android"
         <merges target="window" />
     </js-module>
 
+    <!-- Required for browserify: we always link module below as there is conditional reference
+    to this module from requestFileSystem and resolveLocalFileSystemURI modules. -->
+    <js-module src="www/browser/isChrome.js" name="isChrome">
+        <runs />
+    </js-module>
+
     <info>
 The Android Persistent storage location now defaults to "Internal". Please check this plugins README to see if you application needs any changes in its config.xml.
 
@@ -396,10 +402,6 @@ to config.xml in order for the application to find previously stored files.
     </platform>
 
     <platform name="browser">
-        <js-module src="www/browser/isChrome.js" name="isChrome">
-            <runs />
-        </js-module>
-
         <!-- File for Chrome -->
         <js-module src="www/browser/Preparing.js" name="Preparing">
             <runs />

http://git-wip-us.apache.org/repos/asf/cordova-plugin-file/blob/79956e4c/src/browser/FileProxy.js
----------------------------------------------------------------------
diff --git a/src/browser/FileProxy.js b/src/browser/FileProxy.js
index 0e0e0de..6d5938d 100644
--- a/src/browser/FileProxy.js
+++ b/src/browser/FileProxy.js
@@ -18,942 +18,943 @@
  * under the License.
  *
  */
+(function() {
+    /*global require, exports, module*/
+    /*global FILESYSTEM_PREFIX*/
+    /*global IDBKeyRange*/
+
+    /* Heavily based on https://github.com/ebidel/idb.filesystem.js */
+
+    // For chrome we don't need to implement proxy methods
+    // All functionality can be accessed natively.
+    if (require('./isChrome')()) {
+        var pathsPrefix = {
+            // Read-only directory where the application is installed.
+            applicationDirectory: location.origin + "/",
+            // Where to put app-specific data files.
+            dataDirectory: 'filesystem:file:///persistent/',
+            // Cached files that should survive app restarts.
+            // Apps should not rely on the OS to delete files in here.
+            cacheDirectory: 'filesystem:file:///temporary/',
+        };
 
-/*global require, exports, module*/
-/*global FILESYSTEM_PREFIX*/
-/*global IDBKeyRange*/
-
-/* Heavily based on https://github.com/ebidel/idb.filesystem.js */
-
-// For chrome we don't need to implement proxy methods
-// All functionality can be accessed natively.
-if (require('./isChrome')()) {
-    var pathsPrefix = {
-        // Read-only directory where the application is installed.
-        applicationDirectory: location.origin + "/",
-        // Where to put app-specific data files.
-        dataDirectory: 'filesystem:file:///persistent/',
-        // Cached files that should survive app restarts.
-        // Apps should not rely on the OS to delete files in here.
-        cacheDirectory: 'filesystem:file:///temporary/',
-    };
-
-    exports.requestAllPaths = function(successCallback) {
-        successCallback(pathsPrefix);
-    };
+        exports.requestAllPaths = function(successCallback) {
+            successCallback(pathsPrefix);
+        };
 
-    require("cordova/exec/proxy").add("File", module.exports);
-    return;
-}
-
-var LocalFileSystem = require('./LocalFileSystem'),
-    FileSystem = require('./FileSystem'),
-    FileEntry = require('./FileEntry'),
-    FileError = require('./FileError'),
-    DirectoryEntry = require('./DirectoryEntry'),
-    File = require('./File');
-
-(function(exports, global) {
-    var indexedDB = global.indexedDB || global.mozIndexedDB;
-    if (!indexedDB) {
-        throw "Firefox OS File plugin: indexedDB not supported";
+        require("cordova/exec/proxy").add("File", module.exports);
+        return;
     }
 
-    var fs_ = null;
-
-    var idb_ = {};
-    idb_.db = null;
-    var FILE_STORE_ = 'entries';
+    var LocalFileSystem = require('./LocalFileSystem'),
+        FileSystem = require('./FileSystem'),
+        FileEntry = require('./FileEntry'),
+        FileError = require('./FileError'),
+        DirectoryEntry = require('./DirectoryEntry'),
+        File = require('./File');
+
+    (function(exports, global) {
+        var indexedDB = global.indexedDB || global.mozIndexedDB;
+        if (!indexedDB) {
+            throw "Firefox OS File plugin: indexedDB not supported";
+        }
 
-    var DIR_SEPARATOR = '/';
+        var fs_ = null;
 
-    var pathsPrefix = {
-        // Read-only directory where the application is installed.
-        applicationDirectory: location.origin + "/",
-        // Where to put app-specific data files.
-        dataDirectory: 'file:///persistent/',
-        // Cached files that should survive app restarts.
-        // Apps should not rely on the OS to delete files in here.
-        cacheDirectory: 'file:///temporary/',
-    };
+        var idb_ = {};
+        idb_.db = null;
+        var FILE_STORE_ = 'entries';
 
-    var unicodeLastChar = 65535;
+        var DIR_SEPARATOR = '/';
 
-/*** Exported functionality ***/
+        var pathsPrefix = {
+            // Read-only directory where the application is installed.
+            applicationDirectory: location.origin + "/",
+            // Where to put app-specific data files.
+            dataDirectory: 'file:///persistent/',
+            // Cached files that should survive app restarts.
+            // Apps should not rely on the OS to delete files in here.
+            cacheDirectory: 'file:///temporary/',
+        };
 
-    exports.requestFileSystem = function(successCallback, errorCallback, args) {
-        var type = args[0];
-        // Size is ignored since IDB filesystem size depends
-        // on browser implementation and can't be set up by user
-        var size = args[1]; // jshint ignore: line
+        var unicodeLastChar = 65535;
 
-        if (type !== LocalFileSystem.TEMPORARY && type !== LocalFileSystem.PERSISTENT) {
-            errorCallback && errorCallback(FileError.INVALID_MODIFICATION_ERR);
-            return;
-        }
+    /*** Exported functionality ***/
 
-        var name = type === LocalFileSystem.TEMPORARY ? 'temporary' : 'persistent';
-        var storageName = (location.protocol + location.host).replace(/:/g, '_');
+        exports.requestFileSystem = function(successCallback, errorCallback, args) {
+            var type = args[0];
+            // Size is ignored since IDB filesystem size depends
+            // on browser implementation and can't be set up by user
+            var size = args[1]; // jshint ignore: line
 
-        var root = new DirectoryEntry('', DIR_SEPARATOR);
-        fs_ = new FileSystem(name, root);
+            if (type !== LocalFileSystem.TEMPORARY && type !== LocalFileSystem.PERSISTENT) {
+                errorCallback && errorCallback(FileError.INVALID_MODIFICATION_ERR);
+                return;
+            }
 
-        idb_.open(storageName, function() {
-            successCallback(fs_);
-        }, errorCallback);
-    };
+            var name = type === LocalFileSystem.TEMPORARY ? 'temporary' : 'persistent';
+            var storageName = (location.protocol + location.host).replace(/:/g, '_');
 
-    // Overridden by Android, BlackBerry 10 and iOS to populate fsMap
-    require('./fileSystems').getFs = function(name, callback) {
-        callback(new FileSystem(name, fs_.root));
-    };
+            var root = new DirectoryEntry('', DIR_SEPARATOR);
+            fs_ = new FileSystem(name, root);
 
-    // list a directory's contents (files and folders).
-    exports.readEntries = function(successCallback, errorCallback, args) {
-        var fullPath = args[0];
+            idb_.open(storageName, function() {
+                successCallback(fs_);
+            }, errorCallback);
+        };
 
-        if (typeof successCallback !== 'function') {
-            throw Error('Expected successCallback argument.');
-        }
+        // Overridden by Android, BlackBerry 10 and iOS to populate fsMap
+        require('./fileSystems').getFs = function(name, callback) {
+            callback(new FileSystem(name, fs_.root));
+        };
 
-        var path = resolveToFullPath_(fullPath);
+        // list a directory's contents (files and folders).
+        exports.readEntries = function(successCallback, errorCallback, args) {
+            var fullPath = args[0];
 
-        exports.getDirectory(function() {
-            idb_.getAllEntries(path.fullPath + DIR_SEPARATOR, path.storagePath, function(entries) {
-                successCallback(entries);
-            }, errorCallback);
-        }, function() {
-            if (errorCallback) {
-                errorCallback(FileError.NOT_FOUND_ERR);
+            if (typeof successCallback !== 'function') {
+                throw Error('Expected successCallback argument.');
             }
-        }, [path.storagePath, path.fullPath, {create: false}]);
-    };
-
-    exports.getFile = function(successCallback, errorCallback, args) {
-        var fullPath = args[0];
-        var path = args[1];
-        var options = args[2] || {};
 
-        // Create an absolute path if we were handed a relative one.
-        path = resolveToFullPath_(fullPath, path);
-
-        idb_.get(path.storagePath, function(fileEntry) {
-            if (options.create === true && options.exclusive === true && fileEntry) {
-                // If create and exclusive are both true, and the path already exists,
-                // getFile must fail.
+            var path = resolveToFullPath_(fullPath);
 
+            exports.getDirectory(function() {
+                idb_.getAllEntries(path.fullPath + DIR_SEPARATOR, path.storagePath, function(entries) {
+                    successCallback(entries);
+                }, errorCallback);
+            }, function() {
                 if (errorCallback) {
-                    errorCallback(FileError.PATH_EXISTS_ERR);
+                    errorCallback(FileError.NOT_FOUND_ERR);
                 }
-            } else if (options.create === true && !fileEntry) {
-                // If create is true, the path doesn't exist, and no other error occurs,
-                // getFile must create it as a zero-length file and return a corresponding
-                // FileEntry.
-                var newFileEntry = new FileEntry(path.fileName, path.fullPath, new FileSystem(path.fsName, fs_.root));
-
-                newFileEntry.file_ = new MyFile({
-                    size: 0,
-                    name: newFileEntry.name,
-                    lastModifiedDate: new Date(),
-                    storagePath: path.storagePath
-                });
+            }, [path.storagePath, path.fullPath, {create: false}]);
+        };
+
+        exports.getFile = function(successCallback, errorCallback, args) {
+            var fullPath = args[0];
+            var path = args[1];
+            var options = args[2] || {};
+
+            // Create an absolute path if we were handed a relative one.
+            path = resolveToFullPath_(fullPath, path);
+
+            idb_.get(path.storagePath, function(fileEntry) {
+                if (options.create === true && options.exclusive === true && fileEntry) {
+                    // If create and exclusive are both true, and the path already exists,
+                    // getFile must fail.
 
-                idb_.put(newFileEntry, path.storagePath, successCallback, errorCallback);
-            } else if (options.create === true && fileEntry) {
-                if (fileEntry.isFile) {
-                    // Overwrite file, delete then create new.
-                    idb_['delete'](path.storagePath, function() {
-                        var newFileEntry = new FileEntry(path.fileName, path.fullPath, new FileSystem(path.fsName, fs_.root));
-
-                        newFileEntry.file_ = new MyFile({
-                            size: 0,
-                            name: newFileEntry.name,
-                            lastModifiedDate: new Date(),
-                            storagePath: path.storagePath
-                        });
-
-                        idb_.put(newFileEntry, path.storagePath, successCallback, errorCallback);
-                    }, errorCallback);
-                } else {
                     if (errorCallback) {
-                        errorCallback(FileError.INVALID_MODIFICATION_ERR);
+                        errorCallback(FileError.PATH_EXISTS_ERR);
                     }
+                } else if (options.create === true && !fileEntry) {
+                    // If create is true, the path doesn't exist, and no other error occurs,
+                    // getFile must create it as a zero-length file and return a corresponding
+                    // FileEntry.
+                    var newFileEntry = new FileEntry(path.fileName, path.fullPath, new FileSystem(path.fsName, fs_.root));
+
+                    newFileEntry.file_ = new MyFile({
+                        size: 0,
+                        name: newFileEntry.name,
+                        lastModifiedDate: new Date(),
+                        storagePath: path.storagePath
+                    });
+
+                    idb_.put(newFileEntry, path.storagePath, successCallback, errorCallback);
+                } else if (options.create === true && fileEntry) {
+                    if (fileEntry.isFile) {
+                        // Overwrite file, delete then create new.
+                        idb_['delete'](path.storagePath, function() {
+                            var newFileEntry = new FileEntry(path.fileName, path.fullPath, new FileSystem(path.fsName, fs_.root));
+
+                            newFileEntry.file_ = new MyFile({
+                                size: 0,
+                                name: newFileEntry.name,
+                                lastModifiedDate: new Date(),
+                                storagePath: path.storagePath
+                            });
+
+                            idb_.put(newFileEntry, path.storagePath, successCallback, errorCallback);
+                        }, errorCallback);
+                    } else {
+                        if (errorCallback) {
+                            errorCallback(FileError.INVALID_MODIFICATION_ERR);
+                        }
+                    }
+                } else if ((!options.create || options.create === false) && !fileEntry) {
+                    // If create is not true and the path doesn't exist, getFile must fail.
+                    if (errorCallback) {
+                        errorCallback(FileError.NOT_FOUND_ERR);
+                    }
+                } else if ((!options.create || options.create === false) && fileEntry &&
+                    fileEntry.isDirectory) {
+                    // If create is not true and the path exists, but is a directory, getFile
+                    // must fail.
+                    if (errorCallback) {
+                        errorCallback(FileError.TYPE_MISMATCH_ERR);
+                    }
+                } else {
+                    // Otherwise, if no other error occurs, getFile must return a FileEntry
+                    // corresponding to path.
+
+                    successCallback(fileEntryFromIdbEntry(fileEntry));
                 }
-            } else if ((!options.create || options.create === false) && !fileEntry) {
-                // If create is not true and the path doesn't exist, getFile must fail.
-                if (errorCallback) {
-                    errorCallback(FileError.NOT_FOUND_ERR);
-                }
-            } else if ((!options.create || options.create === false) && fileEntry &&
-                fileEntry.isDirectory) {
-                // If create is not true and the path exists, but is a directory, getFile
-                // must fail.
-                if (errorCallback) {
-                    errorCallback(FileError.TYPE_MISMATCH_ERR);
-                }
-            } else {
-                // Otherwise, if no other error occurs, getFile must return a FileEntry
-                // corresponding to path.
+            }, errorCallback);
+        };
 
-                successCallback(fileEntryFromIdbEntry(fileEntry));
-            }
-        }, errorCallback);
-    };
-
-    exports.getFileMetadata = function(successCallback, errorCallback, args) {
-        var fullPath = args[0];
-
-        exports.getFile(function(fileEntry) {
-            successCallback(new File(fileEntry.file_.name, fileEntry.fullPath, '', fileEntry.file_.lastModifiedDate,
-                fileEntry.file_.size));
-        }, errorCallback, [fullPath, null]);
-    };
-
-    exports.getMetadata = function(successCallback, errorCallback, args) {
-        exports.getFile(function (fileEntry) {
-            successCallback(
-                {
-                    modificationTime: fileEntry.file_.lastModifiedDate,
-                    size: fileEntry.file_.lastModifiedDate
-                });
-        }, errorCallback, args);
-    };
-
-    exports.setMetadata = function(successCallback, errorCallback, args) {
-        var fullPath = args[0];
-        var metadataObject = args[1];
-
-        exports.getFile(function (fileEntry) {
-              fileEntry.file_.lastModifiedDate = metadataObject.modificationTime;
-              idb_.put(fileEntry, fileEntry.file_.storagePath, successCallback, errorCallback);
-        }, errorCallback, [fullPath, null]);
-    };
-
-    exports.write = function(successCallback, errorCallback, args) {
-        var fileName = args[0],
-            data = args[1],
-            position = args[2],
-            isBinary = args[3]; // jshint ignore: line
-
-        if (!data) {
-            errorCallback && errorCallback(FileError.INVALID_MODIFICATION_ERR);
-            return;
-        }
+        exports.getFileMetadata = function(successCallback, errorCallback, args) {
+            var fullPath = args[0];
 
-        if (typeof data === 'string' || data instanceof String) {
-            data = new Blob([data]);
-        }
+            exports.getFile(function(fileEntry) {
+                successCallback(new File(fileEntry.file_.name, fileEntry.fullPath, '', fileEntry.file_.lastModifiedDate,
+                    fileEntry.file_.size));
+            }, errorCallback, [fullPath, null]);
+        };
 
-        exports.getFile(function(fileEntry) {
-            var blob_ = fileEntry.file_.blob_;
+        exports.getMetadata = function(successCallback, errorCallback, args) {
+            exports.getFile(function (fileEntry) {
+                successCallback(
+                    {
+                        modificationTime: fileEntry.file_.lastModifiedDate,
+                        size: fileEntry.file_.lastModifiedDate
+                    });
+            }, errorCallback, args);
+        };
 
-            if (!blob_) {
-                blob_ = new Blob([data], {type: data.type});
-            } else {
-                // Calc the head and tail fragments
-                var head = blob_.slice(0, position);
-                var tail = blob_.slice(position + (data.size || data.byteLength));
-
-                // Calc the padding
-                var padding = position - head.size;
-                if (padding < 0) {
-                    padding = 0;
-                }
+        exports.setMetadata = function(successCallback, errorCallback, args) {
+            var fullPath = args[0];
+            var metadataObject = args[1];
+
+            exports.getFile(function (fileEntry) {
+                  fileEntry.file_.lastModifiedDate = metadataObject.modificationTime;
+                  idb_.put(fileEntry, fileEntry.file_.storagePath, successCallback, errorCallback);
+            }, errorCallback, [fullPath, null]);
+        };
 
-                // Do the "write". In fact, a full overwrite of the Blob.
-                blob_ = new Blob([head, new Uint8Array(padding), data, tail],
-                    {type: data.type});
+        exports.write = function(successCallback, errorCallback, args) {
+            var fileName = args[0],
+                data = args[1],
+                position = args[2],
+                isBinary = args[3]; // jshint ignore: line
+
+            if (!data) {
+                errorCallback && errorCallback(FileError.INVALID_MODIFICATION_ERR);
+                return;
             }
 
-            // Set the blob we're writing on this file entry so we can recall it later.
-            fileEntry.file_.blob_ = blob_;
-            fileEntry.file_.lastModifiedDate = new Date() || null;
-            fileEntry.file_.size = blob_.size;
-            fileEntry.file_.name = blob_.name;
-            fileEntry.file_.type = blob_.type;
+            if (typeof data === 'string' || data instanceof String) {
+                data = new Blob([data]);
+            }
 
-            idb_.put(fileEntry, fileEntry.file_.storagePath, function() {
-                successCallback(data.size || data.byteLength);
-            }, errorCallback);
-        }, errorCallback, [fileName, null]);
-    };
+            exports.getFile(function(fileEntry) {
+                var blob_ = fileEntry.file_.blob_;
 
-    exports.readAsText = function(successCallback, errorCallback, args) {
-        var fileName = args[0],
-            enc = args[1],
-            startPos = args[2],
-            endPos = args[3];
+                if (!blob_) {
+                    blob_ = new Blob([data], {type: data.type});
+                } else {
+                    // Calc the head and tail fragments
+                    var head = blob_.slice(0, position);
+                    var tail = blob_.slice(position + (data.size || data.byteLength));
+
+                    // Calc the padding
+                    var padding = position - head.size;
+                    if (padding < 0) {
+                        padding = 0;
+                    }
 
-        readAs('text', fileName, enc, startPos, endPos, successCallback, errorCallback);
-    };
+                    // Do the "write". In fact, a full overwrite of the Blob.
+                    blob_ = new Blob([head, new Uint8Array(padding), data, tail],
+                        {type: data.type});
+                }
 
-    exports.readAsDataURL = function(successCallback, errorCallback, args) {
-        var fileName = args[0],
-            startPos = args[1],
-            endPos = args[2];
+                // Set the blob we're writing on this file entry so we can recall it later.
+                fileEntry.file_.blob_ = blob_;
+                fileEntry.file_.lastModifiedDate = new Date() || null;
+                fileEntry.file_.size = blob_.size;
+                fileEntry.file_.name = blob_.name;
+                fileEntry.file_.type = blob_.type;
+
+                idb_.put(fileEntry, fileEntry.file_.storagePath, function() {
+                    successCallback(data.size || data.byteLength);
+                }, errorCallback);
+            }, errorCallback, [fileName, null]);
+        };
 
-        readAs('dataURL', fileName, null, startPos, endPos, successCallback, errorCallback);
-    };
+        exports.readAsText = function(successCallback, errorCallback, args) {
+            var fileName = args[0],
+                enc = args[1],
+                startPos = args[2],
+                endPos = args[3];
 
-    exports.readAsBinaryString = function(successCallback, errorCallback, args) {
-        var fileName = args[0],
-            startPos = args[1],
-            endPos = args[2];
+            readAs('text', fileName, enc, startPos, endPos, successCallback, errorCallback);
+        };
 
-        readAs('binaryString', fileName, null, startPos, endPos, successCallback, errorCallback);
-    };
+        exports.readAsDataURL = function(successCallback, errorCallback, args) {
+            var fileName = args[0],
+                startPos = args[1],
+                endPos = args[2];
 
-    exports.readAsArrayBuffer = function(successCallback, errorCallback, args) {
-        var fileName = args[0],
-            startPos = args[1],
-            endPos = args[2];
+            readAs('dataURL', fileName, null, startPos, endPos, successCallback, errorCallback);
+        };
 
-        readAs('arrayBuffer', fileName, null, startPos, endPos, successCallback, errorCallback);
-    };
+        exports.readAsBinaryString = function(successCallback, errorCallback, args) {
+            var fileName = args[0],
+                startPos = args[1],
+                endPos = args[2];
 
-    exports.removeRecursively = exports.remove = function(successCallback, errorCallback, args) {
-        if (typeof successCallback !== 'function') {
-            throw Error('Expected successCallback argument.');
-        }
+            readAs('binaryString', fileName, null, startPos, endPos, successCallback, errorCallback);
+        };
 
-        var fullPath = resolveToFullPath_(args[0]).storagePath;
-        if (fullPath === pathsPrefix.cacheDirectory || fullPath === pathsPrefix.dataDirectory) {
-            errorCallback(FileError.NO_MODIFICATION_ALLOWED_ERR);
-            return;
-        }
+        exports.readAsArrayBuffer = function(successCallback, errorCallback, args) {
+            var fileName = args[0],
+                startPos = args[1],
+                endPos = args[2];
 
-        function deleteEntry(isDirectory) {
-            // TODO: This doesn't protect against directories that have content in it.
-            // Should throw an error instead if the dirEntry is not empty.
-            idb_['delete'](fullPath, function() {
-                successCallback();
-            }, function() {
-                    if (errorCallback) { errorCallback(); }
-            }, isDirectory);
-        }
+            readAs('arrayBuffer', fileName, null, startPos, endPos, successCallback, errorCallback);
+        };
 
-        // We need to to understand what we are deleting:
-        exports.getDirectory(function(entry) {
-            deleteEntry(entry.isDirectory);
-        }, function(){
-            //DirectoryEntry was already deleted or entry is FileEntry
-            deleteEntry(false);
-        }, [fullPath, null, {create: false}]);
-    };
-
-    exports.getDirectory = function(successCallback, errorCallback, args) {
-        var fullPath = args[0];
-        var path = args[1];
-        var options = args[2];
-
-        // Create an absolute path if we were handed a relative one.
-        path = resolveToFullPath_(fullPath, path);
-
-        idb_.get(path.storagePath, function(folderEntry) {
-            if (!options) {
-                options = {};
+        exports.removeRecursively = exports.remove = function(successCallback, errorCallback, args) {
+            if (typeof successCallback !== 'function') {
+                throw Error('Expected successCallback argument.');
             }
 
-            if (options.create === true && options.exclusive === true && folderEntry) {
-                // If create and exclusive are both true, and the path already exists,
-                // getDirectory must fail.
-                if (errorCallback) {
-                    errorCallback(FileError.PATH_EXISTS_ERR);
-                }
-                // There is a strange bug in mobilespec + FF, which results in coming to multiple else-if's
-                // so we are shielding from it with returns.
+            var fullPath = resolveToFullPath_(args[0]).storagePath;
+            if (fullPath === pathsPrefix.cacheDirectory || fullPath === pathsPrefix.dataDirectory) {
+                errorCallback(FileError.NO_MODIFICATION_ALLOWED_ERR);
                 return;
             }
 
-            if (options.create === true && !folderEntry) {
-                // If create is true, the path doesn't exist, and no other error occurs,
-                // getDirectory must create it as a zero-length file and return a corresponding
-                // MyDirectoryEntry.
-                var dirEntry = new DirectoryEntry(path.fileName, path.fullPath, new FileSystem(path.fsName, fs_.root));
-
-                idb_.put(dirEntry, path.storagePath, successCallback, errorCallback);
-                return;
+            function deleteEntry(isDirectory) {
+                // TODO: This doesn't protect against directories that have content in it.
+                // Should throw an error instead if the dirEntry is not empty.
+                idb_['delete'](fullPath, function() {
+                    successCallback();
+                }, function() {
+                        if (errorCallback) { errorCallback(); }
+                }, isDirectory);
             }
 
-            if (options.create === true && folderEntry) {
+            // We need to to understand what we are deleting:
+            exports.getDirectory(function(entry) {
+                deleteEntry(entry.isDirectory);
+            }, function(){
+                //DirectoryEntry was already deleted or entry is FileEntry
+                deleteEntry(false);
+            }, [fullPath, null, {create: false}]);
+        };
 
-                if (folderEntry.isDirectory) {
-                    // IDB won't save methods, so we need re-create the MyDirectoryEntry.
-                    successCallback(new DirectoryEntry(folderEntry.name, folderEntry.fullPath, folderEntry.filesystem));
-                } else {
+        exports.getDirectory = function(successCallback, errorCallback, args) {
+            var fullPath = args[0];
+            var path = args[1];
+            var options = args[2];
+
+            // Create an absolute path if we were handed a relative one.
+            path = resolveToFullPath_(fullPath, path);
+
+            idb_.get(path.storagePath, function(folderEntry) {
+                if (!options) {
+                    options = {};
+                }
+
+                if (options.create === true && options.exclusive === true && folderEntry) {
+                    // If create and exclusive are both true, and the path already exists,
+                    // getDirectory must fail.
                     if (errorCallback) {
-                        errorCallback(FileError.INVALID_MODIFICATION_ERR);
+                        errorCallback(FileError.PATH_EXISTS_ERR);
                     }
+                    // There is a strange bug in mobilespec + FF, which results in coming to multiple else-if's
+                    // so we are shielding from it with returns.
+                    return;
                 }
-                return;
-            }
 
-            if ((!options.create || options.create === false) && !folderEntry) {
-                // Handle root special. It should always exist.
-                if (path.fullPath === DIR_SEPARATOR) {
-                    successCallback(fs_.root);
+                if (options.create === true && !folderEntry) {
+                    // If create is true, the path doesn't exist, and no other error occurs,
+                    // getDirectory must create it as a zero-length file and return a corresponding
+                    // MyDirectoryEntry.
+                    var dirEntry = new DirectoryEntry(path.fileName, path.fullPath, new FileSystem(path.fsName, fs_.root));
+
+                    idb_.put(dirEntry, path.storagePath, successCallback, errorCallback);
                     return;
                 }
 
-                // If create is not true and the path doesn't exist, getDirectory must fail.
-                if (errorCallback) {
-                    errorCallback(FileError.NOT_FOUND_ERR);
-                }
+                if (options.create === true && folderEntry) {
 
-                return;
-            }
-            if ((!options.create || options.create === false) && folderEntry && folderEntry.isFile) {
-                // If create is not true and the path exists, but is a file, getDirectory
-                // must fail.
-                if (errorCallback) {
-                    errorCallback(FileError.TYPE_MISMATCH_ERR);
+                    if (folderEntry.isDirectory) {
+                        // IDB won't save methods, so we need re-create the MyDirectoryEntry.
+                        successCallback(new DirectoryEntry(folderEntry.name, folderEntry.fullPath, folderEntry.filesystem));
+                    } else {
+                        if (errorCallback) {
+                            errorCallback(FileError.INVALID_MODIFICATION_ERR);
+                        }
+                    }
+                    return;
                 }
-                return;
-            }
 
-            // Otherwise, if no other error occurs, getDirectory must return a
-            // MyDirectoryEntry corresponding to path.
+                if ((!options.create || options.create === false) && !folderEntry) {
+                    // Handle root special. It should always exist.
+                    if (path.fullPath === DIR_SEPARATOR) {
+                        successCallback(fs_.root);
+                        return;
+                    }
 
-            // IDB won't' save methods, so we need re-create MyDirectoryEntry.
-            successCallback(new DirectoryEntry(folderEntry.name, folderEntry.fullPath, folderEntry.filesystem));
-        }, errorCallback);
-    };
+                    // If create is not true and the path doesn't exist, getDirectory must fail.
+                    if (errorCallback) {
+                        errorCallback(FileError.NOT_FOUND_ERR);
+                    }
 
-    exports.getParent = function(successCallback, errorCallback, args) {
-        if (typeof successCallback !== 'function') {
-            throw Error('Expected successCallback argument.');
-        }
+                    return;
+                }
+                if ((!options.create || options.create === false) && folderEntry && folderEntry.isFile) {
+                    // If create is not true and the path exists, but is a file, getDirectory
+                    // must fail.
+                    if (errorCallback) {
+                        errorCallback(FileError.TYPE_MISMATCH_ERR);
+                    }
+                    return;
+                }
 
-        var fullPath = args[0];
-        //fullPath is like this:
-        //file:///persistent/path/to/file or
-        //file:///persistent/path/to/directory/
+                // Otherwise, if no other error occurs, getDirectory must return a
+                // MyDirectoryEntry corresponding to path.
 
-        if (fullPath === DIR_SEPARATOR || fullPath === pathsPrefix.cacheDirectory ||
-            fullPath === pathsPrefix.dataDirectory) {
-            successCallback(fs_.root);
-            return;
-        }
+                // IDB won't' save methods, so we need re-create MyDirectoryEntry.
+                successCallback(new DirectoryEntry(folderEntry.name, folderEntry.fullPath, folderEntry.filesystem));
+            }, errorCallback);
+        };
 
-        //To delete all slashes at the end
-        while (fullPath[fullPath.length - 1] === '/') {
-            fullPath = fullPath.substr(0, fullPath.length - 1);
-        }
+        exports.getParent = function(successCallback, errorCallback, args) {
+            if (typeof successCallback !== 'function') {
+                throw Error('Expected successCallback argument.');
+            }
 
-        var pathArr = fullPath.split(DIR_SEPARATOR);
-        pathArr.pop();
-        var parentName = pathArr.pop();
-        var path = pathArr.join(DIR_SEPARATOR) + DIR_SEPARATOR;
+            var fullPath = args[0];
+            //fullPath is like this:
+            //file:///persistent/path/to/file or
+            //file:///persistent/path/to/directory/
 
-        //To get parent of root files
-        var joined = path + parentName + DIR_SEPARATOR;//is like this: file:///persistent/
-        if (joined === pathsPrefix.cacheDirectory || joined === pathsPrefix.dataDirectory) {
-            exports.getDirectory(successCallback, errorCallback, [joined, DIR_SEPARATOR, {create: false}]);
-            return;
-        }
+            if (fullPath === DIR_SEPARATOR || fullPath === pathsPrefix.cacheDirectory ||
+                fullPath === pathsPrefix.dataDirectory) {
+                successCallback(fs_.root);
+                return;
+            }
 
-        exports.getDirectory(successCallback, errorCallback, [path, parentName, {create: false}]);
-    };
+            //To delete all slashes at the end
+            while (fullPath[fullPath.length - 1] === '/') {
+                fullPath = fullPath.substr(0, fullPath.length - 1);
+            }
 
-    exports.copyTo = function(successCallback, errorCallback, args) {
-        var srcPath = args[0];
-        var parentFullPath = args[1];
-        var name = args[2];
+            var pathArr = fullPath.split(DIR_SEPARATOR);
+            pathArr.pop();
+            var parentName = pathArr.pop();
+            var path = pathArr.join(DIR_SEPARATOR) + DIR_SEPARATOR;
 
-        if (name.indexOf('/') !== -1 || srcPath === parentFullPath + name) {
-            if (errorCallback) {
-                errorCallback(FileError.INVALID_MODIFICATION_ERR);
+            //To get parent of root files
+            var joined = path + parentName + DIR_SEPARATOR;//is like this: file:///persistent/
+            if (joined === pathsPrefix.cacheDirectory || joined === pathsPrefix.dataDirectory) {
+                exports.getDirectory(successCallback, errorCallback, [joined, DIR_SEPARATOR, {create: false}]);
+                return;
             }
 
-            return;
-        }
+            exports.getDirectory(successCallback, errorCallback, [path, parentName, {create: false}]);
+        };
 
-        // Read src file
-        exports.getFile(function(srcFileEntry) {
+        exports.copyTo = function(successCallback, errorCallback, args) {
+            var srcPath = args[0];
+            var parentFullPath = args[1];
+            var name = args[2];
 
-            var path = resolveToFullPath_(parentFullPath);
-            //Check directory
-            exports.getDirectory(function() {
+            if (name.indexOf('/') !== -1 || srcPath === parentFullPath + name) {
+                if (errorCallback) {
+                    errorCallback(FileError.INVALID_MODIFICATION_ERR);
+                }
 
-                // Create dest file
-                exports.getFile(function(dstFileEntry) {
+                return;
+            }
 
-                    exports.write(function() {
-                        successCallback(dstFileEntry);
-                    }, errorCallback, [dstFileEntry.file_.storagePath, srcFileEntry.file_.blob_, 0]);
+            // Read src file
+            exports.getFile(function(srcFileEntry) {
 
-                }, errorCallback, [parentFullPath, name, {create: true}]);
+                var path = resolveToFullPath_(parentFullPath);
+                //Check directory
+                exports.getDirectory(function() {
 
-            }, function() { if (errorCallback) { errorCallback(FileError.NOT_FOUND_ERR); }},
-            [path.storagePath, null, {create:false}]);
+                    // Create dest file
+                    exports.getFile(function(dstFileEntry) {
 
-        }, errorCallback, [srcPath, null]);
-    };
+                        exports.write(function() {
+                            successCallback(dstFileEntry);
+                        }, errorCallback, [dstFileEntry.file_.storagePath, srcFileEntry.file_.blob_, 0]);
 
-    exports.moveTo = function(successCallback, errorCallback, args) {
-        var srcPath = args[0];
-        // parentFullPath and name parameters is ignored because
-        // args is being passed downstream to exports.copyTo method
-        var parentFullPath = args[1]; // jshint ignore: line
-        var name = args[2]; // jshint ignore: line
+                    }, errorCallback, [parentFullPath, name, {create: true}]);
 
-        exports.copyTo(function (fileEntry) {
+                }, function() { if (errorCallback) { errorCallback(FileError.NOT_FOUND_ERR); }},
+                [path.storagePath, null, {create:false}]);
 
-            exports.remove(function () {
-                successCallback(fileEntry);
-            }, errorCallback, [srcPath]);
+            }, errorCallback, [srcPath, null]);
+        };
 
-        }, errorCallback, args);
-    };
+        exports.moveTo = function(successCallback, errorCallback, args) {
+            var srcPath = args[0];
+            // parentFullPath and name parameters is ignored because
+            // args is being passed downstream to exports.copyTo method
+            var parentFullPath = args[1]; // jshint ignore: line
+            var name = args[2]; // jshint ignore: line
 
-    exports.resolveLocalFileSystemURI = function(successCallback, errorCallback, args) {
-        var path = args[0];
+            exports.copyTo(function (fileEntry) {
 
-        // Ignore parameters
-        if (path.indexOf('?') !== -1) {
-            path = String(path).split("?")[0];
-        }
+                exports.remove(function () {
+                    successCallback(fileEntry);
+                }, errorCallback, [srcPath]);
 
-        // support for encodeURI
-        if (/\%5/g.test(path) || /\%20/g.test(path)) {
-            path = decodeURI(path);
-        }
+            }, errorCallback, args);
+        };
 
-        if (path.trim()[0] === '/') {
-            errorCallback && errorCallback(FileError.ENCODING_ERR);
-            return;
-        }
+        exports.resolveLocalFileSystemURI = function(successCallback, errorCallback, args) {
+            var path = args[0];
 
-        //support for cdvfile
-        if (path.trim().substr(0,7) === "cdvfile") {
-            if (path.indexOf("cdvfile://localhost") === -1) {
-                errorCallback && errorCallback(FileError.ENCODING_ERR);
-                return;
+            // Ignore parameters
+            if (path.indexOf('?') !== -1) {
+                path = String(path).split("?")[0];
             }
 
-            var indexPersistent = path.indexOf("persistent");
-            var indexTemporary = path.indexOf("temporary");
+            // support for encodeURI
+            if (/\%5/g.test(path) || /\%20/g.test(path)) {
+                path = decodeURI(path);
+            }
 
-            //cdvfile://localhost/persistent/path/to/file
-            if (indexPersistent !== -1) {
-                path =  "file:///persistent" + path.substr(indexPersistent + 10);
-            } else if (indexTemporary !== -1) {
-                path = "file:///temporary" + path.substr(indexTemporary + 9);
-            } else {
+            if (path.trim()[0] === '/') {
                 errorCallback && errorCallback(FileError.ENCODING_ERR);
                 return;
             }
-        }
 
-        // to avoid path form of '///path/to/file'
-        function handlePathSlashes(path) {
-            var cutIndex  = 0;
-            for (var i = 0; i < path.length - 1; i++) {
-                if (path[i] === DIR_SEPARATOR && path[i + 1] === DIR_SEPARATOR) {
-                    cutIndex = i + 1;
-                } else break;
-            }
+            //support for cdvfile
+            if (path.trim().substr(0,7) === "cdvfile") {
+                if (path.indexOf("cdvfile://localhost") === -1) {
+                    errorCallback && errorCallback(FileError.ENCODING_ERR);
+                    return;
+                }
 
-            return path.substr(cutIndex);
-        }
+                var indexPersistent = path.indexOf("persistent");
+                var indexTemporary = path.indexOf("temporary");
 
-        // Handle localhost containing paths (see specs )
-        if (path.indexOf('file://localhost/') === 0) {
-            path = path.replace('file://localhost/', 'file:///');
-        }
+                //cdvfile://localhost/persistent/path/to/file
+                if (indexPersistent !== -1) {
+                    path =  "file:///persistent" + path.substr(indexPersistent + 10);
+                } else if (indexTemporary !== -1) {
+                    path = "file:///temporary" + path.substr(indexTemporary + 9);
+                } else {
+                    errorCallback && errorCallback(FileError.ENCODING_ERR);
+                    return;
+                }
+            }
 
-        if (path.indexOf(pathsPrefix.dataDirectory) === 0) {
-            path = path.substring(pathsPrefix.dataDirectory.length - 1);
-            path = handlePathSlashes(path);
-
-            exports.requestFileSystem(function() {
-                exports.getFile(successCallback, function() {
-                    exports.getDirectory(successCallback, errorCallback, [pathsPrefix.dataDirectory, path,
-                    {create: false}]);
-                }, [pathsPrefix.dataDirectory, path, {create: false}]);
-            }, errorCallback, [LocalFileSystem.PERSISTENT]);
-        } else if (path.indexOf(pathsPrefix.cacheDirectory) === 0) {
-            path = path.substring(pathsPrefix.cacheDirectory.length - 1);
-            path = handlePathSlashes(path);
-
-            exports.requestFileSystem(function() {
-                exports.getFile(successCallback, function() {
-                    exports.getDirectory(successCallback, errorCallback, [pathsPrefix.cacheDirectory, path,
-                    {create: false}]);
-                }, [pathsPrefix.cacheDirectory, path, {create: false}]);
-            }, errorCallback, [LocalFileSystem.TEMPORARY]);
-        } else if (path.indexOf(pathsPrefix.applicationDirectory) === 0) {
-            path = path.substring(pathsPrefix.applicationDirectory.length);
-            //TODO: need to cut out redundant slashes?
-
-            var xhr = new XMLHttpRequest();
-            xhr.open("GET", path, true);
-            xhr.onreadystatechange = function () {
-                if (xhr.status === 200 && xhr.readyState === 4) {
-                    exports.requestFileSystem(function(fs) {
-                        fs.name = location.hostname;
-
-                        //TODO: need to call exports.getFile(...) to handle errors correct
-                        fs.root.getFile(path, {create: true}, writeFile, errorCallback);
-                    }, errorCallback, [LocalFileSystem.PERSISTENT]);
+            // to avoid path form of '///path/to/file'
+            function handlePathSlashes(path) {
+                var cutIndex  = 0;
+                for (var i = 0; i < path.length - 1; i++) {
+                    if (path[i] === DIR_SEPARATOR && path[i + 1] === DIR_SEPARATOR) {
+                        cutIndex = i + 1;
+                    } else break;
                 }
-            };
 
-            xhr.onerror = function () {
-                errorCallback && errorCallback(FileError.NOT_READABLE_ERR);
-            };
+                return path.substr(cutIndex);
+            }
 
-            xhr.send();
-        } else {
-            errorCallback && errorCallback(FileError.NOT_FOUND_ERR);
-        }
+            // Handle localhost containing paths (see specs )
+            if (path.indexOf('file://localhost/') === 0) {
+                path = path.replace('file://localhost/', 'file:///');
+            }
 
-        function writeFile(entry) {
-            entry.createWriter(function (fileWriter) {
-                fileWriter.onwriteend = function (evt) {
-                    if (!evt.target.error) {
-                        entry.filesystemName = location.hostname;
-                        successCallback(entry);
+            if (path.indexOf(pathsPrefix.dataDirectory) === 0) {
+                path = path.substring(pathsPrefix.dataDirectory.length - 1);
+                path = handlePathSlashes(path);
+
+                exports.requestFileSystem(function() {
+                    exports.getFile(successCallback, function() {
+                        exports.getDirectory(successCallback, errorCallback, [pathsPrefix.dataDirectory, path,
+                        {create: false}]);
+                    }, [pathsPrefix.dataDirectory, path, {create: false}]);
+                }, errorCallback, [LocalFileSystem.PERSISTENT]);
+            } else if (path.indexOf(pathsPrefix.cacheDirectory) === 0) {
+                path = path.substring(pathsPrefix.cacheDirectory.length - 1);
+                path = handlePathSlashes(path);
+
+                exports.requestFileSystem(function() {
+                    exports.getFile(successCallback, function() {
+                        exports.getDirectory(successCallback, errorCallback, [pathsPrefix.cacheDirectory, path,
+                        {create: false}]);
+                    }, [pathsPrefix.cacheDirectory, path, {create: false}]);
+                }, errorCallback, [LocalFileSystem.TEMPORARY]);
+            } else if (path.indexOf(pathsPrefix.applicationDirectory) === 0) {
+                path = path.substring(pathsPrefix.applicationDirectory.length);
+                //TODO: need to cut out redundant slashes?
+
+                var xhr = new XMLHttpRequest();
+                xhr.open("GET", path, true);
+                xhr.onreadystatechange = function () {
+                    if (xhr.status === 200 && xhr.readyState === 4) {
+                        exports.requestFileSystem(function(fs) {
+                            fs.name = location.hostname;
+
+                            //TODO: need to call exports.getFile(...) to handle errors correct
+                            fs.root.getFile(path, {create: true}, writeFile, errorCallback);
+                        }, errorCallback, [LocalFileSystem.PERSISTENT]);
                     }
                 };
-                fileWriter.onerror = function () {
+
+                xhr.onerror = function () {
                     errorCallback && errorCallback(FileError.NOT_READABLE_ERR);
                 };
-                fileWriter.write(new Blob([xhr.response]));
-            }, errorCallback);
-        }
-    };
-
-    exports.requestAllPaths = function(successCallback) {
-        successCallback(pathsPrefix);
-    };
-
-/*** Helpers ***/
-
-    /**
-     * Interface to wrap the native File interface.
-     *
-     * This interface is necessary for creating zero-length (empty) files,
-     * something the Filesystem API allows you to do. Unfortunately, File's
-     * constructor cannot be called directly, making it impossible to instantiate
-     * an empty File in JS.
-     *
-     * @param {Object} opts Initial values.
-     * @constructor
-     */
-    function MyFile(opts) {
-        var blob_ = new Blob();
-
-        this.size = opts.size || 0;
-        this.name = opts.name || '';
-        this.type = opts.type || '';
-        this.lastModifiedDate = opts.lastModifiedDate || null;
-        this.storagePath = opts.storagePath || '';
-
-        // Need some black magic to correct the object's size/name/type based on the
-        // blob that is saved.
-        Object.defineProperty(this, 'blob_', {
-            enumerable: true,
-            get: function() {
-                return blob_;
-            },
-            set: function(val) {
-                blob_ = val;
-                this.size = blob_.size;
-                this.name = blob_.name;
-                this.type = blob_.type;
-                this.lastModifiedDate = blob_.lastModifiedDate;
-            }.bind(this)
-        });
-    }
 
-    MyFile.prototype.constructor = MyFile;
+                xhr.send();
+            } else {
+                errorCallback && errorCallback(FileError.NOT_FOUND_ERR);
+            }
+
+            function writeFile(entry) {
+                entry.createWriter(function (fileWriter) {
+                    fileWriter.onwriteend = function (evt) {
+                        if (!evt.target.error) {
+                            entry.filesystemName = location.hostname;
+                            successCallback(entry);
+                        }
+                    };
+                    fileWriter.onerror = function () {
+                        errorCallback && errorCallback(FileError.NOT_READABLE_ERR);
+                    };
+                    fileWriter.write(new Blob([xhr.response]));
+                }, errorCallback);
+            }
+        };
 
-    // When saving an entry, the fullPath should always lead with a slash and never
-    // end with one (e.g. a directory). Also, resolve '.' and '..' to an absolute
-    // one. This method ensures path is legit!
-    function resolveToFullPath_(cwdFullPath, path) {
-        path = path || '';
-        var fullPath = path;
-        var prefix = '';
+        exports.requestAllPaths = function(successCallback) {
+            successCallback(pathsPrefix);
+        };
 
-        cwdFullPath = cwdFullPath || DIR_SEPARATOR;
-        if (cwdFullPath.indexOf(FILESYSTEM_PREFIX) === 0) {
-            prefix = cwdFullPath.substring(0, cwdFullPath.indexOf(DIR_SEPARATOR, FILESYSTEM_PREFIX.length));
-            cwdFullPath = cwdFullPath.substring(cwdFullPath.indexOf(DIR_SEPARATOR, FILESYSTEM_PREFIX.length));
+    /*** Helpers ***/
+
+        /**
+         * Interface to wrap the native File interface.
+         *
+         * This interface is necessary for creating zero-length (empty) files,
+         * something the Filesystem API allows you to do. Unfortunately, File's
+         * constructor cannot be called directly, making it impossible to instantiate
+         * an empty File in JS.
+         *
+         * @param {Object} opts Initial values.
+         * @constructor
+         */
+        function MyFile(opts) {
+            var blob_ = new Blob();
+
+            this.size = opts.size || 0;
+            this.name = opts.name || '';
+            this.type = opts.type || '';
+            this.lastModifiedDate = opts.lastModifiedDate || null;
+            this.storagePath = opts.storagePath || '';
+
+            // Need some black magic to correct the object's size/name/type based on the
+            // blob that is saved.
+            Object.defineProperty(this, 'blob_', {
+                enumerable: true,
+                get: function() {
+                    return blob_;
+                },
+                set: function(val) {
+                    blob_ = val;
+                    this.size = blob_.size;
+                    this.name = blob_.name;
+                    this.type = blob_.type;
+                    this.lastModifiedDate = blob_.lastModifiedDate;
+                }.bind(this)
+            });
         }
 
-        var relativePath = path[0] !== DIR_SEPARATOR;
-        if (relativePath) {
-            fullPath = cwdFullPath;
-            if (cwdFullPath !== DIR_SEPARATOR) {
-                fullPath += DIR_SEPARATOR + path;
-            } else {
-                fullPath += path;
+        MyFile.prototype.constructor = MyFile;
+
+        // When saving an entry, the fullPath should always lead with a slash and never
+        // end with one (e.g. a directory). Also, resolve '.' and '..' to an absolute
+        // one. This method ensures path is legit!
+        function resolveToFullPath_(cwdFullPath, path) {
+            path = path || '';
+            var fullPath = path;
+            var prefix = '';
+
+            cwdFullPath = cwdFullPath || DIR_SEPARATOR;
+            if (cwdFullPath.indexOf(FILESYSTEM_PREFIX) === 0) {
+                prefix = cwdFullPath.substring(0, cwdFullPath.indexOf(DIR_SEPARATOR, FILESYSTEM_PREFIX.length));
+                cwdFullPath = cwdFullPath.substring(cwdFullPath.indexOf(DIR_SEPARATOR, FILESYSTEM_PREFIX.length));
+            }
+
+            var relativePath = path[0] !== DIR_SEPARATOR;
+            if (relativePath) {
+                fullPath = cwdFullPath;
+                if (cwdFullPath !== DIR_SEPARATOR) {
+                    fullPath += DIR_SEPARATOR + path;
+                } else {
+                    fullPath += path;
+                }
             }
-        }
 
-        // Remove doubled separator substrings
-        var re = new RegExp(DIR_SEPARATOR + DIR_SEPARATOR, 'g');
-        fullPath = fullPath.replace(re, DIR_SEPARATOR);
-
-        // Adjust '..'s by removing parent directories when '..' flows in path.
-        var parts = fullPath.split(DIR_SEPARATOR);
-        for (var i = 0; i < parts.length; ++i) {
-            var part = parts[i];
-            if (part === '..') {
-                parts[i - 1] = '';
-                parts[i] = '';
+            // Remove doubled separator substrings
+            var re = new RegExp(DIR_SEPARATOR + DIR_SEPARATOR, 'g');
+            fullPath = fullPath.replace(re, DIR_SEPARATOR);
+
+            // Adjust '..'s by removing parent directories when '..' flows in path.
+            var parts = fullPath.split(DIR_SEPARATOR);
+            for (var i = 0; i < parts.length; ++i) {
+                var part = parts[i];
+                if (part === '..') {
+                    parts[i - 1] = '';
+                    parts[i] = '';
+                }
             }
-        }
-        fullPath = parts.filter(function(el) {
-            return el;
-        }).join(DIR_SEPARATOR);
+            fullPath = parts.filter(function(el) {
+                return el;
+            }).join(DIR_SEPARATOR);
 
-        // Add back in leading slash.
-        if (fullPath[0] !== DIR_SEPARATOR) {
-            fullPath = DIR_SEPARATOR + fullPath;
-        }
+            // Add back in leading slash.
+            if (fullPath[0] !== DIR_SEPARATOR) {
+                fullPath = DIR_SEPARATOR + fullPath;
+            }
 
-        // Replace './' by current dir. ('./one/./two' -> one/two)
-        fullPath = fullPath.replace(/\.\//g, DIR_SEPARATOR);
+            // Replace './' by current dir. ('./one/./two' -> one/two)
+            fullPath = fullPath.replace(/\.\//g, DIR_SEPARATOR);
 
-        // Replace '//' with '/'.
-        fullPath = fullPath.replace(/\/\//g, DIR_SEPARATOR);
+            // Replace '//' with '/'.
+            fullPath = fullPath.replace(/\/\//g, DIR_SEPARATOR);
 
-        // Replace '/.' with '/'.
-        fullPath = fullPath.replace(/\/\./g, DIR_SEPARATOR);
+            // Replace '/.' with '/'.
+            fullPath = fullPath.replace(/\/\./g, DIR_SEPARATOR);
 
-        // Remove '/' if it appears on the end.
-        if (fullPath[fullPath.length - 1] === DIR_SEPARATOR &&
-            fullPath !== DIR_SEPARATOR) {
-            fullPath = fullPath.substring(0, fullPath.length - 1);
-        }
+            // Remove '/' if it appears on the end.
+            if (fullPath[fullPath.length - 1] === DIR_SEPARATOR &&
+                fullPath !== DIR_SEPARATOR) {
+                fullPath = fullPath.substring(0, fullPath.length - 1);
+            }
 
-        var storagePath = prefix + fullPath;
-        storagePath = decodeURI(storagePath);
-        fullPath = decodeURI(fullPath);
+            var storagePath = prefix + fullPath;
+            storagePath = decodeURI(storagePath);
+            fullPath = decodeURI(fullPath);
 
-        return {
-            storagePath: storagePath,
-            fullPath: fullPath,
-            fileName: fullPath.split(DIR_SEPARATOR).pop(),
-            fsName: prefix.split(DIR_SEPARATOR).pop()
-        };
-    }
+            return {
+                storagePath: storagePath,
+                fullPath: fullPath,
+                fileName: fullPath.split(DIR_SEPARATOR).pop(),
+                fsName: prefix.split(DIR_SEPARATOR).pop()
+            };
+        }
 
-    function fileEntryFromIdbEntry(fileEntry) {
-        // IDB won't save methods, so we need re-create the FileEntry.
-        var clonedFileEntry = new FileEntry(fileEntry.name, fileEntry.fullPath, fileEntry.filesystem);
-        clonedFileEntry.file_ = fileEntry.file_;
+        function fileEntryFromIdbEntry(fileEntry) {
+            // IDB won't save methods, so we need re-create the FileEntry.
+            var clonedFileEntry = new FileEntry(fileEntry.name, fileEntry.fullPath, fileEntry.filesystem);
+            clonedFileEntry.file_ = fileEntry.file_;
 
-        return clonedFileEntry;
-    }
+            return clonedFileEntry;
+        }
 
-    function readAs(what, fullPath, encoding, startPos, endPos, successCallback, errorCallback) {
-        exports.getFile(function(fileEntry) {
-            var fileReader = new FileReader(),
-                blob = fileEntry.file_.blob_.slice(startPos, endPos);
+        function readAs(what, fullPath, encoding, startPos, endPos, successCallback, errorCallback) {
+            exports.getFile(function(fileEntry) {
+                var fileReader = new FileReader(),
+                    blob = fileEntry.file_.blob_.slice(startPos, endPos);
 
-            fileReader.onload = function(e) {
-                successCallback(e.target.result);
-            };
+                fileReader.onload = function(e) {
+                    successCallback(e.target.result);
+                };
 
-            fileReader.onerror = errorCallback;
+                fileReader.onerror = errorCallback;
+
+                switch (what) {
+                    case 'text':
+                        fileReader.readAsText(blob, encoding);
+                        break;
+                    case 'dataURL':
+                        fileReader.readAsDataURL(blob);
+                        break;
+                    case 'arrayBuffer':
+                        fileReader.readAsArrayBuffer(blob);
+                        break;
+                    case 'binaryString':
+                        fileReader.readAsBinaryString(blob);
+                        break;
+                }
 
-            switch (what) {
-                case 'text':
-                    fileReader.readAsText(blob, encoding);
-                    break;
-                case 'dataURL':
-                    fileReader.readAsDataURL(blob);
-                    break;
-                case 'arrayBuffer':
-                    fileReader.readAsArrayBuffer(blob);
-                    break;
-                case 'binaryString':
-                    fileReader.readAsBinaryString(blob);
-                    break;
-            }
+            }, errorCallback, [fullPath, null]);
+        }
 
-        }, errorCallback, [fullPath, null]);
-    }
+    /*** Core logic to handle IDB operations ***/
 
-/*** Core logic to handle IDB operations ***/
+        idb_.open = function(dbName, successCallback, errorCallback) {
+            var self = this;
 
-    idb_.open = function(dbName, successCallback, errorCallback) {
-        var self = this;
+            // TODO: FF 12.0a1 isn't liking a db name with : in it.
+            var request = indexedDB.open(dbName.replace(':', '_')/*, 1 /*version*/);
 
-        // TODO: FF 12.0a1 isn't liking a db name with : in it.
-        var request = indexedDB.open(dbName.replace(':', '_')/*, 1 /*version*/);
+            request.onerror = errorCallback || onError;
 
-        request.onerror = errorCallback || onError;
+            request.onupgradeneeded = function(e) {
+                // First open was called or higher db version was used.
 
-        request.onupgradeneeded = function(e) {
-            // First open was called or higher db version was used.
+                // console.log('onupgradeneeded: oldVersion:' + e.oldVersion,
+                //           'newVersion:' + e.newVersion);
 
-            // console.log('onupgradeneeded: oldVersion:' + e.oldVersion,
-            //           'newVersion:' + e.newVersion);
+                self.db = e.target.result;
+                self.db.onerror = onError;
 
-            self.db = e.target.result;
-            self.db.onerror = onError;
+                if (!self.db.objectStoreNames.contains(FILE_STORE_)) {
+                    self.db.createObjectStore(FILE_STORE_/*,{keyPath: 'id', autoIncrement: true}*/);
+                }
+            };
 
-            if (!self.db.objectStoreNames.contains(FILE_STORE_)) {
-                self.db.createObjectStore(FILE_STORE_/*,{keyPath: 'id', autoIncrement: true}*/);
-            }
-        };
+            request.onsuccess = function(e) {
+                self.db = e.target.result;
+                self.db.onerror = onError;
+                successCallback(e);
+            };
 
-        request.onsuccess = function(e) {
-            self.db = e.target.result;
-            self.db.onerror = onError;
-            successCallback(e);
+            request.onblocked = errorCallback || onError;
         };
 
-        request.onblocked = errorCallback || onError;
-    };
-
-    idb_.close = function() {
-        this.db.close();
-        this.db = null;
-    };
+        idb_.close = function() {
+            this.db.close();
+            this.db = null;
+        };
 
-    idb_.get = function(fullPath, successCallback, errorCallback) {
-        if (!this.db) {
-            errorCallback && errorCallback(FileError.INVALID_MODIFICATION_ERR);
-            return;
-        }
+        idb_.get = function(fullPath, successCallback, errorCallback) {
+            if (!this.db) {
+                errorCallback && errorCallback(FileError.INVALID_MODIFICATION_ERR);
+                return;
+            }
 
-        var tx = this.db.transaction([FILE_STORE_], 'readonly');
+            var tx = this.db.transaction([FILE_STORE_], 'readonly');
 
-        var request = tx.objectStore(FILE_STORE_).get(fullPath);
+            var request = tx.objectStore(FILE_STORE_).get(fullPath);
 
-        tx.onabort = errorCallback || onError;
-        tx.oncomplete = function() {
-            successCallback(request.result);
+            tx.onabort = errorCallback || onError;
+            tx.oncomplete = function() {
+                successCallback(request.result);
+            };
         };
-    };
 
-    idb_.getAllEntries = function(fullPath, storagePath, successCallback, errorCallback) {
-        if (!this.db) {
-            errorCallback && errorCallback(FileError.INVALID_MODIFICATION_ERR);
-            return;
-        }
+        idb_.getAllEntries = function(fullPath, storagePath, successCallback, errorCallback) {
+            if (!this.db) {
+                errorCallback && errorCallback(FileError.INVALID_MODIFICATION_ERR);
+                return;
+            }
 
-        var results = [];
+            var results = [];
 
-        if (storagePath[storagePath.length - 1] === DIR_SEPARATOR) {
-            storagePath = storagePath.substring(0, storagePath.length - 1);
-        }
+            if (storagePath[storagePath.length - 1] === DIR_SEPARATOR) {
+                storagePath = storagePath.substring(0, storagePath.length - 1);
+            }
 
-        var range = IDBKeyRange.bound(storagePath + DIR_SEPARATOR + ' ',
-            storagePath + DIR_SEPARATOR + String.fromCharCode(unicodeLastChar));
+            var range = IDBKeyRange.bound(storagePath + DIR_SEPARATOR + ' ',
+                storagePath + DIR_SEPARATOR + String.fromCharCode(unicodeLastChar));
 
-        var tx = this.db.transaction([FILE_STORE_], 'readonly');
-        tx.onabort = errorCallback || onError;
-        tx.oncomplete = function() {
-            results = results.filter(function(val) {
-                var pathWithoutSlash = val.fullPath;
+            var tx = this.db.transaction([FILE_STORE_], 'readonly');
+            tx.onabort = errorCallback || onError;
+            tx.oncomplete = function() {
+                results = results.filter(function(val) {
+                    var pathWithoutSlash = val.fullPath;
 
-                if (val.fullPath[val.fullPath.length - 1] === DIR_SEPARATOR) {
-                    pathWithoutSlash = pathWithoutSlash.substr(0, pathWithoutSlash.length - 1);
-                }
+                    if (val.fullPath[val.fullPath.length - 1] === DIR_SEPARATOR) {
+                        pathWithoutSlash = pathWithoutSlash.substr(0, pathWithoutSlash.length - 1);
+                    }
 
-                var valPartsLen = pathWithoutSlash.split(DIR_SEPARATOR).length;
-                var fullPathPartsLen = fullPath.split(DIR_SEPARATOR).length;
+                    var valPartsLen = pathWithoutSlash.split(DIR_SEPARATOR).length;
+                    var fullPathPartsLen = fullPath.split(DIR_SEPARATOR).length;
+
+                    /* Input fullPath parameter  equals '//' for root folder */
+                    /* Entries in root folder has valPartsLen equals 2 (see below) */
+                    if (fullPath[fullPath.length -1] === DIR_SEPARATOR && fullPath.trim().length === 2) {
+                        fullPathPartsLen = 1;
+                    } else if (fullPath[fullPath.length -1] === DIR_SEPARATOR) {
+                        fullPathPartsLen = fullPath.substr(0, fullPath.length - 1).split(DIR_SEPARATOR).length;
+                    } else {
+                        fullPathPartsLen = fullPath.split(DIR_SEPARATOR).length;
+                    }
 
-                /* Input fullPath parameter  equals '//' for root folder */
-                /* Entries in root folder has valPartsLen equals 2 (see below) */
-                if (fullPath[fullPath.length -1] === DIR_SEPARATOR && fullPath.trim().length === 2) {
-                    fullPathPartsLen = 1;
-                } else if (fullPath[fullPath.length -1] === DIR_SEPARATOR) {
-                    fullPathPartsLen = fullPath.substr(0, fullPath.length - 1).split(DIR_SEPARATOR).length;
-                } else {
-                    fullPathPartsLen = fullPath.split(DIR_SEPARATOR).length;
-                }
+                    if (valPartsLen === fullPathPartsLen + 1) {
+                        // If this a subfolder and entry is a direct child, include it in
+                        // the results. Otherwise, it's not an entry of this folder.
+                        return val;
+                    } else return false;
+                });
 
-                if (valPartsLen === fullPathPartsLen + 1) {
-                    // If this a subfolder and entry is a direct child, include it in
-                    // the results. Otherwise, it's not an entry of this folder.
-                    return val;
-                } else return false;
-            });
+                successCallback(results);
+            };
 
-            successCallback(results);
-        };
+            var request = tx.objectStore(FILE_STORE_).openCursor(range);
 
-        var request = tx.objectStore(FILE_STORE_).openCursor(range);
+            request.onsuccess = function(e) {
+                var cursor = e.target.result;
+                if (cursor) {
+                    var val = cursor.value;
 
-        request.onsuccess = function(e) {
-            var cursor = e.target.result;
-            if (cursor) {
-                var val = cursor.value;
+                    results.push(val.isFile ? fileEntryFromIdbEntry(val) : new DirectoryEntry(val.name, val.fullPath, val.filesystem));
+                    cursor['continue']();
+                }
+            };
+        };
 
-                results.push(val.isFile ? fileEntryFromIdbEntry(val) : new DirectoryEntry(val.name, val.fullPath, val.filesystem));
-                cursor['continue']();
+        idb_['delete'] = function(fullPath, successCallback, errorCallback, isDirectory) {
+            if (!idb_.db) {
+                errorCallback && errorCallback(FileError.INVALID_MODIFICATION_ERR);
+                return;
             }
-        };
-    };
 
-    idb_['delete'] = function(fullPath, successCallback, errorCallback, isDirectory) {
-        if (!idb_.db) {
-            errorCallback && errorCallback(FileError.INVALID_MODIFICATION_ERR);
-            return;
-        }
+            var tx = this.db.transaction([FILE_STORE_], 'readwrite');
+            tx.oncomplete = successCallback;
+            tx.onabort = errorCallback || onError;
+            tx.oncomplete = function() {
+                if (isDirectory) {
+                    //We delete nested files and folders after deleting parent folder
+                    //We use ranges: https://developer.mozilla.org/en-US/docs/Web/API/IDBKeyRange
+                    fullPath = fullPath + DIR_SEPARATOR;
+
+                    //Range contains all entries in the form fullPath<symbol> where
+                    //symbol in the range from ' ' to symbol which has code `unicodeLastChar`
+                    var range = IDBKeyRange.bound(fullPath + ' ', fullPath + String.fromCharCode(unicodeLastChar));
+
+                    var newTx = this.db.transaction([FILE_STORE_], 'readwrite');
+                    newTx.oncomplete = successCallback;
+                    newTx.onabort = errorCallback || onError;
+                    newTx.objectStore(FILE_STORE_)['delete'](range);
+                } else {
+                    successCallback();
+                }
+            };
+            tx.objectStore(FILE_STORE_)['delete'](fullPath);
+        };
 
-        var tx = this.db.transaction([FILE_STORE_], 'readwrite');
-        tx.oncomplete = successCallback;
-        tx.onabort = errorCallback || onError;
-        tx.oncomplete = function() {
-            if (isDirectory) {
-                //We delete nested files and folders after deleting parent folder
-                //We use ranges: https://developer.mozilla.org/en-US/docs/Web/API/IDBKeyRange
-                fullPath = fullPath + DIR_SEPARATOR;
-
-                //Range contains all entries in the form fullPath<symbol> where
-                //symbol in the range from ' ' to symbol which has code `unicodeLastChar`
-                var range = IDBKeyRange.bound(fullPath + ' ', fullPath + String.fromCharCode(unicodeLastChar));
-
-                var newTx = this.db.transaction([FILE_STORE_], 'readwrite');
-                newTx.oncomplete = successCallback;
-                newTx.onabort = errorCallback || onError;
-                newTx.objectStore(FILE_STORE_)['delete'](range);
-            } else {
-                successCallback();
+        idb_.put = function(entry, storagePath, successCallback, errorCallback) {
+            if (!this.db) {
+                errorCallback && errorCallback(FileError.INVALID_MODIFICATION_ERR);
+                return;
             }
-        };
-        tx.objectStore(FILE_STORE_)['delete'](fullPath);
-    };
 
-    idb_.put = function(entry, storagePath, successCallback, errorCallback) {
-        if (!this.db) {
-            errorCallback && errorCallback(FileError.INVALID_MODIFICATION_ERR);
-            return;
-        }
+            var tx = this.db.transaction([FILE_STORE_], 'readwrite');
+            tx.onabort = errorCallback || onError;
+            tx.oncomplete = function() {
+                // TODO: Error is thrown if we pass the request event back instead.
+                successCallback(entry);
+            };
 
-        var tx = this.db.transaction([FILE_STORE_], 'readwrite');
-        tx.onabort = errorCallback || onError;
-        tx.oncomplete = function() {
-            // TODO: Error is thrown if we pass the request event back instead.
-            successCallback(entry);
+            tx.objectStore(FILE_STORE_).put(entry, storagePath);
         };
 
-        tx.objectStore(FILE_STORE_).put(entry, storagePath);
-    };
-
-    // Global error handler. Errors bubble from request, to transaction, to db.
-    function onError(e) {
-        switch (e.target.errorCode) {
-            case 12:
-                console.log('Error - Attempt to open db with a lower version than the ' +
-                    'current one.');
-                break;
-            default:
-                console.log('errorCode: ' + e.target.errorCode);
-        }
+        // Global error handler. Errors bubble from request, to transaction, to db.
+        function onError(e) {
+            switch (e.target.errorCode) {
+                case 12:
+                    console.log('Error - Attempt to open db with a lower version than the ' +
+                        'current one.');
+                    break;
+                default:
+                    console.log('errorCode: ' + e.target.errorCode);
+            }
 
-        console.log(e, e.code, e.message);
-    }
+            console.log(e, e.code, e.message);
+        }
 
-})(module.exports, window);
+    })(module.exports, window);
 
-require("cordova/exec/proxy").add("File", module.exports);
+    require("cordova/exec/proxy").add("File", module.exports);
+})();


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org