[sql] Remove _HAS_EXCEPTIONS=0 from build info.
[chromium-blink-merge.git] / chrome / installer / test / alternate_version_generator.cc
blob2e967377664948f03a4fe4e9a0c33141d979c3cc
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
3 // found in the LICENSE file.
5 // The file contains the implementation of the mini_installer re-versioner.
6 // The main function (GenerateNextVersion) does the following in a temp dir:
7 // - Extracts and unpacks setup.exe and the Chrome-bin folder from
8 // mini_installer.exe.
9 // - Inspects setup.exe to determine the current version.
10 // - Runs through all .dll and .exe files:
11 // - Replacing all occurrences of the Unicode version string in the files'
12 // resources with the updated string.
13 // - For all resources in which the string substitution is made, the binary
14 // form of the version is also replaced.
15 // - Re-packs setup.exe and Chrome-bin.
16 // - Inserts them into the target mini_installer.exe.
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
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
22 // 7za.exe.
24 #include "chrome/installer/test/alternate_version_generator.h"
26 #include <windows.h>
28 #include <algorithm>
29 #include <limits>
30 #include <sstream>
31 #include <utility>
32 #include <vector>
34 #include "base/basictypes.h"
35 #include "base/command_line.h"
36 #include "base/files/file.h"
37 #include "base/files/file_enumerator.h"
38 #include "base/files/file_path.h"
39 #include "base/files/file_util.h"
40 #include "base/logging.h"
41 #include "base/path_service.h"
42 #include "base/process/launch.h"
43 #include "base/process/process_handle.h"
44 #include "base/strings/string_util.h"
45 #include "base/strings/utf_string_conversions.h"
46 #include "base/version.h"
47 #include "base/win/pe_image.h"
48 #include "base/win/scoped_handle.h"
49 #include "chrome/installer/test/pe_image_resources.h"
50 #include "chrome/installer/test/resource_loader.h"
51 #include "chrome/installer/test/resource_updater.h"
52 #include "chrome/installer/util/lzma_util.h"
54 namespace {
56 const wchar_t k7zaExe[] = L"7za.exe";
57 const wchar_t k7zaPathRelative[] = L"..\\..\\third_party\\lzma_sdk\\Executable";
58 const wchar_t kB7[] = L"B7";
59 const wchar_t kBl[] = L"BL";
60 const wchar_t kChromeBin[] = L"Chrome-bin";
61 const wchar_t kChromePacked7z[] = L"chrome.packed.7z";
62 const wchar_t kExe[] = L"exe";
63 const wchar_t kExpandExe[] = L"expand.exe";
64 const wchar_t kExtDll[] = L".dll";
65 const wchar_t kExtExe[] = L".exe";
66 const wchar_t kMakeCab[] = L"makecab.exe";
67 const wchar_t kSetupEx_[] = L"setup.ex_";
68 const wchar_t kSetupExe[] = L"setup.exe";
69 const char kSwitch7zaPath[] = "7za_path";
70 const wchar_t kTempDirPrefix[] = L"mini_installer_test_temp";
72 // A helper class for creating and cleaning a temporary directory. A temporary
73 // directory is created in Initialize and destroyed (along with all of its
74 // contents) when the guard instance is destroyed.
75 class ScopedTempDirectory {
76 public:
77 ScopedTempDirectory() { }
78 ~ScopedTempDirectory() {
79 if (!directory_.empty() && !base::DeleteFile(directory_, true)) {
80 LOG(DFATAL) << "Failed deleting temporary directory \""
81 << directory_.value() << "\"";
84 // Creates a temporary directory.
85 bool Initialize() {
86 DCHECK(directory_.empty());
87 if (!base::CreateNewTempDirectory(&kTempDirPrefix[0], &directory_)) {
88 LOG(DFATAL) << "Failed creating temporary directory.";
89 return false;
91 return true;
93 const base::FilePath& directory() const {
94 DCHECK(!directory_.empty());
95 return directory_;
98 private:
99 base::FilePath directory_;
100 DISALLOW_COPY_AND_ASSIGN(ScopedTempDirectory);
101 }; // class ScopedTempDirectory
103 // A helper class for manipulating a Chrome product version.
104 class ChromeVersion {
105 public:
106 static ChromeVersion FromHighLow(DWORD high, DWORD low) {
107 return ChromeVersion(static_cast<ULONGLONG>(high) << 32 |
108 static_cast<ULONGLONG>(low));
110 static ChromeVersion FromString(const std::string& version_string) {
111 Version version(version_string);
112 DCHECK(version.IsValid());
113 const std::vector<uint32_t>& c(version.components());
114 return ChromeVersion(static_cast<ULONGLONG>(c[0]) << 48 |
115 static_cast<ULONGLONG>(c[1]) << 32 |
116 static_cast<ULONGLONG>(c[2]) << 16 |
117 static_cast<ULONGLONG>(c[3]));
120 ChromeVersion() { }
121 explicit ChromeVersion(ULONGLONG value) : version_(value) { }
122 WORD major() const { return static_cast<WORD>(version_ >> 48); }
123 WORD minor() const { return static_cast<WORD>(version_ >> 32); }
124 WORD build() const { return static_cast<WORD>(version_ >> 16); }
125 WORD patch() const { return static_cast<WORD>(version_); }
126 DWORD high() const { return static_cast<DWORD>(version_ >> 32); }
127 DWORD low() const { return static_cast<DWORD>(version_); }
128 ULONGLONG value() const { return version_; }
129 void set_value(ULONGLONG value) { version_ = value; }
130 std::wstring ToString() const;
131 private:
132 ULONGLONG version_;
133 }; // class ChromeVersion
135 std::wstring ChromeVersion::ToString() const {
136 wchar_t buffer[24];
137 int string_len =
138 swprintf_s(&buffer[0], arraysize(buffer), L"%hu.%hu.%hu.%hu",
139 major(), minor(), build(), patch());
140 DCHECK_NE(-1, string_len);
141 DCHECK_GT(static_cast<int>(arraysize(buffer)), string_len);
142 return std::wstring(&buffer[0], string_len);
146 // A read/write mapping of a file.
147 // Note: base::MemoryMappedFile is not used because it doesn't support
148 // read/write mappings. Adding such support across all platforms for this
149 // Windows-only test code seems like overkill.
150 class MappedFile {
151 public:
152 MappedFile() : size_(), mapping_(), view_() { }
153 ~MappedFile();
154 bool Initialize(base::File file);
155 void* data() const { return view_; }
156 size_t size() const { return size_; }
158 private:
159 size_t size_;
160 base::File file_;
161 HANDLE mapping_;
162 void* view_;
163 DISALLOW_COPY_AND_ASSIGN(MappedFile);
164 }; // class MappedFile
166 MappedFile::~MappedFile() {
167 if (view_ != NULL) {
168 if (UnmapViewOfFile(view_) == 0) {
169 PLOG(DFATAL) << "MappedFile failed to unmap view.";
172 if (mapping_ != NULL) {
173 if (CloseHandle(mapping_) == 0) {
174 PLOG(DFATAL) << "Could not close file mapping handle.";
179 bool MappedFile::Initialize(base::File file) {
180 DCHECK(mapping_ == NULL);
181 bool result = false;
182 base::File::Info file_info;
184 if (file.GetInfo(&file_info)) {
185 if (file_info.size <=
186 static_cast<int64>(std::numeric_limits<DWORD>::max())) {
187 mapping_ = CreateFileMapping(file.GetPlatformFile(), NULL, PAGE_READWRITE,
188 0, static_cast<DWORD>(file_info.size), NULL);
189 if (mapping_ != NULL) {
190 view_ = MapViewOfFile(mapping_, FILE_MAP_WRITE, 0, 0,
191 static_cast<size_t>(file_info.size));
192 if (view_ != NULL) {
193 result = true;
194 } else {
195 PLOG(DFATAL) << "MapViewOfFile failed";
197 } else {
198 PLOG(DFATAL) << "CreateFileMapping failed";
200 } else {
201 LOG(DFATAL) << "Files larger than " << std::numeric_limits<DWORD>::max()
202 << " are not supported.";
204 } else {
205 PLOG(DFATAL) << "file.GetInfo failed";
207 file_ = file.Pass();
208 return result;
211 // Calls CreateProcess with good default parameters and waits for the process
212 // to terminate returning the process exit code.
213 bool RunProcessAndWait(const wchar_t* exe_path, const std::wstring& cmdline,
214 int* exit_code) {
215 bool result = true;
216 base::LaunchOptions options;
217 options.wait = true;
218 options.start_hidden = true;
219 base::Process process = base::LaunchProcess(cmdline, options);
220 if (process.IsValid()) {
221 if (exit_code) {
222 if (!GetExitCodeProcess(process.Handle(),
223 reinterpret_cast<DWORD*>(exit_code))) {
224 PLOG(DFATAL) << "Failed getting the exit code for \""
225 << cmdline << "\".";
226 result = false;
227 } else {
228 DCHECK_NE(*exit_code, static_cast<int>(STILL_ACTIVE));
231 } else {
232 result = false;
235 return result;
238 // Retrieves the version number of |pe_file| from its version
239 // resource, placing the value in |version|. Returns true on success.
240 bool GetFileVersion(const base::FilePath& pe_file, ChromeVersion* version) {
241 DCHECK(version);
242 bool result = false;
243 upgrade_test::ResourceLoader pe_file_loader;
244 std::pair<const uint8*, DWORD> version_info_data;
246 if (pe_file_loader.Initialize(pe_file) &&
247 pe_file_loader.Load(
248 VS_VERSION_INFO,
249 static_cast<WORD>(reinterpret_cast<uintptr_t>(RT_VERSION)),
250 &version_info_data)) {
251 const VS_FIXEDFILEINFO* fixed_file_info;
252 UINT ver_info_len;
253 if (VerQueryValue(version_info_data.first, L"\\",
254 reinterpret_cast<void**>(
255 const_cast<VS_FIXEDFILEINFO**>(&fixed_file_info)),
256 &ver_info_len) != 0) {
257 DCHECK_EQ(sizeof(VS_FIXEDFILEINFO), static_cast<size_t>(ver_info_len));
258 *version = ChromeVersion::FromHighLow(fixed_file_info->dwFileVersionMS,
259 fixed_file_info->dwFileVersionLS);
260 result = true;
261 } else {
262 LOG(DFATAL) << "VerQueryValue failed to retrieve VS_FIXEDFILEINFO";
266 return result;
269 // Retrieves the version number of setup.exe in |work_dir| from its version
270 // resource, placing the value in |version|. Returns true on success.
271 bool GetSetupExeVersion(const base::FilePath& work_dir,
272 ChromeVersion* version) {
273 return GetFileVersion(work_dir.Append(&kSetupExe[0]), version);
277 // Replace all occurrences in the sequence [|dest_first|, |dest_last) that
278 // 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|
280 // is set to true/false accordingly.
281 bool ReplaceAll(uint8* dest_first, uint8* dest_last,
282 const uint8* src_first, const uint8* src_last,
283 const uint8* replacement_first, bool* replacements_made) {
284 bool result = true;
285 bool changed = false;
286 do {
287 dest_first = std::search(dest_first, dest_last, src_first, src_last);
288 if (dest_first == dest_last) {
289 break;
291 changed = true;
292 if (memcpy_s(dest_first, dest_last - dest_first,
293 replacement_first, src_last - src_first) != 0) {
294 result = false;
295 break;
297 dest_first += (src_last - src_first);
298 } while (true);
300 if (replacements_made != NULL) {
301 *replacements_made = changed;
304 return result;
307 // A context structure in support of our EnumResource_Fn callback.
308 struct VisitResourceContext {
309 ChromeVersion current_version;
310 std::wstring current_version_str;
311 ChromeVersion new_version;
312 std::wstring new_version_str;
313 }; // struct VisitResourceContext
315 // 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
317 // second pass is made to replace the binary form (e.g., 0x0000024800000009).
318 void VisitResource(const upgrade_test::EntryPath& path,
319 uint8* data, DWORD size, DWORD code_page,
320 uintptr_t context) {
321 VisitResourceContext& ctx = *reinterpret_cast<VisitResourceContext*>(context);
323 // Replace all occurrences of current_version_str with new_version_str
324 bool changing_version = false;
325 if (ReplaceAll(
326 data,
327 data + size,
328 reinterpret_cast<const uint8*>(ctx.current_version_str.c_str()),
329 reinterpret_cast<const uint8*>(ctx.current_version_str.c_str() +
330 ctx.current_version_str.size() + 1),
331 reinterpret_cast<const uint8*>(ctx.new_version_str.c_str()),
332 &changing_version) &&
333 changing_version) {
334 // Replace all occurrences of current_version with new_version
335 struct VersionPair {
336 DWORD high;
337 DWORD low;
339 VersionPair cur_ver = {
340 ctx.current_version.high(), ctx.current_version.low()
342 VersionPair new_ver = {
343 ctx.new_version.high(), ctx.new_version.low()
345 ReplaceAll(data, data + size, reinterpret_cast<const uint8*>(&cur_ver),
346 reinterpret_cast<const uint8*>(&cur_ver) + sizeof(cur_ver),
347 reinterpret_cast<const uint8*>(&new_ver), NULL);
351 // Updates the version strings and numbers in all of |image_file|'s resources.
352 bool UpdateVersionIfMatch(const base::FilePath& image_file,
353 VisitResourceContext* context) {
354 if (!context ||
355 context->current_version_str.size() < context->new_version_str.size()) {
356 return false;
359 bool result = false;
360 uint32 flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
361 base::File::FLAG_WRITE | base::File::FLAG_EXCLUSIVE_READ |
362 base::File::FLAG_EXCLUSIVE_WRITE;
363 base::File file(image_file, flags);
364 // 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
366 // retries to help tests that use this pass on machines thusly encumbered.
367 int retries = 3;
368 while (!file.IsValid() && retries-- > 0) {
369 LOG(WARNING) << "Failed to open \"" << image_file.value() << "\"."
370 << " Retrying " << retries << " more times.";
371 Sleep(1000);
372 file.Initialize(image_file, flags);
375 if (file.IsValid()) {
376 MappedFile image_mapping;
377 if (image_mapping.Initialize(file.Pass())) {
378 base::win::PEImageAsData image(
379 reinterpret_cast<HMODULE>(image_mapping.data()));
380 // PEImage class does not support other-architecture images.
381 if (image.GetNTHeaders()->OptionalHeader.Magic ==
382 IMAGE_NT_OPTIONAL_HDR_MAGIC) {
383 result = upgrade_test::EnumResources(
384 image, &VisitResource, reinterpret_cast<uintptr_t>(context));
385 } else {
386 result = true;
389 } else {
390 PLOG(DFATAL) << "Failed to open \"" << image_file.value() << "\"";
392 return result;
395 bool IncrementNewVersion(upgrade_test::Direction direction,
396 VisitResourceContext* ctx) {
397 DCHECK(ctx);
399 // Figure out a past or future version with the same string length as this one
400 // by decrementing or incrementing each component.
401 LONGLONG incrementer = (direction == upgrade_test::PREVIOUS_VERSION ? -1 : 1);
403 do {
404 if (incrementer == 0) {
405 LOG(DFATAL) << "Improbable version at the cusp of complete rollover";
406 return false;
408 ctx->new_version.set_value(ctx->current_version.value() + incrementer);
409 ctx->new_version_str = ctx->new_version.ToString();
410 incrementer <<= 16;
411 } while (ctx->new_version_str.size() != ctx->current_version_str.size());
413 return true;
416 // Raises or lowers the version of all .exe and .dll files in |work_dir| as well
417 // as the |work-dir|\Chrome-bin\w.x.y.z directory. |original_version| and
418 // |new_version|, when non-NULL, are given the original and new version numbers
419 // on success.
420 bool ApplyAlternateVersion(const base::FilePath& work_dir,
421 upgrade_test::Direction direction,
422 std::wstring* original_version,
423 std::wstring* new_version) {
424 VisitResourceContext ctx;
425 if (!GetSetupExeVersion(work_dir, &ctx.current_version)) {
426 return false;
428 ctx.current_version_str = ctx.current_version.ToString();
430 if (!IncrementNewVersion(direction, &ctx)) {
431 return false;
434 // Modify all .dll and .exe files with the current version.
435 bool doing_great = true;
436 base::FileEnumerator all_files(work_dir, true, base::FileEnumerator::FILES);
437 do {
438 base::FilePath file = all_files.Next();
439 if (file.empty()) {
440 break;
442 std::wstring extension = file.Extension();
443 if (extension == &kExtExe[0] || extension == &kExtDll[0]) {
444 doing_great = UpdateVersionIfMatch(file, &ctx);
446 } while (doing_great);
448 // Change the versioned directory.
449 base::FilePath chrome_bin = work_dir.Append(&kChromeBin[0]);
450 doing_great = base::Move(chrome_bin.Append(ctx.current_version_str),
451 chrome_bin.Append(ctx.new_version_str));
453 if (doing_great) {
454 // Report the version numbers if requested.
455 if (original_version != NULL)
456 original_version->assign(ctx.current_version_str);
457 if (new_version != NULL)
458 new_version->assign(ctx.new_version_str);
461 return doing_great;
464 // Returns the path to the directory holding the 7za executable. By default, it
465 // is assumed that the test resides in the tree's output directory, so the
466 // relative path "..\..\third_party\lzma_sdk\Executable" is applied to the host
467 // executable's directory. This can be overridden with the --7za_path
468 // command-line switch.
469 base::FilePath Get7zaPath() {
470 base::FilePath l7za_path =
471 base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
472 &kSwitch7zaPath[0]);
473 if (l7za_path.empty()) {
474 base::FilePath dir_exe;
475 if (!PathService::Get(base::DIR_EXE, &dir_exe))
476 LOG(DFATAL) << "Failed getting directory of host executable";
477 l7za_path = dir_exe.Append(&k7zaPathRelative[0]);
479 return l7za_path;
482 bool CreateArchive(const base::FilePath& output_file,
483 const base::FilePath& input_path,
484 int compression_level) {
485 DCHECK(compression_level == 0 ||
486 compression_level >= 1 && compression_level <= 9 &&
487 (compression_level & 0x01) != 0);
489 std::wstring command_line(1, L'"');
490 command_line
491 .append(Get7zaPath().Append(&k7zaExe[0]).value())
492 .append(L"\" a -bd -t7z \"")
493 .append(output_file.value())
494 .append(L"\" \"")
495 .append(input_path.value())
496 .append(L"\" -mx")
497 .append(1, L'0' + compression_level);
498 int exit_code;
499 if (!RunProcessAndWait(NULL, command_line, &exit_code))
500 return false;
501 if (exit_code != 0) {
502 LOG(DFATAL) << Get7zaPath().Append(&k7zaExe[0]).value()
503 << " exited with code " << exit_code
504 << " while creating " << output_file.value();
505 return false;
507 return true;
510 } // namespace
512 namespace upgrade_test {
514 bool GenerateAlternateVersion(const base::FilePath& original_installer_path,
515 const base::FilePath& target_path,
516 Direction direction,
517 std::wstring* original_version,
518 std::wstring* new_version) {
519 // Create a temporary directory in which we'll do our work.
520 ScopedTempDirectory work_dir;
521 if (!work_dir.Initialize())
522 return false;
524 // Copy the original mini_installer.
525 base::FilePath mini_installer =
526 work_dir.directory().Append(original_installer_path.BaseName());
527 if (!base::CopyFile(original_installer_path, mini_installer)) {
528 LOG(DFATAL) << "Failed copying \"" << original_installer_path.value()
529 << "\" to \"" << mini_installer.value() << "\"";
530 return false;
533 base::FilePath setup_ex_ = work_dir.directory().Append(&kSetupEx_[0]);
534 base::FilePath chrome_packed_7z =
535 work_dir.directory().Append(&kChromePacked7z[0]);
536 // Load the original file and extract setup.ex_ and chrome.packed.7z
538 ResourceLoader resource_loader;
539 std::pair<const uint8*, DWORD> resource_data;
541 if (!resource_loader.Initialize(mini_installer))
542 return false;
544 // Write out setup.ex_
545 if (!resource_loader.Load(&kSetupEx_[0], &kBl[0], &resource_data))
546 return false;
547 int written =
548 base::WriteFile(setup_ex_,
549 reinterpret_cast<const char*>(resource_data.first),
550 static_cast<int>(resource_data.second));
551 if (written != static_cast<int>(resource_data.second)) {
552 LOG(DFATAL) << "Failed writing \"" << setup_ex_.value() << "\"";
553 return false;
556 // Write out chrome.packed.7z
557 if (!resource_loader.Load(&kChromePacked7z[0], &kB7[0], &resource_data))
558 return false;
559 written =
560 base::WriteFile(chrome_packed_7z,
561 reinterpret_cast<const char*>(resource_data.first),
562 static_cast<int>(resource_data.second));
563 if (written != static_cast<int>(resource_data.second)) {
564 LOG(DFATAL) << "Failed writing \"" << chrome_packed_7z.value() << "\"";
565 return false;
569 // Expand setup.ex_
570 base::FilePath setup_exe = setup_ex_.ReplaceExtension(&kExe[0]);
571 std::wstring command_line;
572 command_line.append(1, L'"')
573 .append(&kExpandExe[0])
574 .append(L"\" \"")
575 .append(setup_ex_.value())
576 .append(L"\" \"")
577 .append(setup_exe.value())
578 .append(1, L'\"');
579 int exit_code;
580 if (!RunProcessAndWait(NULL, command_line, &exit_code))
581 return false;
582 if (exit_code != 0) {
583 LOG(DFATAL) << &kExpandExe[0] << " exited with code " << exit_code;
584 return false;
587 // Unpack chrome.packed.7z
588 std::wstring chrome_7z_name;
589 if (LzmaUtil::UnPackArchive(chrome_packed_7z.value(),
590 work_dir.directory().value(),
591 &chrome_7z_name) != NO_ERROR) {
592 LOG(DFATAL) << "Failed unpacking \"" << chrome_packed_7z.value() << "\"";
593 return false;
596 // Unpack chrome.7z
597 if (LzmaUtil::UnPackArchive(chrome_7z_name, work_dir.directory().value(),
598 NULL) != NO_ERROR) {
599 LOG(DFATAL) << "Failed unpacking \"" << chrome_7z_name << "\"";
600 return false;
603 // Get rid of intermediate files
604 base::FilePath chrome_7z(chrome_7z_name);
605 if (!base::DeleteFile(chrome_7z, false) ||
606 !base::DeleteFile(chrome_packed_7z, false) ||
607 !base::DeleteFile(setup_ex_, false)) {
608 LOG(DFATAL) << "Failed deleting intermediate files";
609 return false;
612 // Increment the version in all files.
613 ApplyAlternateVersion(work_dir.directory(), direction, original_version,
614 new_version);
616 // Pack up files into chrome.7z
617 if (!CreateArchive(chrome_7z, work_dir.directory().Append(&kChromeBin[0]), 0))
618 return false;
620 // Compress chrome.7z into chrome.packed.7z
621 if (!CreateArchive(chrome_packed_7z, chrome_7z, 9))
622 return false;
624 // Compress setup.exe into setup.ex_
625 command_line.assign(1, L'"')
626 .append(&kMakeCab[0])
627 .append(L"\" /D CompressionType=LZX /L \"")
628 .append(work_dir.directory().value())
629 .append(L"\" \"")
630 .append(setup_exe.value());
631 if (!RunProcessAndWait(NULL, command_line, &exit_code))
632 return false;
633 if (exit_code != 0) {
634 LOG(DFATAL) << &kMakeCab[0] << " exited with code " << exit_code;
635 return false;
638 // Replace the mini_installer's setup.ex_ and chrome.packed.7z resources.
639 ResourceUpdater updater;
640 if (!updater.Initialize(mini_installer) ||
641 !updater.Update(&kSetupEx_[0], &kBl[0],
642 MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
643 setup_ex_) ||
644 !updater.Update(&kChromePacked7z[0], &kB7[0],
645 MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
646 chrome_packed_7z) ||
647 !updater.Commit()) {
648 return false;
651 // Finally, move the updated mini_installer into place.
652 return base::Move(mini_installer, target_path);
655 bool GenerateAlternatePEFileVersion(const base::FilePath& original_file,
656 const base::FilePath& target_file,
657 Direction direction) {
658 VisitResourceContext ctx;
659 if (!GetFileVersion(original_file, &ctx.current_version)) {
660 LOG(DFATAL) << "Failed reading version from \"" << original_file.value()
661 << "\"";
662 return false;
664 ctx.current_version_str = ctx.current_version.ToString();
666 if (!IncrementNewVersion(direction, &ctx)) {
667 LOG(DFATAL) << "Failed to increment version from \""
668 << original_file.value() << "\"";
669 return false;
672 Version new_version(base::UTF16ToASCII(ctx.new_version_str));
673 GenerateSpecificPEFileVersion(original_file, target_file, new_version);
675 return true;
678 bool GenerateSpecificPEFileVersion(const base::FilePath& original_file,
679 const base::FilePath& target_file,
680 const Version& version) {
681 // First copy original_file to target_file.
682 if (!base::CopyFile(original_file, target_file)) {
683 LOG(DFATAL) << "Failed copying \"" << original_file.value()
684 << "\" to \"" << target_file.value() << "\"";
685 return false;
688 VisitResourceContext ctx;
689 if (!GetFileVersion(target_file, &ctx.current_version)) {
690 LOG(DFATAL) << "Failed reading version from \"" << target_file.value()
691 << "\"";
692 return false;
694 ctx.current_version_str = ctx.current_version.ToString();
695 ctx.new_version = ChromeVersion::FromString(version.GetString());
696 ctx.new_version_str = ctx.new_version.ToString();
698 return UpdateVersionIfMatch(target_file, &ctx);
701 } // namespace upgrade_test