summaryrefslogtreecommitdiff
path: root/onlineupdate
diff options
context:
space:
mode:
authorMarkus Mohrhard <markus.mohrhard@googlemail.com>2016-08-29 01:20:07 +0200
committerMarkus Mohrhard <markus.mohrhard@googlemail.com>2017-05-19 03:43:21 +0200
commit853e54226d628b9fc1ac4947e92152066222580d (patch)
treef8c6c8bb68553b521759c5453ebf83eb8441e2ba /onlineupdate
parent011ae9799090faeb8729620396cc942aa2f8c153 (diff)
adapt indentation to LibO defaults
Change-Id: I652428a2f11f12d7a2b54d3d425fc6034e1cbbe3
Diffstat (limited to 'onlineupdate')
-rw-r--r--onlineupdate/source/update/updater/updater.cxx5076
1 files changed, 2538 insertions, 2538 deletions
diff --git a/onlineupdate/source/update/updater/updater.cxx b/onlineupdate/source/update/updater/updater.cxx
index 1f04d61d7bc5..8df53177e437 100644
--- a/onlineupdate/source/update/updater/updater.cxx
+++ b/onlineupdate/source/update/updater/updater.cxx
@@ -106,14 +106,14 @@ void LaunchMacPostProcess(const char* aAppBundle);
// return code specified. This prevents multiple launches of the callback
// application by preventing the elevated process from launching the callback.
#define EXIT_WHEN_ELEVATED(path, handle, retCode) \
- { \
- if (handle != INVALID_HANDLE_VALUE) { \
+{ \
+ if (handle != INVALID_HANDLE_VALUE) { \
CloseHandle(handle); \
- } \
- if (_waccess(path, F_OK) == 0 && NS_tremove(path) != 0) { \
+ } \
+ if (_waccess(path, F_OK) == 0 && NS_tremove(path) != 0) { \
return retCode; \
- } \
- }
+ } \
+}
#endif
//-----------------------------------------------------------------------------
@@ -131,14 +131,14 @@ extern "C" unsigned int BZ2_crc32Table[256];
static unsigned int
crc32(const unsigned char *buf, unsigned int len)
{
- unsigned int crc = 0xffffffffL;
+ unsigned int crc = 0xffffffffL;
- const unsigned char *end = buf + len;
- for (; buf != end; ++buf)
- crc = (crc << 8) ^ BZ2_crc32Table[(crc >> 24) ^ *buf];
+ const unsigned char *end = buf + len;
+ for (; buf != end; ++buf)
+ crc = (crc << 8) ^ BZ2_crc32Table[(crc >> 24) ^ *buf];
- crc = ~crc;
- return crc;
+ crc = ~crc;
+ return crc;
}
//-----------------------------------------------------------------------------
@@ -148,41 +148,41 @@ crc32(const unsigned char *buf, unsigned int len)
class AutoFile
{
public:
- explicit AutoFile(FILE* file = nullptr)
- : mFile(file) {
- }
-
- ~AutoFile() {
- if (mFile != nullptr)
- fclose(mFile);
- }
-
- AutoFile &operator=(FILE* file) {
- if (mFile != 0)
- fclose(mFile);
- mFile = file;
- return *this;
- }
-
- operator FILE*() {
- return mFile;
- }
-
- FILE* get() {
- return mFile;
- }
+ explicit AutoFile(FILE* file = nullptr)
+ : mFile(file) {
+ }
+
+ ~AutoFile() {
+ if (mFile != nullptr)
+ fclose(mFile);
+ }
+
+ AutoFile &operator=(FILE* file) {
+ if (mFile != 0)
+ fclose(mFile);
+ mFile = file;
+ return *this;
+ }
+
+ operator FILE*() {
+ return mFile;
+ }
+
+ FILE* get() {
+ return mFile;
+ }
private:
- FILE* mFile;
+ FILE* mFile;
};
struct MARChannelStringTable {
- MARChannelStringTable()
- {
- MARChannelID[0] = '\0';
- }
+ MARChannelStringTable()
+ {
+ MARChannelID[0] = '\0';
+ }
- char MARChannelID[MAX_TEXT_LEN];
+ char MARChannelID[MAX_TEXT_LEN];
};
//-----------------------------------------------------------------------------
@@ -211,55 +211,55 @@ static const NS_tchar kQuote[] = NS_T("\"");
static inline size_t
mmin(size_t a, size_t b)
{
- return (a > b) ? b : a;
+ return (a > b) ? b : a;
}
static NS_tchar*
mstrtok(const NS_tchar *delims, NS_tchar **str)
{
- if (!*str || !**str) {
+ if (!*str || !**str) {
+ *str = nullptr;
+ return nullptr;
+ }
+
+ // skip leading "whitespace"
+ NS_tchar *ret = *str;
+ const NS_tchar *d;
+ do {
+ for (d = delims; *d != NS_T('\0'); ++d) {
+ if (*ret == *d) {
+ ++ret;
+ break;
+ }
+ }
+ } while (*d);
+
+ if (!*ret) {
+ *str = ret;
+ return nullptr;
+ }
+
+ NS_tchar *i = ret;
+ do {
+ for (d = delims; *d != NS_T('\0'); ++d) {
+ if (*i == *d) {
+ *i = NS_T('\0');
+ *str = ++i;
+ return ret;
+ }
+ }
+ ++i;
+ } while (*i);
+
*str = nullptr;
- return nullptr;
- }
-
- // skip leading "whitespace"
- NS_tchar *ret = *str;
- const NS_tchar *d;
- do {
- for (d = delims; *d != NS_T('\0'); ++d) {
- if (*ret == *d) {
- ++ret;
- break;
- }
- }
- } while (*d);
-
- if (!*ret) {
- *str = ret;
- return nullptr;
- }
-
- NS_tchar *i = ret;
- do {
- for (d = delims; *d != NS_T('\0'); ++d) {
- if (*i == *d) {
- *i = NS_T('\0');
- *str = ++i;
- return ret;
- }
- }
- ++i;
- } while (*i);
-
- *str = nullptr;
- return ret;
+ return ret;
}
static bool
EnvHasValue(const char *name)
{
- const char *val = getenv(name);
- return (val && *val);
+ const char *val = getenv(name);
+ return (val && *val);
}
#ifdef _WIN32
@@ -273,21 +273,21 @@ EnvHasValue(const char *name)
static NS_tchar*
get_full_path(const NS_tchar *relpath)
{
- size_t lendestpath = NS_tstrlen(gDestPath);
- size_t lenrelpath = NS_tstrlen(relpath);
- NS_tchar *s = (NS_tchar *) malloc((lendestpath + lenrelpath + 1) * sizeof(NS_tchar));
- if (!s)
- return nullptr;
+ size_t lendestpath = NS_tstrlen(gDestPath);
+ size_t lenrelpath = NS_tstrlen(relpath);
+ NS_tchar *s = (NS_tchar *) malloc((lendestpath + lenrelpath + 1) * sizeof(NS_tchar));
+ if (!s)
+ return nullptr;
- NS_tchar *c = s;
+ NS_tchar *c = s;
- NS_tstrcpy(c, gDestPath);
- c += lendestpath;
- NS_tstrcat(c, relpath);
- c += lenrelpath;
- *c = NS_T('\0');
- c++;
- return s;
+ NS_tstrcpy(c, gDestPath);
+ c += lendestpath;
+ NS_tstrcat(c, relpath);
+ c += lenrelpath;
+ *c = NS_T('\0');
+ c++;
+ return s;
}
#endif
@@ -304,235 +304,235 @@ get_full_path(const NS_tchar *relpath)
static NS_tchar*
get_valid_path(NS_tchar **line, bool isdir = false)
{
- NS_tchar *path = mstrtok(kQuote, line);
- if (!path) {
- LOG(("get_valid_path: unable to determine path: " LOG_S, line));
- return nullptr;
- }
+ NS_tchar *path = mstrtok(kQuote, line);
+ if (!path) {
+ LOG(("get_valid_path: unable to determine path: " LOG_S, line));
+ return nullptr;
+ }
- // All paths must be relative from the current working directory
- if (path[0] == NS_T('/')) {
- LOG(("get_valid_path: path must be relative: " LOG_S, path));
- return nullptr;
- }
+ // All paths must be relative from the current working directory
+ if (path[0] == NS_T('/')) {
+ LOG(("get_valid_path: path must be relative: " LOG_S, path));
+ return nullptr;
+ }
#ifdef _WIN32
- // All paths must be relative from the current working directory
- if (path[0] == NS_T('\\') || path[1] == NS_T(':')) {
- LOG(("get_valid_path: path must be relative: " LOG_S, path));
- return nullptr;
- }
+ // All paths must be relative from the current working directory
+ if (path[0] == NS_T('\\') || path[1] == NS_T(':')) {
+ LOG(("get_valid_path: path must be relative: " LOG_S, path));
+ return nullptr;
+ }
#endif
- if (isdir) {
- // Directory paths must have a trailing forward slash.
- if (path[NS_tstrlen(path) - 1] != NS_T('/')) {
- LOG(("get_valid_path: directory paths must have a trailing forward " \
- "slash: " LOG_S, path));
- return nullptr;
- }
+ if (isdir) {
+ // Directory paths must have a trailing forward slash.
+ if (path[NS_tstrlen(path) - 1] != NS_T('/')) {
+ LOG(("get_valid_path: directory paths must have a trailing forward " \
+ "slash: " LOG_S, path));
+ return nullptr;
+ }
- // Remove the trailing forward slash because stat on Windows will return
- // ENOENT if the path has a trailing slash.
- path[NS_tstrlen(path) - 1] = NS_T('\0');
- }
+ // Remove the trailing forward slash because stat on Windows will return
+ // ENOENT if the path has a trailing slash.
+ path[NS_tstrlen(path) - 1] = NS_T('\0');
+ }
- // Don't allow relative paths that resolve to a parent directory.
- if (NS_tstrstr(path, NS_T("..")) != nullptr) {
- LOG(("get_valid_path: paths must not contain '..': " LOG_S, path));
- return nullptr;
- }
+ // Don't allow relative paths that resolve to a parent directory.
+ if (NS_tstrstr(path, NS_T("..")) != nullptr) {
+ LOG(("get_valid_path: paths must not contain '..': " LOG_S, path));
+ return nullptr;
+ }
- return path;
+ return path;
}
static NS_tchar*
get_quoted_path(const NS_tchar *path)
{
- size_t lenQuote = NS_tstrlen(kQuote);
- size_t lenPath = NS_tstrlen(path);
- size_t len = lenQuote + lenPath + lenQuote + 1;
-
- NS_tchar *s = (NS_tchar *) malloc(len * sizeof(NS_tchar));
- if (!s)
- return nullptr;
-
- NS_tchar *c = s;
- NS_tstrcpy(c, kQuote);
- c += lenQuote;
- NS_tstrcat(c, path);
- c += lenPath;
- NS_tstrcat(c, kQuote);
- c += lenQuote;
- *c = NS_T('\0');
- c++;
- return s;
+ size_t lenQuote = NS_tstrlen(kQuote);
+ size_t lenPath = NS_tstrlen(path);
+ size_t len = lenQuote + lenPath + lenQuote + 1;
+
+ NS_tchar *s = (NS_tchar *) malloc(len * sizeof(NS_tchar));
+ if (!s)
+ return nullptr;
+
+ NS_tchar *c = s;
+ NS_tstrcpy(c, kQuote);
+ c += lenQuote;
+ NS_tstrcat(c, path);
+ c += lenPath;
+ NS_tstrcat(c, kQuote);
+ c += lenQuote;
+ *c = NS_T('\0');
+ c++;
+ return s;
}
static void ensure_write_permissions(const NS_tchar *path)
{
#ifdef _WIN32
- (void) _wchmod(path, _S_IREAD | _S_IWRITE);
+ (void) _wchmod(path, _S_IREAD | _S_IWRITE);
#else
- struct stat fs;
- if (!stat(path, &fs) && !(fs.st_mode & S_IWUSR)) {
- (void)chmod(path, fs.st_mode | S_IWUSR);
- }
+ struct stat fs;
+ if (!stat(path, &fs) && !(fs.st_mode & S_IWUSR)) {
+ (void)chmod(path, fs.st_mode | S_IWUSR);
+ }
#endif
}
static int ensure_remove(const NS_tchar *path)
{
- ensure_write_permissions(path);
- int rv = NS_tremove(path);
- if (rv)
- LOG(("ensure_remove: failed to remove file: " LOG_S ", rv: %d, err: %d",
- path, rv, errno));
- return rv;
+ ensure_write_permissions(path);
+ int rv = NS_tremove(path);
+ if (rv)
+ LOG(("ensure_remove: failed to remove file: " LOG_S ", rv: %d, err: %d",
+ path, rv, errno));
+ return rv;
}
// Remove the directory pointed to by path and all of its files and sub-directories.
static int ensure_remove_recursive(const NS_tchar *path,
- bool continueEnumOnFailure = false)
-{
- // We use lstat rather than stat here so that we can successfully remove
- // symlinks.
- struct NS_tstat_t sInfo;
- int rv = NS_tlstat(path, &sInfo);
- if (rv) {
- // This error is benign
- return rv;
- }
- if (!S_ISDIR(sInfo.st_mode)) {
- return ensure_remove(path);
- }
-
- NS_tDIR *dir;
- NS_tdirent *entry;
-
- dir = NS_topendir(path);
- if (!dir) {
- LOG(("ensure_remove_recursive: unable to open directory: " LOG_S
- ", rv: %d, err: %d", path, rv, errno));
- return rv;
- }
+ bool continueEnumOnFailure = false)
+{
+ // We use lstat rather than stat here so that we can successfully remove
+ // symlinks.
+ struct NS_tstat_t sInfo;
+ int rv = NS_tlstat(path, &sInfo);
+ if (rv) {
+ // This error is benign
+ return rv;
+ }
+ if (!S_ISDIR(sInfo.st_mode)) {
+ return ensure_remove(path);
+ }
- while ((entry = NS_treaddir(dir)) != 0) {
- if (NS_tstrcmp(entry->d_name, NS_T(".")) &&
- NS_tstrcmp(entry->d_name, NS_T(".."))) {
- NS_tchar childPath[MAXPATHLEN];
- NS_tsnprintf(childPath, sizeof(childPath)/sizeof(childPath[0]),
- NS_T("%s/%s"), path, entry->d_name);
- rv = ensure_remove_recursive(childPath);
- if (rv && !continueEnumOnFailure) {
- break;
- }
+ NS_tDIR *dir;
+ NS_tdirent *entry;
+
+ dir = NS_topendir(path);
+ if (!dir) {
+ LOG(("ensure_remove_recursive: unable to open directory: " LOG_S
+ ", rv: %d, err: %d", path, rv, errno));
+ return rv;
}
- }
- NS_tclosedir(dir);
+ while ((entry = NS_treaddir(dir)) != 0) {
+ if (NS_tstrcmp(entry->d_name, NS_T(".")) &&
+ NS_tstrcmp(entry->d_name, NS_T(".."))) {
+ NS_tchar childPath[MAXPATHLEN];
+ NS_tsnprintf(childPath, sizeof(childPath)/sizeof(childPath[0]),
+ NS_T("%s/%s"), path, entry->d_name);
+ rv = ensure_remove_recursive(childPath);
+ if (rv && !continueEnumOnFailure) {
+ break;
+ }
+ }
+ }
- if (rv == OK) {
- ensure_write_permissions(path);
- rv = NS_trmdir(path);
- if (rv) {
- LOG(("ensure_remove_recursive: unable to remove directory: " LOG_S
- ", rv: %d, err: %d", path, rv, errno));
+ NS_tclosedir(dir);
+
+ if (rv == OK) {
+ ensure_write_permissions(path);
+ rv = NS_trmdir(path);
+ if (rv) {
+ LOG(("ensure_remove_recursive: unable to remove directory: " LOG_S
+ ", rv: %d, err: %d", path, rv, errno));
+ }
}
- }
- return rv;
+ return rv;
}
static bool is_read_only(const NS_tchar *flags)
{
- size_t length = NS_tstrlen(flags);
- if (length == 0)
- return false;
+ size_t length = NS_tstrlen(flags);
+ if (length == 0)
+ return false;
- // Make sure the string begins with "r"
- if (flags[0] != NS_T('r'))
- return false;
+ // Make sure the string begins with "r"
+ if (flags[0] != NS_T('r'))
+ return false;
- // Look for "r+" or "r+b"
- if (length > 1 && flags[1] == NS_T('+'))
- return false;
+ // Look for "r+" or "r+b"
+ if (length > 1 && flags[1] == NS_T('+'))
+ return false;
- // Look for "rb+"
- if (NS_tstrcmp(flags, NS_T("rb+")) == 0)
- return false;
+ // Look for "rb+"
+ if (NS_tstrcmp(flags, NS_T("rb+")) == 0)
+ return false;
- return true;
+ return true;
}
static FILE* ensure_open(const NS_tchar *path, const NS_tchar *flags, unsigned int options)
{
- ensure_write_permissions(path);
- FILE* f = NS_tfopen(path, flags);
- if (is_read_only(flags)) {
- // Don't attempt to modify the file permissions if the file is being opened
- // in read-only mode.
- return f;
- }
- if (NS_tchmod(path, options) != 0) {
- if (f != nullptr) {
- fclose(f);
+ ensure_write_permissions(path);
+ FILE* f = NS_tfopen(path, flags);
+ if (is_read_only(flags)) {
+ // Don't attempt to modify the file permissions if the file is being opened
+ // in read-only mode.
+ return f;
+ }
+ if (NS_tchmod(path, options) != 0) {
+ if (f != nullptr) {
+ fclose(f);
+ }
+ return nullptr;
}
- return nullptr;
- }
- struct NS_tstat_t ss;
- if (NS_tstat(path, &ss) != 0 || ss.st_mode != options) {
- if (f != nullptr) {
- fclose(f);
+ struct NS_tstat_t ss;
+ if (NS_tstat(path, &ss) != 0 || ss.st_mode != options) {
+ if (f != nullptr) {
+ fclose(f);
+ }
+ return nullptr;
}
- return nullptr;
- }
- return f;
+ return f;
}
// Ensure that the directory containing this file exists.
static int ensure_parent_dir(const NS_tchar *path)
{
- int rv = OK;
-
- NS_tchar *slash = (NS_tchar *) NS_tstrrchr(path, NS_T('/'));
- if (slash) {
- *slash = NS_T('\0');
- rv = ensure_parent_dir(path);
- // Only attempt to create the directory if we're not at the root
- if (rv == OK && *path) {
- rv = NS_tmkdir(path, 0755);
- // If the directory already exists, then ignore the error.
- if (rv < 0 && errno != EEXIST) {
- LOG(("ensure_parent_dir: failed to create directory: " LOG_S ", " \
- "err: %d", path, errno));
- rv = WRITE_ERROR;
- } else {
- rv = OK;
- }
- }
- *slash = NS_T('/');
- }
- return rv;
+ int rv = OK;
+
+ NS_tchar *slash = (NS_tchar *) NS_tstrrchr(path, NS_T('/'));
+ if (slash) {
+ *slash = NS_T('\0');
+ rv = ensure_parent_dir(path);
+ // Only attempt to create the directory if we're not at the root
+ if (rv == OK && *path) {
+ rv = NS_tmkdir(path, 0755);
+ // If the directory already exists, then ignore the error.
+ if (rv < 0 && errno != EEXIST) {
+ LOG(("ensure_parent_dir: failed to create directory: " LOG_S ", " \
+ "err: %d", path, errno));
+ rv = WRITE_ERROR;
+ } else {
+ rv = OK;
+ }
+ }
+ *slash = NS_T('/');
+ }
+ return rv;
}
#ifdef UNIX
static int ensure_copy_symlink(const NS_tchar *path, const NS_tchar *dest)
{
- // Copy symlinks by creating a new symlink to the same target
- NS_tchar target[MAXPATHLEN + 1] = {NS_T('\0')};
- int rv = readlink(path, target, MAXPATHLEN);
- if (rv == -1) {
- LOG(("ensure_copy_symlink: failed to read the link: " LOG_S ", err: %d",
- path, errno));
- return READ_ERROR;
- }
- rv = symlink(target, dest);
- if (rv == -1) {
- LOG(("ensure_copy_symlink: failed to create the new link: " LOG_S ", target: " LOG_S " err: %d",
- dest, target, errno));
- return READ_ERROR;
- }
- return 0;
+ // Copy symlinks by creating a new symlink to the same target
+ NS_tchar target[MAXPATHLEN + 1] = {NS_T('\0')};
+ int rv = readlink(path, target, MAXPATHLEN);
+ if (rv == -1) {
+ LOG(("ensure_copy_symlink: failed to read the link: " LOG_S ", err: %d",
+ path, errno));
+ return READ_ERROR;
+ }
+ rv = symlink(target, dest);
+ if (rv == -1) {
+ LOG(("ensure_copy_symlink: failed to create the new link: " LOG_S ", target: " LOG_S " err: %d",
+ dest, target, errno));
+ return READ_ERROR;
+ }
+ return 0;
}
#endif
@@ -547,11 +547,11 @@ static int ensure_copy_symlink(const NS_tchar *path, const NS_tchar *dest)
static int
create_hard_link(const NS_tchar *srcFilename, const NS_tchar *destFilename)
{
- if (link(srcFilename, destFilename) < 0) {
- LOG(("link(%s, %s) failed errno = %d", srcFilename, destFilename, errno));
- return WRITE_ERROR;
- }
- return OK;
+ if (link(srcFilename, destFilename) < 0) {
+ LOG(("link(%s, %s) failed errno = %d", srcFilename, destFilename, errno));
+ return WRITE_ERROR;
+ }
+ return OK;
}
#endif
@@ -559,214 +559,214 @@ create_hard_link(const NS_tchar *srcFilename, const NS_tchar *destFilename)
static int ensure_copy(const NS_tchar *path, const NS_tchar *dest)
{
#ifdef _WIN32
- // Fast path for Windows
- bool result = CopyFileW(path, dest, false);
- if (!result) {
- LOG(("ensure_copy: failed to copy the file " LOG_S " over to " LOG_S ", lasterr: %x",
- path, dest, GetLastError()));
- return WRITE_ERROR_FILE_COPY;
- }
- return OK;
+ // Fast path for Windows
+ bool result = CopyFileW(path, dest, false);
+ if (!result) {
+ LOG(("ensure_copy: failed to copy the file " LOG_S " over to " LOG_S ", lasterr: %x",
+ path, dest, GetLastError()));
+ return WRITE_ERROR_FILE_COPY;
+ }
+ return OK;
#else
- struct NS_tstat_t ss;
- int rv = NS_tlstat(path, &ss);
- if (rv) {
- LOG(("ensure_copy: failed to read file status info: " LOG_S ", err: %d",
- path, errno));
- return READ_ERROR;
- }
+ struct NS_tstat_t ss;
+ int rv = NS_tlstat(path, &ss);
+ if (rv) {
+ LOG(("ensure_copy: failed to read file status info: " LOG_S ", err: %d",
+ path, errno));
+ return READ_ERROR;
+ }
#ifdef UNIX
- if (S_ISLNK(ss.st_mode)) {
- return ensure_copy_symlink(path, dest);
- }
+ if (S_ISLNK(ss.st_mode)) {
+ return ensure_copy_symlink(path, dest);
+ }
#endif
#if MAYBE_USE_HARD_LINKS
- if (sUseHardLinks) {
- if (!create_hard_link(path, dest)) {
- return OK;
+ if (sUseHardLinks) {
+ if (!create_hard_link(path, dest)) {
+ return OK;
+ }
+ // Since we failed to create the hard link, fall through and copy the file.
+ sUseHardLinks = false;
}
- // Since we failed to create the hard link, fall through and copy the file.
- sUseHardLinks = false;
- }
#endif
- AutoFile infile(ensure_open(path, NS_T("rb"), ss.st_mode));
- if (!infile) {
- LOG(("ensure_copy: failed to open the file for reading: " LOG_S ", err: %d",
- path, errno));
- return READ_ERROR;
- }
- AutoFile outfile(ensure_open(dest, NS_T("wb"), ss.st_mode));
- if (!outfile) {
- LOG(("ensure_copy: failed to open the file for writing: " LOG_S ", err: %d",
- dest, errno));
- return WRITE_ERROR;
- }
-
- // This block size was chosen pretty arbitrarily but seems like a reasonable
- // compromise. For example, the optimal block size on a modern OS X machine
- // is 100k */
- const int blockSize = 32 * 1024;
- void* buffer = malloc(blockSize);
- if (!buffer)
- return UPDATER_MEM_ERROR;
-
- while (!feof(infile.get())) {
- size_t read = fread(buffer, 1, blockSize, infile);
- if (ferror(infile.get())) {
- LOG(("ensure_copy: failed to read the file: " LOG_S ", err: %d",
- path, errno));
- free(buffer);
- return READ_ERROR;
- }
-
- size_t written = 0;
-
- while (written < read) {
- size_t chunkWritten = fwrite(buffer, 1, read - written, outfile);
- if (chunkWritten <= 0) {
- LOG(("ensure_copy: failed to write the file: " LOG_S ", err: %d",
- dest, errno));
- free(buffer);
- return WRITE_ERROR_FILE_COPY;
- }
+ AutoFile infile(ensure_open(path, NS_T("rb"), ss.st_mode));
+ if (!infile) {
+ LOG(("ensure_copy: failed to open the file for reading: " LOG_S ", err: %d",
+ path, errno));
+ return READ_ERROR;
+ }
+ AutoFile outfile(ensure_open(dest, NS_T("wb"), ss.st_mode));
+ if (!outfile) {
+ LOG(("ensure_copy: failed to open the file for writing: " LOG_S ", err: %d",
+ dest, errno));
+ return WRITE_ERROR;
+ }
+
+ // This block size was chosen pretty arbitrarily but seems like a reasonable
+ // compromise. For example, the optimal block size on a modern OS X machine
+ // is 100k */
+ const int blockSize = 32 * 1024;
+ void* buffer = malloc(blockSize);
+ if (!buffer)
+ return UPDATER_MEM_ERROR;
+
+ while (!feof(infile.get())) {
+ size_t read = fread(buffer, 1, blockSize, infile);
+ if (ferror(infile.get())) {
+ LOG(("ensure_copy: failed to read the file: " LOG_S ", err: %d",
+ path, errno));
+ free(buffer);
+ return READ_ERROR;
+ }
+
+ size_t written = 0;
- written += chunkWritten;
+ while (written < read) {
+ size_t chunkWritten = fwrite(buffer, 1, read - written, outfile);
+ if (chunkWritten <= 0) {
+ LOG(("ensure_copy: failed to write the file: " LOG_S ", err: %d",
+ dest, errno));
+ free(buffer);
+ return WRITE_ERROR_FILE_COPY;
+ }
+
+ written += chunkWritten;
+ }
}
- }
- rv = NS_tchmod(dest, ss.st_mode);
+ rv = NS_tchmod(dest, ss.st_mode);
- free(buffer);
- return rv;
+ free(buffer);
+ return rv;
#endif
}
template <unsigned N>
struct copy_recursive_skiplist {
- NS_tchar paths[N][MAXPATHLEN];
+ NS_tchar paths[N][MAXPATHLEN];
- void append(unsigned index, const NS_tchar *path, const NS_tchar *suffix) {
- NS_tsnprintf(paths[index], MAXPATHLEN, NS_T("%s/%s"), path, suffix);
- }
+ void append(unsigned index, const NS_tchar *path, const NS_tchar *suffix) {
+ NS_tsnprintf(paths[index], MAXPATHLEN, NS_T("%s/%s"), path, suffix);
+ }
- bool find(const NS_tchar *path) {
- for (int i = 0; i < static_cast<int>(N); ++i) {
- if (!NS_tstricmp(paths[i], path)) {
- return true;
- }
+ bool find(const NS_tchar *path) {
+ for (int i = 0; i < static_cast<int>(N); ++i) {
+ if (!NS_tstricmp(paths[i], path)) {
+ return true;
+ }
+ }
+ return false;
}
- return false;
- }
};
// Copy all of the files and subdirectories under path to a new directory named dest.
// The path names in the skiplist will be skipped and will not be copied.
template <unsigned N>
static int ensure_copy_recursive(const NS_tchar *path, const NS_tchar *dest,
- copy_recursive_skiplist<N>& skiplist)
+ copy_recursive_skiplist<N>& skiplist)
{
- struct NS_tstat_t sInfo;
- int rv = NS_tlstat(path, &sInfo);
- if (rv) {
- LOG(("ensure_copy_recursive: path doesn't exist: " LOG_S ", rv: %d, err: %d",
- path, rv, errno));
- return READ_ERROR;
- }
+ struct NS_tstat_t sInfo;
+ int rv = NS_tlstat(path, &sInfo);
+ if (rv) {
+ LOG(("ensure_copy_recursive: path doesn't exist: " LOG_S ", rv: %d, err: %d",
+ path, rv, errno));
+ return READ_ERROR;
+ }
#ifdef UNIX
- if (S_ISLNK(sInfo.st_mode)) {
- return ensure_copy_symlink(path, dest);
- }
+ if (S_ISLNK(sInfo.st_mode)) {
+ return ensure_copy_symlink(path, dest);
+ }
#endif
- if (!S_ISDIR(sInfo.st_mode)) {
- return ensure_copy(path, dest);
- }
-
- rv = NS_tmkdir(dest, sInfo.st_mode);
- if (rv < 0 && errno != EEXIST) {
- LOG(("ensure_copy_recursive: could not create destination directory: " LOG_S ", rv: %d, err: %d",
- path, rv, errno));
- return WRITE_ERROR;
- }
-
- NS_tDIR *dir;
- NS_tdirent *entry;
-
- dir = NS_topendir(path);
- if (!dir) {
- LOG(("ensure_copy_recursive: path is not a directory: " LOG_S ", rv: %d, err: %d",
- path, rv, errno));
- return READ_ERROR;
- }
-
- while ((entry = NS_treaddir(dir)) != 0) {
- if (NS_tstrcmp(entry->d_name, NS_T(".")) &&
- NS_tstrcmp(entry->d_name, NS_T(".."))) {
- NS_tchar childPath[MAXPATHLEN];
- NS_tsnprintf(childPath, sizeof(childPath)/sizeof(childPath[0]),
- NS_T("%s/%s"), path, entry->d_name);
- if (skiplist.find(childPath)) {
- continue;
- }
- NS_tchar childPathDest[MAXPATHLEN];
- NS_tsnprintf(childPathDest, sizeof(childPathDest)/sizeof(childPathDest[0]),
- NS_T("%s/%s"), dest, entry->d_name);
- rv = ensure_copy_recursive(childPath, childPathDest, skiplist);
- if (rv) {
- break;
- }
- }
- }
- NS_tclosedir(dir);
- return rv;
+ if (!S_ISDIR(sInfo.st_mode)) {
+ return ensure_copy(path, dest);
+ }
+
+ rv = NS_tmkdir(dest, sInfo.st_mode);
+ if (rv < 0 && errno != EEXIST) {
+ LOG(("ensure_copy_recursive: could not create destination directory: " LOG_S ", rv: %d, err: %d",
+ path, rv, errno));
+ return WRITE_ERROR;
+ }
+
+ NS_tDIR *dir;
+ NS_tdirent *entry;
+
+ dir = NS_topendir(path);
+ if (!dir) {
+ LOG(("ensure_copy_recursive: path is not a directory: " LOG_S ", rv: %d, err: %d",
+ path, rv, errno));
+ return READ_ERROR;
+ }
+
+ while ((entry = NS_treaddir(dir)) != 0) {
+ if (NS_tstrcmp(entry->d_name, NS_T(".")) &&
+ NS_tstrcmp(entry->d_name, NS_T(".."))) {
+ NS_tchar childPath[MAXPATHLEN];
+ NS_tsnprintf(childPath, sizeof(childPath)/sizeof(childPath[0]),
+ NS_T("%s/%s"), path, entry->d_name);
+ if (skiplist.find(childPath)) {
+ continue;
+ }
+ NS_tchar childPathDest[MAXPATHLEN];
+ NS_tsnprintf(childPathDest, sizeof(childPathDest)/sizeof(childPathDest[0]),
+ NS_T("%s/%s"), dest, entry->d_name);
+ rv = ensure_copy_recursive(childPath, childPathDest, skiplist);
+ if (rv) {
+ break;
+ }
+ }
+ }
+ NS_tclosedir(dir);
+ return rv;
}
// Renames the specified file to the new file specified. If the destination file
// exists it is removed.
static int rename_file(const NS_tchar *spath, const NS_tchar *dpath,
- bool allowDirs = false)
+ bool allowDirs = false)
{
- int rv = ensure_parent_dir(dpath);
- if (rv)
- return rv;
+ int rv = ensure_parent_dir(dpath);
+ if (rv)
+ return rv;
- struct NS_tstat_t spathInfo;
- rv = NS_tstat(spath, &spathInfo);
- if (rv) {
- LOG(("rename_file: failed to read file status info: " LOG_S ", " \
- "err: %d", spath, errno));
- return READ_ERROR;
- }
-
- if (!S_ISREG(spathInfo.st_mode)) {
- if (allowDirs && !S_ISDIR(spathInfo.st_mode)) {
- LOG(("rename_file: path present, but not a file: " LOG_S ", err: %d",
- spath, errno));
- return RENAME_ERROR_EXPECTED_FILE;
- } else {
- LOG(("rename_file: proceeding to rename the directory"));
+ struct NS_tstat_t spathInfo;
+ rv = NS_tstat(spath, &spathInfo);
+ if (rv) {
+ LOG(("rename_file: failed to read file status info: " LOG_S ", " \
+ "err: %d", spath, errno));
+ return READ_ERROR;
}
- }
- if (!NS_taccess(dpath, F_OK)) {
- if (ensure_remove(dpath)) {
- LOG(("rename_file: destination file exists and could not be " \
- "removed: " LOG_S, dpath));
- return WRITE_ERROR_DELETE_FILE;
+ if (!S_ISREG(spathInfo.st_mode)) {
+ if (allowDirs && !S_ISDIR(spathInfo.st_mode)) {
+ LOG(("rename_file: path present, but not a file: " LOG_S ", err: %d",
+ spath, errno));
+ return RENAME_ERROR_EXPECTED_FILE;
+ } else {
+ LOG(("rename_file: proceeding to rename the directory"));
+ }
}
- }
- if (NS_trename(spath, dpath) != 0) {
- LOG(("rename_file: failed to rename file - src: " LOG_S ", " \
- "dst:" LOG_S ", err: %d", spath, dpath, errno));
- return WRITE_ERROR;
- }
+ if (!NS_taccess(dpath, F_OK)) {
+ if (ensure_remove(dpath)) {
+ LOG(("rename_file: destination file exists and could not be " \
+ "removed: " LOG_S, dpath));
+ return WRITE_ERROR_DELETE_FILE;
+ }
+ }
+
+ if (NS_trename(spath, dpath) != 0) {
+ LOG(("rename_file: failed to rename file - src: " LOG_S ", " \
+ "dst:" LOG_S ", err: %d", spath, dpath, errno));
+ return WRITE_ERROR;
+ }
- return OK;
+ return OK;
}
#ifdef _WIN32
@@ -775,64 +775,64 @@ static int rename_file(const NS_tchar *spath, const NS_tchar *dpath,
// and attempt to schedule removal of the file on reboot
static int remove_recursive_on_reboot(const NS_tchar *path, const NS_tchar *deleteDir)
{
- struct NS_tstat_t sInfo;
- int rv = NS_tlstat(path, &sInfo);
- if (rv) {
- // This error is benign
- return rv;
- }
-
- if (!S_ISDIR(sInfo.st_mode)) {
- NS_tchar tmpDeleteFile[MAXPATHLEN];
- GetTempFileNameW(deleteDir, L"rep", 0, tmpDeleteFile);
- NS_tremove(tmpDeleteFile);
- rv = rename_file(path, tmpDeleteFile, false);
- if (MoveFileEx(rv ? path : tmpDeleteFile, nullptr, MOVEFILE_DELAY_UNTIL_REBOOT)) {
- LOG(("remove_recursive_on_reboot: file will be removed on OS reboot: "
- LOG_S, rv ? path : tmpDeleteFile));
- } else {
- LOG(("remove_recursive_on_reboot: failed to schedule OS reboot removal of "
- "file: " LOG_S, rv ? path : tmpDeleteFile));
+ struct NS_tstat_t sInfo;
+ int rv = NS_tlstat(path, &sInfo);
+ if (rv) {
+ // This error is benign
+ return rv;
}
- return rv;
- }
- NS_tDIR *dir;
- NS_tdirent *entry;
+ if (!S_ISDIR(sInfo.st_mode)) {
+ NS_tchar tmpDeleteFile[MAXPATHLEN];
+ GetTempFileNameW(deleteDir, L"rep", 0, tmpDeleteFile);
+ NS_tremove(tmpDeleteFile);
+ rv = rename_file(path, tmpDeleteFile, false);
+ if (MoveFileEx(rv ? path : tmpDeleteFile, nullptr, MOVEFILE_DELAY_UNTIL_REBOOT)) {
+ LOG(("remove_recursive_on_reboot: file will be removed on OS reboot: "
+ LOG_S, rv ? path : tmpDeleteFile));
+ } else {
+ LOG(("remove_recursive_on_reboot: failed to schedule OS reboot removal of "
+ "file: " LOG_S, rv ? path : tmpDeleteFile));
+ }
+ return rv;
+ }
- dir = NS_topendir(path);
- if (!dir) {
- LOG(("remove_recursive_on_reboot: unable to open directory: " LOG_S
- ", rv: %d, err: %d",
- path, rv, errno));
- return rv;
- }
+ NS_tDIR *dir;
+ NS_tdirent *entry;
- while ((entry = NS_treaddir(dir)) != 0) {
- if (NS_tstrcmp(entry->d_name, NS_T(".")) &&
- NS_tstrcmp(entry->d_name, NS_T(".."))) {
- NS_tchar childPath[MAXPATHLEN];
- NS_tsnprintf(childPath, sizeof(childPath)/sizeof(childPath[0]),
- NS_T("%s/%s"), path, entry->d_name);
- // There is no need to check the return value of this call since this
- // function is only called after an update is successful and there is not
- // much that can be done to recover if it isn't successful. There is also
- // no need to log the value since it will have already been logged.
- remove_recursive_on_reboot(childPath, deleteDir);
+ dir = NS_topendir(path);
+ if (!dir) {
+ LOG(("remove_recursive_on_reboot: unable to open directory: " LOG_S
+ ", rv: %d, err: %d",
+ path, rv, errno));
+ return rv;
}
- }
- NS_tclosedir(dir);
+ while ((entry = NS_treaddir(dir)) != 0) {
+ if (NS_tstrcmp(entry->d_name, NS_T(".")) &&
+ NS_tstrcmp(entry->d_name, NS_T(".."))) {
+ NS_tchar childPath[MAXPATHLEN];
+ NS_tsnprintf(childPath, sizeof(childPath)/sizeof(childPath[0]),
+ NS_T("%s/%s"), path, entry->d_name);
+ // There is no need to check the return value of this call since this
+ // function is only called after an update is successful and there is not
+ // much that can be done to recover if it isn't successful. There is also
+ // no need to log the value since it will have already been logged.
+ remove_recursive_on_reboot(childPath, deleteDir);
+ }
+ }
- if (rv == OK) {
- ensure_write_permissions(path);
- rv = NS_trmdir(path);
- if (rv) {
- LOG(("remove_recursive_on_reboot: unable to remove directory: " LOG_S
- ", rv: %d, err: %d", path, rv, errno));
+ NS_tclosedir(dir);
+
+ if (rv == OK) {
+ ensure_write_permissions(path);
+ rv = NS_trmdir(path);
+ if (rv) {
+ LOG(("remove_recursive_on_reboot: unable to remove directory: " LOG_S
+ ", rv: %d, err: %d", path, rv, errno));
+ }
}
- }
- return rv;
+ return rv;
}
#endif
@@ -841,80 +841,80 @@ static int remove_recursive_on_reboot(const NS_tchar *path, const NS_tchar *dele
// Create a backup of the specified file by renaming it.
static int backup_create(const NS_tchar *path)
{
- NS_tchar backup[MAXPATHLEN];
- NS_tsnprintf(backup, sizeof(backup)/sizeof(backup[0]),
- NS_T("%s") BACKUP_EXT, path);
+ NS_tchar backup[MAXPATHLEN];
+ NS_tsnprintf(backup, sizeof(backup)/sizeof(backup[0]),
+ NS_T("%s") BACKUP_EXT, path);
- return rename_file(path, backup);
+ return rename_file(path, backup);
}
// Rename the backup of the specified file that was created by renaming it back
// to the original file.
static int backup_restore(const NS_tchar *path)
{
- NS_tchar backup[MAXPATHLEN];
- NS_tsnprintf(backup, sizeof(backup)/sizeof(backup[0]),
- NS_T("%s") BACKUP_EXT, path);
+ NS_tchar backup[MAXPATHLEN];
+ NS_tsnprintf(backup, sizeof(backup)/sizeof(backup[0]),
+ NS_T("%s") BACKUP_EXT, path);
- if (NS_taccess(backup, F_OK)) {
- LOG(("backup_restore: backup file doesn't exist: " LOG_S, backup));
- return OK;
- }
+ if (NS_taccess(backup, F_OK)) {
+ LOG(("backup_restore: backup file doesn't exist: " LOG_S, backup));
+ return OK;
+ }
- return rename_file(backup, path);
+ return rename_file(backup, path);
}
// Discard the backup of the specified file that was created by renaming it.
static int backup_discard(const NS_tchar *path)
{
- NS_tchar backup[MAXPATHLEN];
- NS_tsnprintf(backup, sizeof(backup)/sizeof(backup[0]),
- NS_T("%s") BACKUP_EXT, path);
+ NS_tchar backup[MAXPATHLEN];
+ NS_tsnprintf(backup, sizeof(backup)/sizeof(backup[0]),
+ NS_T("%s") BACKUP_EXT, path);
- // Nothing to discard
- if (NS_taccess(backup, F_OK)) {
- return OK;
- }
+ // Nothing to discard
+ if (NS_taccess(backup, F_OK)) {
+ return OK;
+ }
- int rv = ensure_remove(backup);
+ int rv = ensure_remove(backup);
#if defined(_WIN32)
- if (rv && !sStagedUpdate && !sReplaceRequest) {
- LOG(("backup_discard: unable to remove: " LOG_S, backup));
- NS_tchar path[MAXPATHLEN];
- GetTempFileNameW(DELETE_DIR, L"moz", 0, path);
- if (rename_file(backup, path)) {
- LOG(("backup_discard: failed to rename file:" LOG_S ", dst:" LOG_S,
- backup, path));
- return WRITE_ERROR_DELETE_BACKUP;
- }
- // The MoveFileEx call to remove the file on OS reboot will fail if the
- // process doesn't have write access to the HKEY_LOCAL_MACHINE registry key
- // but this is ok since the installer / uninstaller will delete the
- // directory containing the file along with its contents after an update is
- // applied, on reinstall, and on uninstall.
- if (MoveFileEx(path, nullptr, MOVEFILE_DELAY_UNTIL_REBOOT)) {
- LOG(("backup_discard: file renamed and will be removed on OS " \
- "reboot: " LOG_S, path));
- } else {
- LOG(("backup_discard: failed to schedule OS reboot removal of " \
- "file: " LOG_S, path));
+ if (rv && !sStagedUpdate && !sReplaceRequest) {
+ LOG(("backup_discard: unable to remove: " LOG_S, backup));
+ NS_tchar path[MAXPATHLEN];
+ GetTempFileNameW(DELETE_DIR, L"moz", 0, path);
+ if (rename_file(backup, path)) {
+ LOG(("backup_discard: failed to rename file:" LOG_S ", dst:" LOG_S,
+ backup, path));
+ return WRITE_ERROR_DELETE_BACKUP;
+ }
+ // The MoveFileEx call to remove the file on OS reboot will fail if the
+ // process doesn't have write access to the HKEY_LOCAL_MACHINE registry key
+ // but this is ok since the installer / uninstaller will delete the
+ // directory containing the file along with its contents after an update is
+ // applied, on reinstall, and on uninstall.
+ if (MoveFileEx(path, nullptr, MOVEFILE_DELAY_UNTIL_REBOOT)) {
+ LOG(("backup_discard: file renamed and will be removed on OS " \
+ "reboot: " LOG_S, path));
+ } else {
+ LOG(("backup_discard: failed to schedule OS reboot removal of " \
+ "file: " LOG_S, path));
+ }
}
- }
#else
- if (rv)
- return WRITE_ERROR_DELETE_BACKUP;
+ if (rv)
+ return WRITE_ERROR_DELETE_BACKUP;
#endif
- return OK;
+ return OK;
}
// Helper function for post-processing a temporary backup.
static void backup_finish(const NS_tchar *path, int status)
{
- if (status == OK)
- backup_discard(path);
- else
- backup_restore(path);
+ if (status == OK)
+ backup_discard(path);
+ else
+ backup_restore(path);
}
//-----------------------------------------------------------------------------
@@ -924,822 +924,822 @@ static int DoUpdate();
class Action
{
public:
- Action() : mProgressCost(1), mNext(nullptr) { }
- virtual ~Action() { }
+ Action() : mProgressCost(1), mNext(nullptr) { }
+ virtual ~Action() { }
- virtual int Parse(NS_tchar *line) = 0;
+ virtual int Parse(NS_tchar *line) = 0;
- // Do any preprocessing to ensure that the action can be performed. Execute
- // will be called if this Action and all others return OK from this method.
- virtual int Prepare() = 0;
+ // Do any preprocessing to ensure that the action can be performed. Execute
+ // will be called if this Action and all others return OK from this method.
+ virtual int Prepare() = 0;
- // Perform the operation. Return OK to indicate success. After all actions
- // have been executed, Finish will be called. A requirement of Execute is
- // that its operation be reversible from Finish.
- virtual int Execute() = 0;
+ // Perform the operation. Return OK to indicate success. After all actions
+ // have been executed, Finish will be called. A requirement of Execute is
+ // that its operation be reversible from Finish.
+ virtual int Execute() = 0;
- // Finish is called after execution of all actions. If status is OK, then
- // all actions were successfully executed. Otherwise, some action failed.
- virtual void Finish(int status) = 0;
+ // Finish is called after execution of all actions. If status is OK, then
+ // all actions were successfully executed. Otherwise, some action failed.
+ virtual void Finish(int status) = 0;
- int mProgressCost;
+ int mProgressCost;
private:
- Action* mNext;
+ Action* mNext;
- friend class ActionList;
+ friend class ActionList;
};
class RemoveFile : public Action
{
public:
- RemoveFile() : mFile(nullptr), mSkip(0) { }
+ RemoveFile() : mFile(nullptr), mSkip(0) { }
- int Parse(NS_tchar *line);
- int Prepare();
- int Execute();
- void Finish(int status);
+ int Parse(NS_tchar *line);
+ int Prepare();
+ int Execute();
+ void Finish(int status);
private:
- const NS_tchar *mFile;
- int mSkip;
+ const NS_tchar *mFile;
+ int mSkip;
};
int
RemoveFile::Parse(NS_tchar *line)
{
- // format "<deadfile>"
+ // format "<deadfile>"
- mFile = get_valid_path(&line);
- if (!mFile)
- return PARSE_ERROR;
+ mFile = get_valid_path(&line);
+ if (!mFile)
+ return PARSE_ERROR;
- return OK;
+ return OK;
}
int
RemoveFile::Prepare()
{
- // Skip the file if it already doesn't exist.
- int rv = NS_taccess(mFile, F_OK);
- if (rv) {
- mSkip = 1;
- mProgressCost = 0;
- return OK;
- }
+ // Skip the file if it already doesn't exist.
+ int rv = NS_taccess(mFile, F_OK);
+ if (rv) {
+ mSkip = 1;
+ mProgressCost = 0;
+ return OK;
+ }
- LOG(("PREPARE REMOVEFILE " LOG_S, mFile));
+ LOG(("PREPARE REMOVEFILE " LOG_S, mFile));
- // Make sure that we're actually a file...
- struct NS_tstat_t fileInfo;
- rv = NS_tstat(mFile, &fileInfo);
- if (rv) {
- LOG(("failed to read file status info: " LOG_S ", err: %d", mFile,
- errno));
- return READ_ERROR;
- }
+ // Make sure that we're actually a file...
+ struct NS_tstat_t fileInfo;
+ rv = NS_tstat(mFile, &fileInfo);
+ if (rv) {
+ LOG(("failed to read file status info: " LOG_S ", err: %d", mFile,
+ errno));
+ return READ_ERROR;
+ }
- if (!S_ISREG(fileInfo.st_mode)) {
- LOG(("path present, but not a file: " LOG_S, mFile));
- return DELETE_ERROR_EXPECTED_FILE;
- }
+ if (!S_ISREG(fileInfo.st_mode)) {
+ LOG(("path present, but not a file: " LOG_S, mFile));
+ return DELETE_ERROR_EXPECTED_FILE;
+ }
- NS_tchar *slash = (NS_tchar *) NS_tstrrchr(mFile, NS_T('/'));
- if (slash) {
- *slash = NS_T('\0');
- rv = NS_taccess(mFile, W_OK);
- *slash = NS_T('/');
- } else {
- rv = NS_taccess(NS_T("."), W_OK);
- }
+ NS_tchar *slash = (NS_tchar *) NS_tstrrchr(mFile, NS_T('/'));
+ if (slash) {
+ *slash = NS_T('\0');
+ rv = NS_taccess(mFile, W_OK);
+ *slash = NS_T('/');
+ } else {
+ rv = NS_taccess(NS_T("."), W_OK);
+ }
- if (rv) {
- LOG(("access failed: %d", errno));
- return WRITE_ERROR_FILE_ACCESS_DENIED;
- }
+ if (rv) {
+ LOG(("access failed: %d", errno));
+ return WRITE_ERROR_FILE_ACCESS_DENIED;
+ }
- return OK;
+ return OK;
}
int
RemoveFile::Execute()
{
- if (mSkip)
- return OK;
+ if (mSkip)
+ return OK;
- LOG(("EXECUTE REMOVEFILE " LOG_S, mFile));
+ LOG(("EXECUTE REMOVEFILE " LOG_S, mFile));
- // The file is checked for existence here and in Prepare since it might have
- // been removed by a separate instruction: bug 311099.
- int rv = NS_taccess(mFile, F_OK);
- if (rv) {
- LOG(("file cannot be removed because it does not exist; skipping"));
- mSkip = 1;
- return OK;
- }
+ // The file is checked for existence here and in Prepare since it might have
+ // been removed by a separate instruction: bug 311099.
+ int rv = NS_taccess(mFile, F_OK);
+ if (rv) {
+ LOG(("file cannot be removed because it does not exist; skipping"));
+ mSkip = 1;
+ return OK;
+ }
- // Rename the old file. It will be removed in Finish.
- rv = backup_create(mFile);
- if (rv) {
- LOG(("backup_create failed: %d", rv));
- return rv;
- }
+ // Rename the old file. It will be removed in Finish.
+ rv = backup_create(mFile);
+ if (rv) {
+ LOG(("backup_create failed: %d", rv));
+ return rv;
+ }
- return OK;
+ return OK;
}
void
RemoveFile::Finish(int status)
{
- if (mSkip)
- return;
+ if (mSkip)
+ return;
- LOG(("FINISH REMOVEFILE " LOG_S, mFile));
+ LOG(("FINISH REMOVEFILE " LOG_S, mFile));
- backup_finish(mFile, status);
+ backup_finish(mFile, status);
}
class RemoveDir : public Action
{
public:
- RemoveDir() : mDir(nullptr), mSkip(0) { }
+ RemoveDir() : mDir(nullptr), mSkip(0) { }
- virtual int Parse(NS_tchar *line);
- virtual int Prepare(); // check that the source dir exists
- virtual int Execute();
- virtual void Finish(int status);
+ virtual int Parse(NS_tchar *line);
+ virtual int Prepare(); // check that the source dir exists
+ virtual int Execute();
+ virtual void Finish(int status);
private:
- const NS_tchar *mDir;
- int mSkip;
+ const NS_tchar *mDir;
+ int mSkip;
};
int
RemoveDir::Parse(NS_tchar *line)
{
- // format "<deaddir>/"
+ // format "<deaddir>/"
- mDir = get_valid_path(&line, true);
- if (!mDir)
- return PARSE_ERROR;
+ mDir = get_valid_path(&line, true);
+ if (!mDir)
+ return PARSE_ERROR;
- return OK;
+ return OK;
}
int
RemoveDir::Prepare()
{
- // We expect the directory to exist if we are to remove it.
- int rv = NS_taccess(mDir, F_OK);
- if (rv) {
- mSkip = 1;
- mProgressCost = 0;
- return OK;
- }
+ // We expect the directory to exist if we are to remove it.
+ int rv = NS_taccess(mDir, F_OK);
+ if (rv) {
+ mSkip = 1;
+ mProgressCost = 0;
+ return OK;
+ }
- LOG(("PREPARE REMOVEDIR " LOG_S "/", mDir));
+ LOG(("PREPARE REMOVEDIR " LOG_S "/", mDir));
- // Make sure that we're actually a dir.
- struct NS_tstat_t dirInfo;
- rv = NS_tstat(mDir, &dirInfo);
- if (rv) {
- LOG(("failed to read directory status info: " LOG_S ", err: %d", mDir,
- errno));
- return READ_ERROR;
- }
+ // Make sure that we're actually a dir.
+ struct NS_tstat_t dirInfo;
+ rv = NS_tstat(mDir, &dirInfo);
+ if (rv) {
+ LOG(("failed to read directory status info: " LOG_S ", err: %d", mDir,
+ errno));
+ return READ_ERROR;
+ }
- if (!S_ISDIR(dirInfo.st_mode)) {
- LOG(("path present, but not a directory: " LOG_S, mDir));
- return DELETE_ERROR_EXPECTED_DIR;
- }
+ if (!S_ISDIR(dirInfo.st_mode)) {
+ LOG(("path present, but not a directory: " LOG_S, mDir));
+ return DELETE_ERROR_EXPECTED_DIR;
+ }
- rv = NS_taccess(mDir, W_OK);
- if (rv) {
- LOG(("access failed: %d, %d", rv, errno));
- return WRITE_ERROR_DIR_ACCESS_DENIED;
- }
+ rv = NS_taccess(mDir, W_OK);
+ if (rv) {
+ LOG(("access failed: %d, %d", rv, errno));
+ return WRITE_ERROR_DIR_ACCESS_DENIED;
+ }
- return OK;
+ return OK;
}
int
RemoveDir::Execute()
{
- if (mSkip)
- return OK;
+ if (mSkip)
+ return OK;
- LOG(("EXECUTE REMOVEDIR " LOG_S "/", mDir));
+ LOG(("EXECUTE REMOVEDIR " LOG_S "/", mDir));
- // The directory is checked for existence at every step since it might have
- // been removed by a separate instruction: bug 311099.
- int rv = NS_taccess(mDir, F_OK);
- if (rv) {
- LOG(("directory no longer exists; skipping"));
- mSkip = 1;
- }
+ // The directory is checked for existence at every step since it might have
+ // been removed by a separate instruction: bug 311099.
+ int rv = NS_taccess(mDir, F_OK);
+ if (rv) {
+ LOG(("directory no longer exists; skipping"));
+ mSkip = 1;
+ }
- return OK;
+ return OK;
}
void
RemoveDir::Finish(int status)
{
- if (mSkip || status != OK)
- return;
+ if (mSkip || status != OK)
+ return;
- LOG(("FINISH REMOVEDIR " LOG_S "/", mDir));
+ LOG(("FINISH REMOVEDIR " LOG_S "/", mDir));
- // The directory is checked for existence at every step since it might have
- // been removed by a separate instruction: bug 311099.
- int rv = NS_taccess(mDir, F_OK);
- if (rv) {
- LOG(("directory no longer exists; skipping"));
- return;
- }
+ // The directory is checked for existence at every step since it might have
+ // been removed by a separate instruction: bug 311099.
+ int rv = NS_taccess(mDir, F_OK);
+ if (rv) {
+ LOG(("directory no longer exists; skipping"));
+ return;
+ }
- if (status == OK) {
- if (NS_trmdir(mDir)) {
- LOG(("non-fatal error removing directory: " LOG_S "/, rv: %d, err: %d",
- mDir, rv, errno));
+ if (status == OK) {
+ if (NS_trmdir(mDir)) {
+ LOG(("non-fatal error removing directory: " LOG_S "/, rv: %d, err: %d",
+ mDir, rv, errno));
+ }
}
- }
}
class AddFile : public Action
{
public:
- AddFile() : mFile(nullptr)
- , mAdded(false)
- { }
+ AddFile() : mFile(nullptr)
+ , mAdded(false)
+ { }
- virtual int Parse(NS_tchar *line);
- virtual int Prepare();
- virtual int Execute();
- virtual void Finish(int status);
+ virtual int Parse(NS_tchar *line);
+ virtual int Prepare();
+ virtual int Execute();
+ virtual void Finish(int status);
private:
- const NS_tchar *mFile;
- bool mAdded;
+ const NS_tchar *mFile;
+ bool mAdded;
};
int
AddFile::Parse(NS_tchar *line)
{
- // format "<newfile>"
+ // format "<newfile>"
- mFile = get_valid_path(&line);
- if (!mFile)
- return PARSE_ERROR;
+ mFile = get_valid_path(&line);
+ if (!mFile)
+ return PARSE_ERROR;
- return OK;
+ return OK;
}
int
AddFile::Prepare()
{
- LOG(("PREPARE ADD " LOG_S, mFile));
+ LOG(("PREPARE ADD " LOG_S, mFile));
- return OK;
+ return OK;
}
int
AddFile::Execute()
{
- LOG(("EXECUTE ADD " LOG_S, mFile));
+ LOG(("EXECUTE ADD " LOG_S, mFile));
- int rv;
+ int rv;
- // First make sure that we can actually get rid of any existing file.
- rv = NS_taccess(mFile, F_OK);
- if (rv == 0) {
- rv = backup_create(mFile);
- if (rv)
- return rv;
- } else {
- rv = ensure_parent_dir(mFile);
- if (rv)
- return rv;
- }
+ // First make sure that we can actually get rid of any existing file.
+ rv = NS_taccess(mFile, F_OK);
+ if (rv == 0) {
+ rv = backup_create(mFile);
+ if (rv)
+ return rv;
+ } else {
+ rv = ensure_parent_dir(mFile);
+ if (rv)
+ return rv;
+ }
#ifdef _WIN32
- char sourcefile[MAXPATHLEN];
- if (!WideCharToMultiByte(CP_UTF8, 0, mFile, -1, sourcefile, MAXPATHLEN,
- nullptr, nullptr)) {
- LOG(("error converting wchar to utf8: %d", GetLastError()));
- return STRING_CONVERSION_ERROR;
- }
-
- rv = gArchiveReader.ExtractFile(sourcefile, mFile);
+ char sourcefile[MAXPATHLEN];
+ if (!WideCharToMultiByte(CP_UTF8, 0, mFile, -1, sourcefile, MAXPATHLEN,
+ nullptr, nullptr)) {
+ LOG(("error converting wchar to utf8: %d", GetLastError()));
+ return STRING_CONVERSION_ERROR;
+ }
+
+ rv = gArchiveReader.ExtractFile(sourcefile, mFile);
#else
- rv = gArchiveReader.ExtractFile(mFile, mFile);
+ rv = gArchiveReader.ExtractFile(mFile, mFile);
#endif
- if (!rv) {
- mAdded = true;
- }
- return rv;
+ if (!rv) {
+ mAdded = true;
+ }
+ return rv;
}
void
AddFile::Finish(int status)
{
- LOG(("FINISH ADD " LOG_S, mFile));
- // When there is an update failure and a file has been added it is removed
- // here since there might not be a backup to replace it.
- if (status && mAdded)
- NS_tremove(mFile);
- backup_finish(mFile, status);
+ LOG(("FINISH ADD " LOG_S, mFile));
+ // When there is an update failure and a file has been added it is removed
+ // here since there might not be a backup to replace it.
+ if (status && mAdded)
+ NS_tremove(mFile);
+ backup_finish(mFile, status);
}
class PatchFile : public Action
{
public:
- PatchFile() : mPatchIndex(-1), buf(nullptr) { }
+ PatchFile() : mPatchIndex(-1), buf(nullptr) { }
- virtual ~PatchFile();
+ virtual ~PatchFile();
- virtual int Parse(NS_tchar *line);
- virtual int Prepare(); // should check for patch file and for checksum here
- virtual int Execute();
- virtual void Finish(int status);
+ virtual int Parse(NS_tchar *line);
+ virtual int Prepare(); // should check for patch file and for checksum here
+ virtual int Execute();
+ virtual void Finish(int status);
private:
- int LoadSourceFile(FILE* ofile);
+ int LoadSourceFile(FILE* ofile);
- static int sPatchIndex;
+ static int sPatchIndex;
- const NS_tchar *mPatchFile;
- const NS_tchar *mFile;
- int mPatchIndex;
- MBSPatchHeader header;
- unsigned char *buf;
- NS_tchar spath[MAXPATHLEN];
+ const NS_tchar *mPatchFile;
+ const NS_tchar *mFile;
+ int mPatchIndex;
+ MBSPatchHeader header;
+ unsigned char *buf;
+ NS_tchar spath[MAXPATHLEN];
};
int PatchFile::sPatchIndex = 0;
PatchFile::~PatchFile()
{
- // delete the temporary patch file
- if (spath[0])
- NS_tremove(spath);
+ // delete the temporary patch file
+ if (spath[0])
+ NS_tremove(spath);
- if (buf)
- free(buf);
+ if (buf)
+ free(buf);
}
int
PatchFile::LoadSourceFile(FILE* ofile)
{
- struct stat os;
- int rv = fstat(fileno((FILE *)ofile), &os);
- if (rv) {
- LOG(("LoadSourceFile: unable to stat destination file: " LOG_S ", " \
- "err: %d", mFile, errno));
- return READ_ERROR;
- }
-
- if (uint32_t(os.st_size) != header.slen) {
- LOG(("LoadSourceFile: destination file size %d does not match expected size %d",
- uint32_t(os.st_size), header.slen));
- return LOADSOURCE_ERROR_WRONG_SIZE;
- }
-
- buf = (unsigned char *) malloc(header.slen);
- if (!buf)
- return UPDATER_MEM_ERROR;
+ struct stat os;
+ int rv = fstat(fileno((FILE *)ofile), &os);
+ if (rv) {
+ LOG(("LoadSourceFile: unable to stat destination file: " LOG_S ", " \
+ "err: %d", mFile, errno));
+ return READ_ERROR;
+ }
+
+ if (uint32_t(os.st_size) != header.slen) {
+ LOG(("LoadSourceFile: destination file size %d does not match expected size %d",
+ uint32_t(os.st_size), header.slen));
+ return LOADSOURCE_ERROR_WRONG_SIZE;
+ }
+
+ buf = (unsigned char *) malloc(header.slen);
+ if (!buf)
+ return UPDATER_MEM_ERROR;
+
+ size_t r = header.slen;
+ unsigned char *rb = buf;
+ while (r) {
+ const size_t count = mmin(SSIZE_MAX, r);
+ size_t c = fread(rb, 1, count, ofile);
+ if (c != count) {
+ LOG(("LoadSourceFile: error reading destination file: " LOG_S,
+ mFile));
+ return READ_ERROR;
+ }
- size_t r = header.slen;
- unsigned char *rb = buf;
- while (r) {
- const size_t count = mmin(SSIZE_MAX, r);
- size_t c = fread(rb, 1, count, ofile);
- if (c != count) {
- LOG(("LoadSourceFile: error reading destination file: " LOG_S,
- mFile));
- return READ_ERROR;
+ r -= c;
+ rb += c;
}
- r -= c;
- rb += c;
- }
-
- // Verify that the contents of the source file correspond to what we expect.
+ // Verify that the contents of the source file correspond to what we expect.
- unsigned int crc = crc32(buf, header.slen);
+ unsigned int crc = crc32(buf, header.slen);
- if (crc != header.scrc32) {
- LOG(("LoadSourceFile: destination file crc %d does not match expected " \
- "crc %d", crc, header.scrc32));
- return CRC_ERROR;
- }
+ if (crc != header.scrc32) {
+ LOG(("LoadSourceFile: destination file crc %d does not match expected " \
+ "crc %d", crc, header.scrc32));
+ return CRC_ERROR;
+ }
- return OK;
+ return OK;
}
int
PatchFile::Parse(NS_tchar *line)
{
- // format "<patchfile>" "<filetopatch>"
+ // format "<patchfile>" "<filetopatch>"
- // Get the path to the patch file inside of the mar
- mPatchFile = mstrtok(kQuote, &line);
- if (!mPatchFile)
- return PARSE_ERROR;
+ // Get the path to the patch file inside of the mar
+ mPatchFile = mstrtok(kQuote, &line);
+ if (!mPatchFile)
+ return PARSE_ERROR;
- // consume whitespace between args
- NS_tchar *q = mstrtok(kQuote, &line);
- if (!q)
- return PARSE_ERROR;
+ // consume whitespace between args
+ NS_tchar *q = mstrtok(kQuote, &line);
+ if (!q)
+ return PARSE_ERROR;
- mFile = get_valid_path(&line);
- if (!mFile)
- return PARSE_ERROR;
+ mFile = get_valid_path(&line);
+ if (!mFile)
+ return PARSE_ERROR;
- return OK;
+ return OK;
}
int
PatchFile::Prepare()
{
- LOG(("PREPARE PATCH " LOG_S, mFile));
+ LOG(("PREPARE PATCH " LOG_S, mFile));
- // extract the patch to a temporary file
- mPatchIndex = sPatchIndex++;
+ // extract the patch to a temporary file
+ mPatchIndex = sPatchIndex++;
- NS_tsnprintf(spath, sizeof(spath)/sizeof(spath[0]),
- NS_T("%s/updating/%d.patch"), gWorkingDirPath, mPatchIndex);
+ NS_tsnprintf(spath, sizeof(spath)/sizeof(spath[0]),
+ NS_T("%s/updating/%d.patch"), gWorkingDirPath, mPatchIndex);
- NS_tremove(spath);
+ NS_tremove(spath);
- FILE *fp = NS_tfopen(spath, NS_T("wb"));
- if (!fp)
- return WRITE_ERROR;
+ FILE *fp = NS_tfopen(spath, NS_T("wb"));
+ if (!fp)
+ return WRITE_ERROR;
#ifdef _WIN32
- char sourcefile[MAXPATHLEN];
- if (!WideCharToMultiByte(CP_UTF8, 0, mPatchFile, -1, sourcefile, MAXPATHLEN,
- nullptr, nullptr)) {
- LOG(("error converting wchar to utf8: %d", GetLastError()));
- return STRING_CONVERSION_ERROR;
- }
-
- int rv = gArchiveReader.ExtractFileToStream(sourcefile, fp);
+ char sourcefile[MAXPATHLEN];
+ if (!WideCharToMultiByte(CP_UTF8, 0, mPatchFile, -1, sourcefile, MAXPATHLEN,
+ nullptr, nullptr)) {
+ LOG(("error converting wchar to utf8: %d", GetLastError()));
+ return STRING_CONVERSION_ERROR;
+ }
+
+ int rv = gArchiveReader.ExtractFileToStream(sourcefile, fp);
#else
- int rv = gArchiveReader.ExtractFileToStream(mPatchFile, fp);
+ int rv = gArchiveReader.ExtractFileToStream(mPatchFile, fp);
#endif
- fclose(fp);
- return rv;
+ fclose(fp);
+ return rv;
}
int
PatchFile::Execute()
{
- LOG(("EXECUTE PATCH " LOG_S, mFile));
+ LOG(("EXECUTE PATCH " LOG_S, mFile));
- AutoFile pfile(NS_tfopen(spath, NS_T("rb")));
- if (pfile == nullptr)
- return READ_ERROR;
+ AutoFile pfile(NS_tfopen(spath, NS_T("rb")));
+ if (pfile == nullptr)
+ return READ_ERROR;
- int rv = MBS_ReadHeader(pfile, &header);
- if (rv)
- return rv;
+ int rv = MBS_ReadHeader(pfile, &header);
+ if (rv)
+ return rv;
- FILE *origfile = nullptr;
+ FILE *origfile = nullptr;
#ifdef _WIN32
- if (NS_tstrcmp(mFile, gCallbackRelPath) == 0) {
- // Read from the copy of the callback when patching since the callback can't
- // be opened for reading to prevent the application from being launched.
- origfile = NS_tfopen(gCallbackBackupPath, NS_T("rb"));
- } else {
- origfile = NS_tfopen(mFile, NS_T("rb"));
- }
+ if (NS_tstrcmp(mFile, gCallbackRelPath) == 0) {
+ // Read from the copy of the callback when patching since the callback can't
+ // be opened for reading to prevent the application from being launched.
+ origfile = NS_tfopen(gCallbackBackupPath, NS_T("rb"));
+ } else {
+ origfile = NS_tfopen(mFile, NS_T("rb"));
+ }
#else
- origfile = NS_tfopen(mFile, NS_T("rb"));
+ origfile = NS_tfopen(mFile, NS_T("rb"));
#endif
- if (!origfile) {
- LOG(("unable to open destination file: " LOG_S ", err: %d", mFile,
- errno));
- return READ_ERROR;
- }
+ if (!origfile) {
+ LOG(("unable to open destination file: " LOG_S ", err: %d", mFile,
+ errno));
+ return READ_ERROR;
+ }
- rv = LoadSourceFile(origfile);
- fclose(origfile);
- if (rv) {
- LOG(("LoadSourceFile failed"));
- return rv;
- }
-
- // Rename the destination file if it exists before proceeding so it can be
- // used to restore the file to its original state if there is an error.
- struct NS_tstat_t ss;
- rv = NS_tstat(mFile, &ss);
- if (rv) {
- LOG(("failed to read file status info: " LOG_S ", err: %d", mFile,
- errno));
- return READ_ERROR;
- }
-
- rv = backup_create(mFile);
- if (rv)
- return rv;
+ rv = LoadSourceFile(origfile);
+ fclose(origfile);
+ if (rv) {
+ LOG(("LoadSourceFile failed"));
+ return rv;
+ }
+
+ // Rename the destination file if it exists before proceeding so it can be
+ // used to restore the file to its original state if there is an error.
+ struct NS_tstat_t ss;
+ rv = NS_tstat(mFile, &ss);
+ if (rv) {
+ LOG(("failed to read file status info: " LOG_S ", err: %d", mFile,
+ errno));
+ return READ_ERROR;
+ }
+
+ rv = backup_create(mFile);
+ if (rv)
+ return rv;
#if defined(HAVE_POSIX_FALLOCATE)
- AutoFile ofile(ensure_open(mFile, NS_T("wb+"), ss.st_mode));
- posix_fallocate(fileno((FILE *)ofile), 0, header.dlen);
+ AutoFile ofile(ensure_open(mFile, NS_T("wb+"), ss.st_mode));
+ posix_fallocate(fileno((FILE *)ofile), 0, header.dlen);
#elif defined(WNT)
- bool shouldTruncate = true;
- // Creating the file, setting the size, and then closing the file handle
- // lessens fragmentation more than any other method tested. Other methods that
- // have been tested are:
- // 1. _chsize / _chsize_s reduced fragmentation though not completely.
- // 2. _get_osfhandle and then setting the size reduced fragmentation though
- // not completely. There are also reports of _get_osfhandle failing on
- // mingw.
- HANDLE hfile = CreateFileW(mFile,
- GENERIC_WRITE,
- 0,
- nullptr,
- CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL,
- nullptr);
-
- if (hfile != INVALID_HANDLE_VALUE) {
- if (SetFilePointer(hfile, header.dlen,
- nullptr, FILE_BEGIN) != INVALID_SET_FILE_POINTER &&
- SetEndOfFile(hfile) != 0) {
- shouldTruncate = false;
- }
- CloseHandle(hfile);
- }
-
- AutoFile ofile(ensure_open(mFile, shouldTruncate ? NS_T("wb+") : NS_T("rb+"),
- ss.st_mode));
+ bool shouldTruncate = true;
+ // Creating the file, setting the size, and then closing the file handle
+ // lessens fragmentation more than any other method tested. Other methods that
+ // have been tested are:
+ // 1. _chsize / _chsize_s reduced fragmentation though not completely.
+ // 2. _get_osfhandle and then setting the size reduced fragmentation though
+ // not completely. There are also reports of _get_osfhandle failing on
+ // mingw.
+ HANDLE hfile = CreateFileW(mFile,
+ GENERIC_WRITE,
+ 0,
+ nullptr,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ nullptr);
+
+ if (hfile != INVALID_HANDLE_VALUE) {
+ if (SetFilePointer(hfile, header.dlen,
+ nullptr, FILE_BEGIN) != INVALID_SET_FILE_POINTER &&
+ SetEndOfFile(hfile) != 0) {
+ shouldTruncate = false;
+ }
+ CloseHandle(hfile);
+ }
+
+ AutoFile ofile(ensure_open(mFile, shouldTruncate ? NS_T("wb+") : NS_T("rb+"),
+ ss.st_mode));
#elif defined(MACOSX)
- AutoFile ofile(ensure_open(mFile, NS_T("wb+"), ss.st_mode));
- // Modified code from FileUtils.cpp
- fstore_t store = {F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, header.dlen};
- // Try to get a continuous chunk of disk space
- rv = fcntl(fileno((FILE *)ofile), F_PREALLOCATE, &store);
- if (rv == -1) {
- // OK, perhaps we are too fragmented, allocate non-continuous
- store.fst_flags = F_ALLOCATEALL;
+ AutoFile ofile(ensure_open(mFile, NS_T("wb+"), ss.st_mode));
+ // Modified code from FileUtils.cpp
+ fstore_t store = {F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, header.dlen};
+ // Try to get a continuous chunk of disk space
rv = fcntl(fileno((FILE *)ofile), F_PREALLOCATE, &store);
- }
+ if (rv == -1) {
+ // OK, perhaps we are too fragmented, allocate non-continuous
+ store.fst_flags = F_ALLOCATEALL;
+ rv = fcntl(fileno((FILE *)ofile), F_PREALLOCATE, &store);
+ }
- if (rv != -1) {
- ftruncate(fileno((FILE *)ofile), header.dlen);
- }
+ if (rv != -1) {
+ ftruncate(fileno((FILE *)ofile), header.dlen);
+ }
#else
- AutoFile ofile(ensure_open(mFile, NS_T("wb+"), ss.st_mode));
+ AutoFile ofile(ensure_open(mFile, NS_T("wb+"), ss.st_mode));
#endif
- if (ofile == nullptr) {
- LOG(("unable to create new file: " LOG_S ", err: %d", mFile, errno));
- return WRITE_ERROR_OPEN_PATCH_FILE;
- }
+ if (ofile == nullptr) {
+ LOG(("unable to create new file: " LOG_S ", err: %d", mFile, errno));
+ return WRITE_ERROR_OPEN_PATCH_FILE;
+ }
#ifdef _WIN32
- if (!shouldTruncate) {
- fseek(ofile, 0, SEEK_SET);
- }
+ if (!shouldTruncate) {
+ fseek(ofile, 0, SEEK_SET);
+ }
#endif
- rv = MBS_ApplyPatch(&header, pfile, buf, ofile);
+ rv = MBS_ApplyPatch(&header, pfile, buf, ofile);
- // Go ahead and do a bit of cleanup now to minimize runtime overhead.
- // Set pfile to nullptr to make AutoFile close the file so it can be deleted
- // on Windows.
- pfile = nullptr;
- NS_tremove(spath);
- spath[0] = NS_T('\0');
- free(buf);
- buf = nullptr;
+ // Go ahead and do a bit of cleanup now to minimize runtime overhead.
+ // Set pfile to nullptr to make AutoFile close the file so it can be deleted
+ // on Windows.
+ pfile = nullptr;
+ NS_tremove(spath);
+ spath[0] = NS_T('\0');
+ free(buf);
+ buf = nullptr;
- return rv;
+ return rv;
}
void
PatchFile::Finish(int status)
{
- LOG(("FINISH PATCH " LOG_S, mFile));
+ LOG(("FINISH PATCH " LOG_S, mFile));
- backup_finish(mFile, status);
+ backup_finish(mFile, status);
}
class AddIfFile : public AddFile
{
public:
- AddIfFile() : mTestFile(nullptr) { }
+ AddIfFile() : mTestFile(nullptr) { }
- virtual int Parse(NS_tchar *line);
- virtual int Prepare();
- virtual int Execute();
- virtual void Finish(int status);
+ virtual int Parse(NS_tchar *line);
+ virtual int Prepare();
+ virtual int Execute();
+ virtual void Finish(int status);
protected:
- const NS_tchar *mTestFile;
+ const NS_tchar *mTestFile;
};
int
AddIfFile::Parse(NS_tchar *line)
{
- // format "<testfile>" "<newfile>"
+ // format "<testfile>" "<newfile>"
- mTestFile = get_valid_path(&line);
- if (!mTestFile)
- return PARSE_ERROR;
+ mTestFile = get_valid_path(&line);
+ if (!mTestFile)
+ return PARSE_ERROR;
- // consume whitespace between args
- NS_tchar *q = mstrtok(kQuote, &line);
- if (!q)
- return PARSE_ERROR;
+ // consume whitespace between args
+ NS_tchar *q = mstrtok(kQuote, &line);
+ if (!q)
+ return PARSE_ERROR;
- return AddFile::Parse(line);
+ return AddFile::Parse(line);
}
int
AddIfFile::Prepare()
{
- // If the test file does not exist, then skip this action.
- if (NS_taccess(mTestFile, F_OK)) {
- mTestFile = nullptr;
- return OK;
- }
+ // If the test file does not exist, then skip this action.
+ if (NS_taccess(mTestFile, F_OK)) {
+ mTestFile = nullptr;
+ return OK;
+ }
- return AddFile::Prepare();
+ return AddFile::Prepare();
}
int
AddIfFile::Execute()
{
- if (!mTestFile)
- return OK;
+ if (!mTestFile)
+ return OK;
- return AddFile::Execute();
+ return AddFile::Execute();
}
void
AddIfFile::Finish(int status)
{
- if (!mTestFile)
- return;
+ if (!mTestFile)
+ return;
- AddFile::Finish(status);
+ AddFile::Finish(status);
}
class AddIfNotFile : public AddFile
{
public:
- AddIfNotFile() : mTestFile(NULL) { }
+ AddIfNotFile() : mTestFile(NULL) { }
- virtual int Parse(NS_tchar *line);
- virtual int Prepare();
- virtual int Execute();
- virtual void Finish(int status);
+ virtual int Parse(NS_tchar *line);
+ virtual int Prepare();
+ virtual int Execute();
+ virtual void Finish(int status);
protected:
- const NS_tchar *mTestFile;
+ const NS_tchar *mTestFile;
};
int
AddIfNotFile::Parse(NS_tchar *line)
{
- // format "<testfile>" "<newfile>"
+ // format "<testfile>" "<newfile>"
- mTestFile = get_valid_path(&line);
- if (!mTestFile)
- return PARSE_ERROR;
+ mTestFile = get_valid_path(&line);
+ if (!mTestFile)
+ return PARSE_ERROR;
- // consume whitespace between args
- NS_tchar *q = mstrtok(kQuote, &line);
- if (!q)
- return PARSE_ERROR;
+ // consume whitespace between args
+ NS_tchar *q = mstrtok(kQuote, &line);
+ if (!q)
+ return PARSE_ERROR;
- return AddFile::Parse(line);
+ return AddFile::Parse(line);
}
int
AddIfNotFile::Prepare()
{
- // If the test file exists, then skip this action.
- if (!NS_taccess(mTestFile, F_OK)) {
- mTestFile = NULL;
- return OK;
- }
+ // If the test file exists, then skip this action.
+ if (!NS_taccess(mTestFile, F_OK)) {
+ mTestFile = NULL;
+ return OK;
+ }
- return AddFile::Prepare();
+ return AddFile::Prepare();
}
int
AddIfNotFile::Execute()
{
- if (!mTestFile)
- return OK;
+ if (!mTestFile)
+ return OK;
- return AddFile::Execute();
+ return AddFile::Execute();
}
void
AddIfNotFile::Finish(int status)
{
- if (!mTestFile)
- return;
+ if (!mTestFile)
+ return;
- AddFile::Finish(status);
+ AddFile::Finish(status);
}
class PatchIfFile : public PatchFile
{
public:
- PatchIfFile() : mTestFile(nullptr) { }
+ PatchIfFile() : mTestFile(nullptr) { }
- virtual int Parse(NS_tchar *line);
- virtual int Prepare(); // should check for patch file and for checksum here
- virtual int Execute();
- virtual void Finish(int status);
+ virtual int Parse(NS_tchar *line);
+ virtual int Prepare(); // should check for patch file and for checksum here
+ virtual int Execute();
+ virtual void Finish(int status);
private:
- const NS_tchar *mTestFile;
+ const NS_tchar *mTestFile;
};
int
PatchIfFile::Parse(NS_tchar *line)
{
- // format "<testfile>" "<patchfile>" "<filetopatch>"
+ // format "<testfile>" "<patchfile>" "<filetopatch>"
- mTestFile = get_valid_path(&line);
- if (!mTestFile)
- return PARSE_ERROR;
+ mTestFile = get_valid_path(&line);
+ if (!mTestFile)
+ return PARSE_ERROR;
- // consume whitespace between args
- NS_tchar *q = mstrtok(kQuote, &line);
- if (!q)
- return PARSE_ERROR;
+ // consume whitespace between args
+ NS_tchar *q = mstrtok(kQuote, &line);
+ if (!q)
+ return PARSE_ERROR;
- return PatchFile::Parse(line);
+ return PatchFile::Parse(line);
}
int
PatchIfFile::Prepare()
{
- // If the test file does not exist, then skip this action.
- if (NS_taccess(mTestFile, F_OK)) {
- mTestFile = nullptr;
- return OK;
- }
+ // If the test file does not exist, then skip this action.
+ if (NS_taccess(mTestFile, F_OK)) {
+ mTestFile = nullptr;
+ return OK;
+ }
- return PatchFile::Prepare();
+ return PatchFile::Prepare();
}
int
PatchIfFile::Execute()
{
- if (!mTestFile)
- return OK;
+ if (!mTestFile)
+ return OK;
- return PatchFile::Execute();
+ return PatchFile::Execute();
}
void
PatchIfFile::Finish(int status)
{
- if (!mTestFile)
- return;
+ if (!mTestFile)
+ return;
- PatchFile::Finish(status);
+ PatchFile::Finish(status);
}
//-----------------------------------------------------------------------------
static void
LaunchCallbackApp(const NS_tchar *workingDir,
- int argc,
- NS_tchar **argv,
- bool usingService)
+ int argc,
+ NS_tchar **argv,
+ bool usingService)
{
- putenv(const_cast<char*>("NO_EM_RESTART="));
- putenv(const_cast<char*>("MOZ_LAUNCHED_CHILD=1"));
+ putenv(const_cast<char*>("NO_EM_RESTART="));
+ putenv(const_cast<char*>("MOZ_LAUNCHED_CHILD=1"));
- // Run from the specified working directory (see bug 312360). This is not
- // necessary on Windows CE since the application that launches the updater
- // passes the working directory as an --environ: command line argument.
- if (NS_tchdir(workingDir) != 0) {
- LOG(("Warning: chdir failed"));
- }
+ // Run from the specified working directory (see bug 312360). This is not
+ // necessary on Windows CE since the application that launches the updater
+ // passes the working directory as an --environ: command line argument.
+ if (NS_tchdir(workingDir) != 0) {
+ LOG(("Warning: chdir failed"));
+ }
#if defined(USE_EXECV)
- (void) argc; (void) usingService; // avoid warnings
- execv(argv[0], argv);
+ (void) argc; (void) usingService; // avoid warnings
+ execv(argv[0], argv);
#elif defined(MACOSX)
- (void) usingService; // avoid warnings
- LaunchChild(argc, argv);
+ (void) usingService; // avoid warnings
+ LaunchChild(argc, argv);
#elif defined(WNT)
- // Do not allow the callback to run when running an update through the
- // service as session 0. The unelevated updater.exe will do the launching.
- if (!usingService) {
- WinLaunchChild(argv[0], argc, argv, nullptr);
- }
+ // Do not allow the callback to run when running an update through the
+ // service as session 0. The unelevated updater.exe will do the launching.
+ if (!usingService) {
+ WinLaunchChild(argv[0], argc, argv, nullptr);
+ }
#else
# warning "Need implementation of LaunchCallbackApp"
#endif
@@ -1748,42 +1748,42 @@ LaunchCallbackApp(const NS_tchar *workingDir,
static bool
WriteStatusFile(const char* aStatus)
{
- NS_tchar filename[MAXPATHLEN];
- NS_tsnprintf(filename, sizeof(filename)/sizeof(filename[0]),
- NS_T("%s/update.status"), gPatchDirPath);
+ NS_tchar filename[MAXPATHLEN];
+ NS_tsnprintf(filename, sizeof(filename)/sizeof(filename[0]),
+ NS_T("%s/update.status"), gPatchDirPath);
- // Make sure that the directory for the update status file exists
- if (ensure_parent_dir(filename))
- return false;
+ // Make sure that the directory for the update status file exists
+ if (ensure_parent_dir(filename))
+ return false;
- AutoFile file(NS_tfopen(filename, NS_T("wb+")));
- if (file == nullptr)
- return false;
+ AutoFile file(NS_tfopen(filename, NS_T("wb+")));
+ if (file == nullptr)
+ return false;
- if (fwrite(aStatus, strlen(aStatus), 1, file) != 1)
- return false;
+ if (fwrite(aStatus, strlen(aStatus), 1, file) != 1)
+ return false;
- return true;
+ return true;
}
static void
WriteStatusFile(int status)
{
- const char *text;
+ const char *text;
- char buf[32];
- if (status == OK) {
- if (sStagedUpdate) {
- text = "applied\n";
+ char buf[32];
+ if (status == OK) {
+ if (sStagedUpdate) {
+ text = "applied\n";
+ } else {
+ text = "succeeded\n";
+ }
} else {
- text = "succeeded\n";
+ snprintf(buf, sizeof(buf)/sizeof(buf[0]), "failed: %d\n", status);
+ text = buf;
}
- } else {
- snprintf(buf, sizeof(buf)/sizeof(buf[0]), "failed: %d\n", status);
- text = buf;
- }
- WriteStatusFile(text);
+ WriteStatusFile(text);
}
#ifdef MOZ_MAINTENANCE_SERVICE
@@ -1795,28 +1795,28 @@ WriteStatusFile(int status)
* is set to pending-service or not.
* @return true if the information was retrieved and it is pending
* or pending-service.
-*/
+ */
static bool
IsUpdateStatusPendingService()
{
- NS_tchar filename[MAXPATHLEN];
- NS_tsnprintf(filename, sizeof(filename)/sizeof(filename[0]),
- NS_T("%s/update.status"), gPatchDirPath);
+ NS_tchar filename[MAXPATHLEN];
+ NS_tsnprintf(filename, sizeof(filename)/sizeof(filename[0]),
+ NS_T("%s/update.status"), gPatchDirPath);
- AutoFile file(NS_tfopen(filename, NS_T("rb")));
- if (file == nullptr)
- return false;
+ AutoFile file(NS_tfopen(filename, NS_T("rb")));
+ if (file == nullptr)
+ return false;
- char buf[32] = { 0 };
- fread(buf, sizeof(buf), 1, file);
+ char buf[32] = { 0 };
+ fread(buf, sizeof(buf), 1, file);
- const char kPendingService[] = "pending-service";
- const char kAppliedService[] = "applied-service";
+ const char kPendingService[] = "pending-service";
+ const char kAppliedService[] = "applied-service";
- return (strncmp(buf, kPendingService,
- sizeof(kPendingService) - 1) == 0) ||
- (strncmp(buf, kAppliedService,
- sizeof(kAppliedService) - 1) == 0);
+ return (strncmp(buf, kPendingService,
+ sizeof(kPendingService) - 1) == 0) ||
+ (strncmp(buf, kAppliedService,
+ sizeof(kAppliedService) - 1) == 0);
}
#endif
@@ -1828,26 +1828,26 @@ IsUpdateStatusPendingService()
* @param isSucceeded Out parameter for specifying if the status
* is set to succeeded or not.
* @return true if the information was retrieved and it is succeeded.
-*/
+ */
static bool
IsUpdateStatusSucceeded(bool &isSucceeded)
{
- isSucceeded = false;
- NS_tchar filename[MAXPATHLEN];
- NS_tsnprintf(filename, sizeof(filename)/sizeof(filename[0]),
- NS_T("%s/update.status"), gPatchDirPath);
+ isSucceeded = false;
+ NS_tchar filename[MAXPATHLEN];
+ NS_tsnprintf(filename, sizeof(filename)/sizeof(filename[0]),
+ NS_T("%s/update.status"), gPatchDirPath);
- AutoFile file(NS_tfopen(filename, NS_T("rb")));
- if (file == nullptr)
- return false;
+ AutoFile file(NS_tfopen(filename, NS_T("rb")));
+ if (file == nullptr)
+ return false;
- char buf[32] = { 0 };
- fread(buf, sizeof(buf), 1, file);
+ char buf[32] = { 0 };
+ fread(buf, sizeof(buf), 1, file);
- const char kSucceeded[] = "succeeded";
- isSucceeded = strncmp(buf, kSucceeded,
- sizeof(kSucceeded) - 1) == 0;
- return true;
+ const char kSucceeded[] = "succeeded";
+ isSucceeded = strncmp(buf, kSucceeded,
+ sizeof(kSucceeded) - 1) == 0;
+ return true;
}
#endif
@@ -1860,7 +1860,7 @@ IsUpdateStatusSucceeded(bool &isSucceeded)
static int
CopyInstallDirToDestDir()
{
- // These files should not be copied over to the updated app
+ // These files should not be copied over to the updated app
#ifdef _WIN32
#define SKIPLIST_COUNT 3
#elif defined(MACOSX)
@@ -1868,16 +1868,16 @@ CopyInstallDirToDestDir()
#else
#define SKIPLIST_COUNT 2
#endif
- copy_recursive_skiplist<SKIPLIST_COUNT> skiplist;
+ copy_recursive_skiplist<SKIPLIST_COUNT> skiplist;
#ifndef MACOSX
- skiplist.append(0, gInstallDirPath, NS_T("updated"));
- skiplist.append(1, gInstallDirPath, NS_T("updates/0"));
+ skiplist.append(0, gInstallDirPath, NS_T("updated"));
+ skiplist.append(1, gInstallDirPath, NS_T("updates/0"));
#ifdef _WIN32
- skiplist.append(2, gInstallDirPath, NS_T("updated.update_in_progress.lock"));
+ skiplist.append(2, gInstallDirPath, NS_T("updated.update_in_progress.lock"));
#endif
#endif
- return ensure_copy_recursive(gInstallDirPath, gWorkingDirPath, skiplist);
+ return ensure_copy_recursive(gInstallDirPath, gWorkingDirPath, skiplist);
}
/*
@@ -1889,140 +1889,140 @@ CopyInstallDirToDestDir()
static int
ProcessReplaceRequest()
{
- // The replacement algorithm is like this:
- // 1. Move destDir to tmpDir. In case of failure, abort.
- // 2. Move newDir to destDir. In case of failure, revert step 1 and abort.
- // 3. Delete tmpDir (or defer it to the next reboot).
+ // The replacement algorithm is like this:
+ // 1. Move destDir to tmpDir. In case of failure, abort.
+ // 2. Move newDir to destDir. In case of failure, revert step 1 and abort.
+ // 3. Delete tmpDir (or defer it to the next reboot).
#ifdef MACOSX
- NS_tchar destDir[MAXPATHLEN];
- NS_tsnprintf(destDir, sizeof(destDir)/sizeof(destDir[0]),
- NS_T("%s/Contents"), gInstallDirPath);
+ NS_tchar destDir[MAXPATHLEN];
+ NS_tsnprintf(destDir, sizeof(destDir)/sizeof(destDir[0]),
+ NS_T("%s/Contents"), gInstallDirPath);
#elif defined(WNT)
- // Windows preserves the case of the file/directory names. We use the
- // GetLongPathName API in order to get the correct case for the directory
- // name, so that if the user has used a different case when launching the
- // application, the installation directory's name does not change.
- NS_tchar destDir[MAXPATHLEN];
- if (!GetLongPathNameW(gInstallDirPath, destDir,
- sizeof(destDir)/sizeof(destDir[0]))) {
- return NO_INSTALLDIR_ERROR;
- }
+ // Windows preserves the case of the file/directory names. We use the
+ // GetLongPathName API in order to get the correct case for the directory
+ // name, so that if the user has used a different case when launching the
+ // application, the installation directory's name does not change.
+ NS_tchar destDir[MAXPATHLEN];
+ if (!GetLongPathNameW(gInstallDirPath, destDir,
+ sizeof(destDir)/sizeof(destDir[0]))) {
+ return NO_INSTALLDIR_ERROR;
+ }
#else
- NS_tchar* destDir = gInstallDirPath;
+ NS_tchar* destDir = gInstallDirPath;
#endif
- NS_tchar tmpDir[MAXPATHLEN];
- NS_tsnprintf(tmpDir, sizeof(tmpDir)/sizeof(tmpDir[0]),
- NS_T("%s.bak"), destDir);
+ NS_tchar tmpDir[MAXPATHLEN];
+ NS_tsnprintf(tmpDir, sizeof(tmpDir)/sizeof(tmpDir[0]),
+ NS_T("%s.bak"), destDir);
- NS_tchar newDir[MAXPATHLEN];
- NS_tsnprintf(newDir, sizeof(newDir)/sizeof(newDir[0]),
+ NS_tchar newDir[MAXPATHLEN];
+ NS_tsnprintf(newDir, sizeof(newDir)/sizeof(newDir[0]),
#ifdef MACOSX
- NS_T("%s/Contents"),
- gWorkingDirPath);
+ NS_T("%s/Contents"),
+ gWorkingDirPath);
#else
- NS_T("%s.bak/updated"),
- gInstallDirPath);
+ NS_T("%s.bak/updated"),
+ gInstallDirPath);
#endif
- // First try to remove the possibly existing temp directory, because if this
- // directory exists, we will fail to rename destDir.
- // No need to error check here because if this fails, we will fail in the
- // next step anyways.
- ensure_remove_recursive(tmpDir);
+ // First try to remove the possibly existing temp directory, because if this
+ // directory exists, we will fail to rename destDir.
+ // No need to error check here because if this fails, we will fail in the
+ // next step anyways.
+ ensure_remove_recursive(tmpDir);
- LOG(("Begin moving destDir (" LOG_S ") to tmpDir (" LOG_S ")",
- destDir, tmpDir));
- int rv = rename_file(destDir, tmpDir, true);
+ LOG(("Begin moving destDir (" LOG_S ") to tmpDir (" LOG_S ")",
+ destDir, tmpDir));
+ int rv = rename_file(destDir, tmpDir, true);
#ifdef _WIN32
- // On Windows, if Firefox is launched using the shortcut, it will hold a handle
- // to its installation directory open, which might not get released in time.
- // Therefore we wait a little bit here to see if the handle is released.
- // If it's not released, we just fail to perform the replace request.
- const int max_retries = 10;
- int retries = 0;
- while (rv == WRITE_ERROR && (retries++ < max_retries)) {
- LOG(("PerformReplaceRequest: destDir rename attempt %d failed. " \
- "File: " LOG_S ". Last error: %d, err: %d", retries,
- destDir, GetLastError(), rv));
-
- Sleep(100);
-
- rv = rename_file(destDir, tmpDir, true);
- }
+ // On Windows, if Firefox is launched using the shortcut, it will hold a handle
+ // to its installation directory open, which might not get released in time.
+ // Therefore we wait a little bit here to see if the handle is released.
+ // If it's not released, we just fail to perform the replace request.
+ const int max_retries = 10;
+ int retries = 0;
+ while (rv == WRITE_ERROR && (retries++ < max_retries)) {
+ LOG(("PerformReplaceRequest: destDir rename attempt %d failed. " \
+ "File: " LOG_S ". Last error: %d, err: %d", retries,
+ destDir, GetLastError(), rv));
+
+ Sleep(100);
+
+ rv = rename_file(destDir, tmpDir, true);
+ }
#endif
- if (rv) {
- // The status file will have 'pending' written to it so there is no value in
- // returning an error specific for this failure.
- LOG(("Moving destDir to tmpDir failed, err: %d", rv));
- return rv;
- }
+ if (rv) {
+ // The status file will have 'pending' written to it so there is no value in
+ // returning an error specific for this failure.
+ LOG(("Moving destDir to tmpDir failed, err: %d", rv));
+ return rv;
+ }
- LOG(("Begin moving newDir (" LOG_S ") to destDir (" LOG_S ")",
- newDir, destDir));
- rv = rename_file(newDir, destDir, true);
+ LOG(("Begin moving newDir (" LOG_S ") to destDir (" LOG_S ")",
+ newDir, destDir));
+ rv = rename_file(newDir, destDir, true);
#ifdef MACOSX
- if (rv) {
- LOG(("Moving failed. Begin copying newDir (" LOG_S ") to destDir (" LOG_S ")",
- newDir, destDir));
- copy_recursive_skiplist<0> skiplist;
- rv = ensure_copy_recursive(newDir, destDir, skiplist);
- }
+ if (rv) {
+ LOG(("Moving failed. Begin copying newDir (" LOG_S ") to destDir (" LOG_S ")",
+ newDir, destDir));
+ copy_recursive_skiplist<0> skiplist;
+ rv = ensure_copy_recursive(newDir, destDir, skiplist);
+ }
#endif
- if (rv) {
- LOG(("Moving newDir to destDir failed, err: %d", rv));
- LOG(("Now, try to move tmpDir back to destDir"));
- ensure_remove_recursive(destDir);
- int rv2 = rename_file(tmpDir, destDir, true);
- if (rv2) {
- LOG(("Moving tmpDir back to destDir failed, err: %d", rv2));
- }
- // The status file will be have 'pending' written to it so there is no value
- // in returning an error specific for this failure.
- return rv;
- }
+ if (rv) {
+ LOG(("Moving newDir to destDir failed, err: %d", rv));
+ LOG(("Now, try to move tmpDir back to destDir"));
+ ensure_remove_recursive(destDir);
+ int rv2 = rename_file(tmpDir, destDir, true);
+ if (rv2) {
+ LOG(("Moving tmpDir back to destDir failed, err: %d", rv2));
+ }
+ // The status file will be have 'pending' written to it so there is no value
+ // in returning an error specific for this failure.
+ return rv;
+ }
- LOG(("Now, remove the tmpDir"));
- rv = ensure_remove_recursive(tmpDir, true);
- if (rv) {
- LOG(("Removing tmpDir failed, err: %d", rv));
+ LOG(("Now, remove the tmpDir"));
+ rv = ensure_remove_recursive(tmpDir, true);
+ if (rv) {
+ LOG(("Removing tmpDir failed, err: %d", rv));
#ifdef _WIN32
- NS_tchar deleteDir[MAXPATHLEN];
- NS_tsnprintf(deleteDir, sizeof(deleteDir)/sizeof(deleteDir[0]),
- NS_T("%s\\%s"), destDir, DELETE_DIR);
- // Attempt to remove the tobedeleted directory and then recreate it if it
- // was successfully removed.
- _wrmdir(deleteDir);
- if (NS_taccess(deleteDir, F_OK)) {
- NS_tmkdir(deleteDir, 0755);
- }
- remove_recursive_on_reboot(tmpDir, deleteDir);
+ NS_tchar deleteDir[MAXPATHLEN];
+ NS_tsnprintf(deleteDir, sizeof(deleteDir)/sizeof(deleteDir[0]),
+ NS_T("%s\\%s"), destDir, DELETE_DIR);
+ // Attempt to remove the tobedeleted directory and then recreate it if it
+ // was successfully removed.
+ _wrmdir(deleteDir);
+ if (NS_taccess(deleteDir, F_OK)) {
+ NS_tmkdir(deleteDir, 0755);
+ }
+ remove_recursive_on_reboot(tmpDir, deleteDir);
#endif
- }
+ }
#ifdef MACOSX
- // On OS X, we need to remove the staging directory after its Contents
- // directory has been moved.
- NS_tchar updatedAppDir[MAXPATHLEN];
- NS_tsnprintf(updatedAppDir, sizeof(updatedAppDir)/sizeof(updatedAppDir[0]),
- NS_T("%s/Updated.app"), gPatchDirPath);
- ensure_remove_recursive(updatedAppDir);
+ // On OS X, we need to remove the staging directory after its Contents
+ // directory has been moved.
+ NS_tchar updatedAppDir[MAXPATHLEN];
+ NS_tsnprintf(updatedAppDir, sizeof(updatedAppDir)/sizeof(updatedAppDir[0]),
+ NS_T("%s/Updated.app"), gPatchDirPath);
+ ensure_remove_recursive(updatedAppDir);
#endif
- gSucceeded = true;
+ gSucceeded = true;
- return 0;
+ return 0;
}
#ifdef _WIN32
static void
WaitForServiceFinishThread(void *param)
{
- // We wait at most 10 minutes, we already waited 5 seconds previously
- // before deciding to show this UI.
- WaitForServiceStop(SVC_NAME, 595);
- QuitProgressUI();
+ // We wait at most 10 minutes, we already waited 5 seconds previously
+ // before deciding to show this UI.
+ WaitForServiceStop(SVC_NAME, 595);
+ QuitProgressUI();
}
#endif
@@ -2037,1607 +2037,1607 @@ WaitForServiceFinishThread(void *param)
static int
ReadMARChannelIDs(const NS_tchar *path, MARChannelStringTable *results)
{
- const unsigned int kNumStrings = 1;
- const char *kUpdaterKeys = "ACCEPTED_MAR_CHANNEL_IDS\0";
- char updater_strings[kNumStrings][MAX_TEXT_LEN];
+ const unsigned int kNumStrings = 1;
+ const char *kUpdaterKeys = "ACCEPTED_MAR_CHANNEL_IDS\0";
+ char updater_strings[kNumStrings][MAX_TEXT_LEN];
- int result = ReadStrings(path, kUpdaterKeys, kNumStrings,
- updater_strings, "Settings");
+ int result = ReadStrings(path, kUpdaterKeys, kNumStrings,
+ updater_strings, "Settings");
- strncpy(results->MARChannelID, updater_strings[0], MAX_TEXT_LEN - 1);
- results->MARChannelID[MAX_TEXT_LEN - 1] = 0;
+ strncpy(results->MARChannelID, updater_strings[0], MAX_TEXT_LEN - 1);
+ results->MARChannelID[MAX_TEXT_LEN - 1] = 0;
- return result;
+ return result;
}
#endif
static int
GetUpdateFileName(NS_tchar *fileName, int maxChars)
{
- NS_tsnprintf(fileName, maxChars,
- NS_T("%s/update.mar"), gPatchDirPath);
- return OK;
+ NS_tsnprintf(fileName, maxChars,
+ NS_T("%s/update.mar"), gPatchDirPath);
+ return OK;
}
static void
UpdateThreadFunc(void * /*param*/)
{
- // open ZIP archive and process...
- int rv;
- if (sReplaceRequest) {
- rv = ProcessReplaceRequest();
- } else {
- NS_tchar dataFile[MAXPATHLEN];
- rv = GetUpdateFileName(dataFile, sizeof(dataFile)/sizeof(dataFile[0]));
- if (rv == OK) {
- rv = gArchiveReader.Open(dataFile);
- }
+ // open ZIP archive and process...
+ int rv;
+ if (sReplaceRequest) {
+ rv = ProcessReplaceRequest();
+ } else {
+ NS_tchar dataFile[MAXPATHLEN];
+ rv = GetUpdateFileName(dataFile, sizeof(dataFile)/sizeof(dataFile[0]));
+ if (rv == OK) {
+ rv = gArchiveReader.Open(dataFile);
+ }
#ifdef MOZ_VERIFY_MAR_SIGNATURE
- if (rv == OK) {
+ if (rv == OK) {
#ifdef _WIN32
- HKEY baseKey = nullptr;
- wchar_t valueName[] = L"Image Path";
- wchar_t rasenh[] = L"rsaenh.dll";
- bool reset = false;
- if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+ HKEY baseKey = nullptr;
+ wchar_t valueName[] = L"Image Path";
+ wchar_t rasenh[] = L"rsaenh.dll";
+ bool reset = false;
+ if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Cryptography\\Defaults\\Provider\\Microsoft Enhanced Cryptographic Provider v1.0",
0, KEY_READ | KEY_WRITE,
&baseKey) == ERROR_SUCCESS) {
- wchar_t path[MAX_PATH + 1];
- DWORD size = sizeof(path);
- DWORD type;
- if (RegQueryValueExW(baseKey, valueName, 0, &type,
- (LPBYTE)path, &size) == ERROR_SUCCESS) {
- if (type == REG_SZ && wcscmp(path, rasenh) == 0) {
- wchar_t rasenhFullPath[] = L"%SystemRoot%\\System32\\rsaenh.dll";
- if (RegSetValueExW(baseKey, valueName, 0, REG_SZ,
- (const BYTE*)rasenhFullPath,
- sizeof(rasenhFullPath)) == ERROR_SUCCESS) {
- reset = true;
+ wchar_t path[MAX_PATH + 1];
+ DWORD size = sizeof(path);
+ DWORD type;
+ if (RegQueryValueExW(baseKey, valueName, 0, &type,
+ (LPBYTE)path, &size) == ERROR_SUCCESS) {
+ if (type == REG_SZ && wcscmp(path, rasenh) == 0) {
+ wchar_t rasenhFullPath[] = L"%SystemRoot%\\System32\\rsaenh.dll";
+ if (RegSetValueExW(baseKey, valueName, 0, REG_SZ,
+ (const BYTE*)rasenhFullPath,
+ sizeof(rasenhFullPath)) == ERROR_SUCCESS) {
+ reset = true;
+ }
+ }
+ }
}
- }
- }
- }
#endif
- rv = gArchiveReader.VerifySignature();
+ rv = gArchiveReader.VerifySignature();
#ifdef _WIN32
- if (baseKey) {
- if (reset) {
- RegSetValueExW(baseKey, valueName, 0, REG_SZ,
- (const BYTE*)rasenh,
- sizeof(rasenh));
- }
- RegCloseKey(baseKey);
- }
+ if (baseKey) {
+ if (reset) {
+ RegSetValueExW(baseKey, valueName, 0, REG_SZ,
+ (const BYTE*)rasenh,
+ sizeof(rasenh));
+ }
+ RegCloseKey(baseKey);
+ }
#endif
- }
+ }
- if (rv == OK) {
- if (rv == OK) {
- NS_tchar updateSettingsPath[MAX_TEXT_LEN];
- NS_tsnprintf(updateSettingsPath,
- sizeof(updateSettingsPath) / sizeof(updateSettingsPath[0]),
+ if (rv == OK) {
+ if (rv == OK) {
+ NS_tchar updateSettingsPath[MAX_TEXT_LEN];
+ NS_tsnprintf(updateSettingsPath,
+ sizeof(updateSettingsPath) / sizeof(updateSettingsPath[0]),
#ifdef MACOSX
- NS_T("%s/Contents/Resources/update-settings.ini"),
+ NS_T("%s/Contents/Resources/update-settings.ini"),
#else
- NS_T("%s/update-settings.ini"),
+ NS_T("%s/update-settings.ini"),
#endif
- gWorkingDirPath);
- MARChannelStringTable MARStrings;
- if (ReadMARChannelIDs(updateSettingsPath, &MARStrings) != OK) {
- // If we can't read from update-settings.ini then we shouldn't impose
- // a MAR restriction. Some installations won't even include this file.
- MARStrings.MARChannelID[0] = '\0';
+ gWorkingDirPath);
+ MARChannelStringTable MARStrings;
+ if (ReadMARChannelIDs(updateSettingsPath, &MARStrings) != OK) {
+ // If we can't read from update-settings.ini then we shouldn't impose
+ // a MAR restriction. Some installations won't even include this file.
+ MARStrings.MARChannelID[0] = '\0';
+ }
+
+ rv = gArchiveReader.VerifyProductInformation(MARStrings.MARChannelID,
+ MOZ_APP_VERSION);
+ }
}
-
- rv = gArchiveReader.VerifyProductInformation(MARStrings.MARChannelID,
- MOZ_APP_VERSION);
- }
- }
#endif
- if (rv == OK && sStagedUpdate && !sIsOSUpdate) {
+ if (rv == OK && sStagedUpdate && !sIsOSUpdate) {
#ifdef TEST_UPDATER
- // The MOZ_TEST_SKIP_UPDATE_STAGE environment variable prevents copying
- // the files in dist/bin in the test updater when staging an update since
- // this can cause tests to timeout.
- if (EnvHasValue("MOZ_TEST_SKIP_UPDATE_STAGE")) {
- rv = OK;
- } else {
- rv = CopyInstallDirToDestDir();
- }
+ // The MOZ_TEST_SKIP_UPDATE_STAGE environment variable prevents copying
+ // the files in dist/bin in the test updater when staging an update since
+ // this can cause tests to timeout.
+ if (EnvHasValue("MOZ_TEST_SKIP_UPDATE_STAGE")) {
+ rv = OK;
+ } else {
+ rv = CopyInstallDirToDestDir();
+ }
#else
- rv = CopyInstallDirToDestDir();
+ rv = CopyInstallDirToDestDir();
#endif
+ }
+
+ if (rv == OK) {
+ rv = DoUpdate();
+ gArchiveReader.Close();
+ NS_tchar updatingDir[MAXPATHLEN];
+ NS_tsnprintf(updatingDir, sizeof(updatingDir)/sizeof(updatingDir[0]),
+ NS_T("%s/updating"), gWorkingDirPath);
+ ensure_remove_recursive(updatingDir);
+ }
}
- if (rv == OK) {
- rv = DoUpdate();
- gArchiveReader.Close();
- NS_tchar updatingDir[MAXPATHLEN];
- NS_tsnprintf(updatingDir, sizeof(updatingDir)/sizeof(updatingDir[0]),
- NS_T("%s/updating"), gWorkingDirPath);
- ensure_remove_recursive(updatingDir);
- }
- }
-
- if (sReplaceRequest && rv) {
- // When attempting to replace the application, we should fall back
- // to non-staged updates in case of a failure. We do this by
- // setting the status to pending, exiting the updater, and
- // launching the callback application. The callback application's
- // startup path will see the pending status, and will start the
- // updater application again in order to apply the update without
- // staging.
- ensure_remove_recursive(gWorkingDirPath);
- WriteStatusFile(sUsingService ? "pending-service" : "pending");
+ if (sReplaceRequest && rv) {
+ // When attempting to replace the application, we should fall back
+ // to non-staged updates in case of a failure. We do this by
+ // setting the status to pending, exiting the updater, and
+ // launching the callback application. The callback application's
+ // startup path will see the pending status, and will start the
+ // updater application again in order to apply the update without
+ // staging.
+ ensure_remove_recursive(gWorkingDirPath);
+ WriteStatusFile(sUsingService ? "pending-service" : "pending");
#ifdef TEST_UPDATER
- // Some tests need to use --test-process-updates again.
- putenv(const_cast<char*>("MOZ_TEST_PROCESS_UPDATES="));
+ // Some tests need to use --test-process-updates again.
+ putenv(const_cast<char*>("MOZ_TEST_PROCESS_UPDATES="));
#endif
- } else {
- if (rv) {
- LOG(("failed: %d", rv));
} else {
+ if (rv) {
+ LOG(("failed: %d", rv));
+ } else {
#ifdef MACOSX
- // If the update was successful we need to update the timestamp on the
- // top-level Mac OS X bundle directory so that Mac OS X's Launch Services
- // picks up any major changes when the bundle is updated.
- if (!sStagedUpdate && utimes(gInstallDirPath, nullptr) != 0) {
- LOG(("Couldn't set access/modification time on application bundle."));
- }
+ // If the update was successful we need to update the timestamp on the
+ // top-level Mac OS X bundle directory so that Mac OS X's Launch Services
+ // picks up any major changes when the bundle is updated.
+ if (!sStagedUpdate && utimes(gInstallDirPath, nullptr) != 0) {
+ LOG(("Couldn't set access/modification time on application bundle."));
+ }
#endif
- LOG(("succeeded"));
+ LOG(("succeeded"));
+ }
+ WriteStatusFile(rv);
}
- WriteStatusFile(rv);
- }
- LOG(("calling QuitProgressUI"));
- QuitProgressUI();
+ LOG(("calling QuitProgressUI"));
+ QuitProgressUI();
}
int NS_main(int argc, NS_tchar **argv)
{
#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(_WIN32) && !defined(MACOSX)
- // On Windows and Mac we rely on native APIs to do verifications so we don't
- // need to initialize NSS at all there.
- // Otherwise, minimize the amount of NSS we depend on by avoiding all the NSS
- // databases.
- if (NSS_NoDB_Init(NULL) != SECSuccess) {
- PRErrorCode error = PR_GetError();
- fprintf(stderr, "Could not initialize NSS: %s (%d)",
- PR_ErrorToName(error), (int) error);
- _exit(1);
- }
+ // On Windows and Mac we rely on native APIs to do verifications so we don't
+ // need to initialize NSS at all there.
+ // Otherwise, minimize the amount of NSS we depend on by avoiding all the NSS
+ // databases.
+ if (NSS_NoDB_Init(NULL) != SECSuccess) {
+ PRErrorCode error = PR_GetError();
+ fprintf(stderr, "Could not initialize NSS: %s (%d)",
+ PR_ErrorToName(error), (int) error);
+ _exit(1);
+ }
#endif
- InitProgressUI(&argc, &argv);
-
- // To process an update the updater command line must at a minimum have the
- // directory path containing the updater.mar file to process as the first
- // argument, the install directory as the second argument, and the directory
- // to apply the update to as the third argument. When the updater is launched
- // by another process the PID of the parent process should be provided in the
- // optional fourth argument and the updater will wait on the parent process to
- // exit if the value is non-zero and the process is present. This is necessary
- // due to not being able to update files that are in use on Windows. The
- // optional fifth argument is the callback's working directory and the
- // optional sixth argument is the callback path. The callback is the
- // application to launch after updating and it will be launched when these
- // arguments are provided whether the update was successful or not. All
- // remaining arguments are optional and are passed to the callback when it is
- // launched.
- if (argc < 4) {
- fprintf(stderr, "Usage: updater patch-dir install-dir apply-to-dir [wait-pid [callback-working-dir callback-path args...]]\n");
- return 1;
- }
-
- // The directory containing the update information.
- gPatchDirPath = argv[1];
- // The directory we're going to update to.
- // We copy this string because we need to remove trailing slashes. The C++
- // standard says that it's always safe to write to strings pointed to by argv
- // elements, but I don't necessarily believe it.
- NS_tstrncpy(gInstallDirPath, argv[2], MAXPATHLEN);
- gInstallDirPath[MAXPATHLEN - 1] = NS_T('\0');
- NS_tchar *slash = NS_tstrrchr(gInstallDirPath, NS_SLASH);
- if (slash && !slash[1]) {
- *slash = NS_T('\0');
- }
+ InitProgressUI(&argc, &argv);
+
+ // To process an update the updater command line must at a minimum have the
+ // directory path containing the updater.mar file to process as the first
+ // argument, the install directory as the second argument, and the directory
+ // to apply the update to as the third argument. When the updater is launched
+ // by another process the PID of the parent process should be provided in the
+ // optional fourth argument and the updater will wait on the parent process to
+ // exit if the value is non-zero and the process is present. This is necessary
+ // due to not being able to update files that are in use on Windows. The
+ // optional fifth argument is the callback's working directory and the
+ // optional sixth argument is the callback path. The callback is the
+ // application to launch after updating and it will be launched when these
+ // arguments are provided whether the update was successful or not. All
+ // remaining arguments are optional and are passed to the callback when it is
+ // launched.
+ if (argc < 4) {
+ fprintf(stderr, "Usage: updater patch-dir install-dir apply-to-dir [wait-pid [callback-working-dir callback-path args...]]\n");
+ return 1;
+ }
+
+ // The directory containing the update information.
+ gPatchDirPath = argv[1];
+ // The directory we're going to update to.
+ // We copy this string because we need to remove trailing slashes. The C++
+ // standard says that it's always safe to write to strings pointed to by argv
+ // elements, but I don't necessarily believe it.
+ NS_tstrncpy(gInstallDirPath, argv[2], MAXPATHLEN);
+ gInstallDirPath[MAXPATHLEN - 1] = NS_T('\0');
+ NS_tchar *slash = NS_tstrrchr(gInstallDirPath, NS_SLASH);
+ if (slash && !slash[1]) {
+ *slash = NS_T('\0');
+ }
#ifdef _WIN32
- bool useService = false;
- bool testOnlyFallbackKeyExists = false;
- bool noServiceFallback = EnvHasValue("MOZ_NO_SERVICE_FALLBACK");
- putenv(const_cast<char*>("MOZ_NO_SERVICE_FALLBACK="));
+ bool useService = false;
+ bool testOnlyFallbackKeyExists = false;
+ bool noServiceFallback = EnvHasValue("MOZ_NO_SERVICE_FALLBACK");
+ putenv(const_cast<char*>("MOZ_NO_SERVICE_FALLBACK="));
- // We never want the service to be used unless we build with
- // the maintenance service.
+ // We never want the service to be used unless we build with
+ // the maintenance service.
#ifdef MOZ_MAINTENANCE_SERVICE
- useService = IsUpdateStatusPendingService();
- // Our tests run with a different apply directory for each test.
- // We use this registry key on our test slaves to store the
- // allowed name/issuers.
- testOnlyFallbackKeyExists = DoesFallbackKeyExist();
+ useService = IsUpdateStatusPendingService();
+ // Our tests run with a different apply directory for each test.
+ // We use this registry key on our test slaves to store the
+ // allowed name/issuers.
+ testOnlyFallbackKeyExists = DoesFallbackKeyExist();
#endif
- // Remove everything except close window from the context menu
- {
- HKEY hkApp = nullptr;
- RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\Classes\\Applications",
- 0, nullptr, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, nullptr,
- &hkApp, nullptr);
- RegCloseKey(hkApp);
- if (RegCreateKeyExW(HKEY_CURRENT_USER,
- L"Software\\Classes\\Applications\\updater.exe",
- 0, nullptr, REG_OPTION_VOLATILE, KEY_SET_VALUE, nullptr,
- &hkApp, nullptr) == ERROR_SUCCESS) {
- RegSetValueExW(hkApp, L"IsHostApp", 0, REG_NONE, 0, 0);
- RegSetValueExW(hkApp, L"NoOpenWith", 0, REG_NONE, 0, 0);
- RegSetValueExW(hkApp, L"NoStartPage", 0, REG_NONE, 0, 0);
- RegCloseKey(hkApp);
- }
- }
+ // Remove everything except close window from the context menu
+ {
+ HKEY hkApp = nullptr;
+ RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\Classes\\Applications",
+ 0, nullptr, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, nullptr,
+ &hkApp, nullptr);
+ RegCloseKey(hkApp);
+ if (RegCreateKeyExW(HKEY_CURRENT_USER,
+ L"Software\\Classes\\Applications\\updater.exe",
+ 0, nullptr, REG_OPTION_VOLATILE, KEY_SET_VALUE, nullptr,
+ &hkApp, nullptr) == ERROR_SUCCESS) {
+ RegSetValueExW(hkApp, L"IsHostApp", 0, REG_NONE, 0, 0);
+ RegSetValueExW(hkApp, L"NoOpenWith", 0, REG_NONE, 0, 0);
+ RegSetValueExW(hkApp, L"NoStartPage", 0, REG_NONE, 0, 0);
+ RegCloseKey(hkApp);
+ }
+ }
#endif
- // If there is a PID specified and it is not '0' then wait for the process to exit.
+ // If there is a PID specified and it is not '0' then wait for the process to exit.
#ifdef _WIN32
- __int64 pid = 0;
+ __int64 pid = 0;
#else
- int pid = 0;
+ int pid = 0;
#endif
- if (argc > 4) {
+ if (argc > 4) {
#ifdef _WIN32
- pid = _wtoi64(argv[4]);
+ pid = _wtoi64(argv[4]);
#else
- pid = atoi(argv[4]);
+ pid = atoi(argv[4]);
#endif
- if (pid == -1) {
- // This is a signal from the parent process that the updater should stage
- // the update.
- sStagedUpdate = true;
- } else if (NS_tstrstr(argv[4], NS_T("/replace"))) {
- // We're processing a request to replace the application with a staged
- // update.
- sReplaceRequest = true;
- }
- }
-
- // The directory we're going to update to.
- // We copy this string because we need to remove trailing slashes. The C++
- // standard says that it's always safe to write to strings pointed to by argv
- // elements, but I don't necessarily believe it.
- NS_tstrncpy(gWorkingDirPath, argv[3], MAXPATHLEN);
- gWorkingDirPath[MAXPATHLEN - 1] = NS_T('\0');
- slash = NS_tstrrchr(gWorkingDirPath, NS_SLASH);
- if (slash && !slash[1]) {
- *slash = NS_T('\0');
- }
-
- if (EnvHasValue("MOZ_OS_UPDATE")) {
- sIsOSUpdate = true;
- putenv(const_cast<char*>("MOZ_OS_UPDATE="));
- }
-
- if (sReplaceRequest) {
- // If we're attempting to replace the application, try to append to the
- // log generated when staging the staged update.
+ if (pid == -1) {
+ // This is a signal from the parent process that the updater should stage
+ // the update.
+ sStagedUpdate = true;
+ } else if (NS_tstrstr(argv[4], NS_T("/replace"))) {
+ // We're processing a request to replace the application with a staged
+ // update.
+ sReplaceRequest = true;
+ }
+ }
+
+ // The directory we're going to update to.
+ // We copy this string because we need to remove trailing slashes. The C++
+ // standard says that it's always safe to write to strings pointed to by argv
+ // elements, but I don't necessarily believe it.
+ NS_tstrncpy(gWorkingDirPath, argv[3], MAXPATHLEN);
+ gWorkingDirPath[MAXPATHLEN - 1] = NS_T('\0');
+ slash = NS_tstrrchr(gWorkingDirPath, NS_SLASH);
+ if (slash && !slash[1]) {
+ *slash = NS_T('\0');
+ }
+
+ if (EnvHasValue("MOZ_OS_UPDATE")) {
+ sIsOSUpdate = true;
+ putenv(const_cast<char*>("MOZ_OS_UPDATE="));
+ }
+
+ if (sReplaceRequest) {
+ // If we're attempting to replace the application, try to append to the
+ // log generated when staging the staged update.
#ifdef _WIN32
- NS_tchar* logDir = gPatchDirPath;
+ NS_tchar* logDir = gPatchDirPath;
#else
#ifdef MACOSX
- NS_tchar* logDir = gPatchDirPath;
+ NS_tchar* logDir = gPatchDirPath;
#else
- NS_tchar logDir[MAXPATHLEN];
- NS_tsnprintf(logDir, sizeof(logDir)/sizeof(logDir[0]),
- NS_T("%s/updated/updates"),
- gInstallDirPath);
+ NS_tchar logDir[MAXPATHLEN];
+ NS_tsnprintf(logDir, sizeof(logDir)/sizeof(logDir[0]),
+ NS_T("%s/updated/updates"),
+ gInstallDirPath);
#endif
#endif
- LogInitAppend(logDir, NS_T("last-update.log"), NS_T("update.log"));
- } else {
- LogInit(gPatchDirPath, NS_T("update.log"));
- }
+ LogInitAppend(logDir, NS_T("last-update.log"), NS_T("update.log"));
+ } else {
+ LogInit(gPatchDirPath, NS_T("update.log"));
+ }
- if (!WriteStatusFile("applying")) {
- LOG(("failed setting status to 'applying'"));
- return 1;
- }
+ if (!WriteStatusFile("applying")) {
+ LOG(("failed setting status to 'applying'"));
+ return 1;
+ }
- if (sStagedUpdate) {
- LOG(("Performing a staged update"));
- } else if (sReplaceRequest) {
- LOG(("Performing a replace request"));
- }
+ if (sStagedUpdate) {
+ LOG(("Performing a staged update"));
+ } else if (sReplaceRequest) {
+ LOG(("Performing a replace request"));
+ }
- LOG(("PATCH DIRECTORY " LOG_S, gPatchDirPath));
- LOG(("INSTALLATION DIRECTORY " LOG_S, gInstallDirPath));
- LOG(("WORKING DIRECTORY " LOG_S, gWorkingDirPath));
+ LOG(("PATCH DIRECTORY " LOG_S, gPatchDirPath));
+ LOG(("INSTALLATION DIRECTORY " LOG_S, gInstallDirPath));
+ LOG(("WORKING DIRECTORY " LOG_S, gWorkingDirPath));
#ifdef _WIN32
- if (pid > 0) {
- HANDLE parent = OpenProcess(SYNCHRONIZE, false, (DWORD) pid);
- // May return nullptr if the parent process has already gone away.
- // Otherwise, wait for the parent process to exit before starting the
- // update.
- if (parent) {
- DWORD waitTime = PARENT_WAIT;
- DWORD result = WaitForSingleObject(parent, waitTime);
- CloseHandle(parent);
- if (result != WAIT_OBJECT_0)
- return 1;
+ if (pid > 0) {
+ HANDLE parent = OpenProcess(SYNCHRONIZE, false, (DWORD) pid);
+ // May return nullptr if the parent process has already gone away.
+ // Otherwise, wait for the parent process to exit before starting the
+ // update.
+ if (parent) {
+ DWORD waitTime = PARENT_WAIT;
+ DWORD result = WaitForSingleObject(parent, waitTime);
+ CloseHandle(parent);
+ if (result != WAIT_OBJECT_0)
+ return 1;
+ }
}
- }
#else
- if (pid > 0)
- waitpid(pid, nullptr, 0);
+ if (pid > 0)
+ waitpid(pid, nullptr, 0);
#endif
- if (sReplaceRequest) {
+ if (sReplaceRequest) {
#ifdef _WIN32
- // On Windows, the current working directory of the process should be changed
- // so that it's not locked.
- NS_tchar sysDir[MAX_PATH + 1] = { L'\0' };
- if (GetSystemDirectoryW(sysDir, MAX_PATH + 1)) {
- NS_tchdir(sysDir);
- }
+ // On Windows, the current working directory of the process should be changed
+ // so that it's not locked.
+ NS_tchar sysDir[MAX_PATH + 1] = { L'\0' };
+ if (GetSystemDirectoryW(sysDir, MAX_PATH + 1)) {
+ NS_tchdir(sysDir);
+ }
#endif
- }
+ }
- // The callback is the remaining arguments starting at callbackIndex.
- // The argument specified by callbackIndex is the callback executable and the
- // argument prior to callbackIndex is the working directory.
- const int callbackIndex = 6;
+ // The callback is the remaining arguments starting at callbackIndex.
+ // The argument specified by callbackIndex is the callback executable and the
+ // argument prior to callbackIndex is the working directory.
+ const int callbackIndex = 6;
#if defined(_WIN32)
- sUsingService = EnvHasValue("MOZ_USING_SERVICE");
- putenv(const_cast<char*>("MOZ_USING_SERVICE="));
- // lastFallbackError keeps track of the last error for the service not being
- // used, in case of an error when fallback is not enabled we write the
- // error to the update.status file.
- // When fallback is disabled (MOZ_NO_SERVICE_FALLBACK does not exist) then
- // we will instead fallback to not using the service and display a UAC prompt.
- int lastFallbackError = FALLBACKKEY_UNKNOWN_ERROR;
-
- // Launch a second instance of the updater with the runas verb on Windows
- // when write access is denied to the installation directory.
- HANDLE updateLockFileHandle = INVALID_HANDLE_VALUE;
- NS_tchar elevatedLockFilePath[MAXPATHLEN] = {NS_T('\0')};
- if (!sUsingService &&
- (argc > callbackIndex || sStagedUpdate || sReplaceRequest)) {
- NS_tchar updateLockFilePath[MAXPATHLEN];
- if (sStagedUpdate) {
- // When staging an update, the lock file is:
- // <install_dir>\updated.update_in_progress.lock
- NS_tsnprintf(updateLockFilePath,
- sizeof(updateLockFilePath)/sizeof(updateLockFilePath[0]),
- NS_T("%s/updated.update_in_progress.lock"), gInstallDirPath);
- } else if (sReplaceRequest) {
- // When processing a replace request, the lock file is:
- // <install_dir>\..\moz_update_in_progress.lock
- NS_tchar installDir[MAXPATHLEN];
- NS_tstrcpy(installDir, gInstallDirPath);
- NS_tchar *slash = (NS_tchar *) NS_tstrrchr(installDir, NS_SLASH);
- *slash = NS_T('\0');
- NS_tsnprintf(updateLockFilePath,
- sizeof(updateLockFilePath)/sizeof(updateLockFilePath[0]),
- NS_T("%s\\moz_update_in_progress.lock"), installDir);
- } else {
- // In the non-staging update case, the lock file is:
- // <install_dir>\<app_name>.exe.update_in_progress.lock
- NS_tsnprintf(updateLockFilePath,
- sizeof(updateLockFilePath)/sizeof(updateLockFilePath[0]),
- NS_T("%s.update_in_progress.lock"), argv[callbackIndex]);
- }
-
- // The update_in_progress.lock file should only exist during an update. In
- // case it exists attempt to remove it and exit if that fails to prevent
- // simultaneous updates occurring.
- if (!_waccess(updateLockFilePath, F_OK) &&
- NS_tremove(updateLockFilePath) != 0) {
- // Try to fall back to the old way of doing updates if a staged
- // update fails.
- if (sStagedUpdate || sReplaceRequest) {
- // Note that this could fail, but if it does, there isn't too much we
- // can do in order to recover anyways.
- WriteStatusFile("pending");
- }
- LOG(("Update already in progress! Exiting"));
- return 1;
- }
-
- updateLockFileHandle = CreateFileW(updateLockFilePath,
- GENERIC_READ | GENERIC_WRITE,
- 0,
- nullptr,
- OPEN_ALWAYS,
- FILE_FLAG_DELETE_ON_CLOSE,
- nullptr);
-
- NS_tsnprintf(elevatedLockFilePath,
- sizeof(elevatedLockFilePath)/sizeof(elevatedLockFilePath[0]),
- NS_T("%s/update_elevated.lock"), gPatchDirPath);
-
- // Even if a file has no sharing access, you can still get its attributes
- bool startedFromUnelevatedUpdater =
- GetFileAttributesW(elevatedLockFilePath) != INVALID_FILE_ATTRIBUTES;
-
- // If we're running from the service, then we were started with the same
- // token as the service so the permissions are already dropped. If we're
- // running from an elevated updater that was started from an unelevated
- // updater, then we drop the permissions here. We do not drop the
- // permissions on the originally called updater because we use its token
- // to start the callback application.
- if (startedFromUnelevatedUpdater) {
- // Disable every privilege we don't need. Processes started using
- // CreateProcess will use the same token as this process.
- UACHelper::DisablePrivileges(nullptr);
- }
-
- if (updateLockFileHandle == INVALID_HANDLE_VALUE ||
- (useService && testOnlyFallbackKeyExists && noServiceFallback)) {
- if (!_waccess(elevatedLockFilePath, F_OK) &&
- NS_tremove(elevatedLockFilePath) != 0) {
- fprintf(stderr, "Unable to create elevated lock file! Exiting\n");
- return 1;
- }
-
- HANDLE elevatedFileHandle;
- elevatedFileHandle = CreateFileW(elevatedLockFilePath,
- GENERIC_READ | GENERIC_WRITE,
- 0,
- nullptr,
- OPEN_ALWAYS,
- FILE_FLAG_DELETE_ON_CLOSE,
- nullptr);
-
- if (elevatedFileHandle == INVALID_HANDLE_VALUE) {
- LOG(("Unable to create elevated lock file! Exiting"));
- return 1;
- }
+ sUsingService = EnvHasValue("MOZ_USING_SERVICE");
+ putenv(const_cast<char*>("MOZ_USING_SERVICE="));
+ // lastFallbackError keeps track of the last error for the service not being
+ // used, in case of an error when fallback is not enabled we write the
+ // error to the update.status file.
+ // When fallback is disabled (MOZ_NO_SERVICE_FALLBACK does not exist) then
+ // we will instead fallback to not using the service and display a UAC prompt.
+ int lastFallbackError = FALLBACKKEY_UNKNOWN_ERROR;
+
+ // Launch a second instance of the updater with the runas verb on Windows
+ // when write access is denied to the installation directory.
+ HANDLE updateLockFileHandle = INVALID_HANDLE_VALUE;
+ NS_tchar elevatedLockFilePath[MAXPATHLEN] = {NS_T('\0')};
+ if (!sUsingService &&
+ (argc > callbackIndex || sStagedUpdate || sReplaceRequest)) {
+ NS_tchar updateLockFilePath[MAXPATHLEN];
+ if (sStagedUpdate) {
+ // When staging an update, the lock file is:
+ // <install_dir>\updated.update_in_progress.lock
+ NS_tsnprintf(updateLockFilePath,
+ sizeof(updateLockFilePath)/sizeof(updateLockFilePath[0]),
+ NS_T("%s/updated.update_in_progress.lock"), gInstallDirPath);
+ } else if (sReplaceRequest) {
+ // When processing a replace request, the lock file is:
+ // <install_dir>\..\moz_update_in_progress.lock
+ NS_tchar installDir[MAXPATHLEN];
+ NS_tstrcpy(installDir, gInstallDirPath);
+ NS_tchar *slash = (NS_tchar *) NS_tstrrchr(installDir, NS_SLASH);
+ *slash = NS_T('\0');
+ NS_tsnprintf(updateLockFilePath,
+ sizeof(updateLockFilePath)/sizeof(updateLockFilePath[0]),
+ NS_T("%s\\moz_update_in_progress.lock"), installDir);
+ } else {
+ // In the non-staging update case, the lock file is:
+ // <install_dir>\<app_name>.exe.update_in_progress.lock
+ NS_tsnprintf(updateLockFilePath,
+ sizeof(updateLockFilePath)/sizeof(updateLockFilePath[0]),
+ NS_T("%s.update_in_progress.lock"), argv[callbackIndex]);
+ }
- wchar_t *cmdLine = MakeCommandLine(argc - 1, argv + 1);
- if (!cmdLine) {
- CloseHandle(elevatedFileHandle);
- return 1;
- }
-
- // Make sure the path to the updater to use for the update is on local.
- // We do this check to make sure that file locking is available for
- // race condition security checks.
- if (useService) {
- BOOL isLocal = FALSE;
- useService = IsLocalFile(argv[0], isLocal) && isLocal;
- }
-
- // If we have unprompted elevation we should NOT use the service
- // for the update. Service updates happen with the SYSTEM account
- // which has more privs than we need to update with.
- // Windows 8 provides a user interface so users can configure this
- // behavior and it can be configured in the registry in all Windows
- // versions that support UAC.
- if (useService) {
- BOOL unpromptedElevation;
- if (IsUnpromptedElevation(unpromptedElevation)) {
- useService = !unpromptedElevation;
- }
- }
-
- // Make sure the service registry entries for the installation path
- // are available. If not don't use the service.
- if (useService) {
- WCHAR maintenanceServiceKey[MAX_PATH + 1];
- if (CalculateRegistryPathFromFilePath(gInstallDirPath,
- maintenanceServiceKey)) {
- HKEY baseKey = nullptr;
- if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
- maintenanceServiceKey, 0,
- KEY_READ | KEY_WOW64_64KEY,
- &baseKey) == ERROR_SUCCESS) {
- RegCloseKey(baseKey);
- } else {
- useService = testOnlyFallbackKeyExists;
- if (!useService) {
- lastFallbackError = FALLBACKKEY_NOKEY_ERROR;
+ // The update_in_progress.lock file should only exist during an update. In
+ // case it exists attempt to remove it and exit if that fails to prevent
+ // simultaneous updates occurring.
+ if (!_waccess(updateLockFilePath, F_OK) &&
+ NS_tremove(updateLockFilePath) != 0) {
+ // Try to fall back to the old way of doing updates if a staged
+ // update fails.
+ if (sStagedUpdate || sReplaceRequest) {
+ // Note that this could fail, but if it does, there isn't too much we
+ // can do in order to recover anyways.
+ WriteStatusFile("pending");
}
- }
- } else {
- useService = false;
- lastFallbackError = FALLBACKKEY_REGPATH_ERROR;
- }
- }
-
- // Originally we used to write "pending" to update.status before
- // launching the service command. This is no longer needed now
- // since the service command is launched from updater.exe. If anything
- // fails in between, we can fall back to using the normal update process
- // on our own.
-
- // If we still want to use the service try to launch the service
- // comamnd for the update.
- if (useService) {
- // If the update couldn't be started, then set useService to false so
- // we do the update the old way.
- DWORD ret = LaunchServiceSoftwareUpdateCommand(argc, (LPCWSTR *)argv);
- useService = (ret == ERROR_SUCCESS);
- // If the command was launched then wait for the service to be done.
- if (useService) {
- bool showProgressUI = false;
- // Never show the progress UI when staging updates.
- if (!sStagedUpdate) {
- // We need to call this separately instead of allowing ShowProgressUI
- // to initialize the strings because the service will move the
- // ini file out of the way when running updater.
- showProgressUI = !InitProgressUIStrings();
- }
-
- // Wait for the service to stop for 5 seconds. If the service
- // has still not stopped then show an indeterminate progress bar.
- DWORD lastState = WaitForServiceStop(SVC_NAME, 5);
- if (lastState != SERVICE_STOPPED) {
- std::thread waitThread(WaitForServiceFinishThread, nullptr);
- if (showProgressUI) {
- ShowProgressUI(true, false);
+ LOG(("Update already in progress! Exiting"));
+ return 1;
+ }
+
+ updateLockFileHandle = CreateFileW(updateLockFilePath,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ nullptr,
+ OPEN_ALWAYS,
+ FILE_FLAG_DELETE_ON_CLOSE,
+ nullptr);
+
+ NS_tsnprintf(elevatedLockFilePath,
+ sizeof(elevatedLockFilePath)/sizeof(elevatedLockFilePath[0]),
+ NS_T("%s/update_elevated.lock"), gPatchDirPath);
+
+ // Even if a file has no sharing access, you can still get its attributes
+ bool startedFromUnelevatedUpdater =
+ GetFileAttributesW(elevatedLockFilePath) != INVALID_FILE_ATTRIBUTES;
+
+ // If we're running from the service, then we were started with the same
+ // token as the service so the permissions are already dropped. If we're
+ // running from an elevated updater that was started from an unelevated
+ // updater, then we drop the permissions here. We do not drop the
+ // permissions on the originally called updater because we use its token
+ // to start the callback application.
+ if (startedFromUnelevatedUpdater) {
+ // Disable every privilege we don't need. Processes started using
+ // CreateProcess will use the same token as this process.
+ UACHelper::DisablePrivileges(nullptr);
+ }
+
+ if (updateLockFileHandle == INVALID_HANDLE_VALUE ||
+ (useService && testOnlyFallbackKeyExists && noServiceFallback)) {
+ if (!_waccess(elevatedLockFilePath, F_OK) &&
+ NS_tremove(elevatedLockFilePath) != 0) {
+ fprintf(stderr, "Unable to create elevated lock file! Exiting\n");
+ return 1;
}
- waitThread.join();
- }
-
- lastState = WaitForServiceStop(SVC_NAME, 1);
- if (lastState != SERVICE_STOPPED) {
- // If the service doesn't stop after 10 minutes there is
- // something seriously wrong.
- lastFallbackError = FALLBACKKEY_SERVICE_NO_STOP_ERROR;
- useService = false;
- }
- } else {
- lastFallbackError = FALLBACKKEY_LAUNCH_ERROR;
- }
- }
-
- // If the service can't be used when staging and update, make sure that
- // the UAC prompt is not shown! In this case, just set the status to
- // pending and the update will be applied during the next startup.
- if (!useService && sStagedUpdate) {
- if (updateLockFileHandle != INVALID_HANDLE_VALUE) {
- CloseHandle(updateLockFileHandle);
- }
- WriteStatusPending(gPatchDirPath);
- return 0;
- }
-
- // If we started the service command, and it finished, check the
- // update.status file to make sure it succeeded, and if it did
- // we need to manually start the PostUpdate process from the
- // current user's session of this unelevated updater.exe the
- // current process is running as.
- // Note that we don't need to do this if we're just staging the update,
- // as the PostUpdate step runs when performing the replacing in that case.
- if (useService && !sStagedUpdate) {
- bool updateStatusSucceeded = false;
- if (IsUpdateStatusSucceeded(updateStatusSucceeded) &&
- updateStatusSucceeded) {
- if (!LaunchWinPostProcess(gInstallDirPath, gPatchDirPath, false,
- nullptr)) {
- fprintf(stderr, "The post update process which runs as the user"
- " for service update could not be launched.");
- }
- }
- }
-
- // If we didn't want to use the service at all, or if an update was
- // already happening, or launching the service command failed, then
- // launch the elevated updater.exe as we do without the service.
- // We don't launch the elevated updater in the case that we did have
- // write access all along because in that case the only reason we're
- // using the service is because we are testing.
- if (!useService && !noServiceFallback &&
- updateLockFileHandle == INVALID_HANDLE_VALUE) {
- SHELLEXECUTEINFO sinfo;
- memset(&sinfo, 0, sizeof(SHELLEXECUTEINFO));
- sinfo.cbSize = sizeof(SHELLEXECUTEINFO);
- sinfo.fMask = SEE_MASK_FLAG_NO_UI |
- SEE_MASK_FLAG_DDEWAIT |
- SEE_MASK_NOCLOSEPROCESS;
- sinfo.hwnd = nullptr;
- sinfo.lpFile = argv[0];
- sinfo.lpParameters = cmdLine;
- sinfo.lpVerb = L"runas";
- sinfo.nShow = SW_SHOWNORMAL;
-
- bool result = ShellExecuteEx(&sinfo);
- free(cmdLine);
-
- if (result) {
- WaitForSingleObject(sinfo.hProcess, INFINITE);
- CloseHandle(sinfo.hProcess);
- } else {
- WriteStatusFile(ELEVATION_CANCELED);
- }
- }
-
- if (argc > callbackIndex) {
- LaunchCallbackApp(argv[5], argc - callbackIndex,
- argv + callbackIndex, sUsingService);
- }
-
- CloseHandle(elevatedFileHandle);
-
- if (!useService && !noServiceFallback &&
- INVALID_HANDLE_VALUE == updateLockFileHandle) {
- // We didn't use the service and we did run the elevated updater.exe.
- // The elevated updater.exe is responsible for writing out the
- // update.status file.
- return 0;
- } else if(useService) {
- // The service command was launched. The service is responsible for
- // writing out the update.status file.
- if (updateLockFileHandle != INVALID_HANDLE_VALUE) {
- CloseHandle(updateLockFileHandle);
- }
- return 0;
- } else {
- // Otherwise the service command was not launched at all.
- // We are only reaching this code path because we had write access
- // all along to the directory and a fallback key existed, and we
- // have fallback disabled (MOZ_NO_SERVICE_FALLBACK env var exists).
- // We only currently use this env var from XPCShell tests.
- CloseHandle(updateLockFileHandle);
- WriteStatusFile(lastFallbackError);
- return 0;
- }
- }
- }
+
+ HANDLE elevatedFileHandle;
+ elevatedFileHandle = CreateFileW(elevatedLockFilePath,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ nullptr,
+ OPEN_ALWAYS,
+ FILE_FLAG_DELETE_ON_CLOSE,
+ nullptr);
+
+ if (elevatedFileHandle == INVALID_HANDLE_VALUE) {
+ LOG(("Unable to create elevated lock file! Exiting"));
+ return 1;
+ }
+
+ wchar_t *cmdLine = MakeCommandLine(argc - 1, argv + 1);
+ if (!cmdLine) {
+ CloseHandle(elevatedFileHandle);
+ return 1;
+ }
+
+ // Make sure the path to the updater to use for the update is on local.
+ // We do this check to make sure that file locking is available for
+ // race condition security checks.
+ if (useService) {
+ BOOL isLocal = FALSE;
+ useService = IsLocalFile(argv[0], isLocal) && isLocal;
+ }
+
+ // If we have unprompted elevation we should NOT use the service
+ // for the update. Service updates happen with the SYSTEM account
+ // which has more privs than we need to update with.
+ // Windows 8 provides a user interface so users can configure this
+ // behavior and it can be configured in the registry in all Windows
+ // versions that support UAC.
+ if (useService) {
+ BOOL unpromptedElevation;
+ if (IsUnpromptedElevation(unpromptedElevation)) {
+ useService = !unpromptedElevation;
+ }
+ }
+
+ // Make sure the service registry entries for the installation path
+ // are available. If not don't use the service.
+ if (useService) {
+ WCHAR maintenanceServiceKey[MAX_PATH + 1];
+ if (CalculateRegistryPathFromFilePath(gInstallDirPath,
+ maintenanceServiceKey)) {
+ HKEY baseKey = nullptr;
+ if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+ maintenanceServiceKey, 0,
+ KEY_READ | KEY_WOW64_64KEY,
+ &baseKey) == ERROR_SUCCESS) {
+ RegCloseKey(baseKey);
+ } else {
+ useService = testOnlyFallbackKeyExists;
+ if (!useService) {
+ lastFallbackError = FALLBACKKEY_NOKEY_ERROR;
+ }
+ }
+ } else {
+ useService = false;
+ lastFallbackError = FALLBACKKEY_REGPATH_ERROR;
+ }
+ }
+
+ // Originally we used to write "pending" to update.status before
+ // launching the service command. This is no longer needed now
+ // since the service command is launched from updater.exe. If anything
+ // fails in between, we can fall back to using the normal update process
+ // on our own.
+
+ // If we still want to use the service try to launch the service
+ // comamnd for the update.
+ if (useService) {
+ // If the update couldn't be started, then set useService to false so
+ // we do the update the old way.
+ DWORD ret = LaunchServiceSoftwareUpdateCommand(argc, (LPCWSTR *)argv);
+ useService = (ret == ERROR_SUCCESS);
+ // If the command was launched then wait for the service to be done.
+ if (useService) {
+ bool showProgressUI = false;
+ // Never show the progress UI when staging updates.
+ if (!sStagedUpdate) {
+ // We need to call this separately instead of allowing ShowProgressUI
+ // to initialize the strings because the service will move the
+ // ini file out of the way when running updater.
+ showProgressUI = !InitProgressUIStrings();
+ }
+
+ // Wait for the service to stop for 5 seconds. If the service
+ // has still not stopped then show an indeterminate progress bar.
+ DWORD lastState = WaitForServiceStop(SVC_NAME, 5);
+ if (lastState != SERVICE_STOPPED) {
+ std::thread waitThread(WaitForServiceFinishThread, nullptr);
+ if (showProgressUI) {
+ ShowProgressUI(true, false);
+ }
+ waitThread.join();
+ }
+
+ lastState = WaitForServiceStop(SVC_NAME, 1);
+ if (lastState != SERVICE_STOPPED) {
+ // If the service doesn't stop after 10 minutes there is
+ // something seriously wrong.
+ lastFallbackError = FALLBACKKEY_SERVICE_NO_STOP_ERROR;
+ useService = false;
+ }
+ } else {
+ lastFallbackError = FALLBACKKEY_LAUNCH_ERROR;
+ }
+ }
+
+ // If the service can't be used when staging and update, make sure that
+ // the UAC prompt is not shown! In this case, just set the status to
+ // pending and the update will be applied during the next startup.
+ if (!useService && sStagedUpdate) {
+ if (updateLockFileHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(updateLockFileHandle);
+ }
+ WriteStatusPending(gPatchDirPath);
+ return 0;
+ }
+
+ // If we started the service command, and it finished, check the
+ // update.status file to make sure it succeeded, and if it did
+ // we need to manually start the PostUpdate process from the
+ // current user's session of this unelevated updater.exe the
+ // current process is running as.
+ // Note that we don't need to do this if we're just staging the update,
+ // as the PostUpdate step runs when performing the replacing in that case.
+ if (useService && !sStagedUpdate) {
+ bool updateStatusSucceeded = false;
+ if (IsUpdateStatusSucceeded(updateStatusSucceeded) &&
+ updateStatusSucceeded) {
+ if (!LaunchWinPostProcess(gInstallDirPath, gPatchDirPath, false,
+ nullptr)) {
+ fprintf(stderr, "The post update process which runs as the user"
+ " for service update could not be launched.");
+ }
+ }
+ }
+
+ // If we didn't want to use the service at all, or if an update was
+ // already happening, or launching the service command failed, then
+ // launch the elevated updater.exe as we do without the service.
+ // We don't launch the elevated updater in the case that we did have
+ // write access all along because in that case the only reason we're
+ // using the service is because we are testing.
+ if (!useService && !noServiceFallback &&
+ updateLockFileHandle == INVALID_HANDLE_VALUE) {
+ SHELLEXECUTEINFO sinfo;
+ memset(&sinfo, 0, sizeof(SHELLEXECUTEINFO));
+ sinfo.cbSize = sizeof(SHELLEXECUTEINFO);
+ sinfo.fMask = SEE_MASK_FLAG_NO_UI |
+ SEE_MASK_FLAG_DDEWAIT |
+ SEE_MASK_NOCLOSEPROCESS;
+ sinfo.hwnd = nullptr;
+ sinfo.lpFile = argv[0];
+ sinfo.lpParameters = cmdLine;
+ sinfo.lpVerb = L"runas";
+ sinfo.nShow = SW_SHOWNORMAL;
+
+ bool result = ShellExecuteEx(&sinfo);
+ free(cmdLine);
+
+ if (result) {
+ WaitForSingleObject(sinfo.hProcess, INFINITE);
+ CloseHandle(sinfo.hProcess);
+ } else {
+ WriteStatusFile(ELEVATION_CANCELED);
+ }
+ }
+
+ if (argc > callbackIndex) {
+ LaunchCallbackApp(argv[5], argc - callbackIndex,
+ argv + callbackIndex, sUsingService);
+ }
+
+ CloseHandle(elevatedFileHandle);
+
+ if (!useService && !noServiceFallback &&
+ INVALID_HANDLE_VALUE == updateLockFileHandle) {
+ // We didn't use the service and we did run the elevated updater.exe.
+ // The elevated updater.exe is responsible for writing out the
+ // update.status file.
+ return 0;
+ } else if(useService) {
+ // The service command was launched. The service is responsible for
+ // writing out the update.status file.
+ if (updateLockFileHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(updateLockFileHandle);
+ }
+ return 0;
+ } else {
+ // Otherwise the service command was not launched at all.
+ // We are only reaching this code path because we had write access
+ // all along to the directory and a fallback key existed, and we
+ // have fallback disabled (MOZ_NO_SERVICE_FALLBACK env var exists).
+ // We only currently use this env var from XPCShell tests.
+ CloseHandle(updateLockFileHandle);
+ WriteStatusFile(lastFallbackError);
+ return 0;
+ }
+ }
+ }
#endif
- if (sStagedUpdate) {
- // When staging updates, blow away the old installation directory and create
- // it from scratch.
- ensure_remove_recursive(gWorkingDirPath);
- }
- if (!sReplaceRequest) {
- // Change current directory to the directory where we need to apply the update.
- if (NS_tchdir(gWorkingDirPath) != 0) {
- // Try to create the destination directory if it doesn't exist
- int rv = NS_tmkdir(gWorkingDirPath, 0755);
- if (rv == OK && errno != EEXIST) {
- // Try changing the current directory again
+ if (sStagedUpdate) {
+ // When staging updates, blow away the old installation directory and create
+ // it from scratch.
+ ensure_remove_recursive(gWorkingDirPath);
+ }
+ if (!sReplaceRequest) {
+ // Change current directory to the directory where we need to apply the update.
if (NS_tchdir(gWorkingDirPath) != 0) {
- // OK, time to give up!
- return 1;
+ // Try to create the destination directory if it doesn't exist
+ int rv = NS_tmkdir(gWorkingDirPath, 0755);
+ if (rv == OK && errno != EEXIST) {
+ // Try changing the current directory again
+ if (NS_tchdir(gWorkingDirPath) != 0) {
+ // OK, time to give up!
+ return 1;
+ }
+ } else {
+ // Failed to create the directory, bail out
+ return 1;
+ }
}
- } else {
- // Failed to create the directory, bail out
- return 1;
- }
}
- }
#ifdef _WIN32
- // For replace requests, we don't need to do any real updates, so this is not
- // necessary.
- if (!sReplaceRequest) {
- // Allocate enough space for the length of the path an optional additional
- // trailing slash and null termination.
- NS_tchar *destpath = (NS_tchar *) malloc((NS_tstrlen(gWorkingDirPath) + 2) * sizeof(NS_tchar));
- if (!destpath)
- return 1;
-
- NS_tchar *c = destpath;
- NS_tstrcpy(c, gWorkingDirPath);
- c += NS_tstrlen(gWorkingDirPath);
- if (gWorkingDirPath[NS_tstrlen(gWorkingDirPath) - 1] != NS_T('/') &&
- gWorkingDirPath[NS_tstrlen(gWorkingDirPath) - 1] != NS_T('\\')) {
- NS_tstrcat(c, NS_T("/"));
- c += NS_tstrlen(NS_T("/"));
+ // For replace requests, we don't need to do any real updates, so this is not
+ // necessary.
+ if (!sReplaceRequest) {
+ // Allocate enough space for the length of the path an optional additional
+ // trailing slash and null termination.
+ NS_tchar *destpath = (NS_tchar *) malloc((NS_tstrlen(gWorkingDirPath) + 2) * sizeof(NS_tchar));
+ if (!destpath)
+ return 1;
+
+ NS_tchar *c = destpath;
+ NS_tstrcpy(c, gWorkingDirPath);
+ c += NS_tstrlen(gWorkingDirPath);
+ if (gWorkingDirPath[NS_tstrlen(gWorkingDirPath) - 1] != NS_T('/') &&
+ gWorkingDirPath[NS_tstrlen(gWorkingDirPath) - 1] != NS_T('\\')) {
+ NS_tstrcat(c, NS_T("/"));
+ c += NS_tstrlen(NS_T("/"));
+ }
+ *c = NS_T('\0');
+ c++;
+
+ gDestPath = destpath;
+ }
+
+ NS_tchar applyDirLongPath[MAXPATHLEN];
+ if (!GetLongPathNameW(gWorkingDirPath, applyDirLongPath,
+ sizeof(applyDirLongPath)/sizeof(applyDirLongPath[0]))) {
+ LOG(("NS_main: unable to find apply to dir: " LOG_S, gWorkingDirPath));
+ LogFinish();
+ WriteStatusFile(WRITE_ERROR_APPLY_DIR_PATH);
+ EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1);
+ if (argc > callbackIndex) {
+ LaunchCallbackApp(argv[5], argc - callbackIndex,
+ argv + callbackIndex, sUsingService);
+ }
+ return 1;
}
- *c = NS_T('\0');
- c++;
- gDestPath = destpath;
- }
-
- NS_tchar applyDirLongPath[MAXPATHLEN];
- if (!GetLongPathNameW(gWorkingDirPath, applyDirLongPath,
- sizeof(applyDirLongPath)/sizeof(applyDirLongPath[0]))) {
- LOG(("NS_main: unable to find apply to dir: " LOG_S, gWorkingDirPath));
- LogFinish();
- WriteStatusFile(WRITE_ERROR_APPLY_DIR_PATH);
- EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1);
+ HANDLE callbackFile = INVALID_HANDLE_VALUE;
if (argc > callbackIndex) {
- LaunchCallbackApp(argv[5], argc - callbackIndex,
- argv + callbackIndex, sUsingService);
- }
- return 1;
- }
-
- HANDLE callbackFile = INVALID_HANDLE_VALUE;
- if (argc > callbackIndex) {
- // If the callback executable is specified it must exist for a successful
- // update. It is important we null out the whole buffer here because later
- // we make the assumption that the callback application is inside the
- // apply-to dir. If we don't have a fully null'ed out buffer it can lead
- // to stack corruption which causes crashes and other problems.
- NS_tchar callbackLongPath[MAXPATHLEN];
- ZeroMemory(callbackLongPath, sizeof(callbackLongPath));
- NS_tchar *targetPath = argv[callbackIndex];
- NS_tchar buffer[MAXPATHLEN * 2] = { NS_T('\0') };
- size_t bufferLeft = MAXPATHLEN * 2;
- if (sReplaceRequest) {
- // In case of replace requests, we should look for the callback file in
- // the destination directory.
- size_t commonPrefixLength = PathCommonPrefixW(argv[callbackIndex],
- gInstallDirPath,
- nullptr);
- NS_tchar *p = buffer;
- NS_tstrncpy(p, argv[callbackIndex], commonPrefixLength);
- p += commonPrefixLength;
- bufferLeft -= commonPrefixLength;
- NS_tstrncpy(p, gInstallDirPath + commonPrefixLength, bufferLeft);
-
- size_t len = NS_tstrlen(gInstallDirPath + commonPrefixLength);
- p += len;
- bufferLeft -= len;
- *p = NS_T('\\');
- ++p;
- bufferLeft--;
- *p = NS_T('\0');
- NS_tchar installDir[MAXPATHLEN];
- NS_tstrcpy(installDir, gInstallDirPath);
- size_t callbackPrefixLength = PathCommonPrefixW(argv[callbackIndex],
- installDir,
- nullptr);
- NS_tstrncpy(p, argv[callbackIndex] + std::max(callbackPrefixLength,
- commonPrefixLength), bufferLeft);
- targetPath = buffer;
- }
- if (!GetLongPathNameW(targetPath, callbackLongPath,
- sizeof(callbackLongPath)/sizeof(callbackLongPath[0]))) {
- LOG(("NS_main: unable to find callback file: " LOG_S, targetPath));
- LogFinish();
- WriteStatusFile(WRITE_ERROR_CALLBACK_PATH);
- EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1);
- if (argc > callbackIndex) {
- LaunchCallbackApp(argv[5],
- argc - callbackIndex,
- argv + callbackIndex,
- sUsingService);
- }
- return 1;
- }
-
- // Doing this is only necessary when we're actually applying a patch.
- if (!sReplaceRequest) {
- int len = NS_tstrlen(applyDirLongPath);
- NS_tchar *s = callbackLongPath;
- NS_tchar *d = gCallbackRelPath;
- // advance to the apply to directory and advance past the trailing backslash
- // if present.
- s += len;
- if (*s == NS_T('\\'))
- ++s;
-
- // Copy the string and replace backslashes with forward slashes along the
- // way.
- do {
- if (*s == NS_T('\\'))
- *d = NS_T('/');
- else
- *d = *s;
- ++s;
- ++d;
- } while (*s);
- *d = NS_T('\0');
- ++d;
-
- // Make a copy of the callback executable so it can be read when patching.
- NS_tsnprintf(gCallbackBackupPath,
- sizeof(gCallbackBackupPath)/sizeof(gCallbackBackupPath[0]),
- NS_T("%s" CALLBACK_BACKUP_EXT), argv[callbackIndex]);
- NS_tremove(gCallbackBackupPath);
- CopyFileW(argv[callbackIndex], gCallbackBackupPath, false);
-
- // Since the process may be signaled as exited by WaitForSingleObject before
- // the release of the executable image try to lock the main executable file
- // multiple times before giving up. If we end up giving up, we won't
- // fail the update.
- const int max_retries = 10;
- int retries = 1;
- DWORD lastWriteError = 0;
- do {
- // By opening a file handle without FILE_SHARE_READ to the callback
- // executable, the OS will prevent launching the process while it is
- // being updated.
- callbackFile = CreateFileW(targetPath,
- DELETE | GENERIC_WRITE,
- // allow delete, rename, and write
- FILE_SHARE_DELETE | FILE_SHARE_WRITE,
- nullptr, OPEN_EXISTING, 0, nullptr);
- if (callbackFile != INVALID_HANDLE_VALUE)
- break;
-
- lastWriteError = GetLastError();
- LOG(("NS_main: callback app file open attempt %d failed. " \
- "File: " LOG_S ". Last error: %d", retries,
- targetPath, lastWriteError));
+ // If the callback executable is specified it must exist for a successful
+ // update. It is important we null out the whole buffer here because later
+ // we make the assumption that the callback application is inside the
+ // apply-to dir. If we don't have a fully null'ed out buffer it can lead
+ // to stack corruption which causes crashes and other problems.
+ NS_tchar callbackLongPath[MAXPATHLEN];
+ ZeroMemory(callbackLongPath, sizeof(callbackLongPath));
+ NS_tchar *targetPath = argv[callbackIndex];
+ NS_tchar buffer[MAXPATHLEN * 2] = { NS_T('\0') };
+ size_t bufferLeft = MAXPATHLEN * 2;
+ if (sReplaceRequest) {
+ // In case of replace requests, we should look for the callback file in
+ // the destination directory.
+ size_t commonPrefixLength = PathCommonPrefixW(argv[callbackIndex],
+ gInstallDirPath,
+ nullptr);
+ NS_tchar *p = buffer;
+ NS_tstrncpy(p, argv[callbackIndex], commonPrefixLength);
+ p += commonPrefixLength;
+ bufferLeft -= commonPrefixLength;
+ NS_tstrncpy(p, gInstallDirPath + commonPrefixLength, bufferLeft);
+
+ size_t len = NS_tstrlen(gInstallDirPath + commonPrefixLength);
+ p += len;
+ bufferLeft -= len;
+ *p = NS_T('\\');
+ ++p;
+ bufferLeft--;
+ *p = NS_T('\0');
+ NS_tchar installDir[MAXPATHLEN];
+ NS_tstrcpy(installDir, gInstallDirPath);
+ size_t callbackPrefixLength = PathCommonPrefixW(argv[callbackIndex],
+ installDir,
+ nullptr);
+ NS_tstrncpy(p, argv[callbackIndex] + std::max(callbackPrefixLength,
+ commonPrefixLength), bufferLeft);
+ targetPath = buffer;
+ }
+ if (!GetLongPathNameW(targetPath, callbackLongPath,
+ sizeof(callbackLongPath)/sizeof(callbackLongPath[0]))) {
+ LOG(("NS_main: unable to find callback file: " LOG_S, targetPath));
+ LogFinish();
+ WriteStatusFile(WRITE_ERROR_CALLBACK_PATH);
+ EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1);
+ if (argc > callbackIndex) {
+ LaunchCallbackApp(argv[5],
+ argc - callbackIndex,
+ argv + callbackIndex,
+ sUsingService);
+ }
+ return 1;
+ }
- Sleep(100);
- } while (++retries <= max_retries);
-
- // CreateFileW will fail if the callback executable is already in use.
- if (callbackFile == INVALID_HANDLE_VALUE) {
- // Only fail the update if the last error was not a sharing violation.
- if (lastWriteError != ERROR_SHARING_VIOLATION) {
- LOG(("NS_main: callback app file in use, failed to exclusively open " \
- "executable file: " LOG_S, argv[callbackIndex]));
- LogFinish();
- if (lastWriteError == ERROR_ACCESS_DENIED) {
- WriteStatusFile(WRITE_ERROR_ACCESS_DENIED);
- } else {
- WriteStatusFile(WRITE_ERROR_CALLBACK_APP);
- }
-
- NS_tremove(gCallbackBackupPath);
- EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1);
- LaunchCallbackApp(argv[5],
+ // Doing this is only necessary when we're actually applying a patch.
+ if (!sReplaceRequest) {
+ int len = NS_tstrlen(applyDirLongPath);
+ NS_tchar *s = callbackLongPath;
+ NS_tchar *d = gCallbackRelPath;
+ // advance to the apply to directory and advance past the trailing backslash
+ // if present.
+ s += len;
+ if (*s == NS_T('\\'))
+ ++s;
+
+ // Copy the string and replace backslashes with forward slashes along the
+ // way.
+ do {
+ if (*s == NS_T('\\'))
+ *d = NS_T('/');
+ else
+ *d = *s;
+ ++s;
+ ++d;
+ } while (*s);
+ *d = NS_T('\0');
+ ++d;
+
+ // Make a copy of the callback executable so it can be read when patching.
+ NS_tsnprintf(gCallbackBackupPath,
+ sizeof(gCallbackBackupPath)/sizeof(gCallbackBackupPath[0]),
+ NS_T("%s" CALLBACK_BACKUP_EXT), argv[callbackIndex]);
+ NS_tremove(gCallbackBackupPath);
+ CopyFileW(argv[callbackIndex], gCallbackBackupPath, false);
+
+ // Since the process may be signaled as exited by WaitForSingleObject before
+ // the release of the executable image try to lock the main executable file
+ // multiple times before giving up. If we end up giving up, we won't
+ // fail the update.
+ const int max_retries = 10;
+ int retries = 1;
+ DWORD lastWriteError = 0;
+ do {
+ // By opening a file handle without FILE_SHARE_READ to the callback
+ // executable, the OS will prevent launching the process while it is
+ // being updated.
+ callbackFile = CreateFileW(targetPath,
+ DELETE | GENERIC_WRITE,
+ // allow delete, rename, and write
+ FILE_SHARE_DELETE | FILE_SHARE_WRITE,
+ nullptr, OPEN_EXISTING, 0, nullptr);
+ if (callbackFile != INVALID_HANDLE_VALUE)
+ break;
+
+ lastWriteError = GetLastError();
+ LOG(("NS_main: callback app file open attempt %d failed. " \
+ "File: " LOG_S ". Last error: %d", retries,
+ targetPath, lastWriteError));
+
+ Sleep(100);
+ } while (++retries <= max_retries);
+
+ // CreateFileW will fail if the callback executable is already in use.
+ if (callbackFile == INVALID_HANDLE_VALUE) {
+ // Only fail the update if the last error was not a sharing violation.
+ if (lastWriteError != ERROR_SHARING_VIOLATION) {
+ LOG(("NS_main: callback app file in use, failed to exclusively open " \
+ "executable file: " LOG_S, argv[callbackIndex]));
+ LogFinish();
+ if (lastWriteError == ERROR_ACCESS_DENIED) {
+ WriteStatusFile(WRITE_ERROR_ACCESS_DENIED);
+ } else {
+ WriteStatusFile(WRITE_ERROR_CALLBACK_APP);
+ }
+
+ NS_tremove(gCallbackBackupPath);
+ EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1);
+ LaunchCallbackApp(argv[5],
argc - callbackIndex,
argv + callbackIndex,
sUsingService);
- return 1;
+ return 1;
+ }
+ LOG(("NS_main: callback app file in use, continuing without " \
+ "exclusive access for executable file: " LOG_S,
+ argv[callbackIndex]));
+ }
}
- LOG(("NS_main: callback app file in use, continuing without " \
- "exclusive access for executable file: " LOG_S,
- argv[callbackIndex]));
- }
}
- }
- // DELETE_DIR is not required when staging an update.
- if (!sStagedUpdate && !sReplaceRequest) {
- // The directory to move files that are in use to on Windows. This directory
- // will be deleted after the update is finished or on OS reboot using
- // MoveFileEx if it contains files that are in use.
- if (NS_taccess(DELETE_DIR, F_OK)) {
- NS_tmkdir(DELETE_DIR, 0755);
+ // DELETE_DIR is not required when staging an update.
+ if (!sStagedUpdate && !sReplaceRequest) {
+ // The directory to move files that are in use to on Windows. This directory
+ // will be deleted after the update is finished or on OS reboot using
+ // MoveFileEx if it contains files that are in use.
+ if (NS_taccess(DELETE_DIR, F_OK)) {
+ NS_tmkdir(DELETE_DIR, 0755);
+ }
}
- }
#endif /* WNT */
- // Run update process on a background thread. ShowProgressUI may return
- // before QuitProgressUI has been called, so wait for UpdateThreadFunc to
- // terminate. Avoid showing the progress UI when staging an update.
- std::thread updateThread(UpdateThreadFunc, nullptr);
- if (!sStagedUpdate && !sReplaceRequest)
- {
- ShowProgressUI();
- }
- updateThread.join();
+ // Run update process on a background thread. ShowProgressUI may return
+ // before QuitProgressUI has been called, so wait for UpdateThreadFunc to
+ // terminate. Avoid showing the progress UI when staging an update.
+ std::thread updateThread(UpdateThreadFunc, nullptr);
+ if (!sStagedUpdate && !sReplaceRequest)
+ {
+ ShowProgressUI();
+ }
+ updateThread.join();
#ifdef _WIN32
- if (argc > callbackIndex && !sReplaceRequest) {
- if (callbackFile != INVALID_HANDLE_VALUE) {
- CloseHandle(callbackFile);
- }
- // Remove the copy of the callback executable.
- NS_tremove(gCallbackBackupPath);
- }
-
- if (!sStagedUpdate && !sReplaceRequest && _wrmdir(DELETE_DIR)) {
- LOG(("NS_main: unable to remove directory: " LOG_S ", err: %d",
- DELETE_DIR, errno));
- // The directory probably couldn't be removed due to it containing files
- // that are in use and will be removed on OS reboot. The call to remove the
- // directory on OS reboot is done after the calls to remove the files so the
- // files are removed first on OS reboot since the directory must be empty
- // for the directory removal to be successful. The MoveFileEx call to remove
- // the directory on OS reboot will fail if the process doesn't have write
- // access to the HKEY_LOCAL_MACHINE registry key but this is ok since the
- // installer / uninstaller will delete the directory along with its contents
- // after an update is applied, on reinstall, and on uninstall.
- if (MoveFileEx(DELETE_DIR, nullptr, MOVEFILE_DELAY_UNTIL_REBOOT)) {
- LOG(("NS_main: directory will be removed on OS reboot: " LOG_S,
- DELETE_DIR));
- } else {
- LOG(("NS_main: failed to schedule OS reboot removal of " \
- "directory: " LOG_S, DELETE_DIR));
+ if (argc > callbackIndex && !sReplaceRequest) {
+ if (callbackFile != INVALID_HANDLE_VALUE) {
+ CloseHandle(callbackFile);
+ }
+ // Remove the copy of the callback executable.
+ NS_tremove(gCallbackBackupPath);
+ }
+
+ if (!sStagedUpdate && !sReplaceRequest && _wrmdir(DELETE_DIR)) {
+ LOG(("NS_main: unable to remove directory: " LOG_S ", err: %d",
+ DELETE_DIR, errno));
+ // The directory probably couldn't be removed due to it containing files
+ // that are in use and will be removed on OS reboot. The call to remove the
+ // directory on OS reboot is done after the calls to remove the files so the
+ // files are removed first on OS reboot since the directory must be empty
+ // for the directory removal to be successful. The MoveFileEx call to remove
+ // the directory on OS reboot will fail if the process doesn't have write
+ // access to the HKEY_LOCAL_MACHINE registry key but this is ok since the
+ // installer / uninstaller will delete the directory along with its contents
+ // after an update is applied, on reinstall, and on uninstall.
+ if (MoveFileEx(DELETE_DIR, nullptr, MOVEFILE_DELAY_UNTIL_REBOOT)) {
+ LOG(("NS_main: directory will be removed on OS reboot: " LOG_S,
+ DELETE_DIR));
+ } else {
+ LOG(("NS_main: failed to schedule OS reboot removal of " \
+ "directory: " LOG_S, DELETE_DIR));
+ }
}
- }
#endif /* WNT */
#ifdef MACOSX
- // When the update is successful remove the precomplete file in the root of
- // the application bundle and move the distribution directory from
- // Contents/MacOS to Contents/Resources and if both exist delete the
- // directory under Contents/MacOS (see Bug 1068439).
- if (gSucceeded && !sStagedUpdate) {
- NS_tchar oldPrecomplete[MAXPATHLEN];
- NS_tsnprintf(oldPrecomplete, sizeof(oldPrecomplete)/sizeof(oldPrecomplete[0]),
- NS_T("%s/precomplete"), gInstallDirPath);
- NS_tremove(oldPrecomplete);
-
- NS_tchar oldDistDir[MAXPATHLEN];
- NS_tsnprintf(oldDistDir, sizeof(oldDistDir)/sizeof(oldDistDir[0]),
- NS_T("%s/Contents/MacOS/distribution"), gInstallDirPath);
- int rv = NS_taccess(oldDistDir, F_OK);
- if (!rv) {
- NS_tchar newDistDir[MAXPATHLEN];
- NS_tsnprintf(newDistDir, sizeof(newDistDir)/sizeof(newDistDir[0]),
- NS_T("%s/Contents/Resources/distribution"), gInstallDirPath);
- rv = NS_taccess(newDistDir, F_OK);
- if (!rv) {
- LOG(("New distribution directory already exists... removing old " \
- "distribution directory: " LOG_S, oldDistDir));
- rv = ensure_remove_recursive(oldDistDir);
- if (rv) {
- LOG(("Removing old distribution directory failed - err: %d", rv));
- }
- } else {
- LOG(("Moving old distribution directory to new location. src: " LOG_S \
- ", dst:" LOG_S, oldDistDir, newDistDir));
- rv = rename_file(oldDistDir, newDistDir, true);
- if (rv) {
- LOG(("Moving old distribution directory to new location failed - " \
- "err: %d", rv));
+ // When the update is successful remove the precomplete file in the root of
+ // the application bundle and move the distribution directory from
+ // Contents/MacOS to Contents/Resources and if both exist delete the
+ // directory under Contents/MacOS (see Bug 1068439).
+ if (gSucceeded && !sStagedUpdate) {
+ NS_tchar oldPrecomplete[MAXPATHLEN];
+ NS_tsnprintf(oldPrecomplete, sizeof(oldPrecomplete)/sizeof(oldPrecomplete[0]),
+ NS_T("%s/precomplete"), gInstallDirPath);
+ NS_tremove(oldPrecomplete);
+
+ NS_tchar oldDistDir[MAXPATHLEN];
+ NS_tsnprintf(oldDistDir, sizeof(oldDistDir)/sizeof(oldDistDir[0]),
+ NS_T("%s/Contents/MacOS/distribution"), gInstallDirPath);
+ int rv = NS_taccess(oldDistDir, F_OK);
+ if (!rv) {
+ NS_tchar newDistDir[MAXPATHLEN];
+ NS_tsnprintf(newDistDir, sizeof(newDistDir)/sizeof(newDistDir[0]),
+ NS_T("%s/Contents/Resources/distribution"), gInstallDirPath);
+ rv = NS_taccess(newDistDir, F_OK);
+ if (!rv) {
+ LOG(("New distribution directory already exists... removing old " \
+ "distribution directory: " LOG_S, oldDistDir));
+ rv = ensure_remove_recursive(oldDistDir);
+ if (rv) {
+ LOG(("Removing old distribution directory failed - err: %d", rv));
+ }
+ } else {
+ LOG(("Moving old distribution directory to new location. src: " LOG_S \
+ ", dst:" LOG_S, oldDistDir, newDistDir));
+ rv = rename_file(oldDistDir, newDistDir, true);
+ if (rv) {
+ LOG(("Moving old distribution directory to new location failed - " \
+ "err: %d", rv));
+ }
+ }
}
- }
}
- }
#endif /* MACOSX */
- LogFinish();
+ LogFinish();
- if (argc > callbackIndex) {
+ if (argc > callbackIndex) {
#if defined(_WIN32)
- if (gSucceeded) {
- // The service update will only be executed if it is already installed.
- // For first time installs of the service, the install will happen from
- // the PostUpdate process. We do the service update process here
- // because it's possible we are updating with updater.exe without the
- // service if the service failed to apply the update. We want to update
- // the service to a newer version in that case. If we are not running
- // through the service, then MOZ_USING_SERVICE will not exist.
- if (!sUsingService) {
- if (!LaunchWinPostProcess(gInstallDirPath, gPatchDirPath, false, nullptr)) {
- LOG(("NS_main: The post update process could not be launched."));
- }
-
- StartServiceUpdate(gInstallDirPath);
- }
- }
- EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 0);
+ if (gSucceeded) {
+ // The service update will only be executed if it is already installed.
+ // For first time installs of the service, the install will happen from
+ // the PostUpdate process. We do the service update process here
+ // because it's possible we are updating with updater.exe without the
+ // service if the service failed to apply the update. We want to update
+ // the service to a newer version in that case. If we are not running
+ // through the service, then MOZ_USING_SERVICE will not exist.
+ if (!sUsingService) {
+ if (!LaunchWinPostProcess(gInstallDirPath, gPatchDirPath, false, nullptr)) {
+ LOG(("NS_main: The post update process could not be launched."));
+ }
+
+ StartServiceUpdate(gInstallDirPath);
+ }
+ }
+ EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 0);
#endif /* WNT */
#ifdef MACOSX
- if (gSucceeded) {
- LaunchMacPostProcess(gInstallDirPath);
- }
+ if (gSucceeded) {
+ LaunchMacPostProcess(gInstallDirPath);
+ }
#endif /* MACOSX */
- LaunchCallbackApp(argv[5],
- argc - callbackIndex,
- argv + callbackIndex,
- sUsingService);
- }
+ LaunchCallbackApp(argv[5],
+ argc - callbackIndex,
+ argv + callbackIndex,
+ sUsingService);
+ }
- return gSucceeded ? 0 : 1;
+ return gSucceeded ? 0 : 1;
}
class ActionList
{
public:
- ActionList() : mFirst(nullptr), mLast(nullptr), mCount(0) { }
- ~ActionList();
+ ActionList() : mFirst(nullptr), mLast(nullptr), mCount(0) { }
+ ~ActionList();
- void Append(Action* action);
- int Prepare();
- int Execute();
- void Finish(int status);
+ void Append(Action* action);
+ int Prepare();
+ int Execute();
+ void Finish(int status);
private:
- Action *mFirst;
- Action *mLast;
- int mCount;
+ Action *mFirst;
+ Action *mLast;
+ int mCount;
};
ActionList::~ActionList()
{
- Action* a = mFirst;
- while (a) {
- Action *b = a;
- a = a->mNext;
- delete b;
- }
+ Action* a = mFirst;
+ while (a) {
+ Action *b = a;
+ a = a->mNext;
+ delete b;
+ }
}
void
ActionList::Append(Action *action)
{
- if (mLast)
- mLast->mNext = action;
- else
- mFirst = action;
+ if (mLast)
+ mLast->mNext = action;
+ else
+ mFirst = action;
- mLast = action;
- mCount++;
+ mLast = action;
+ mCount++;
}
int
ActionList::Prepare()
{
- // If the action list is empty then we should fail in order to signal that
- // something has gone wrong. Otherwise we report success when nothing is
- // actually done. See bug 327140.
- if (mCount == 0) {
- LOG(("empty action list"));
- return MAR_ERROR_EMPTY_ACTION_LIST;
- }
-
- Action *a = mFirst;
- int i = 0;
- while (a) {
- int rv = a->Prepare();
- if (rv)
- return rv;
+ // If the action list is empty then we should fail in order to signal that
+ // something has gone wrong. Otherwise we report success when nothing is
+ // actually done. See bug 327140.
+ if (mCount == 0) {
+ LOG(("empty action list"));
+ return MAR_ERROR_EMPTY_ACTION_LIST;
+ }
+
+ Action *a = mFirst;
+ int i = 0;
+ while (a) {
+ int rv = a->Prepare();
+ if (rv)
+ return rv;
- float percent = float(++i) / float(mCount);
- UpdateProgressUI(PROGRESS_PREPARE_SIZE * percent);
+ float percent = float(++i) / float(mCount);
+ UpdateProgressUI(PROGRESS_PREPARE_SIZE * percent);
- a = a->mNext;
- }
+ a = a->mNext;
+ }
- return OK;
+ return OK;
}
int
ActionList::Execute()
{
- int currentProgress = 0, maxProgress = 0;
- Action *a = mFirst;
- while (a) {
- maxProgress += a->mProgressCost;
- a = a->mNext;
- }
-
- a = mFirst;
- while (a) {
- int rv = a->Execute();
- if (rv) {
- LOG(("### execution failed"));
- return rv;
+ int currentProgress = 0, maxProgress = 0;
+ Action *a = mFirst;
+ while (a) {
+ maxProgress += a->mProgressCost;
+ a = a->mNext;
}
- currentProgress += a->mProgressCost;
- float percent = float(currentProgress) / float(maxProgress);
- UpdateProgressUI(PROGRESS_PREPARE_SIZE +
- PROGRESS_EXECUTE_SIZE * percent);
+ a = mFirst;
+ while (a) {
+ int rv = a->Execute();
+ if (rv) {
+ LOG(("### execution failed"));
+ return rv;
+ }
- a = a->mNext;
- }
+ currentProgress += a->mProgressCost;
+ float percent = float(currentProgress) / float(maxProgress);
+ UpdateProgressUI(PROGRESS_PREPARE_SIZE +
+ PROGRESS_EXECUTE_SIZE * percent);
+
+ a = a->mNext;
+ }
- return OK;
+ return OK;
}
void
ActionList::Finish(int status)
{
- Action *a = mFirst;
- int i = 0;
- while (a) {
- a->Finish(status);
+ Action *a = mFirst;
+ int i = 0;
+ while (a) {
+ a->Finish(status);
- float percent = float(++i) / float(mCount);
- UpdateProgressUI(PROGRESS_PREPARE_SIZE +
- PROGRESS_EXECUTE_SIZE +
- PROGRESS_FINISH_SIZE * percent);
+ float percent = float(++i) / float(mCount);
+ UpdateProgressUI(PROGRESS_PREPARE_SIZE +
+ PROGRESS_EXECUTE_SIZE +
+ PROGRESS_FINISH_SIZE * percent);
- a = a->mNext;
- }
+ a = a->mNext;
+ }
- if (status == OK)
- gSucceeded = true;
+ if (status == OK)
+ gSucceeded = true;
}
#ifdef _WIN32
int add_dir_entries(const NS_tchar *dirpath, ActionList *list)
{
- int rv = OK;
- WIN32_FIND_DATAW finddata;
- HANDLE hFindFile;
- NS_tchar searchspec[MAXPATHLEN];
- NS_tchar foundpath[MAXPATHLEN];
-
- NS_tsnprintf(searchspec, sizeof(searchspec)/sizeof(searchspec[0]),
- NS_T("%s*"), dirpath);
- const NS_tchar *pszSpec = get_full_path(searchspec);
-
- hFindFile = FindFirstFileW(pszSpec, &finddata);
- if (hFindFile != INVALID_HANDLE_VALUE) {
- do {
- // Don't process the current or parent directory.
- if (NS_tstrcmp(finddata.cFileName, NS_T(".")) == 0 ||
- NS_tstrcmp(finddata.cFileName, NS_T("..")) == 0)
- continue;
-
- NS_tsnprintf(foundpath, sizeof(foundpath)/sizeof(foundpath[0]),
- NS_T("%s%s"), dirpath, finddata.cFileName);
- if (finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- NS_tsnprintf(foundpath, sizeof(foundpath)/sizeof(foundpath[0]),
- NS_T("%s/"), foundpath);
- // Recurse into the directory.
- rv = add_dir_entries(foundpath, list);
- if (rv) {
- LOG(("add_dir_entries error: " LOG_S ", err: %d", foundpath, rv));
- return rv;
- }
- } else {
- // Add the file to be removed to the ActionList.
- NS_tchar *quotedpath = get_quoted_path(foundpath);
- if (!quotedpath)
- return PARSE_ERROR;
+ int rv = OK;
+ WIN32_FIND_DATAW finddata;
+ HANDLE hFindFile;
+ NS_tchar searchspec[MAXPATHLEN];
+ NS_tchar foundpath[MAXPATHLEN];
- Action *action = new RemoveFile();
- rv = action->Parse(quotedpath);
- if (rv) {
- LOG(("add_dir_entries Parse error on recurse: " LOG_S ", err: %d",
- quotedpath, rv));
- return rv;
+ NS_tsnprintf(searchspec, sizeof(searchspec)/sizeof(searchspec[0]),
+ NS_T("%s*"), dirpath);
+ const NS_tchar *pszSpec = get_full_path(searchspec);
+
+ hFindFile = FindFirstFileW(pszSpec, &finddata);
+ if (hFindFile != INVALID_HANDLE_VALUE) {
+ do {
+ // Don't process the current or parent directory.
+ if (NS_tstrcmp(finddata.cFileName, NS_T(".")) == 0 ||
+ NS_tstrcmp(finddata.cFileName, NS_T("..")) == 0)
+ continue;
+
+ NS_tsnprintf(foundpath, sizeof(foundpath)/sizeof(foundpath[0]),
+ NS_T("%s%s"), dirpath, finddata.cFileName);
+ if (finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ NS_tsnprintf(foundpath, sizeof(foundpath)/sizeof(foundpath[0]),
+ NS_T("%s/"), foundpath);
+ // Recurse into the directory.
+ rv = add_dir_entries(foundpath, list);
+ if (rv) {
+ LOG(("add_dir_entries error: " LOG_S ", err: %d", foundpath, rv));
+ return rv;
+ }
+ } else {
+ // Add the file to be removed to the ActionList.
+ NS_tchar *quotedpath = get_quoted_path(foundpath);
+ if (!quotedpath)
+ return PARSE_ERROR;
+
+ Action *action = new RemoveFile();
+ rv = action->Parse(quotedpath);
+ if (rv) {
+ LOG(("add_dir_entries Parse error on recurse: " LOG_S ", err: %d",
+ quotedpath, rv));
+ return rv;
+ }
+
+ list->Append(action);
+ }
+ } while (FindNextFileW(hFindFile, &finddata) != 0);
+
+ FindClose(hFindFile);
+ {
+ // Add the directory to be removed to the ActionList.
+ NS_tchar *quotedpath = get_quoted_path(dirpath);
+ if (!quotedpath)
+ return PARSE_ERROR;
+
+ Action *action = new RemoveDir();
+ rv = action->Parse(quotedpath);
+ if (rv)
+ LOG(("add_dir_entries Parse error on close: " LOG_S ", err: %d",
+ quotedpath, rv));
+ else
+ list->Append(action);
}
-
- list->Append(action);
- }
- } while (FindNextFileW(hFindFile, &finddata) != 0);
-
- FindClose(hFindFile);
- {
- // Add the directory to be removed to the ActionList.
- NS_tchar *quotedpath = get_quoted_path(dirpath);
- if (!quotedpath)
- return PARSE_ERROR;
-
- Action *action = new RemoveDir();
- rv = action->Parse(quotedpath);
- if (rv)
- LOG(("add_dir_entries Parse error on close: " LOG_S ", err: %d",
- quotedpath, rv));
- else
- list->Append(action);
}
- }
- return rv;
+ return rv;
}
#elif defined(__sun)
int add_dir_entries(const NS_tchar *dirpath, ActionList *list)
{
- int rv = OK;
- NS_tchar searchpath[MAXPATHLEN];
- NS_tchar foundpath[MAXPATHLEN];
- struct {
- dirent dent_buffer;
- char chars[MAXNAMLEN];
- } ent_buf;
- struct dirent* ent;
-
-
- NS_tsnprintf(searchpath, sizeof(searchpath)/sizeof(searchpath[0]), NS_T("%s"),
- dirpath);
- // Remove the trailing slash so the paths don't contain double slashes. The
- // existence of the slash has already been checked in DoUpdate.
- searchpath[NS_tstrlen(searchpath) - 1] = NS_T('\0');
-
- DIR* dir = opendir(searchpath);
- if (!dir) {
- LOG(("add_dir_entries error on opendir: " LOG_S ", err: %d", searchpath,
- errno));
- return UNEXPECTED_FILE_OPERATION_ERROR;
- }
-
- while (readdir_r(dir, (dirent *)&ent_buf, &ent) == 0 && ent) {
- if ((strcmp(ent->d_name, ".") == 0) ||
- (strcmp(ent->d_name, "..") == 0))
- continue;
-
- NS_tsnprintf(foundpath, sizeof(foundpath)/sizeof(foundpath[0]),
- NS_T("%s%s"), dirpath, ent->d_name);
- struct stat64 st_buf;
- int test = stat64(foundpath, &st_buf);
- if (test) {
- closedir(dir);
- return UNEXPECTED_FILE_OPERATION_ERROR;
- }
- if (S_ISDIR(st_buf.st_mode)) {
- NS_tsnprintf(foundpath, sizeof(foundpath)/sizeof(foundpath[0]),
- NS_T("%s/"), foundpath);
- // Recurse into the directory.
- rv = add_dir_entries(foundpath, list);
- if (rv) {
- LOG(("add_dir_entries error: " LOG_S ", err: %d", foundpath, rv));
- closedir(dir);
- return rv;
- }
- } else {
- // Add the file to be removed to the ActionList.
- NS_tchar *quotedpath = get_quoted_path(foundpath);
- if (!quotedpath) {
- closedir(dir);
- return PARSE_ERROR;
- }
-
- Action *action = new RemoveFile();
- rv = action->Parse(quotedpath);
- if (rv) {
- LOG(("add_dir_entries Parse error on recurse: " LOG_S ", err: %d",
- quotedpath, rv));
- closedir(dir);
- return rv;
- }
-
- list->Append(action);
- }
- }
- closedir(dir);
+ int rv = OK;
+ NS_tchar searchpath[MAXPATHLEN];
+ NS_tchar foundpath[MAXPATHLEN];
+ struct {
+ dirent dent_buffer;
+ char chars[MAXNAMLEN];
+ } ent_buf;
+ struct dirent* ent;
- // Add the directory to be removed to the ActionList.
- NS_tchar *quotedpath = get_quoted_path(dirpath);
- if (!quotedpath)
- return PARSE_ERROR;
- Action *action = new RemoveDir();
- rv = action->Parse(quotedpath);
- if (rv) {
- LOG(("add_dir_entries Parse error on close: " LOG_S ", err: %d",
- quotedpath, rv));
- }
- else {
- list->Append(action);
- }
+ NS_tsnprintf(searchpath, sizeof(searchpath)/sizeof(searchpath[0]), NS_T("%s"),
+ dirpath);
+ // Remove the trailing slash so the paths don't contain double slashes. The
+ // existence of the slash has already been checked in DoUpdate.
+ searchpath[NS_tstrlen(searchpath) - 1] = NS_T('\0');
- return rv;
-}
+ DIR* dir = opendir(searchpath);
+ if (!dir) {
+ LOG(("add_dir_entries error on opendir: " LOG_S ", err: %d", searchpath,
+ errno));
+ return UNEXPECTED_FILE_OPERATION_ERROR;
+ }
-#else
+ while (readdir_r(dir, (dirent *)&ent_buf, &ent) == 0 && ent) {
+ if ((strcmp(ent->d_name, ".") == 0) ||
+ (strcmp(ent->d_name, "..") == 0))
+ continue;
-int add_dir_entries(const NS_tchar *dirpath, ActionList *list)
-{
- int rv = OK;
- FTS *ftsdir;
- FTSENT *ftsdirEntry;
- NS_tchar searchpath[MAXPATHLEN];
-
- NS_tsnprintf(searchpath, sizeof(searchpath)/sizeof(searchpath[0]), NS_T("%s"),
- dirpath);
- // Remove the trailing slash so the paths don't contain double slashes. The
- // existence of the slash has already been checked in DoUpdate.
- searchpath[NS_tstrlen(searchpath) - 1] = NS_T('\0');
- char* const pathargv[] = {searchpath, nullptr};
-
- // FTS_NOCHDIR is used so relative paths from the destination directory are
- // returned.
- if (!(ftsdir = fts_open(pathargv,
- FTS_PHYSICAL | FTS_NOSTAT | FTS_XDEV | FTS_NOCHDIR,
- nullptr)))
- return UNEXPECTED_FILE_OPERATION_ERROR;
-
- while ((ftsdirEntry = fts_read(ftsdir)) != nullptr) {
- NS_tchar foundpath[MAXPATHLEN];
- NS_tchar *quotedpath;
- Action *action = nullptr;
-
- switch (ftsdirEntry->fts_info) {
- // Filesystem objects that shouldn't be in the application's directories
- case FTS_SL:
- case FTS_SLNONE:
- case FTS_DEFAULT:
- LOG(("add_dir_entries: found a non-standard file: " LOG_S,
- ftsdirEntry->fts_path));
- // Fall through and try to remove as a file
-
- // Files
- case FTS_F:
- case FTS_NSOK:
- // Add the file to be removed to the ActionList.
NS_tsnprintf(foundpath, sizeof(foundpath)/sizeof(foundpath[0]),
- NS_T("%s"), ftsdirEntry->fts_accpath);
- quotedpath = get_quoted_path(foundpath);
- if (!quotedpath) {
- rv = UPDATER_QUOTED_PATH_MEM_ERROR;
- break;
- }
- action = new RemoveFile();
- rv = action->Parse(quotedpath);
- if (!rv)
- list->Append(action);
- break;
-
- // Directories
- case FTS_DP:
- rv = OK;
- // Add the directory to be removed to the ActionList.
- NS_tsnprintf(foundpath, sizeof(foundpath)/sizeof(foundpath[0]),
- NS_T("%s/"), ftsdirEntry->fts_accpath);
- quotedpath = get_quoted_path(foundpath);
- if (!quotedpath) {
- rv = UPDATER_QUOTED_PATH_MEM_ERROR;
- break;
+ NS_T("%s%s"), dirpath, ent->d_name);
+ struct stat64 st_buf;
+ int test = stat64(foundpath, &st_buf);
+ if (test) {
+ closedir(dir);
+ return UNEXPECTED_FILE_OPERATION_ERROR;
}
+ if (S_ISDIR(st_buf.st_mode)) {
+ NS_tsnprintf(foundpath, sizeof(foundpath)/sizeof(foundpath[0]),
+ NS_T("%s/"), foundpath);
+ // Recurse into the directory.
+ rv = add_dir_entries(foundpath, list);
+ if (rv) {
+ LOG(("add_dir_entries error: " LOG_S ", err: %d", foundpath, rv));
+ closedir(dir);
+ return rv;
+ }
+ } else {
+ // Add the file to be removed to the ActionList.
+ NS_tchar *quotedpath = get_quoted_path(foundpath);
+ if (!quotedpath) {
+ closedir(dir);
+ return PARSE_ERROR;
+ }
- action = new RemoveDir();
- rv = action->Parse(quotedpath);
- if (!rv)
- list->Append(action);
- break;
+ Action *action = new RemoveFile();
+ rv = action->Parse(quotedpath);
+ if (rv) {
+ LOG(("add_dir_entries Parse error on recurse: " LOG_S ", err: %d",
+ quotedpath, rv));
+ closedir(dir);
+ return rv;
+ }
- // Errors
- case FTS_DNR:
- case FTS_NS:
- // ENOENT is an acceptable error for FTS_DNR and FTS_NS and means that
- // we're racing with ourselves. Though strange, the entry will be
- // removed anyway.
- if (ENOENT == ftsdirEntry->fts_errno) {
- rv = OK;
- break;
+ list->Append(action);
}
- // Fall through
-
- case FTS_ERR:
- rv = UNEXPECTED_FILE_OPERATION_ERROR;
- LOG(("add_dir_entries: fts_read() error: " LOG_S ", err: %d",
- ftsdirEntry->fts_path, ftsdirEntry->fts_errno));
- break;
+ }
+ closedir(dir);
- case FTS_DC:
- rv = UNEXPECTED_FILE_OPERATION_ERROR;
- LOG(("add_dir_entries: fts_read() returned FT_DC: " LOG_S,
- ftsdirEntry->fts_path));
- break;
+ // Add the directory to be removed to the ActionList.
+ NS_tchar *quotedpath = get_quoted_path(dirpath);
+ if (!quotedpath)
+ return PARSE_ERROR;
- default:
- // FTS_D is ignored and FTS_DP is used instead (post-order).
- rv = OK;
- break;
+ Action *action = new RemoveDir();
+ rv = action->Parse(quotedpath);
+ if (rv) {
+ LOG(("add_dir_entries Parse error on close: " LOG_S ", err: %d",
+ quotedpath, rv));
}
+ else {
+ list->Append(action);
+ }
+
+ return rv;
+}
+
+#else
+
+int add_dir_entries(const NS_tchar *dirpath, ActionList *list)
+{
+ int rv = OK;
+ FTS *ftsdir;
+ FTSENT *ftsdirEntry;
+ NS_tchar searchpath[MAXPATHLEN];
+
+ NS_tsnprintf(searchpath, sizeof(searchpath)/sizeof(searchpath[0]), NS_T("%s"),
+ dirpath);
+ // Remove the trailing slash so the paths don't contain double slashes. The
+ // existence of the slash has already been checked in DoUpdate.
+ searchpath[NS_tstrlen(searchpath) - 1] = NS_T('\0');
+ char* const pathargv[] = {searchpath, nullptr};
+
+ // FTS_NOCHDIR is used so relative paths from the destination directory are
+ // returned.
+ if (!(ftsdir = fts_open(pathargv,
+ FTS_PHYSICAL | FTS_NOSTAT | FTS_XDEV | FTS_NOCHDIR,
+ nullptr)))
+ return UNEXPECTED_FILE_OPERATION_ERROR;
+
+ while ((ftsdirEntry = fts_read(ftsdir)) != nullptr) {
+ NS_tchar foundpath[MAXPATHLEN];
+ NS_tchar *quotedpath;
+ Action *action = nullptr;
+
+ switch (ftsdirEntry->fts_info) {
+ // Filesystem objects that shouldn't be in the application's directories
+ case FTS_SL:
+ case FTS_SLNONE:
+ case FTS_DEFAULT:
+ LOG(("add_dir_entries: found a non-standard file: " LOG_S,
+ ftsdirEntry->fts_path));
+ // Fall through and try to remove as a file
+
+ // Files
+ case FTS_F:
+ case FTS_NSOK:
+ // Add the file to be removed to the ActionList.
+ NS_tsnprintf(foundpath, sizeof(foundpath)/sizeof(foundpath[0]),
+ NS_T("%s"), ftsdirEntry->fts_accpath);
+ quotedpath = get_quoted_path(foundpath);
+ if (!quotedpath) {
+ rv = UPDATER_QUOTED_PATH_MEM_ERROR;
+ break;
+ }
+ action = new RemoveFile();
+ rv = action->Parse(quotedpath);
+ if (!rv)
+ list->Append(action);
+ break;
+
+ // Directories
+ case FTS_DP:
+ rv = OK;
+ // Add the directory to be removed to the ActionList.
+ NS_tsnprintf(foundpath, sizeof(foundpath)/sizeof(foundpath[0]),
+ NS_T("%s/"), ftsdirEntry->fts_accpath);
+ quotedpath = get_quoted_path(foundpath);
+ if (!quotedpath) {
+ rv = UPDATER_QUOTED_PATH_MEM_ERROR;
+ break;
+ }
+
+ action = new RemoveDir();
+ rv = action->Parse(quotedpath);
+ if (!rv)
+ list->Append(action);
+ break;
+
+ // Errors
+ case FTS_DNR:
+ case FTS_NS:
+ // ENOENT is an acceptable error for FTS_DNR and FTS_NS and means that
+ // we're racing with ourselves. Though strange, the entry will be
+ // removed anyway.
+ if (ENOENT == ftsdirEntry->fts_errno) {
+ rv = OK;
+ break;
+ }
+ // Fall through
+
+ case FTS_ERR:
+ rv = UNEXPECTED_FILE_OPERATION_ERROR;
+ LOG(("add_dir_entries: fts_read() error: " LOG_S ", err: %d",
+ ftsdirEntry->fts_path, ftsdirEntry->fts_errno));
+ break;
+
+ case FTS_DC:
+ rv = UNEXPECTED_FILE_OPERATION_ERROR;
+ LOG(("add_dir_entries: fts_read() returned FT_DC: " LOG_S,
+ ftsdirEntry->fts_path));
+ break;
+
+ default:
+ // FTS_D is ignored and FTS_DP is used instead (post-order).
+ rv = OK;
+ break;
+ }
- if (rv != OK)
- break;
- }
+ if (rv != OK)
+ break;
+ }
- fts_close(ftsdir);
+ fts_close(ftsdir);
- return rv;
+ return rv;
}
#endif
static NS_tchar*
GetManifestContents(const NS_tchar *manifest)
{
- AutoFile mfile(NS_tfopen(manifest, NS_T("rb")));
- if (mfile == nullptr) {
- LOG(("GetManifestContents: error opening manifest file: " LOG_S, manifest));
- return nullptr;
- }
-
- struct stat ms;
- int rv = fstat(fileno((FILE *)mfile), &ms);
- if (rv) {
- LOG(("GetManifestContents: error stating manifest file: " LOG_S, manifest));
- return nullptr;
- }
-
- char *mbuf = (char *) malloc(ms.st_size + 1);
- if (!mbuf)
- return nullptr;
-
- size_t r = ms.st_size;
- char *rb = mbuf;
- while (r) {
- const size_t count = mmin(SSIZE_MAX, r);
- size_t c = fread(rb, 1, count, mfile);
- if (c != count) {
- LOG(("GetManifestContents: error reading manifest file: " LOG_S, manifest));
- return nullptr;
- }
-
- r -= c;
- rb += c;
- }
- mbuf[ms.st_size] = '\0';
- rb = mbuf;
+ AutoFile mfile(NS_tfopen(manifest, NS_T("rb")));
+ if (mfile == nullptr) {
+ LOG(("GetManifestContents: error opening manifest file: " LOG_S, manifest));
+ return nullptr;
+ }
+
+ struct stat ms;
+ int rv = fstat(fileno((FILE *)mfile), &ms);
+ if (rv) {
+ LOG(("GetManifestContents: error stating manifest file: " LOG_S, manifest));
+ return nullptr;
+ }
+
+ char *mbuf = (char *) malloc(ms.st_size + 1);
+ if (!mbuf)
+ return nullptr;
+
+ size_t r = ms.st_size;
+ char *rb = mbuf;
+ while (r) {
+ const size_t count = mmin(SSIZE_MAX, r);
+ size_t c = fread(rb, 1, count, mfile);
+ if (c != count) {
+ LOG(("GetManifestContents: error reading manifest file: " LOG_S, manifest));
+ return nullptr;
+ }
+
+ r -= c;
+ rb += c;
+ }
+ mbuf[ms.st_size] = '\0';
+ rb = mbuf;
#ifndef _WIN32
- return rb;
+ return rb;
#else
- NS_tchar *wrb = (NS_tchar *) malloc((ms.st_size + 1) * sizeof(NS_tchar));
- if (!wrb)
- return nullptr;
+ NS_tchar *wrb = (NS_tchar *) malloc((ms.st_size + 1) * sizeof(NS_tchar));
+ if (!wrb)
+ return nullptr;
- if (!MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, rb, -1, wrb,
- ms.st_size + 1)) {
- LOG(("GetManifestContents: error converting utf8 to utf16le: %d", GetLastError()));
+ if (!MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, rb, -1, wrb,
+ ms.st_size + 1)) {
+ LOG(("GetManifestContents: error converting utf8 to utf16le: %d", GetLastError()));
+ free(mbuf);
+ free(wrb);
+ return nullptr;
+ }
free(mbuf);
- free(wrb);
- return nullptr;
- }
- free(mbuf);
- return wrb;
+ return wrb;
#endif
}
int AddPreCompleteActions(ActionList *list)
{
- if (sIsOSUpdate) {
- return OK;
- }
+ if (sIsOSUpdate) {
+ return OK;
+ }
#ifdef MACOSX
- NS_tchar *rb = GetManifestContents(NS_T("Contents/Resources/precomplete"));
+ NS_tchar *rb = GetManifestContents(NS_T("Contents/Resources/precomplete"));
#else
- NS_tchar *rb = GetManifestContents(NS_T("precomplete"));
+ NS_tchar *rb = GetManifestContents(NS_T("precomplete"));
#endif
- if (rb == nullptr) {
- LOG(("AddPreCompleteActions: error getting contents of precomplete " \
- "manifest"));
- // Applications aren't required to have a precomplete manifest. The mar
- // generation scripts enforce the presence of a precomplete manifest.
- return OK;
- }
-
- int rv;
- NS_tchar *line;
- while((line = mstrtok(kNL, &rb)) != 0) {
- // skip comments
- if (*line == NS_T('#'))
- continue;
-
- NS_tchar *token = mstrtok(kWhitespace, &line);
- if (!token) {
- LOG(("AddPreCompleteActions: token not found in manifest"));
- return PARSE_ERROR;
- }
+ if (rb == nullptr) {
+ LOG(("AddPreCompleteActions: error getting contents of precomplete " \
+ "manifest"));
+ // Applications aren't required to have a precomplete manifest. The mar
+ // generation scripts enforce the presence of a precomplete manifest.
+ return OK;
+ }
+
+ int rv;
+ NS_tchar *line;
+ while((line = mstrtok(kNL, &rb)) != 0) {
+ // skip comments
+ if (*line == NS_T('#'))
+ continue;
+
+ NS_tchar *token = mstrtok(kWhitespace, &line);
+ if (!token) {
+ LOG(("AddPreCompleteActions: token not found in manifest"));
+ return PARSE_ERROR;
+ }
- Action *action = nullptr;
- if (NS_tstrcmp(token, NS_T("remove")) == 0) { // rm file
- action = new RemoveFile();
- }
- else if (NS_tstrcmp(token, NS_T("remove-cc")) == 0) { // no longer supported
- continue;
- }
- else if (NS_tstrcmp(token, NS_T("rmdir")) == 0) { // rmdir if empty
- action = new RemoveDir();
- }
- else {
- LOG(("AddPreCompleteActions: unknown token: " LOG_S, token));
- return PARSE_ERROR;
- }
+ Action *action = nullptr;
+ if (NS_tstrcmp(token, NS_T("remove")) == 0) { // rm file
+ action = new RemoveFile();
+ }
+ else if (NS_tstrcmp(token, NS_T("remove-cc")) == 0) { // no longer supported
+ continue;
+ }
+ else if (NS_tstrcmp(token, NS_T("rmdir")) == 0) { // rmdir if empty
+ action = new RemoveDir();
+ }
+ else {
+ LOG(("AddPreCompleteActions: unknown token: " LOG_S, token));
+ return PARSE_ERROR;
+ }
- if (!action)
- return BAD_ACTION_ERROR;
+ if (!action)
+ return BAD_ACTION_ERROR;
- rv = action->Parse(line);
- if (rv)
- return rv;
+ rv = action->Parse(line);
+ if (rv)
+ return rv;
- list->Append(action);
- }
+ list->Append(action);
+ }
- return OK;
+ return OK;
}
int DoUpdate()
{
- NS_tchar manifest[MAXPATHLEN];
- NS_tsnprintf(manifest, sizeof(manifest)/sizeof(manifest[0]),
- NS_T("%s/updating/update.manifest"), gWorkingDirPath);
- ensure_parent_dir(manifest);
+ NS_tchar manifest[MAXPATHLEN];
+ NS_tsnprintf(manifest, sizeof(manifest)/sizeof(manifest[0]),
+ NS_T("%s/updating/update.manifest"), gWorkingDirPath);
+ ensure_parent_dir(manifest);
- // extract the manifest
- int rv = gArchiveReader.ExtractFile("updatev3.manifest", manifest);
- if (rv) {
- rv = gArchiveReader.ExtractFile("updatev2.manifest", manifest);
+ // extract the manifest
+ int rv = gArchiveReader.ExtractFile("updatev3.manifest", manifest);
if (rv) {
- LOG(("DoUpdate: error extracting manifest file"));
- return rv;
- }
- }
-
- NS_tchar *rb = GetManifestContents(manifest);
- NS_tremove(manifest);
- if (rb == nullptr) {
- LOG(("DoUpdate: error opening manifest file: " LOG_S, manifest));
- return READ_ERROR;
- }
-
-
- ActionList list;
- NS_tchar *line;
- bool isFirstAction = true;
-
- while((line = mstrtok(kNL, &rb)) != 0) {
- // skip comments
- if (*line == NS_T('#'))
- continue;
-
- NS_tchar *token = mstrtok(kWhitespace, &line);
- if (!token) {
- LOG(("DoUpdate: token not found in manifest"));
- return PARSE_ERROR;
- }
-
- if (isFirstAction) {
- isFirstAction = false;
- // The update manifest isn't required to have a type declaration. The mar
- // generation scripts enforce the presence of the type declaration.
- if (NS_tstrcmp(token, NS_T("type")) == 0) {
- const NS_tchar *type = mstrtok(kQuote, &line);
- LOG(("UPDATE TYPE " LOG_S, type));
- if (NS_tstrcmp(type, NS_T("complete")) == 0) {
- rv = AddPreCompleteActions(&list);
- if (rv)
+ rv = gArchiveReader.ExtractFile("updatev2.manifest", manifest);
+ if (rv) {
+ LOG(("DoUpdate: error extracting manifest file"));
return rv;
}
- continue;
- }
}
- Action *action = nullptr;
- if (NS_tstrcmp(token, NS_T("remove")) == 0) { // rm file
- action = new RemoveFile();
+ NS_tchar *rb = GetManifestContents(manifest);
+ NS_tremove(manifest);
+ if (rb == nullptr) {
+ LOG(("DoUpdate: error opening manifest file: " LOG_S, manifest));
+ return READ_ERROR;
}
- else if (NS_tstrcmp(token, NS_T("rmdir")) == 0) { // rmdir if empty
- action = new RemoveDir();
- }
- else if (NS_tstrcmp(token, NS_T("rmrfdir")) == 0) { // rmdir recursive
- const NS_tchar *reldirpath = mstrtok(kQuote, &line);
- if (!reldirpath)
- return PARSE_ERROR;
- if (reldirpath[NS_tstrlen(reldirpath) - 1] != NS_T('/'))
- return PARSE_ERROR;
- rv = add_dir_entries(reldirpath, &list);
- if (rv)
- return rv;
+ ActionList list;
+ NS_tchar *line;
+ bool isFirstAction = true;
- continue;
- }
- else if (NS_tstrcmp(token, NS_T("add")) == 0) {
- action = new AddFile();
- }
- else if (NS_tstrcmp(token, NS_T("patch")) == 0) {
- action = new PatchFile();
- }
- else if (NS_tstrcmp(token, NS_T("add-if")) == 0) { // Add if exists
- action = new AddIfFile();
- }
- else if (NS_tstrcmp(token, NS_T("add-if-not")) == 0) { // Add if not exists
- action = new AddIfNotFile();
- }
- else if (NS_tstrcmp(token, NS_T("patch-if")) == 0) { // Patch if exists
- action = new PatchIfFile();
- }
- else {
- LOG(("DoUpdate: unknown token: " LOG_S, token));
- return PARSE_ERROR;
- }
+ while((line = mstrtok(kNL, &rb)) != 0) {
+ // skip comments
+ if (*line == NS_T('#'))
+ continue;
- if (!action)
- return BAD_ACTION_ERROR;
+ NS_tchar *token = mstrtok(kWhitespace, &line);
+ if (!token) {
+ LOG(("DoUpdate: token not found in manifest"));
+ return PARSE_ERROR;
+ }
- rv = action->Parse(line);
- if (rv)
- return rv;
+ if (isFirstAction) {
+ isFirstAction = false;
+ // The update manifest isn't required to have a type declaration. The mar
+ // generation scripts enforce the presence of the type declaration.
+ if (NS_tstrcmp(token, NS_T("type")) == 0) {
+ const NS_tchar *type = mstrtok(kQuote, &line);
+ LOG(("UPDATE TYPE " LOG_S, type));
+ if (NS_tstrcmp(type, NS_T("complete")) == 0) {
+ rv = AddPreCompleteActions(&list);
+ if (rv)
+ return rv;
+ }
+ continue;
+ }
+ }
- list.Append(action);
- }
+ Action *action = nullptr;
+ if (NS_tstrcmp(token, NS_T("remove")) == 0) { // rm file
+ action = new RemoveFile();
+ }
+ else if (NS_tstrcmp(token, NS_T("rmdir")) == 0) { // rmdir if empty
+ action = new RemoveDir();
+ }
+ else if (NS_tstrcmp(token, NS_T("rmrfdir")) == 0) { // rmdir recursive
+ const NS_tchar *reldirpath = mstrtok(kQuote, &line);
+ if (!reldirpath)
+ return PARSE_ERROR;
- rv = list.Prepare();
- if (rv)
- return rv;
+ if (reldirpath[NS_tstrlen(reldirpath) - 1] != NS_T('/'))
+ return PARSE_ERROR;
- rv = list.Execute();
+ rv = add_dir_entries(reldirpath, &list);
+ if (rv)
+ return rv;
- list.Finish(rv);
- return rv;
+ continue;
+ }
+ else if (NS_tstrcmp(token, NS_T("add")) == 0) {
+ action = new AddFile();
+ }
+ else if (NS_tstrcmp(token, NS_T("patch")) == 0) {
+ action = new PatchFile();
+ }
+ else if (NS_tstrcmp(token, NS_T("add-if")) == 0) { // Add if exists
+ action = new AddIfFile();
+ }
+ else if (NS_tstrcmp(token, NS_T("add-if-not")) == 0) { // Add if not exists
+ action = new AddIfNotFile();
+ }
+ else if (NS_tstrcmp(token, NS_T("patch-if")) == 0) { // Patch if exists
+ action = new PatchIfFile();
+ }
+ else {
+ LOG(("DoUpdate: unknown token: " LOG_S, token));
+ return PARSE_ERROR;
+ }
+
+ if (!action)
+ return BAD_ACTION_ERROR;
+
+ rv = action->Parse(line);
+ if (rv)
+ return rv;
+
+ list.Append(action);
+ }
+
+ rv = list.Prepare();
+ if (rv)
+ return rv;
+
+ rv = list.Execute();
+
+ list.Finish(rv);
+ return rv;
}