Index: chrome/installer/test/alternate_version_generator.cc |
diff --git a/chrome/installer/test/alternate_version_generator.cc b/chrome/installer/test/alternate_version_generator.cc |
index bf492c4cb7b291c7277ebedae8e348a96decc0db..c0ec33334b4d7a5ff3242008ed091314ba42838e 100644 |
--- a/chrome/installer/test/alternate_version_generator.cc |
+++ b/chrome/installer/test/alternate_version_generator.cc |
@@ -43,6 +43,7 @@ |
#include "base/path_service.h" |
#include "base/process/launch.h" |
#include "base/process/process_handle.h" |
+#include "base/strings/string16.h" |
#include "base/strings/string_util.h" |
#include "base/strings/utf_string_conversions.h" |
#include "base/version.h" |
@@ -60,7 +61,8 @@ const wchar_t k7zaPathRelative[] = L"..\\..\\third_party\\lzma_sdk\\Executable"; |
const wchar_t kB7[] = L"B7"; |
const wchar_t kBl[] = L"BL"; |
const wchar_t kChromeBin[] = L"Chrome-bin"; |
-const wchar_t kChromePacked7z[] = L"chrome.packed.7z"; |
+const wchar_t kChromePacked7z[] = L"CHROME.PACKED.7Z"; |
+const wchar_t kChrome7z[] = L"CHROME.7Z"; |
const wchar_t kExe[] = L"exe"; |
const wchar_t kExpandExe[] = L"expand.exe"; |
const wchar_t kExtDll[] = L".dll"; |
@@ -130,6 +132,8 @@ class ChromeVersion { |
ULONGLONG value() const { return version_; } |
void set_value(ULONGLONG value) { version_ = value; } |
std::wstring ToString() const; |
+ std::string ToASCII() const; |
+ |
private: |
ULONGLONG version_; |
}; // class ChromeVersion |
@@ -144,6 +148,14 @@ std::wstring ChromeVersion::ToString() const { |
return std::wstring(&buffer[0], string_len); |
} |
+std::string ChromeVersion::ToASCII() const { |
+ char buffer[24]; |
+ int string_len = sprintf_s(&buffer[0], arraysize(buffer), "%hu.%hu.%hu.%hu", |
+ major(), minor(), build(), patch()); |
+ DCHECK_NE(-1, string_len); |
+ DCHECK_GT(static_cast<int>(arraysize(buffer)), string_len); |
+ return std::string(&buffer[0], string_len); |
+} |
// A read/write mapping of a file. |
// Note: base::MemoryMappedFile is not used because it doesn't support |
@@ -166,16 +178,10 @@ class MappedFile { |
}; // class MappedFile |
MappedFile::~MappedFile() { |
- if (view_ != NULL) { |
- if (UnmapViewOfFile(view_) == 0) { |
- PLOG(DFATAL) << "MappedFile failed to unmap view."; |
- } |
- } |
- if (mapping_ != NULL) { |
- if (CloseHandle(mapping_) == 0) { |
- PLOG(DFATAL) << "Could not close file mapping handle."; |
- } |
- } |
+ if (view_ && !UnmapViewOfFile(view_)) |
+ PLOG(DFATAL) << "MappedFile failed to unmap view."; |
+ if (mapping_ && !CloseHandle(mapping_)) |
+ PLOG(DFATAL) << "Could not close file mapping handle."; |
} |
bool MappedFile::Initialize(base::File file) { |
@@ -191,11 +197,10 @@ bool MappedFile::Initialize(base::File file) { |
if (mapping_ != NULL) { |
view_ = MapViewOfFile(mapping_, FILE_MAP_WRITE, 0, 0, |
static_cast<size_t>(file_info.size)); |
- if (view_ != NULL) { |
+ if (view_) |
result = true; |
- } else { |
+ else |
PLOG(DFATAL) << "MapViewOfFile failed"; |
- } |
} else { |
PLOG(DFATAL) << "CreateFileMapping failed"; |
} |
@@ -275,9 +280,8 @@ bool GetSetupExeVersion(const base::FilePath& work_dir, |
return GetFileVersion(work_dir.Append(&kSetupExe[0]), version); |
} |
- |
-// Replace all occurrences in the sequence [|dest_first|, |dest_last) that |
-// equals [|src_first|, |src_last) with the sequence at |replacement_first| of |
+// Replace all occurrences in the sequence [|dest_first|, |dest_last|) that |
+// equals [|src_first|, |src_last|) with the sequence at |replacement_first| of |
// the same length. Returns true on success. If non-NULL, |replacements_made| |
// is set to true/false accordingly. |
bool ReplaceAll(uint8_t* dest_first, |
@@ -290,9 +294,8 @@ bool ReplaceAll(uint8_t* dest_first, |
bool changed = false; |
do { |
dest_first = std::search(dest_first, dest_last, src_first, src_last); |
- if (dest_first == dest_last) { |
+ if (dest_first == dest_last) |
break; |
- } |
changed = true; |
if (memcpy_s(dest_first, dest_last - dest_first, |
replacement_first, src_last - src_first) != 0) { |
@@ -302,9 +305,8 @@ bool ReplaceAll(uint8_t* dest_first, |
dest_first += (src_last - src_first); |
} while (true); |
- if (replacements_made != NULL) { |
+ if (replacements_made != NULL) |
*replacements_made = changed; |
- } |
return result; |
} |
@@ -320,6 +322,7 @@ struct VisitResourceContext { |
// Replaces the old version with the new in a resource. A first pass is made to |
// replace the string form (e.g., "9.0.584.0"). If any replacements are made, a |
// second pass is made to replace the binary form (e.g., 0x0000024800000009). |
+// A final pass is made to replace the ASCII string form. |
void VisitResource(const upgrade_test::EntryPath& path, |
uint8_t* data, |
DWORD size, |
@@ -337,7 +340,7 @@ void VisitResource(const upgrade_test::EntryPath& path, |
reinterpret_cast<const uint8_t*>(ctx.new_version_str.c_str()), |
&changing_version) && |
changing_version) { |
- // Replace all occurrences of current_version with new_version |
+ // Replace all binary occurrences of current_version with new_version. |
struct VersionPair { |
DWORD high; |
DWORD low; |
@@ -352,6 +355,14 @@ void VisitResource(const upgrade_test::EntryPath& path, |
reinterpret_cast<const uint8_t*>(&cur_ver) + sizeof(cur_ver), |
reinterpret_cast<const uint8_t*>(&new_ver), NULL); |
} |
+ |
+ // Replace all ASCII occurrences of current_version with new_version. |
+ std::string current_version(ctx.current_version.ToASCII()); |
+ std::string new_version(ctx.new_version.ToASCII()); |
+ ReplaceAll( |
+ data, data + size, reinterpret_cast<uint8_t*>(¤t_version[0]), |
+ reinterpret_cast<uint8_t*>(¤t_version[current_version.size()]), |
+ reinterpret_cast<uint8_t*>(&new_version[0]), NULL); |
} |
// Updates the version strings and numbers in all of |image_file|'s resources. |
@@ -398,6 +409,26 @@ bool UpdateVersionIfMatch(const base::FilePath& image_file, |
return result; |
} |
+bool UpdateManifestVersion(const base::FilePath& manifest, |
+ VisitResourceContext* context) { |
+ std::string contents; |
+ if (!base::ReadFileToString(manifest, &contents)) |
+ return false; |
+ std::string old_version(context->current_version.ToASCII()); |
+ std::string new_version(context->new_version.ToASCII()); |
+ bool modified = false; |
+ if (!ReplaceAll(reinterpret_cast<uint8_t*>(&contents[0]), |
+ reinterpret_cast<uint8_t*>(&contents[contents.size()]), |
+ reinterpret_cast<uint8_t*>(&old_version[0]), |
+ reinterpret_cast<uint8_t*>(&old_version[old_version.size()]), |
+ reinterpret_cast<uint8_t*>(&new_version[0]), &modified)) { |
+ return false; |
+ } |
+ DCHECK(modified); |
+ return base::WriteFile(manifest, &contents[0], contents.size()) == |
+ contents.size(); |
+} |
+ |
bool IncrementNewVersion(upgrade_test::Direction direction, |
VisitResourceContext* ctx) { |
DCHECK(ctx); |
@@ -421,50 +452,60 @@ bool IncrementNewVersion(upgrade_test::Direction direction, |
// Raises or lowers the version of all .exe and .dll files in |work_dir| as well |
// as the |work-dir|\Chrome-bin\w.x.y.z directory. |original_version| and |
-// |new_version|, when non-NULL, are given the original and new version numbers |
+// |new_version|, when non-null, are given the original and new version numbers |
// on success. |
bool ApplyAlternateVersion(const base::FilePath& work_dir, |
upgrade_test::Direction direction, |
std::wstring* original_version, |
std::wstring* new_version) { |
VisitResourceContext ctx; |
- if (!GetSetupExeVersion(work_dir, &ctx.current_version)) { |
+ if (!GetSetupExeVersion(work_dir, &ctx.current_version)) |
return false; |
- } |
ctx.current_version_str = ctx.current_version.ToString(); |
- if (!IncrementNewVersion(direction, &ctx)) { |
+ if (!IncrementNewVersion(direction, &ctx)) |
return false; |
- } |
// Modify all .dll and .exe files with the current version. |
- bool doing_great = true; |
base::FileEnumerator all_files(work_dir, true, base::FileEnumerator::FILES); |
- do { |
+ while (true) { |
base::FilePath file = all_files.Next(); |
- if (file.empty()) { |
+ if (file.empty()) |
break; |
- } |
std::wstring extension = file.Extension(); |
- if (extension == &kExtExe[0] || extension == &kExtDll[0]) { |
- doing_great = UpdateVersionIfMatch(file, &ctx); |
+ if ((extension == &kExtExe[0] || extension == &kExtDll[0]) && |
+ !UpdateVersionIfMatch(file, &ctx)) { |
+ return false; |
} |
- } while (doing_great); |
+ } |
// Change the versioned directory. |
base::FilePath chrome_bin = work_dir.Append(&kChromeBin[0]); |
- doing_great = base::Move(chrome_bin.Append(ctx.current_version_str), |
- chrome_bin.Append(ctx.new_version_str)); |
- |
- if (doing_great) { |
- // Report the version numbers if requested. |
- if (original_version != NULL) |
- original_version->assign(ctx.current_version_str); |
- if (new_version != NULL) |
- new_version->assign(ctx.new_version_str); |
+ if (!base::Move(chrome_bin.Append(ctx.current_version_str), |
+ chrome_bin.Append(ctx.new_version_str))) { |
+ return false; |
} |
- return doing_great; |
+ // Update the manifest (revise post-XP; see https://crbug.com/581133). |
+ base::FilePath current_manifest = |
+ chrome_bin.Append(ctx.new_version_str) |
+ .Append(ctx.current_version_str + L".manifest"); |
+ if (base::PathExists(current_manifest)) { |
+ base::FilePath new_manifest = |
+ current_manifest.DirName().Append(ctx.new_version_str + L".manifest"); |
+ if (!base::Move(current_manifest, new_manifest) || |
+ !UpdateManifestVersion(new_manifest, &ctx)) { |
+ return false; |
+ } |
+ } |
+ |
+ // Report the version numbers if requested. |
+ if (original_version) |
+ original_version->assign(ctx.current_version_str); |
+ if (new_version) |
+ new_version->assign(ctx.new_version_str); |
+ |
+ return true; |
} |
// Returns the path to the directory holding the 7za executable. By default, it |
@@ -537,8 +578,10 @@ bool GenerateAlternateVersion(const base::FilePath& original_installer_path, |
} |
base::FilePath setup_ex_ = work_dir.directory().Append(&kSetupEx_[0]); |
- base::FilePath chrome_packed_7z = |
- work_dir.directory().Append(&kChromePacked7z[0]); |
+ base::FilePath chrome_packed_7z; // Empty for component builds. |
+ base::FilePath chrome_7z; |
+ const wchar_t* archive_resource_name = nullptr; |
+ base::FilePath* archive_file = nullptr; |
// Load the original file and extract setup.ex_ and chrome.packed.7z |
{ |
ResourceLoader resource_loader; |
@@ -559,15 +602,26 @@ bool GenerateAlternateVersion(const base::FilePath& original_installer_path, |
return false; |
} |
- // Write out chrome.packed.7z |
- if (!resource_loader.Load(&kChromePacked7z[0], &kB7[0], &resource_data)) |
+ // Write out chrome.packed.7z (static build) or chrome.7z (component build) |
+ if (resource_loader.Load(&kChromePacked7z[0], &kB7[0], &resource_data)) { |
+ archive_resource_name = &kChromePacked7z[0]; |
+ chrome_packed_7z = work_dir.directory().Append(archive_resource_name); |
+ archive_file = &chrome_packed_7z; |
+ } else if (resource_loader.Load(&kChrome7z[0], &kB7[0], &resource_data)) { |
+ archive_resource_name = &kChrome7z[0]; |
+ chrome_7z = work_dir.directory().Append(archive_resource_name); |
+ archive_file = &chrome_7z; |
+ } else { |
return false; |
- written = |
- base::WriteFile(chrome_packed_7z, |
- reinterpret_cast<const char*>(resource_data.first), |
- static_cast<int>(resource_data.second)); |
+ } |
+ DCHECK(archive_resource_name); |
+ DCHECK(!chrome_packed_7z.empty() || !chrome_7z.empty()); |
+ DCHECK(archive_file); |
+ written = base::WriteFile( |
+ *archive_file, reinterpret_cast<const char*>(resource_data.first), |
+ static_cast<int>(resource_data.second)); |
if (written != static_cast<int>(resource_data.second)) { |
- LOG(DFATAL) << "Failed writing \"" << chrome_packed_7z.value() << "\""; |
+ LOG(DFATAL) << "Failed writing \"" << archive_file->value() << "\""; |
return false; |
} |
} |
@@ -590,26 +644,30 @@ bool GenerateAlternateVersion(const base::FilePath& original_installer_path, |
return false; |
} |
- // Unpack chrome.packed.7z |
- std::wstring chrome_7z_name; |
- if (LzmaUtil::UnPackArchive(chrome_packed_7z.value(), |
- work_dir.directory().value(), |
- &chrome_7z_name) != NO_ERROR) { |
- LOG(DFATAL) << "Failed unpacking \"" << chrome_packed_7z.value() << "\""; |
- return false; |
+ // Unpack chrome.packed.7z (static build only). |
+ if (!chrome_packed_7z.empty()) { |
+ base::string16 chrome_7z_name; |
+ if (LzmaUtil::UnPackArchive(chrome_packed_7z.value(), |
+ work_dir.directory().value(), |
+ &chrome_7z_name) != NO_ERROR) { |
+ LOG(DFATAL) << "Failed unpacking \"" << chrome_packed_7z.value() << "\""; |
+ return false; |
+ } |
+ chrome_7z = base::FilePath(chrome_7z_name); |
} |
+ DCHECK(!chrome_7z.empty()); |
// Unpack chrome.7z |
- if (LzmaUtil::UnPackArchive(chrome_7z_name, work_dir.directory().value(), |
+ if (LzmaUtil::UnPackArchive(chrome_7z.value(), work_dir.directory().value(), |
NULL) != NO_ERROR) { |
- LOG(DFATAL) << "Failed unpacking \"" << chrome_7z_name << "\""; |
+ LOG(DFATAL) << "Failed unpacking \"" << chrome_7z.value() << "\""; |
return false; |
} |
// Get rid of intermediate files |
- base::FilePath chrome_7z(chrome_7z_name); |
if (!base::DeleteFile(chrome_7z, false) || |
- !base::DeleteFile(chrome_packed_7z, false) || |
+ (!chrome_packed_7z.empty() && |
+ !base::DeleteFile(chrome_packed_7z, false)) || |
!base::DeleteFile(setup_ex_, false)) { |
LOG(DFATAL) << "Failed deleting intermediate files"; |
return false; |
@@ -623,9 +681,11 @@ bool GenerateAlternateVersion(const base::FilePath& original_installer_path, |
if (!CreateArchive(chrome_7z, work_dir.directory().Append(&kChromeBin[0]), 0)) |
return false; |
- // Compress chrome.7z into chrome.packed.7z |
- if (!CreateArchive(chrome_packed_7z, chrome_7z, 9)) |
+ // Compress chrome.7z into chrome.packed.7z for static builds. |
+ if (!chrome_packed_7z.empty() && |
+ !CreateArchive(chrome_packed_7z, chrome_7z, 9)) { |
return false; |
+ } |
// Compress setup.exe into setup.ex_ |
command_line.assign(1, L'"') |
@@ -641,16 +701,20 @@ bool GenerateAlternateVersion(const base::FilePath& original_installer_path, |
return false; |
} |
- // Replace the mini_installer's setup.ex_ and chrome.packed.7z resources. |
+ // Replace the mini_installer's setup.ex_ and chrome.packed.7z (or chrome.7z |
+ // in component builds) resources. |
ResourceUpdater updater; |
if (!updater.Initialize(mini_installer) || |
!updater.Update(&kSetupEx_[0], &kBl[0], |
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), |
setup_ex_) || |
- !updater.Update(&kChromePacked7z[0], &kB7[0], |
+ !updater.Update(archive_resource_name, &kB7[0], |
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), |
- chrome_packed_7z) || |
+ *archive_file) || |
!updater.Commit()) { |
+ LOG(ERROR) << "It is common for this step to fail for very large resources," |
+ " as is the case for Debug component=shared_library builds. " |
+ "Try with a Release or component=static_library build."; |
return false; |
} |