1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/mozapps/update/nsUpdateServiceStub.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,183 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +const Ci = Components.interfaces; 1.10 +const Cc = Components.classes; 1.11 +const Cu = Components.utils; 1.12 + 1.13 +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); 1.14 +Cu.import("resource://gre/modules/FileUtils.jsm"); 1.15 +Cu.import("resource://gre/modules/Services.jsm"); 1.16 + 1.17 +const DIR_UPDATES = "updates"; 1.18 +const FILE_UPDATES_DB = "updates.xml"; 1.19 +const FILE_UPDATE_ACTIVE = "active-update.xml"; 1.20 +const FILE_LAST_LOG = "last-update.log"; 1.21 +const FILE_BACKUP_LOG = "backup-update.log"; 1.22 +const FILE_UPDATE_STATUS = "update.status"; 1.23 + 1.24 +const KEY_UPDROOT = "UpdRootD"; 1.25 + 1.26 +#ifdef XP_WIN 1.27 + 1.28 +const PREF_APP_UPDATE_MIGRATE_APP_DIR = "app.update.migrated.updateDir"; 1.29 + 1.30 + 1.31 +function getTaskbarIDHash(rootKey, exePath, appInfoName) { 1.32 + let registry = Cc["@mozilla.org/windows-registry-key;1"]. 1.33 + createInstance(Ci.nsIWindowsRegKey); 1.34 + try { 1.35 + registry.open(rootKey, "Software\\Mozilla\\" + appInfoName + "\\TaskBarIDs", 1.36 + Ci.nsIWindowsRegKey.ACCESS_READ); 1.37 + if (registry.hasValue(exePath)) { 1.38 + return registry.readStringValue(exePath); 1.39 + } 1.40 + } catch (ex) { 1.41 + } finally { 1.42 + registry.close(); 1.43 + } 1.44 + return undefined; 1.45 +}; 1.46 + 1.47 +/* 1.48 + * Migrates old update directory files to the new update directory 1.49 + * which is based on a hash of the installation. 1.50 + */ 1.51 +function migrateOldUpdateDir() { 1.52 + // Get the old udpate root leaf dir. It is based on the sub directory of 1.53 + // program files, or if the exe path is not inside program files, the appname. 1.54 + var appinfo = Components.classes["@mozilla.org/xre/app-info;1"]. 1.55 + getService(Components.interfaces.nsIXULAppInfo). 1.56 + QueryInterface(Components.interfaces.nsIXULRuntime); 1.57 + var updateLeafName; 1.58 + var programFiles = FileUtils.getFile("ProgF", []); 1.59 + var exeFile = FileUtils.getFile("XREExeF", []); 1.60 + if (exeFile.path.substring(0, programFiles.path.length).toLowerCase() == 1.61 + programFiles.path.toLowerCase()) { 1.62 + updateLeafName = exeFile.parent.leafName; 1.63 + } else { 1.64 + updateLeafName = appinfo.name; 1.65 + } 1.66 + 1.67 + // Get the old update root dir 1.68 + var oldUpdateRoot; 1.69 + if (appinfo.vendor) { 1.70 + oldUpdateRoot = FileUtils.getDir("LocalAppData", [appinfo.vendor, 1.71 + appinfo.name, 1.72 + updateLeafName], false); 1.73 + } else { 1.74 + oldUpdateRoot = FileUtils.getDir("LocalAppData", [appinfo.name, 1.75 + updateLeafName], false); 1.76 + } 1.77 + 1.78 + // Obtain the new update root 1.79 + var newUpdateRoot = FileUtils.getDir("UpdRootD", [], true); 1.80 + 1.81 + // If there is no taskbar ID then we want to retry this migration 1.82 + // at a later time if the application gets a taskbar ID. 1.83 + var taskbarID = getTaskbarIDHash(Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, 1.84 + exeFile.parent.path, appinfo.name); 1.85 + if (!taskbarID) { 1.86 + taskbarID = getTaskbarIDHash(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, 1.87 + exeFile.parent.path, appinfo.name); 1.88 + if (!taskbarID) { 1.89 + return; 1.90 + } 1.91 + } 1.92 + 1.93 + Services.prefs.setBoolPref(PREF_APP_UPDATE_MIGRATE_APP_DIR, true); 1.94 + 1.95 + // Sanity checks only to ensure we don't delete something we don't mean to. 1.96 + if (oldUpdateRoot.path.toLowerCase() == newUpdateRoot.path.toLowerCase() || 1.97 + updateLeafName.length == 0) { 1.98 + return; 1.99 + } 1.100 + 1.101 + // If the old update root doesn't exist then we have already migrated 1.102 + // or else there is no work to do. 1.103 + if (!oldUpdateRoot.exists()) { 1.104 + return; 1.105 + } 1.106 + 1.107 + // Get an array of all of the files we want to migrate. 1.108 + // We do this so we don't copy anything extra. 1.109 + var filesToMigrate = [FILE_UPDATES_DB, FILE_UPDATE_ACTIVE, 1.110 + ["updates", FILE_LAST_LOG], ["updates", FILE_BACKUP_LOG], 1.111 + ["updates", "0", FILE_UPDATE_STATUS]]; 1.112 + 1.113 + // Move each of those files to the new directory 1.114 + filesToMigrate.forEach(relPath => { 1.115 + let oldFile = oldUpdateRoot.clone(); 1.116 + let newFile = newUpdateRoot.clone(); 1.117 + if (relPath instanceof Array) { 1.118 + relPath.forEach(relPathPart => { 1.119 + oldFile.append(relPathPart); 1.120 + newFile.append(relPathPart); 1.121 + }); 1.122 + } else { 1.123 + oldFile.append(relPath); 1.124 + newFile.append(relPath); 1.125 + } 1.126 + 1.127 + try { 1.128 + if (!newFile.exists()) { 1.129 + oldFile.moveTo(newFile.parent, newFile.leafName); 1.130 + } 1.131 + } catch (e) { 1.132 + Components.utils.reportError(e); 1.133 + } 1.134 + }); 1.135 + 1.136 + oldUpdateRoot.remove(true); 1.137 +} 1.138 +#endif 1.139 + 1.140 +/** 1.141 + * Gets the specified directory at the specified hierarchy under the update root 1.142 + * directory without creating it if it doesn't exist. 1.143 + * @param pathArray 1.144 + * An array of path components to locate beneath the directory 1.145 + * specified by |key| 1.146 + * @return nsIFile object for the location specified. 1.147 + */ 1.148 +function getUpdateDirNoCreate(pathArray) { 1.149 + return FileUtils.getDir(KEY_UPDROOT, pathArray, false); 1.150 +} 1.151 + 1.152 +function UpdateServiceStub() { 1.153 +#ifdef XP_WIN 1.154 + // Don't attempt this migration more than once for perf reasons 1.155 + var migrated = 0; 1.156 + try { 1.157 + migrated = Services.prefs.getBoolPref(PREF_APP_UPDATE_MIGRATE_APP_DIR); 1.158 + } catch (e) { 1.159 + } 1.160 + 1.161 + if (!migrated) { 1.162 + try { 1.163 + migrateOldUpdateDir(); 1.164 + } catch (e) { 1.165 + Components.utils.reportError(e); 1.166 + } 1.167 + } 1.168 +#endif 1.169 + 1.170 + let statusFile = getUpdateDirNoCreate([DIR_UPDATES, "0"]); 1.171 + statusFile.append(FILE_UPDATE_STATUS); 1.172 + // If the update.status file exists then initiate post update processing. 1.173 + if (statusFile.exists()) { 1.174 + let aus = Components.classes["@mozilla.org/updates/update-service;1"]. 1.175 + getService(Ci.nsIApplicationUpdateService). 1.176 + QueryInterface(Ci.nsIObserver); 1.177 + aus.observe(null, "post-update-processing", ""); 1.178 + } 1.179 +} 1.180 +UpdateServiceStub.prototype = { 1.181 + observe: function(){}, 1.182 + classID: Components.ID("{e43b0010-04ba-4da6-b523-1f92580bc150}"), 1.183 + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]) 1.184 +}; 1.185 + 1.186 +this.NSGetFactory = XPCOMUtils.generateNSGetFactory([UpdateServiceStub]);