Skip to content

Commit 85abd24

Browse files
author
Robert Strong
committed
Bug 313057: Automatic updater downgrades/overwrites browser version when an older/identical version is in the queue. r=bsmedberg, a1.9.1b2=beltzner
1 parent 2ada5a0 commit 85abd24

File tree

4 files changed

+88
-7
lines changed

4 files changed

+88
-7
lines changed

toolkit/mozapps/update/src/nsUpdateService.js.in

+26
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ const KEY_UAPPDATA = "UAppData";
8484

8585
const DIR_UPDATES = "updates";
8686
const FILE_UPDATE_STATUS = "update.status";
87+
const FILE_UPDATE_VERSION = "update.version";
8788
const FILE_UPDATE_ARCHIVE = "update.mar";
8889
const FILE_UPDATE_LOG = "update.log"
8990
const FILE_UPDATES_DB = "updates.xml";
@@ -398,6 +399,28 @@ function writeStatusFile(dir, state) {
398399
writeStringToFile(statusFile, state);
399400
}
400401

402+
/**
403+
# Writes the update's application version to a file in the patch directory. If
404+
# the update doesn't provide application version information via the
405+
# extensionVersion attribute the string "null" will be written to the file.
406+
# This value is compared during startup (in nsUpdateDriver.cpp) to determine if
407+
# the update should be applied. Note that this won't provide protection from
408+
# downgrade of the application for the nightly user case where the application
409+
# version doesn't change.
410+
# @param dir
411+
# The patch directory where the update.version file should be
412+
# written.
413+
# @param version
414+
# The version value to write. Will be the string "null" when the
415+
# update doesn't provide the extensionVersion attribute in the update
416+
# xml.
417+
*/
418+
function writeVersionFile(dir, version) {
419+
var versionFile = dir.clone();
420+
versionFile.append(FILE_UPDATE_VERSION);
421+
writeStringToFile(versionFile, version);
422+
}
423+
401424
/**
402425
* Removes the Updates Directory
403426
* @param key
@@ -1228,6 +1251,7 @@ UpdateService.prototype = {
12281251
if (update.errorCode == WRITE_ERROR) {
12291252
prompter.showUpdateError(update);
12301253
writeStatusFile(getUpdatesDir(), update.state = STATE_PENDING);
1254+
writeVersionFile(getUpdatesDir(), update.extensionVersion);
12311255
return;
12321256
}
12331257
}
@@ -2410,6 +2434,7 @@ Downloader.prototype = {
24102434
// This is a pretty fatal error. Just bail.
24112435
LOG("Downloader", "_selectPatch - failed to apply complete patch!");
24122436
writeStatusFile(updateDir, STATE_NONE);
2437+
writeVersionFile(getUpdatesDir(), null);
24132438
return null;
24142439
}
24152440
}
@@ -2635,6 +2660,7 @@ Downloader.prototype = {
26352660

26362661
// Tell the updater.exe we're ready to apply.
26372662
writeStatusFile(getUpdatesDir(), state);
2663+
writeVersionFile(getUpdatesDir(), this._update.extensionVersion);
26382664
this._update.installDate = (new Date()).getTime();
26392665
this._update.statusText = updateStrings.GetStringFromName("installPending");
26402666
}

toolkit/xre/nsAppRunner.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -2976,7 +2976,8 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
29762976
dirProvider.GetAppDir(),
29772977
updRoot,
29782978
gRestartArgc,
2979-
gRestartArgv);
2979+
gRestartArgv,
2980+
appData.version);
29802981
#endif
29812982

29822983
nsCOMPtr<nsIProfileLock> profileLock;

toolkit/xre/nsUpdateDriver.cpp

+53-5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
* Contributor(s):
2323
* Darin Fisher <darin@meer.net>
2424
* Ben Turner <mozilla@songbirdnest.com>
25+
* Robert Strong <robert.bugzilla@gmail.com>
2526
*
2627
* Alternatively, the contents of this file may be used under the terms of
2728
* either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -51,6 +52,7 @@
5152
#include "nsPrintfCString.h"
5253
#include "prproces.h"
5354
#include "prlog.h"
55+
#include "nsVersionComparator.h"
5456

5557
#ifdef XP_MACOSX
5658
#include "nsILocalFileMac.h"
@@ -222,16 +224,16 @@ GetFile(nsIFile *dir, const nsCSubstring &name, nsCOMPtr<nsILocalFile> &result)
222224
{
223225
nsresult rv;
224226

225-
nsCOMPtr<nsIFile> statusFile;
226-
rv = dir->Clone(getter_AddRefs(statusFile));
227+
nsCOMPtr<nsIFile> file;
228+
rv = dir->Clone(getter_AddRefs(file));
227229
if (NS_FAILED(rv))
228230
return PR_FALSE;
229231

230-
rv = statusFile->AppendNative(name);
232+
rv = file->AppendNative(name);
231233
if (NS_FAILED(rv))
232234
return PR_FALSE;
233235

234-
result = do_QueryInterface(statusFile, &rv);
236+
result = do_QueryInterface(file, &rv);
235237
return NS_SUCCEEDED(rv);
236238
}
237239

@@ -274,6 +276,42 @@ SetStatus(nsILocalFile *statusFile, const char *status)
274276
return PR_TRUE;
275277
}
276278

279+
static PRBool
280+
GetVersionFile(nsIFile *dir, nsCOMPtr<nsILocalFile> &result)
281+
{
282+
return GetFile(dir, NS_LITERAL_CSTRING("update.version"), result);
283+
}
284+
285+
// Compares the current application version with the update's application
286+
// version.
287+
static PRBool
288+
IsOlderVersion(nsILocalFile *versionFile, const char *&appVersion)
289+
{
290+
nsresult rv;
291+
292+
FILE *fp;
293+
rv = versionFile->OpenANSIFileDesc("r", &fp);
294+
if (NS_FAILED(rv))
295+
return PR_TRUE;
296+
297+
char buf[32];
298+
char *result = fgets(buf, sizeof(buf), fp);
299+
fclose(fp);
300+
if (!result)
301+
return PR_TRUE;
302+
303+
// If the update xml doesn't provide the application version the file will
304+
// contain the string "null" and it is assumed that the update is not older.
305+
const char kNull[] = "null";
306+
if (strncmp(buf, kNull, sizeof(kNull) - 1) == 0)
307+
return PR_FALSE;
308+
309+
if (NS_CompareVersions(appVersion, result) > 0)
310+
return PR_TRUE;
311+
312+
return PR_FALSE;
313+
}
314+
277315
static PRBool
278316
CopyFileIntoUpdateDir(nsIFile *parentDir, const char *leafName, nsIFile *updateDir)
279317
{
@@ -505,7 +543,7 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsILocalFile *statusFile,
505543

506544
nsresult
507545
ProcessUpdates(nsIFile *greDir, nsIFile *appDir, nsIFile *updRootDir,
508-
int argc, char **argv)
546+
int argc, char **argv, const char *&appVersion)
509547
{
510548
nsresult rv;
511549

@@ -533,6 +571,16 @@ ProcessUpdates(nsIFile *greDir, nsIFile *appDir, nsIFile *updRootDir,
533571
for (int i = 0; i < dirEntries.Count(); ++i) {
534572
nsCOMPtr<nsILocalFile> statusFile;
535573
if (GetStatusFile(dirEntries[i], statusFile) && IsPending(statusFile)) {
574+
nsCOMPtr<nsILocalFile> versionFile;
575+
// Remove the update if the update application version file doesn't exist
576+
// or if the update's application version is less than the current
577+
// application version.
578+
if (!GetVersionFile(dirEntries[i], versionFile) ||
579+
IsOlderVersion(versionFile, appVersion)) {
580+
dirEntries[i]->Remove(PR_TRUE);
581+
continue;
582+
}
583+
536584
ApplyUpdate(greDir, dirEntries[i], statusFile, appDir, argc, argv);
537585
break;
538586
}

toolkit/xre/nsUpdateDriver.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
* Contributor(s):
2323
* Darin Fisher <darin@meer.net>
2424
* Ben Turner <mozilla@songbirdnest.com>
25+
* Robert Strong <robert.bugzilla@gmail.com>
2526
*
2627
* Alternatively, the contents of this file may be used under the terms of
2728
* either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -55,10 +56,15 @@ class nsIFile;
5556
* The argc and argv passed to this function should be what is needed to
5657
* relaunch the current process.
5758
*
59+
* The appVersion param passed to this function is the current application's
60+
* version and is used to determine if an update's version is older than the
61+
* current application version.
62+
*
5863
* This function does not modify appDir.
5964
*/
6065
NS_HIDDEN_(nsresult) ProcessUpdates(nsIFile *greDir, nsIFile *appDir,
6166
nsIFile *updRootDir,
62-
int argc, char **argv);
67+
int argc, char **argv,
68+
const char *&appVersion);
6369

6470
#endif // nsUpdateDriver_h__

0 commit comments

Comments
 (0)