| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // The file contains the implementation of the mini_installer re-versioner. | 5 // The file contains the implementation of the mini_installer re-versioner. |
| 6 // The main function (GenerateNextVersion) does the following in a temp dir: | 6 // The main function (GenerateNextVersion) does the following in a temp dir: |
| 7 // - Extracts and unpacks setup.exe and the Chrome-bin folder from | 7 // - Extracts and unpacks setup.exe and the Chrome-bin folder from |
| 8 // mini_installer.exe. | 8 // mini_installer.exe. |
| 9 // - Inspects setup.exe to determine the current version. | 9 // - Inspects setup.exe to determine the current version. |
| 10 // - Runs through all .dll and .exe files: | 10 // - Runs through all .dll and .exe files: |
| 11 // - Replacing all occurrences of the Unicode version string in the files' | 11 // - Replacing all occurrences of the Unicode version string in the files' |
| 12 // resources with the updated string. | 12 // resources with the updated string. |
| 13 // - For all resources in which the string substitution is made, the binary | 13 // - For all resources in which the string substitution is made, the binary |
| 14 // form of the version is also replaced. | 14 // form of the version is also replaced. |
| 15 // - Re-packs setup.exe and Chrome-bin. | 15 // - Re-packs setup.exe and Chrome-bin. |
| 16 // - Inserts them into the target mini_installer.exe. | 16 // - Inserts them into the target mini_installer.exe. |
| 17 // | 17 // |
| 18 // This code assumes that the host program 1) initializes the process-wide | 18 // This code assumes that the host program 1) initializes the process-wide |
| 19 // CommandLine instance, and 2) resides in the output directory of a build | 19 // CommandLine instance, and 2) resides in the output directory of a build |
| 20 // tree. When #2 is not the case, the --7za_path command-line switch may be | 20 // tree. When #2 is not the case, the --7za_path command-line switch may be |
| 21 // used to provide the (relative or absolute) path to the directory containing | 21 // used to provide the (relative or absolute) path to the directory containing |
| 22 // 7za.exe. | 22 // 7za.exe. |
| 23 | 23 |
| 24 #include "chrome/installer/test/alternate_version_generator.h" | 24 #include "chrome/installer/test/alternate_version_generator.h" |
| 25 | 25 |
| 26 #include <windows.h> | 26 #include <windows.h> |
| 27 #include <stddef.h> |
| 28 #include <stdint.h> |
| 27 | 29 |
| 28 #include <algorithm> | 30 #include <algorithm> |
| 29 #include <limits> | 31 #include <limits> |
| 30 #include <sstream> | 32 #include <sstream> |
| 31 #include <utility> | 33 #include <utility> |
| 32 #include <vector> | 34 #include <vector> |
| 33 | 35 |
| 34 #include "base/basictypes.h" | |
| 35 #include "base/command_line.h" | 36 #include "base/command_line.h" |
| 36 #include "base/files/file.h" | 37 #include "base/files/file.h" |
| 37 #include "base/files/file_enumerator.h" | 38 #include "base/files/file_enumerator.h" |
| 38 #include "base/files/file_path.h" | 39 #include "base/files/file_path.h" |
| 39 #include "base/files/file_util.h" | 40 #include "base/files/file_util.h" |
| 40 #include "base/logging.h" | 41 #include "base/logging.h" |
| 42 #include "base/macros.h" |
| 41 #include "base/path_service.h" | 43 #include "base/path_service.h" |
| 42 #include "base/process/launch.h" | 44 #include "base/process/launch.h" |
| 43 #include "base/process/process_handle.h" | 45 #include "base/process/process_handle.h" |
| 44 #include "base/strings/string_util.h" | 46 #include "base/strings/string_util.h" |
| 45 #include "base/strings/utf_string_conversions.h" | 47 #include "base/strings/utf_string_conversions.h" |
| 46 #include "base/version.h" | 48 #include "base/version.h" |
| 47 #include "base/win/pe_image.h" | 49 #include "base/win/pe_image.h" |
| 48 #include "base/win/scoped_handle.h" | 50 #include "base/win/scoped_handle.h" |
| 49 #include "chrome/installer/test/pe_image_resources.h" | 51 #include "chrome/installer/test/pe_image_resources.h" |
| 50 #include "chrome/installer/test/resource_loader.h" | 52 #include "chrome/installer/test/resource_loader.h" |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 176 } | 178 } |
| 177 } | 179 } |
| 178 | 180 |
| 179 bool MappedFile::Initialize(base::File file) { | 181 bool MappedFile::Initialize(base::File file) { |
| 180 DCHECK(mapping_ == NULL); | 182 DCHECK(mapping_ == NULL); |
| 181 bool result = false; | 183 bool result = false; |
| 182 base::File::Info file_info; | 184 base::File::Info file_info; |
| 183 | 185 |
| 184 if (file.GetInfo(&file_info)) { | 186 if (file.GetInfo(&file_info)) { |
| 185 if (file_info.size <= | 187 if (file_info.size <= |
| 186 static_cast<int64>(std::numeric_limits<DWORD>::max())) { | 188 static_cast<int64_t>(std::numeric_limits<DWORD>::max())) { |
| 187 mapping_ = CreateFileMapping(file.GetPlatformFile(), NULL, PAGE_READWRITE, | 189 mapping_ = CreateFileMapping(file.GetPlatformFile(), NULL, PAGE_READWRITE, |
| 188 0, static_cast<DWORD>(file_info.size), NULL); | 190 0, static_cast<DWORD>(file_info.size), NULL); |
| 189 if (mapping_ != NULL) { | 191 if (mapping_ != NULL) { |
| 190 view_ = MapViewOfFile(mapping_, FILE_MAP_WRITE, 0, 0, | 192 view_ = MapViewOfFile(mapping_, FILE_MAP_WRITE, 0, 0, |
| 191 static_cast<size_t>(file_info.size)); | 193 static_cast<size_t>(file_info.size)); |
| 192 if (view_ != NULL) { | 194 if (view_ != NULL) { |
| 193 result = true; | 195 result = true; |
| 194 } else { | 196 } else { |
| 195 PLOG(DFATAL) << "MapViewOfFile failed"; | 197 PLOG(DFATAL) << "MapViewOfFile failed"; |
| 196 } | 198 } |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 234 | 236 |
| 235 return result; | 237 return result; |
| 236 } | 238 } |
| 237 | 239 |
| 238 // Retrieves the version number of |pe_file| from its version | 240 // Retrieves the version number of |pe_file| from its version |
| 239 // resource, placing the value in |version|. Returns true on success. | 241 // resource, placing the value in |version|. Returns true on success. |
| 240 bool GetFileVersion(const base::FilePath& pe_file, ChromeVersion* version) { | 242 bool GetFileVersion(const base::FilePath& pe_file, ChromeVersion* version) { |
| 241 DCHECK(version); | 243 DCHECK(version); |
| 242 bool result = false; | 244 bool result = false; |
| 243 upgrade_test::ResourceLoader pe_file_loader; | 245 upgrade_test::ResourceLoader pe_file_loader; |
| 244 std::pair<const uint8*, DWORD> version_info_data; | 246 std::pair<const uint8_t*, DWORD> version_info_data; |
| 245 | 247 |
| 246 if (pe_file_loader.Initialize(pe_file) && | 248 if (pe_file_loader.Initialize(pe_file) && |
| 247 pe_file_loader.Load( | 249 pe_file_loader.Load( |
| 248 VS_VERSION_INFO, | 250 VS_VERSION_INFO, |
| 249 static_cast<WORD>(reinterpret_cast<uintptr_t>(RT_VERSION)), | 251 static_cast<WORD>(reinterpret_cast<uintptr_t>(RT_VERSION)), |
| 250 &version_info_data)) { | 252 &version_info_data)) { |
| 251 const VS_FIXEDFILEINFO* fixed_file_info; | 253 const VS_FIXEDFILEINFO* fixed_file_info; |
| 252 UINT ver_info_len; | 254 UINT ver_info_len; |
| 253 if (VerQueryValue(version_info_data.first, L"\\", | 255 if (VerQueryValue(version_info_data.first, L"\\", |
| 254 reinterpret_cast<void**>( | 256 reinterpret_cast<void**>( |
| (...skipping 16 matching lines...) Expand all Loading... |
| 271 bool GetSetupExeVersion(const base::FilePath& work_dir, | 273 bool GetSetupExeVersion(const base::FilePath& work_dir, |
| 272 ChromeVersion* version) { | 274 ChromeVersion* version) { |
| 273 return GetFileVersion(work_dir.Append(&kSetupExe[0]), version); | 275 return GetFileVersion(work_dir.Append(&kSetupExe[0]), version); |
| 274 } | 276 } |
| 275 | 277 |
| 276 | 278 |
| 277 // Replace all occurrences in the sequence [|dest_first|, |dest_last) that | 279 // Replace all occurrences in the sequence [|dest_first|, |dest_last) that |
| 278 // equals [|src_first|, |src_last) with the sequence at |replacement_first| of | 280 // equals [|src_first|, |src_last) with the sequence at |replacement_first| of |
| 279 // the same length. Returns true on success. If non-NULL, |replacements_made| | 281 // the same length. Returns true on success. If non-NULL, |replacements_made| |
| 280 // is set to true/false accordingly. | 282 // is set to true/false accordingly. |
| 281 bool ReplaceAll(uint8* dest_first, uint8* dest_last, | 283 bool ReplaceAll(uint8_t* dest_first, |
| 282 const uint8* src_first, const uint8* src_last, | 284 uint8_t* dest_last, |
| 283 const uint8* replacement_first, bool* replacements_made) { | 285 const uint8_t* src_first, |
| 286 const uint8_t* src_last, |
| 287 const uint8_t* replacement_first, |
| 288 bool* replacements_made) { |
| 284 bool result = true; | 289 bool result = true; |
| 285 bool changed = false; | 290 bool changed = false; |
| 286 do { | 291 do { |
| 287 dest_first = std::search(dest_first, dest_last, src_first, src_last); | 292 dest_first = std::search(dest_first, dest_last, src_first, src_last); |
| 288 if (dest_first == dest_last) { | 293 if (dest_first == dest_last) { |
| 289 break; | 294 break; |
| 290 } | 295 } |
| 291 changed = true; | 296 changed = true; |
| 292 if (memcpy_s(dest_first, dest_last - dest_first, | 297 if (memcpy_s(dest_first, dest_last - dest_first, |
| 293 replacement_first, src_last - src_first) != 0) { | 298 replacement_first, src_last - src_first) != 0) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 309 ChromeVersion current_version; | 314 ChromeVersion current_version; |
| 310 std::wstring current_version_str; | 315 std::wstring current_version_str; |
| 311 ChromeVersion new_version; | 316 ChromeVersion new_version; |
| 312 std::wstring new_version_str; | 317 std::wstring new_version_str; |
| 313 }; // struct VisitResourceContext | 318 }; // struct VisitResourceContext |
| 314 | 319 |
| 315 // Replaces the old version with the new in a resource. A first pass is made to | 320 // Replaces the old version with the new in a resource. A first pass is made to |
| 316 // replace the string form (e.g., "9.0.584.0"). If any replacements are made, a | 321 // replace the string form (e.g., "9.0.584.0"). If any replacements are made, a |
| 317 // second pass is made to replace the binary form (e.g., 0x0000024800000009). | 322 // second pass is made to replace the binary form (e.g., 0x0000024800000009). |
| 318 void VisitResource(const upgrade_test::EntryPath& path, | 323 void VisitResource(const upgrade_test::EntryPath& path, |
| 319 uint8* data, DWORD size, DWORD code_page, | 324 uint8_t* data, |
| 325 DWORD size, |
| 326 DWORD code_page, |
| 320 uintptr_t context) { | 327 uintptr_t context) { |
| 321 VisitResourceContext& ctx = *reinterpret_cast<VisitResourceContext*>(context); | 328 VisitResourceContext& ctx = *reinterpret_cast<VisitResourceContext*>(context); |
| 322 | 329 |
| 323 // Replace all occurrences of current_version_str with new_version_str | 330 // Replace all occurrences of current_version_str with new_version_str |
| 324 bool changing_version = false; | 331 bool changing_version = false; |
| 325 if (ReplaceAll( | 332 if (ReplaceAll( |
| 326 data, | 333 data, data + size, |
| 327 data + size, | 334 reinterpret_cast<const uint8_t*>(ctx.current_version_str.c_str()), |
| 328 reinterpret_cast<const uint8*>(ctx.current_version_str.c_str()), | 335 reinterpret_cast<const uint8_t*>(ctx.current_version_str.c_str() + |
| 329 reinterpret_cast<const uint8*>(ctx.current_version_str.c_str() + | 336 ctx.current_version_str.size() + 1), |
| 330 ctx.current_version_str.size() + 1), | 337 reinterpret_cast<const uint8_t*>(ctx.new_version_str.c_str()), |
| 331 reinterpret_cast<const uint8*>(ctx.new_version_str.c_str()), | |
| 332 &changing_version) && | 338 &changing_version) && |
| 333 changing_version) { | 339 changing_version) { |
| 334 // Replace all occurrences of current_version with new_version | 340 // Replace all occurrences of current_version with new_version |
| 335 struct VersionPair { | 341 struct VersionPair { |
| 336 DWORD high; | 342 DWORD high; |
| 337 DWORD low; | 343 DWORD low; |
| 338 }; | 344 }; |
| 339 VersionPair cur_ver = { | 345 VersionPair cur_ver = { |
| 340 ctx.current_version.high(), ctx.current_version.low() | 346 ctx.current_version.high(), ctx.current_version.low() |
| 341 }; | 347 }; |
| 342 VersionPair new_ver = { | 348 VersionPair new_ver = { |
| 343 ctx.new_version.high(), ctx.new_version.low() | 349 ctx.new_version.high(), ctx.new_version.low() |
| 344 }; | 350 }; |
| 345 ReplaceAll(data, data + size, reinterpret_cast<const uint8*>(&cur_ver), | 351 ReplaceAll(data, data + size, reinterpret_cast<const uint8_t*>(&cur_ver), |
| 346 reinterpret_cast<const uint8*>(&cur_ver) + sizeof(cur_ver), | 352 reinterpret_cast<const uint8_t*>(&cur_ver) + sizeof(cur_ver), |
| 347 reinterpret_cast<const uint8*>(&new_ver), NULL); | 353 reinterpret_cast<const uint8_t*>(&new_ver), NULL); |
| 348 } | 354 } |
| 349 } | 355 } |
| 350 | 356 |
| 351 // Updates the version strings and numbers in all of |image_file|'s resources. | 357 // Updates the version strings and numbers in all of |image_file|'s resources. |
| 352 bool UpdateVersionIfMatch(const base::FilePath& image_file, | 358 bool UpdateVersionIfMatch(const base::FilePath& image_file, |
| 353 VisitResourceContext* context) { | 359 VisitResourceContext* context) { |
| 354 if (!context || | 360 if (!context || |
| 355 context->current_version_str.size() < context->new_version_str.size()) { | 361 context->current_version_str.size() < context->new_version_str.size()) { |
| 356 return false; | 362 return false; |
| 357 } | 363 } |
| 358 | 364 |
| 359 bool result = false; | 365 bool result = false; |
| 360 uint32 flags = base::File::FLAG_OPEN | base::File::FLAG_READ | | 366 uint32_t flags = base::File::FLAG_OPEN | base::File::FLAG_READ | |
| 361 base::File::FLAG_WRITE | base::File::FLAG_EXCLUSIVE_READ | | 367 base::File::FLAG_WRITE | base::File::FLAG_EXCLUSIVE_READ | |
| 362 base::File::FLAG_EXCLUSIVE_WRITE; | 368 base::File::FLAG_EXCLUSIVE_WRITE; |
| 363 base::File file(image_file, flags); | 369 base::File file(image_file, flags); |
| 364 // It turns out that the underlying CreateFile can fail due to unhelpful | 370 // It turns out that the underlying CreateFile can fail due to unhelpful |
| 365 // security software locking the newly created DLL. So add a few brief | 371 // security software locking the newly created DLL. So add a few brief |
| 366 // retries to help tests that use this pass on machines thusly encumbered. | 372 // retries to help tests that use this pass on machines thusly encumbered. |
| 367 int retries = 3; | 373 int retries = 3; |
| 368 while (!file.IsValid() && retries-- > 0) { | 374 while (!file.IsValid() && retries-- > 0) { |
| 369 LOG(WARNING) << "Failed to open \"" << image_file.value() << "\"." | 375 LOG(WARNING) << "Failed to open \"" << image_file.value() << "\"." |
| 370 << " Retrying " << retries << " more times."; | 376 << " Retrying " << retries << " more times."; |
| 371 Sleep(1000); | 377 Sleep(1000); |
| 372 file.Initialize(image_file, flags); | 378 file.Initialize(image_file, flags); |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 529 << "\" to \"" << mini_installer.value() << "\""; | 535 << "\" to \"" << mini_installer.value() << "\""; |
| 530 return false; | 536 return false; |
| 531 } | 537 } |
| 532 | 538 |
| 533 base::FilePath setup_ex_ = work_dir.directory().Append(&kSetupEx_[0]); | 539 base::FilePath setup_ex_ = work_dir.directory().Append(&kSetupEx_[0]); |
| 534 base::FilePath chrome_packed_7z = | 540 base::FilePath chrome_packed_7z = |
| 535 work_dir.directory().Append(&kChromePacked7z[0]); | 541 work_dir.directory().Append(&kChromePacked7z[0]); |
| 536 // Load the original file and extract setup.ex_ and chrome.packed.7z | 542 // Load the original file and extract setup.ex_ and chrome.packed.7z |
| 537 { | 543 { |
| 538 ResourceLoader resource_loader; | 544 ResourceLoader resource_loader; |
| 539 std::pair<const uint8*, DWORD> resource_data; | 545 std::pair<const uint8_t*, DWORD> resource_data; |
| 540 | 546 |
| 541 if (!resource_loader.Initialize(mini_installer)) | 547 if (!resource_loader.Initialize(mini_installer)) |
| 542 return false; | 548 return false; |
| 543 | 549 |
| 544 // Write out setup.ex_ | 550 // Write out setup.ex_ |
| 545 if (!resource_loader.Load(&kSetupEx_[0], &kBl[0], &resource_data)) | 551 if (!resource_loader.Load(&kSetupEx_[0], &kBl[0], &resource_data)) |
| 546 return false; | 552 return false; |
| 547 int written = | 553 int written = |
| 548 base::WriteFile(setup_ex_, | 554 base::WriteFile(setup_ex_, |
| 549 reinterpret_cast<const char*>(resource_data.first), | 555 reinterpret_cast<const char*>(resource_data.first), |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 692 return false; | 698 return false; |
| 693 } | 699 } |
| 694 ctx.current_version_str = ctx.current_version.ToString(); | 700 ctx.current_version_str = ctx.current_version.ToString(); |
| 695 ctx.new_version = ChromeVersion::FromString(version.GetString()); | 701 ctx.new_version = ChromeVersion::FromString(version.GetString()); |
| 696 ctx.new_version_str = ctx.new_version.ToString(); | 702 ctx.new_version_str = ctx.new_version.ToString(); |
| 697 | 703 |
| 698 return UpdateVersionIfMatch(target_file, &ctx); | 704 return UpdateVersionIfMatch(target_file, &ctx); |
| 699 } | 705 } |
| 700 | 706 |
| 701 } // namespace upgrade_test | 707 } // namespace upgrade_test |
| OLD | NEW |