| Index: lib/io.js | 
| =================================================================== | 
| --- a/lib/io.js | 
| +++ b/lib/io.js | 
| @@ -71,16 +71,55 @@ function callLegacy(method, ...args) | 
| function legacyFile(fileName) | 
| { | 
| let file = LegacyIO.resolveFilePath("adblockplus"); | 
| file.append(fileName); | 
| return file; | 
| } | 
| +let fallback = { | 
| + readFromFile(fileName, listener) | 
| + { | 
| + let wrapper = { | 
| + process(line) | 
| + { | 
| + if (line !== null) | 
| + listener(line); | 
| + } | 
| + }; | 
| + return callLegacy("readFromFile", legacyFile(fileName), wrapper); | 
| + }, | 
| + | 
| + writeToFile(fileName, data) | 
| + { | 
| + return callLegacy("writeToFile", legacyFile(fileName), data); | 
| + }, | 
| + | 
| + copyFile(fromFile, toFile) | 
| + { | 
| + return callLegacy("copyFile", legacyFile(fromFile), legacyFile(toFile)); | 
| + }, | 
| + | 
| + renameFile(fromFile, newName) | 
| + { | 
| + return callLegacy("renameFile", legacyFile(fromFile), newName); | 
| + }, | 
| + | 
| + removeFile(fileName) | 
| + { | 
| + return callLegacy("removeFile", legacyFile(fileName)); | 
| + }, | 
| + | 
| + statFile(fileName) | 
| + { | 
| + return callLegacy("statFile", legacyFile(fileName)); | 
| + } | 
| +}; | 
| + | 
| exports.IO = | 
| { | 
| /** | 
| * @callback TextSink | 
| * @param {string} line | 
| */ | 
| /** | 
| @@ -111,30 +150,16 @@ exports.IO = | 
| return; | 
| } | 
| } | 
| resolve(); | 
| } | 
| processBatch(); | 
| }); | 
| - }).catch(error => | 
| - { | 
| - if (error == "NoSuchFile") | 
| - { | 
| - let wrapper = { | 
| - process(line) | 
| - { | 
| - if (line !== null) | 
| - listener(line); | 
| - } | 
| - }; | 
| - return callLegacy("readFromFile", legacyFile(fileName), wrapper); | 
| - } | 
| - throw error; | 
| }); | 
| }, | 
| /** | 
| * Writes text lines to a file. | 
| * @param {string} fileName | 
| * Name of the file to be written | 
| * @param {Iterable.<string>} data | 
| @@ -154,58 +179,43 @@ exports.IO = | 
| * Name of the file to be copied | 
| * @param {string} toFile | 
| * Name of the file to be written, will be overwritten if exists | 
| * @return {Promise} | 
| * Promise to be resolved or rejected once the operation is completed | 
| */ | 
| copyFile(fromFile, toFile) | 
| { | 
| - return callWebExt("copyFile", fromFile, toFile).catch(error => | 
| - { | 
| - if (error == "NoSuchFile") | 
| - return callLegacy("copyFile", legacyFile(fromFile), legacyFile(toFile)); | 
| - throw error; | 
| - }); | 
| + return callWebExt("copyFile", fromFile, toFile); | 
| }, | 
| /** | 
| * Renames a file. | 
| * @param {string} fromFile | 
| * Name of the file to be renamed | 
| * @param {string} newName | 
| * New file name, will be overwritten if exists | 
| * @return {Promise} | 
| * Promise to be resolved or rejected once the operation is completed | 
| */ | 
| renameFile(fromFile, newName) | 
| { | 
| - return callWebExt("renameFile", fromFile, newName).catch(error => | 
| - { | 
| - if (error == "NoSuchFile") | 
| - return callLegacy("renameFile", legacyFile(fromFile), newName); | 
| - throw error; | 
| - }); | 
| + return callWebExt("renameFile", fromFile, newName); | 
| }, | 
| /** | 
| * Removes a file. | 
| * @param {string} fileName | 
| * Name of the file to be removed | 
| * @return {Promise} | 
| * Promise to be resolved or rejected once the operation is completed | 
| */ | 
| removeFile(fileName) | 
| { | 
| - return callWebExt("removeFile", fileName).catch(error => | 
| - { | 
| - if (error == "NoSuchFile") | 
| - return callLegacy("removeFile", legacyFile(fileName)); | 
| - throw error; | 
| - }); | 
| + return callWebExt("removeFile", fileName); | 
| }, | 
| /** | 
| * @typedef StatData | 
| * @type {object} | 
| * @property {boolean} exists | 
| * true if the file exists | 
| * @property {number} lastModified | 
| @@ -217,16 +227,42 @@ exports.IO = | 
| * @param {string} fileName | 
| * Name of the file to be looked up | 
| * @return {Promise.<StatData>} | 
| * Promise to be resolved with file metadata once the operation is | 
| * completed | 
| */ | 
| statFile(fileName) | 
| { | 
| - return callWebExt("statFile", fileName).catch(error => | 
| - { | 
| - if (error == "NoSuchFile") | 
| - return callLegacy("statFile", legacyFile(fileName)); | 
| - throw error; | 
| - }); | 
| + return callWebExt("statFile", fileName); | 
| } | 
| }; | 
| + | 
| +let {application} = require("info"); | 
| +if (application != "firefox" && application != "fennec2") | 
| +{ | 
| + // Currently, only Firefox has a working WebExtensions implementation, other | 
| + // applications should just use the fallback. | 
| + exports.IO = fallback; | 
| +} | 
| +else | 
| +{ | 
| + // Add fallbacks to IO methods - fall back to legacy I/O if file wasn't found. | 
| + for (let name of Object.getOwnPropertyNames(exports.IO)) | 
| + { | 
| + // No fallback for writeToFile method, new data should always be stored to | 
| + // new storage only. | 
| + if (name == "writeToFile") | 
| + continue; | 
| + | 
| + let method = exports.IO[name]; | 
| + let fallbackMethod = fallback[name]; | 
| + exports.IO[name] = (...args) => | 
| + { | 
| + return method(...args).catch(error => | 
| + { | 
| + if (error == "NoSuchFile") | 
| + return fallbackMethod(...args); | 
| + throw error; | 
| + }); | 
| + }; | 
| + } | 
| +} |