www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | Submodules | README | LICENSE

commit c6ab18634de37aa829f479c9fc98af3726c113fc
parent ffc32d992d3315feeef154b4066f425036cef818
Author: Dan Stillman <dstillman@zotero.org>
Date:   Mon, 31 Jul 2017 05:40:34 -0400

Improve data directory startup error handling

Better instructions and behavior if the data directory is inaccessible
or missing, including automatically detecting a directory at the default
location if the configured directory is missing and offering to use the
default instead. Together, this means that if, say, security software
prevents Zotero from accessing the data directory within the Firefox
profile, it will suggest that the user move it to ~/Zotero and then
prompt to use that directory.

Diffstat:
Mchrome/content/zotero/xpcom/zotero.js | 145+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Mchrome/locale/en-US/zotero/zotero.properties | 10+++++++---
2 files changed, 115 insertions(+), 40 deletions(-)

diff --git a/chrome/content/zotero/xpcom/zotero.js b/chrome/content/zotero/xpcom/zotero.js @@ -292,33 +292,82 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js"); catch (e) { // Zotero dir not found if (e.name == 'NS_ERROR_FILE_NOT_FOUND') { - Zotero.startupError = Zotero.getString('dataDir.notFound'); + let foundInDefault = false; + try { + foundInDefault = (yield OS.File.exists(Zotero.DataDirectory.defaultDir)) + && (yield OS.File.exists( + OS.Path.join( + Zotero.DataDirectory.defaultDir, + Zotero.DataDirectory.getDatabaseFilename() + ) + )); + } + catch (e) { + Zotero.logError(e); + } + + let previousDir = Zotero.Prefs.get('lastDataDir') || Zotero.Prefs.get('dataDir'); + Zotero.startupError = foundInDefault + ? Zotero.getString( + 'dataDir.notFound.defaultFound', + [ + Zotero.clientName, + previousDir, + Zotero.DataDirectory.defaultDir + ] + ) + : Zotero.getString('dataDir.notFound', Zotero.clientName); _startupErrorHandler = function() { var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]. createInstance(Components.interfaces.nsIPromptService); - var buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING) - + (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_IS_STRING) - + (ps.BUTTON_POS_2) * (ps.BUTTON_TITLE_IS_STRING); + var buttonFlags = ps.BUTTON_POS_0 * ps.BUTTON_TITLE_IS_STRING + + ps.BUTTON_POS_1 * ps.BUTTON_TITLE_IS_STRING + + ps.BUTTON_POS_2 * ps.BUTTON_TITLE_IS_STRING; // TEMP: lastDataDir can be removed once old persistent descriptors have been // converted, which they are in getZoteroDirectory() in 5.0 - var previousDir = Zotero.Prefs.get('lastDataDir') || Zotero.Prefs.get('dataDir'); - var index = ps.confirmEx(null, - Zotero.getString('general.error'), - Zotero.startupError + '\n\n' + - Zotero.getString('dataDir.previousDir') + ' ' + previousDir, - buttonFlags, - Zotero.getString('general.quit'), - Zotero.getString('dataDir.useDefaultLocation'), - Zotero.getString('general.locate'), - null, {}); - - // Revert to home directory - if (index == 1) { - Zotero.DataDirectory.choose(true, true); + if (foundInDefault) { + let index = ps.confirmEx(null, + Zotero.getString('general.error'), + Zotero.startupError, + buttonFlags, + Zotero.getString('dataDir.useNewLocation'), + Zotero.getString('general.quit'), + Zotero.getString('general.locate'), + null, {} + ); + // Revert to home directory + if (index == 0) { + Zotero.DataDirectory.set(Zotero.DataDirectory.defaultDir); + Zotero.Utilities.Internal.quit(true); + return; + } + // Locate data directory + else if (index == 2) { + Zotero.DataDirectory.choose(true); + } + } - // Locate data directory - else if (index == 2) { - Zotero.DataDirectory.choose(true); + else { + let index = ps.confirmEx(null, + Zotero.getString('general.error'), + Zotero.startupError + '\n\n' + + Zotero.getString('dataDir.previousDir') + ' ' + previousDir, + buttonFlags, + Zotero.getString('general.quit'), + Zotero.getString('dataDir.useDefaultLocation'), + Zotero.getString('general.locate'), + null, {} + ); + // Revert to home directory + if (index == 1) { + Zotero.DataDirectory.set(Zotero.DataDirectory.defaultDir); + Zotero.Utilities.Internal.quit(true); + return; + } + // Locate data directory + else if (index == 2) { + Zotero.DataDirectory.choose(true); + } } } return; @@ -351,13 +400,7 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js"); Zotero.IPC.init(); } catch (e) { - if (e.name == 'NS_ERROR_FILE_ACCESS_DENIED') { - var msg = Zotero.localeJoin([ - Zotero.getString('startupError.databaseCannotBeOpened'), - Zotero.getString('startupError.checkPermissions') - ]); - Zotero.startupError = msg; - Zotero.logError(e); + if (_checkDataDirAccessError(e)) { return false; } throw (e); @@ -847,20 +890,15 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js"); } } catch (e) { - if (e.name == 'NS_ERROR_FILE_ACCESS_DENIED') { - var msg = Zotero.localeJoin([ - Zotero.getString('startupError.databaseCannotBeOpened'), - Zotero.getString('startupError.checkPermissions') - ]); - Zotero.startupError = msg; - } + if (_checkDataDirAccessError(e)) {} // Storage busy - else if (e.message.endsWith('2153971713')) { + else if (e.message.includes('2153971713')) { Zotero.startupError = Zotero.getString('startupError.databaseInUse') + "\n\n" + Zotero.getString( "startupError.close" + (Zotero.isStandalone ? 'Firefox' : 'Standalone') ); - } else { + } + else { Zotero.startupError = Zotero.getString('startupError') + "\n\n" + (e.stack || e); } @@ -873,6 +911,39 @@ Services.scriptloader.loadSubScript("resource://zotero/polyfill.js"); return true; }); + + function _checkDataDirAccessError(e) { + if (e.name != 'NS_ERROR_FILE_ACCESS_DENIED' && !e.message.includes('2152857621')) { + return false; + } + + var msg = Zotero.getString('dataDir.databaseCannotBeOpened', Zotero.clientName) + + "\n\n" + + Zotero.getString('dataDir.checkPermissions', Zotero.clientName); + // If already using default directory, just show it + if (Zotero.DataDirectory.dir == Zotero.DataDirectory.defaultDir) { + msg += "\n\n" + Zotero.getString('dataDir.location', Zotero.DataDirectory.dir); + } + // Otherwise suggest moving to default, since there's a good chance this is due to security + // software preventing Zotero from accessing the selected directory (particularly if it's + // a Firefox profile) + else { + msg += "\n\n" + + Zotero.getString('dataDir.moveToDefaultLocation', Zotero.clientName) + + "\n\n" + + Zotero.getString( + 'dataDir.migration.failure.full.current', Zotero.DataDirectory.dir + ) + + "\n" + + Zotero.getString( + 'dataDir.migration.failure.full.recommended', Zotero.DataDirectory.defaultDir + ); + } + Zotero.startupError = msg; + return true; + } + + /** * Called when the DB has been released by another Zotero process to perform necessary * initialization steps diff --git a/chrome/locale/en-US/zotero/zotero.properties b/chrome/locale/en-US/zotero/zotero.properties @@ -119,7 +119,13 @@ attachmentBasePath.clearBasePath.existingAttachments.singular = One existing at attachmentBasePath.clearBasePath.existingAttachments.plural = %S existing attachments within the old base directory will be converted to use absolute paths. attachmentBasePath.clearBasePath.button = Clear Base Directory Setting -dataDir.notFound = The Zotero data directory could not be found. +dataDir.databaseCannotBeOpened = The %S database cannot be opened. +dataDir.checkPermissions = Make sure you have read and write permissions for all files in the %1$S data directory and that security software isn’t preventing %1$S from accessing that directory. +dataDir.moveToDefaultLocation = You may be able to fix this problem by moving the data directory to the new default location in your home directory. %S will automatically detect the new location. +dataDir.location = Data Directory: %S +dataDir.notFound = The %S data directory could not be found. +dataDir.notFound.defaultFound = The %S data directory could not be found at %S, but a data directory was found at %S. Use this directory instead? +dataDir.useNewLocation = Use New Location dataDir.previousDir = Previous directory: dataDir.default = Default (%S) dataDir.useDefaultLocation = Use Default Location @@ -165,8 +171,6 @@ startupError = There was an error starting Zotero. startupError.databaseInUse = Your Zotero database is currently in use. Only one instance of Zotero using the same database may be opened simultaneously at this time. startupError.closeStandalone = If Zotero Standalone is open, please close it and restart Firefox. startupError.closeFirefox = If Firefox with the Zotero extension is open, please close it and restart Zotero Standalone. -startupError.databaseCannotBeOpened = The Zotero database cannot be opened. -startupError.checkPermissions = Make sure you have read and write permissions for all files in the Zotero data directory. startupError.zoteroVersionIsOlder = This version of Zotero is older than the version last used with your database. startupError.incompatibleDBVersion = This %1$S database requires %1$S %2$S or later. startupError.zoteroVersionIsOlder.current = Current version: %S