Don't auto-migrate data dir if target on a different drive

See https://forums.zotero.org/discussion/comment/277632/#Comment_277632
This commit is contained in:
Adomas Venčkauskas 2017-06-12 14:14:36 +03:00 committed by Dan Stillman
parent 98544edde5
commit a17b486e4b
3 changed files with 108 additions and 31 deletions

View file

@ -428,6 +428,36 @@ Zotero.DataDirectory = {
},
isNewDirOnDifferentDrive: Zotero.Promise.coroutine(function* (oldDir, newDir) {
yield this.markForMigration(oldDir, true);
let oldMarkerFile = OS.Path.join(oldDir, this.MIGRATION_MARKER);
let testPath = OS.Path.join(newDir, '..', this.MIGRATION_MARKER);
try {
// Attempt moving the marker with noCopy
yield OS.File.move(oldMarkerFile, testPath, {noCopy: true});
} catch(e) {
yield OS.File.remove(oldMarkerFile);
Components.classes["@mozilla.org/net/osfileconstantsservice;1"].
getService(Components.interfaces.nsIOSFileConstantsService).
init();
if (e instanceof OS.File.Error) {
if (typeof e.unixErrno != "undefined") {
return e.unixErrno == OS.Constants.libc.EXDEV;
}
if (typeof e.winLastError != "undefined") {
// ERROR_NOT_SAME_DEVICE is undefined
// return e.winLastError == OS.Constants.Win.ERROR_NOT_SAME_DEVICE;
return e.winLastError == 17;
}
}
throw e;
}
yield OS.File.remove(testPath);
return false;
}),
/**
* Determine if current data directory is in a legacy location
*/
@ -438,6 +468,10 @@ Zotero.DataDirectory = {
return false;
}
if (this.newDirOnDifferentDrive) {
return false;
}
// Legacy default or set to legacy default from other program (Standalone/Z4Fx) to share data
if (!Zotero.Prefs.get('useDataDir') || this.isLegacy(currentDir)) {
return true;
@ -487,12 +521,24 @@ Zotero.DataDirectory = {
automatic = true;
// Skip automatic migration if there's a non-empty directory at the new location
// TODO: Notify user
if ((yield OS.File.exists(newDir)) && !(yield Zotero.File.directoryIsEmpty(newDir))) {
Zotero.debug(`${newDir} exists and is non-empty -- skipping migration`);
return false;
}
}
// Skip migration if new dir on different drive and prompt
if (yield this.isNewDirOnDifferentDrive(dataDir, newDir)) {
Zotero.debug(`New dataDir ${newDir} is on a different drive from ${dataDir} -- skipping migration`);
Zotero.DataDirectory.newDirOnDifferentDrive = true;
let error = Zotero.getString(`dataDir.migration.failure.full.automatic.newDirOnDifferentDrive`, Zotero.clientName)
+ "\n\n"
+ Zotero.getString(`dataDir.migration.failure.full.automatic.text2`, Zotero.appName);
return this.fullMigrationFailurePrompt(dataDir, newDir, error);
}
// Check for an existing pipe from other running versions of Zotero pointing at the same data
// directory, and skip migration if found
try {
@ -593,7 +639,7 @@ Zotero.DataDirectory = {
false,
null,
// Don't show message in a popup in Standalone if pane isn't ready
Zotero.iStandalone
Zotero.isStandalone
);
}
catch (e) {
@ -607,31 +653,13 @@ Zotero.DataDirectory = {
Zotero.debug("Migration failed", 1);
Zotero.logError(e);
let ps = Services.prompt;
let buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_IS_STRING);
let index = ps.confirmEx(null,
Zotero.getString('dataDir.migration.failure.title'),
Zotero.getString(`dataDir.migration.failure.full.${mode}.text1`, ZOTERO_CONFIG.CLIENT_NAME)
+ "\n\n"
+ e
+ "\n\n"
+ Zotero.getString(`dataDir.migration.failure.full.${mode}.text2`, Zotero.appName)
+ "\n\n"
+ Zotero.getString('dataDir.migration.failure.full.current', oldDir)
+ "\n\n"
+ Zotero.getString('dataDir.migration.failure.full.recommended', newDir),
buttonFlags,
Zotero.getString('dataDir.migration.failure.full.showCurrentDirectoryAndQuit', Zotero.appName),
Zotero.getString('general.notNow'),
null, null, {}
);
if (index == 0) {
yield Zotero.File.reveal(oldDir);
Zotero.skipLoading = true;
Zotero.Utilities.Internal.quitZotero();
}
return;
let error = Zotero.getString(`dataDir.migration.failure.full.${mode}.text1`, Zotero.clientName)
+ "\n\n"
+ e;
+ "\n\n"
+ Zotero.getString(`dataDir.migration.failure.full.${mode}.text2`, Zotero.appName);
return this.fullMigrationFailurePrompt(oldDir, newDir, error);
}
// Set data directory again
@ -700,6 +728,29 @@ Zotero.DataDirectory = {
}),
fullMigrationFailurePrompt: Zotero.Promise.coroutine(function* (oldDir, newDir, error) {
let ps = Services.prompt;
let buttonFlags = (ps.BUTTON_POS_0) * (ps.BUTTON_TITLE_IS_STRING)
+ (ps.BUTTON_POS_1) * (ps.BUTTON_TITLE_IS_STRING);
let index = ps.confirmEx(null,
Zotero.getString('dataDir.migration.failure.title'),
error + "\n\n"
+ Zotero.getString('dataDir.migration.failure.full.current', oldDir)
+ "\n\n"
+ Zotero.getString('dataDir.migration.failure.full.recommended', newDir),
buttonFlags,
Zotero.getString('dataDir.migration.failure.full.showCurrentDirectoryAndQuit', Zotero.appName),
Zotero.getString('general.notNow'),
null, null, {}
);
if (index == 0) {
yield Zotero.File.reveal(oldDir);
Zotero.skipLoading = true;
Zotero.Utilities.Internal.quitZotero();
}
}),
/**
* Recursively moves data directory from one location to another and updates the data directory
* setting in this profile and any profiles pointing to the old location

View file

@ -146,6 +146,7 @@ dataDir.migration.failure.partial.new = New directory: %S
dataDir.migration.failure.partial.showDirectoriesAndQuit = Show Directories and Quit
dataDir.migration.failure.full.automatic.text1 = %S attempted to move your data directory to a new default location, but the migration could not be completed.
dataDir.migration.failure.full.automatic.text2 = It is recommended that you close %S and move your data directory manually.
dataDir.migration.failure.full.automatic.newDirOnDifferentDrive = %S attempted to move your data directory to a new default location, but the old directory is on a different drive and cannot be migrated automatically.
dataDir.migration.failure.full.manual.text1 = Your %S data directory could not be migrated.
dataDir.migration.failure.full.manual.text2 = It is recommended that you close %S and manually move your data directory to the new default location.
dataDir.migration.failure.full.firefoxOpen = Your data directory cannot be migrated while Zotero for Firefox is open. Please close Firefox and try again.

View file

@ -39,10 +39,12 @@ describe("Zotero.DataDirectory", function () {
stubs.canMigrate = sinon.stub(Zotero.DataDirectory, "canMigrate").returns(true);
// A pipe always exists during tests, since Zotero is running
stubs.pipeExists = sinon.stub(Zotero.IPC, "pipeExists").returns(Zotero.Promise.resolve(false));
stubs.setDataDir = sinon.stub(Zotero.DataDirectory, "set");
stubs.isNewDirOnDifferentDrive = sinon.stub(Zotero.DataDirectory, 'isNewDirOnDifferentDrive').resolves(true);
});
beforeEach(function* () {
stubs.setDataDir = sinon.stub(Zotero.DataDirectory, "set");
stubs.setDataDir.reset();
});
afterEach(function* () {
@ -50,13 +52,14 @@ describe("Zotero.DataDirectory", function () {
yield removeDir(newDir);
Zotero.DataDirectory._cache(false);
yield Zotero.DataDirectory.init();
stubs.setDataDir.restore();
});
after(function* () {
stubs.canMigrate.restore();
stubs.pipeExists.restore();
for (let key in stubs) {
try {
stubs[key].restore();
} catch(e) {}
}
});
// Force non-mv mode
@ -183,6 +186,28 @@ describe("Zotero.DataDirectory", function () {
yield assert.eventually.isFalse(Zotero.DataDirectory.checkForMigration(oldDir, newDir));
});
it("should skip automatic migration and show prompt if target directory is on a different drive", function* () {
resetCommandMode();
resetFunctionMode();
yield populateDataDirectory(oldDir);
yield OS.File.remove(oldMigrationMarker);
stubs.isNewDirOnDifferentDrive.resolves(true);
var promise = waitForDialog(function (dialog) {
assert.include(
dialog.document.documentElement.textContent,
Zotero.getString(`dataDir.migration.failure.full.automatic.newDirOnDifferentDrive`, Zotero.clientName)
);
}, 'cancel');
yield assert.eventually.isNotOk(Zotero.DataDirectory.checkForMigration(oldDir, newDir));
yield promise;
stubs.isNewDirOnDifferentDrive.resolves(false);
});
add("should show error on partial failure", function (automatic) {
return function* () {
yield populateDataDirectory(oldDir, null, automatic);