1/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ 2/* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6const { XPCOMUtils } = ChromeUtils.import( 7 "resource://gre/modules/XPCOMUtils.jsm" 8); 9const { FileUtils } = ChromeUtils.import( 10 "resource://gre/modules/FileUtils.jsm" 11); 12const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); 13const { AppConstants } = ChromeUtils.import( 14 "resource://gre/modules/AppConstants.jsm" 15); 16 17const DIR_UPDATES = "updates"; 18const FILE_UPDATE_STATUS = "update.status"; 19const FILE_ACTIVE_UPDATE_XML = "active-update.xml"; 20const FILE_LAST_UPDATE_LOG = "last-update.log"; 21const FILE_UPDATES_XML = "updates.xml"; 22const FILE_UPDATE_LOG = "update.log"; 23const FILE_UPDATE_MESSAGES = "update_messages.log"; 24const FILE_BACKUP_MESSAGES = "update_messages_old.log"; 25 26const KEY_UPDROOT = "UpdRootD"; 27const KEY_OLD_UPDROOT = "OldUpdRootD"; 28const KEY_PROFILE_DIR = "ProfD"; 29 30// The pref prefix below should have the hash of the install path appended to 31// ensure that this is a per-installation pref (i.e. to ensure that migration 32// happens for every install rather than once per profile) 33const PREF_PREFIX_UPDATE_DIR_MIGRATED = "app.update.migrated.updateDir2."; 34const PREF_APP_UPDATE_ALTUPDATEDIRPATH = "app.update.altUpdateDirPath"; 35const PREF_APP_UPDATE_LOG = "app.update.log"; 36const PREF_APP_UPDATE_FILE_LOGGING = "app.update.log.file"; 37 38XPCOMUtils.defineLazyGetter(this, "gLogEnabled", function aus_gLogEnabled() { 39 return Services.prefs.getBoolPref(PREF_APP_UPDATE_LOG, false); 40}); 41 42function getUpdateBaseDirNoCreate() { 43 if (Cu.isInAutomation) { 44 // This allows tests to use an alternate updates directory so they can test 45 // startup behavior. 46 const MAGIC_TEST_ROOT_PREFIX = "<test-root>"; 47 const PREF_TEST_ROOT = "mochitest.testRoot"; 48 let alternatePath = Services.prefs.getCharPref( 49 PREF_APP_UPDATE_ALTUPDATEDIRPATH, 50 null 51 ); 52 if (alternatePath && alternatePath.startsWith(MAGIC_TEST_ROOT_PREFIX)) { 53 let testRoot = Services.prefs.getCharPref(PREF_TEST_ROOT); 54 let relativePath = alternatePath.substring(MAGIC_TEST_ROOT_PREFIX.length); 55 if (AppConstants.platform == "win") { 56 relativePath = relativePath.replace(/\//g, "\\"); 57 } 58 alternatePath = testRoot + relativePath; 59 let updateDir = Cc["@mozilla.org/file/local;1"].createInstance( 60 Ci.nsIFile 61 ); 62 updateDir.initWithPath(alternatePath); 63 LOG( 64 "getUpdateBaseDirNoCreate returning test directory, path: " + 65 updateDir.path 66 ); 67 return updateDir; 68 } 69 } 70 71 return FileUtils.getDir(KEY_UPDROOT, [], false); 72} 73 74function UpdateServiceStub() { 75 let updateDir = getUpdateBaseDirNoCreate(); 76 let prefUpdateDirMigrated = 77 PREF_PREFIX_UPDATE_DIR_MIGRATED + updateDir.leafName; 78 79 let statusFile = updateDir; 80 statusFile.append(DIR_UPDATES); 81 statusFile.append("0"); 82 statusFile.append(FILE_UPDATE_STATUS); 83 updateDir = null; // We don't need updateDir anymore, plus now its nsIFile 84 // contains the status file's path 85 86 // We may need to migrate update data 87 if ( 88 AppConstants.platform == "win" && 89 !Services.prefs.getBoolPref(prefUpdateDirMigrated, false) 90 ) { 91 migrateUpdateDirectory(); 92 Services.prefs.setBoolPref(prefUpdateDirMigrated, true); 93 } 94 95 // Prevent file logging from persisting for more than a session by disabling 96 // it on startup. 97 if (Services.prefs.getBoolPref(PREF_APP_UPDATE_FILE_LOGGING, false)) { 98 deactivateUpdateLogFile(); 99 } 100 101 // If the update.status file exists then initiate post update processing. 102 if (statusFile.exists()) { 103 let aus = Cc["@mozilla.org/updates/update-service;1"] 104 .getService(Ci.nsIApplicationUpdateService) 105 .QueryInterface(Ci.nsIObserver); 106 aus.observe(null, "post-update-processing", ""); 107 } 108} 109UpdateServiceStub.prototype = { 110 observe() {}, 111 classID: Components.ID("{e43b0010-04ba-4da6-b523-1f92580bc150}"), 112 QueryInterface: ChromeUtils.generateQI(["nsIObserver"]), 113}; 114 115var EXPORTED_SYMBOLS = ["UpdateServiceStub"]; 116 117function deactivateUpdateLogFile() { 118 LOG("Application update file logging being automatically turned off"); 119 Services.prefs.setBoolPref(PREF_APP_UPDATE_FILE_LOGGING, false); 120 let logFile = Services.dirsvc.get(KEY_PROFILE_DIR, Ci.nsIFile); 121 logFile.append(FILE_UPDATE_MESSAGES); 122 123 try { 124 logFile.moveTo(null, FILE_BACKUP_MESSAGES); 125 } catch (e) { 126 LOG( 127 "Failed to backup update messages log (" + 128 e + 129 "). Attempting to " + 130 "remove it." 131 ); 132 try { 133 logFile.remove(false); 134 } catch (e) { 135 LOG("Also failed to remove the update messages log: " + e); 136 } 137 } 138} 139 140/** 141 * This function should be called when there are files in the old update 142 * directory that may need to be migrated to the new update directory. 143 */ 144function migrateUpdateDirectory() { 145 let sourceRootDir = FileUtils.getDir(KEY_OLD_UPDROOT, [], false); 146 let destRootDir = FileUtils.getDir(KEY_UPDROOT, [], false); 147 148 if (!sourceRootDir.exists()) { 149 LOG( 150 "UpdateServiceStub:_migrateUpdateDirectory - Abort: No migration " + 151 "necessary. Nothing to migrate." 152 ); 153 return; 154 } 155 156 if (destRootDir.exists()) { 157 // Migration must have already been done by another user 158 LOG( 159 "UpdateServiceStub:_migrateUpdateDirectory - migrated and unmigrated " + 160 "update directories found. Deleting the unmigrated directory: " + 161 sourceRootDir.path 162 ); 163 try { 164 sourceRootDir.remove(true); 165 } catch (e) { 166 LOG( 167 "UpdateServiceStub:_migrateUpdateDirectory - Deletion of " + 168 "unmigrated directory failed. Exception: " + 169 e 170 ); 171 } 172 return; 173 } 174 175 let sourceUpdateDir = sourceRootDir.clone(); 176 sourceUpdateDir.append(DIR_UPDATES); 177 let destUpdateDir = destRootDir.clone(); 178 destUpdateDir.append(DIR_UPDATES); 179 180 let sourcePatchDir = sourceUpdateDir.clone(); 181 sourcePatchDir.append("0"); 182 let destPatchDir = destUpdateDir.clone(); 183 destPatchDir.append("0"); 184 185 let sourceStatusFile = sourcePatchDir.clone(); 186 sourceStatusFile.append(FILE_UPDATE_STATUS); 187 let destStatusFile = destPatchDir.clone(); 188 destStatusFile.append(FILE_UPDATE_STATUS); 189 190 let sourceActiveXML = sourceRootDir.clone(); 191 sourceActiveXML.append(FILE_ACTIVE_UPDATE_XML); 192 try { 193 sourceActiveXML.moveTo(destRootDir, sourceActiveXML.leafName); 194 } catch (e) { 195 LOG( 196 "UpdateServiceStub:_migrateUpdateDirectory - Unable to move active " + 197 "update XML file. Exception: " + 198 e 199 ); 200 } 201 202 let sourceUpdateXML = sourceRootDir.clone(); 203 sourceUpdateXML.append(FILE_UPDATES_XML); 204 try { 205 sourceUpdateXML.moveTo(destRootDir, sourceUpdateXML.leafName); 206 } catch (e) { 207 LOG( 208 "UpdateServiceStub:_migrateUpdateDirectory - Unable to move " + 209 "update XML file. Exception: " + 210 e 211 ); 212 } 213 214 let sourceUpdateLog = sourcePatchDir.clone(); 215 sourceUpdateLog.append(FILE_UPDATE_LOG); 216 try { 217 sourceUpdateLog.moveTo(destPatchDir, sourceUpdateLog.leafName); 218 } catch (e) { 219 LOG( 220 "UpdateServiceStub:_migrateUpdateDirectory - Unable to move " + 221 "update log file. Exception: " + 222 e 223 ); 224 } 225 226 let sourceLastUpdateLog = sourceUpdateDir.clone(); 227 sourceLastUpdateLog.append(FILE_LAST_UPDATE_LOG); 228 try { 229 sourceLastUpdateLog.moveTo(destUpdateDir, sourceLastUpdateLog.leafName); 230 } catch (e) { 231 LOG( 232 "UpdateServiceStub:_migrateUpdateDirectory - Unable to move " + 233 "last-update log file. Exception: " + 234 e 235 ); 236 } 237 238 try { 239 sourceStatusFile.moveTo(destStatusFile.parent, destStatusFile.leafName); 240 } catch (e) { 241 LOG( 242 "UpdateServiceStub:_migrateUpdateDirectory - Unable to move update " + 243 "status file. Exception: " + 244 e 245 ); 246 } 247 248 // Remove all remaining files in the old update directory. We don't need 249 // them anymore 250 try { 251 sourceRootDir.remove(true); 252 } catch (e) { 253 LOG( 254 "UpdateServiceStub:_migrateUpdateDirectory - Deletion of old update " + 255 "directory failed. Exception: " + 256 e 257 ); 258 } 259} 260 261/** 262 * Logs a string to the error console. 263 * @param string 264 * The string to write to the error console. 265 */ 266function LOG(string) { 267 if (gLogEnabled) { 268 dump("*** AUS:SVC " + string + "\n"); 269 Services.console.logStringMessage("AUS:SVC " + string); 270 } 271} 272