gecko/toolkit/mozapps/update/nsUpdateServiceStub.js

184 lines
6.1 KiB
JavaScript

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const Ci = Components.interfaces;
const Cc = Components.classes;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
const DIR_UPDATES = "updates";
const FILE_UPDATES_DB = "updates.xml";
const FILE_UPDATE_ACTIVE = "active-update.xml";
const FILE_LAST_LOG = "last-update.log";
const FILE_BACKUP_LOG = "backup-update.log";
const FILE_UPDATE_STATUS = "update.status";
const KEY_UPDROOT = "UpdRootD";
#ifdef XP_WIN
const PREF_APP_UPDATE_MIGRATE_APP_DIR = "app.update.migrated.updateDir";
function getTaskbarIDHash(rootKey, exePath, appInfoName) {
let registry = Cc["@mozilla.org/windows-registry-key;1"].
createInstance(Ci.nsIWindowsRegKey);
try {
registry.open(rootKey, "Software\\Mozilla\\" + appInfoName + "\\TaskBarIDs",
Ci.nsIWindowsRegKey.ACCESS_READ);
if (registry.hasValue(exePath)) {
return registry.readStringValue(exePath);
}
} catch (ex) {
} finally {
registry.close();
}
return undefined;
};
/*
* Migrates old update directory files to the new update directory
* which is based on a hash of the installation.
*/
function migrateOldUpdateDir() {
// Get the old udpate root leaf dir. It is based on the sub directory of
// program files, or if the exe path is not inside program files, the appname.
var appinfo = Components.classes["@mozilla.org/xre/app-info;1"].
getService(Components.interfaces.nsIXULAppInfo).
QueryInterface(Components.interfaces.nsIXULRuntime);
var updateLeafName;
var programFiles = FileUtils.getFile("ProgF", []);
var exeFile = FileUtils.getFile("XREExeF", []);
if (exeFile.path.substring(0, programFiles.path.length).toLowerCase() ==
programFiles.path.toLowerCase()) {
updateLeafName = exeFile.parent.leafName;
} else {
updateLeafName = appinfo.name;
}
// Get the old update root dir
var oldUpdateRoot;
if (appinfo.vendor) {
oldUpdateRoot = FileUtils.getDir("LocalAppData", [appinfo.vendor,
appinfo.name,
updateLeafName], false);
} else {
oldUpdateRoot = FileUtils.getDir("LocalAppData", [appinfo.name,
updateLeafName], false);
}
// Obtain the new update root
var newUpdateRoot = FileUtils.getDir("UpdRootD", [], true);
// If there is no taskbar ID then we want to retry this migration
// at a later time if the application gets a taskbar ID.
var taskbarID = getTaskbarIDHash(Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE,
exeFile.parent.path, appinfo.name);
if (!taskbarID) {
taskbarID = getTaskbarIDHash(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
exeFile.parent.path, appinfo.name);
if (!taskbarID) {
return;
}
}
Services.prefs.setBoolPref(PREF_APP_UPDATE_MIGRATE_APP_DIR, true);
// Sanity checks only to ensure we don't delete something we don't mean to.
if (oldUpdateRoot.path.toLowerCase() == newUpdateRoot.path.toLowerCase() ||
updateLeafName.length == 0) {
return;
}
// If the old update root doesn't exist then we have already migrated
// or else there is no work to do.
if (!oldUpdateRoot.exists()) {
return;
}
// Get an array of all of the files we want to migrate.
// We do this so we don't copy anything extra.
var filesToMigrate = [FILE_UPDATES_DB, FILE_UPDATE_ACTIVE,
["updates", FILE_LAST_LOG], ["updates", FILE_BACKUP_LOG],
["updates", "0", FILE_UPDATE_STATUS]];
// Move each of those files to the new directory
filesToMigrate.forEach(relPath => {
let oldFile = oldUpdateRoot.clone();
let newFile = newUpdateRoot.clone();
if (relPath instanceof Array) {
relPath.forEach(relPathPart => {
oldFile.append(relPathPart);
newFile.append(relPathPart);
});
} else {
oldFile.append(relPath);
newFile.append(relPath);
}
try {
if (!newFile.exists()) {
oldFile.moveTo(newFile.parent, newFile.leafName);
}
} catch (e) {
Components.utils.reportError(e);
}
});
oldUpdateRoot.remove(true);
}
#endif
/**
* Gets the specified directory at the specified hierarchy under the update root
* directory without creating it if it doesn't exist.
* @param pathArray
* An array of path components to locate beneath the directory
* specified by |key|
* @return nsIFile object for the location specified.
*/
function getUpdateDirNoCreate(pathArray) {
return FileUtils.getDir(KEY_UPDROOT, pathArray, false);
}
function UpdateServiceStub() {
#ifdef XP_WIN
// Don't attempt this migration more than once for perf reasons
var migrated = 0;
try {
migrated = Services.prefs.getBoolPref(PREF_APP_UPDATE_MIGRATE_APP_DIR);
} catch (e) {
}
if (!migrated) {
try {
migrateOldUpdateDir();
} catch (e) {
Components.utils.reportError(e);
}
}
#endif
let statusFile = getUpdateDirNoCreate([DIR_UPDATES, "0"]);
statusFile.append(FILE_UPDATE_STATUS);
// If the update.status file exists then initiate post update processing.
if (statusFile.exists()) {
let aus = Components.classes["@mozilla.org/updates/update-service;1"].
getService(Ci.nsIApplicationUpdateService).
QueryInterface(Ci.nsIObserver);
aus.observe(null, "post-update-processing", "");
}
}
UpdateServiceStub.prototype = {
observe: function(){},
classID: Components.ID("{e43b0010-04ba-4da6-b523-1f92580bc150}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([UpdateServiceStub]);