toolkit/mozapps/update/nsUpdateServiceStub.js

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:8eac48361d87
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 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
6 const Ci = Components.interfaces;
7 const Cc = Components.classes;
8 const Cu = Components.utils;
9
10 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
11 Cu.import("resource://gre/modules/FileUtils.jsm");
12 Cu.import("resource://gre/modules/Services.jsm");
13
14 const DIR_UPDATES = "updates";
15 const FILE_UPDATES_DB = "updates.xml";
16 const FILE_UPDATE_ACTIVE = "active-update.xml";
17 const FILE_LAST_LOG = "last-update.log";
18 const FILE_BACKUP_LOG = "backup-update.log";
19 const FILE_UPDATE_STATUS = "update.status";
20
21 const KEY_UPDROOT = "UpdRootD";
22
23 #ifdef XP_WIN
24
25 const PREF_APP_UPDATE_MIGRATE_APP_DIR = "app.update.migrated.updateDir";
26
27
28 function getTaskbarIDHash(rootKey, exePath, appInfoName) {
29 let registry = Cc["@mozilla.org/windows-registry-key;1"].
30 createInstance(Ci.nsIWindowsRegKey);
31 try {
32 registry.open(rootKey, "Software\\Mozilla\\" + appInfoName + "\\TaskBarIDs",
33 Ci.nsIWindowsRegKey.ACCESS_READ);
34 if (registry.hasValue(exePath)) {
35 return registry.readStringValue(exePath);
36 }
37 } catch (ex) {
38 } finally {
39 registry.close();
40 }
41 return undefined;
42 };
43
44 /*
45 * Migrates old update directory files to the new update directory
46 * which is based on a hash of the installation.
47 */
48 function migrateOldUpdateDir() {
49 // Get the old udpate root leaf dir. It is based on the sub directory of
50 // program files, or if the exe path is not inside program files, the appname.
51 var appinfo = Components.classes["@mozilla.org/xre/app-info;1"].
52 getService(Components.interfaces.nsIXULAppInfo).
53 QueryInterface(Components.interfaces.nsIXULRuntime);
54 var updateLeafName;
55 var programFiles = FileUtils.getFile("ProgF", []);
56 var exeFile = FileUtils.getFile("XREExeF", []);
57 if (exeFile.path.substring(0, programFiles.path.length).toLowerCase() ==
58 programFiles.path.toLowerCase()) {
59 updateLeafName = exeFile.parent.leafName;
60 } else {
61 updateLeafName = appinfo.name;
62 }
63
64 // Get the old update root dir
65 var oldUpdateRoot;
66 if (appinfo.vendor) {
67 oldUpdateRoot = FileUtils.getDir("LocalAppData", [appinfo.vendor,
68 appinfo.name,
69 updateLeafName], false);
70 } else {
71 oldUpdateRoot = FileUtils.getDir("LocalAppData", [appinfo.name,
72 updateLeafName], false);
73 }
74
75 // Obtain the new update root
76 var newUpdateRoot = FileUtils.getDir("UpdRootD", [], true);
77
78 // If there is no taskbar ID then we want to retry this migration
79 // at a later time if the application gets a taskbar ID.
80 var taskbarID = getTaskbarIDHash(Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE,
81 exeFile.parent.path, appinfo.name);
82 if (!taskbarID) {
83 taskbarID = getTaskbarIDHash(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
84 exeFile.parent.path, appinfo.name);
85 if (!taskbarID) {
86 return;
87 }
88 }
89
90 Services.prefs.setBoolPref(PREF_APP_UPDATE_MIGRATE_APP_DIR, true);
91
92 // Sanity checks only to ensure we don't delete something we don't mean to.
93 if (oldUpdateRoot.path.toLowerCase() == newUpdateRoot.path.toLowerCase() ||
94 updateLeafName.length == 0) {
95 return;
96 }
97
98 // If the old update root doesn't exist then we have already migrated
99 // or else there is no work to do.
100 if (!oldUpdateRoot.exists()) {
101 return;
102 }
103
104 // Get an array of all of the files we want to migrate.
105 // We do this so we don't copy anything extra.
106 var filesToMigrate = [FILE_UPDATES_DB, FILE_UPDATE_ACTIVE,
107 ["updates", FILE_LAST_LOG], ["updates", FILE_BACKUP_LOG],
108 ["updates", "0", FILE_UPDATE_STATUS]];
109
110 // Move each of those files to the new directory
111 filesToMigrate.forEach(relPath => {
112 let oldFile = oldUpdateRoot.clone();
113 let newFile = newUpdateRoot.clone();
114 if (relPath instanceof Array) {
115 relPath.forEach(relPathPart => {
116 oldFile.append(relPathPart);
117 newFile.append(relPathPart);
118 });
119 } else {
120 oldFile.append(relPath);
121 newFile.append(relPath);
122 }
123
124 try {
125 if (!newFile.exists()) {
126 oldFile.moveTo(newFile.parent, newFile.leafName);
127 }
128 } catch (e) {
129 Components.utils.reportError(e);
130 }
131 });
132
133 oldUpdateRoot.remove(true);
134 }
135 #endif
136
137 /**
138 * Gets the specified directory at the specified hierarchy under the update root
139 * directory without creating it if it doesn't exist.
140 * @param pathArray
141 * An array of path components to locate beneath the directory
142 * specified by |key|
143 * @return nsIFile object for the location specified.
144 */
145 function getUpdateDirNoCreate(pathArray) {
146 return FileUtils.getDir(KEY_UPDROOT, pathArray, false);
147 }
148
149 function UpdateServiceStub() {
150 #ifdef XP_WIN
151 // Don't attempt this migration more than once for perf reasons
152 var migrated = 0;
153 try {
154 migrated = Services.prefs.getBoolPref(PREF_APP_UPDATE_MIGRATE_APP_DIR);
155 } catch (e) {
156 }
157
158 if (!migrated) {
159 try {
160 migrateOldUpdateDir();
161 } catch (e) {
162 Components.utils.reportError(e);
163 }
164 }
165 #endif
166
167 let statusFile = getUpdateDirNoCreate([DIR_UPDATES, "0"]);
168 statusFile.append(FILE_UPDATE_STATUS);
169 // If the update.status file exists then initiate post update processing.
170 if (statusFile.exists()) {
171 let aus = Components.classes["@mozilla.org/updates/update-service;1"].
172 getService(Ci.nsIApplicationUpdateService).
173 QueryInterface(Ci.nsIObserver);
174 aus.observe(null, "post-update-processing", "");
175 }
176 }
177 UpdateServiceStub.prototype = {
178 observe: function(){},
179 classID: Components.ID("{e43b0010-04ba-4da6-b523-1f92580bc150}"),
180 QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver])
181 };
182
183 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([UpdateServiceStub]);

mercurial