diff options
author | robertshield@chromium.org <robertshield@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-20 21:00:45 +0000 |
---|---|---|
committer | robertshield@chromium.org <robertshield@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-10-20 21:00:45 +0000 |
commit | 1f9e089f4335ae5487a884eba25efbdee5dc076d (patch) | |
tree | 4a09df86e95c079b9e393730030ff6fe2fa7322c /chrome/installer | |
parent | 1a6fff54665ded8a4be408f112938ad0328556dc (diff) | |
download | chromium_src-1f9e089f4335ae5487a884eba25efbdee5dc076d.zip chromium_src-1f9e089f4335ae5487a884eba25efbdee5dc076d.tar.gz chromium_src-1f9e089f4335ae5487a884eba25efbdee5dc076d.tar.bz2 |
Make the installer append to its log file instead of replacing it. Cap the log file size at something reasonable.BUG=100984TEST=Install twice, notice that both install runs are present in the log file.
Review URL: http://codereview.chromium.org/8352035
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@106576 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/installer')
-rw-r--r-- | chrome/installer/util/logging_installer.cc | 61 | ||||
-rw-r--r-- | chrome/installer/util/logging_installer.h | 32 | ||||
-rw-r--r-- | chrome/installer/util/logging_installer_unittest.cc | 118 |
3 files changed, 204 insertions, 7 deletions
diff --git a/chrome/installer/util/logging_installer.cc b/chrome/installer/util/logging_installer.cc index 73e1719..ea62723 100644 --- a/chrome/installer/util/logging_installer.cc +++ b/chrome/installer/util/logging_installer.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -8,11 +8,14 @@ #include "base/command_line.h" #include "base/file_path.h" +#include "base/file_util.h" #include "base/logging.h" #include "base/logging_win.h" #include "base/path_service.h" +#include "base/platform_file.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" +#include "base/win/scoped_handle.h" #include "chrome/installer/util/master_preferences.h" #include "chrome/installer/util/master_preferences_constants.h" #include "chrome/installer/util/util_constants.h" @@ -27,22 +30,70 @@ namespace installer { // InitInstallerLogging() and the beginning of EndInstallerLogging(). bool installer_logging_ = false; +TruncateResult TruncateLogFileIfNeeded(const FilePath& log_file) { + TruncateResult result = LOGFILE_UNTOUCHED; + + int64 log_size = 0; + if (file_util::GetFileSize(log_file, &log_size) && + log_size > kMaxInstallerLogFileSize) { + // Cause the old log file to be deleted when we are done with it. + const int file_flags = base::PLATFORM_FILE_OPEN | + base::PLATFORM_FILE_READ | + base::PLATFORM_FILE_SHARE_DELETE | + base::PLATFORM_FILE_DELETE_ON_CLOSE; + base::win::ScopedHandle old_log_file( + base::CreatePlatformFile(log_file, file_flags, NULL, NULL)); + + if (old_log_file.IsValid()) { + result = LOGFILE_DELETED; + FilePath tmp_log(log_file.value() + FILE_PATH_LITERAL(".tmp")); + // Note that file_util::Move will attempt to replace existing files. + if (file_util::Move(log_file, tmp_log)) { + int64 offset = log_size - kTruncatedInstallerLogFileSize; + std::string old_log_data(kTruncatedInstallerLogFileSize, 0); + int bytes_read = base::ReadPlatformFile(old_log_file, + offset, + &old_log_data[0], + kTruncatedInstallerLogFileSize); + if (bytes_read > 0 && + (bytes_read == file_util::WriteFile(log_file, + &old_log_data[0], + bytes_read) || + file_util::PathExists(log_file))) { + result = LOGFILE_TRUNCATED; + } + } + } else if (file_util::Delete(log_file, false)) { + // Couldn't get sufficient access to the log file, optimistically try to + // delete it. + result = LOGFILE_DELETED; + } + } + + return result; +} + + void InitInstallerLogging(const installer::MasterPreferences& prefs) { if (installer_logging_) return; + installer_logging_ = true; + bool value = false; if (prefs.GetBool(installer::master_preferences::kDisableLogging, &value) && value) { - installer_logging_ = true; return; } + FilePath log_file_path(GetLogFilePath(prefs)); + TruncateLogFileIfNeeded(log_file_path); + logging::InitLogging( - GetLogFilePath(prefs).value().c_str(), + log_file_path.value().c_str(), logging::LOG_ONLY_TO_FILE, logging::LOCK_LOG_FILE, - logging::DELETE_OLD_LOG_FILE, + logging::APPEND_TO_OLD_LOG_FILE, logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS); if (prefs.GetBool(installer::master_preferences::kVerboseLogging, @@ -54,8 +105,6 @@ void InitInstallerLogging(const installer::MasterPreferences& prefs) { // Enable ETW logging. logging::LogEventProvider::Initialize(kSetupTraceProvider); - - installer_logging_ = true; } void EndInstallerLogging() { diff --git a/chrome/installer/util/logging_installer.h b/chrome/installer/util/logging_installer.h index d8c14c2..706b553 100644 --- a/chrome/installer/util/logging_installer.h +++ b/chrome/installer/util/logging_installer.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,6 +6,8 @@ #define CHROME_INSTALLER_UTIL_LOGGING_INSTALLER_H_ #pragma once +#include "base/basictypes.h" + namespace installer { class MasterPreferences; } @@ -14,6 +16,34 @@ class FilePath; namespace installer { +// Verbose installer runs clock in at around 50K, non-verbose much less than +// that. Some installer operations span multiple setup.exe runs, so we try +// to keep enough for at least 10 runs or so at any given time. +const int kMaxInstallerLogFileSize = 1024 * 1024; + +// Truncate the file down to half of the max, such that we don't incur +// truncation on every update. +const int kTruncatedInstallerLogFileSize = kMaxInstallerLogFileSize / 2; + +COMPILE_ASSERT(kTruncatedInstallerLogFileSize < kMaxInstallerLogFileSize, + kTruncatedInstallerLogFileSize_not_lt_kMaxInstallerLogFileSize); + +enum TruncateResult { + LOGFILE_UNTOUCHED, + LOGFILE_TRUNCATED, + LOGFILE_DELETED, +}; + +// Cuts off the _beginning_ of the file at |log_file| down to +// kTruncatedInstallerLogFileSize if it exceeds kMaxInstallerLogFileSize bytes. +// +// If the file is not changed, returns LOGFILE_UNTOUCHED. +// If the file is successfully truncated, returns LOGFILE_TRUNCATED. +// If the file needed truncation, but the truncation failed, the file will be +// deleted and the function returns LOGFILE_DELETED. This is done to prevent +// run-away log files and guard against full disks. +TruncateResult TruncateLogFileIfNeeded(const FilePath& log_file); + // Call to initialize logging for Chrome installer. void InitInstallerLogging(const installer::MasterPreferences& prefs); diff --git a/chrome/installer/util/logging_installer_unittest.cc b/chrome/installer/util/logging_installer_unittest.cc new file mode 100644 index 0000000..e77b046 --- /dev/null +++ b/chrome/installer/util/logging_installer_unittest.cc @@ -0,0 +1,118 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <string> + +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/platform_file.h" +#include "base/scoped_temp_dir.h" +#include "base/win/scoped_handle.h" +#include "chrome/installer/util/logging_installer.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(LoggingInstallerTest, TestTruncate) { + const std::string test_data(installer::kMaxInstallerLogFileSize + 1, 'a'); + + ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + + FilePath temp_file = temp_dir.path().Append(L"temp"); + EXPECT_EQ(test_data.size(), + file_util::WriteFile(temp_file, &test_data[0], test_data.size())); + ASSERT_TRUE(file_util::PathExists(temp_file)); + + int64 file_size = 0; + EXPECT_TRUE(file_util::GetFileSize(temp_file, &file_size)); + EXPECT_EQ(test_data.size(), file_size); + + EXPECT_EQ(installer::LOGFILE_TRUNCATED, + installer::TruncateLogFileIfNeeded(temp_file)); + + EXPECT_TRUE(file_util::GetFileSize(temp_file, &file_size)); + EXPECT_EQ(installer::kTruncatedInstallerLogFileSize , file_size); + + // Check that the temporary file was deleted. + EXPECT_FALSE(file_util::PathExists(temp_file.Append(L".tmp"))); +} + +TEST(LoggingInstallerTest, TestTruncationNotNeeded) { + const std::string test_data(installer::kMaxInstallerLogFileSize, 'a'); + + ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + + FilePath temp_file = temp_dir.path().Append(L"temp"); + EXPECT_EQ(test_data.size(), + file_util::WriteFile(temp_file, &test_data[0], test_data.size())); + ASSERT_TRUE(file_util::PathExists(temp_file)); + + int64 file_size = 0; + EXPECT_TRUE(file_util::GetFileSize(temp_file, &file_size)); + EXPECT_EQ(test_data.size(), file_size); + + EXPECT_EQ(installer::LOGFILE_UNTOUCHED, + installer::TruncateLogFileIfNeeded(temp_file)); + EXPECT_TRUE(file_util::PathExists(temp_file)); + EXPECT_TRUE(file_util::GetFileSize(temp_file, &file_size)); + EXPECT_EQ(test_data.size(), file_size); +} + +TEST(LoggingInstallerTest, TestInUseNeedsTruncation) { + const std::string test_data(installer::kMaxInstallerLogFileSize + 1, 'a'); + + ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + + FilePath temp_file = temp_dir.path().Append(L"temp"); + EXPECT_EQ(test_data.size(), + file_util::WriteFile(temp_file, &test_data[0], test_data.size())); + ASSERT_TRUE(file_util::PathExists(temp_file)); + int64 file_size = 0; + EXPECT_TRUE(file_util::GetFileSize(temp_file, &file_size)); + EXPECT_EQ(test_data.size(), file_size); + + // Prevent the log file from being moved or deleted. + const int file_flags = base::PLATFORM_FILE_OPEN | + base::PLATFORM_FILE_READ | + base::PLATFORM_FILE_EXCLUSIVE_READ; + base::win::ScopedHandle temp_platform_file( + base::CreatePlatformFile(temp_file, file_flags, NULL, NULL)); + ASSERT_TRUE(temp_platform_file.IsValid()); + + EXPECT_EQ(installer::LOGFILE_UNTOUCHED, + installer::TruncateLogFileIfNeeded(temp_file)); + EXPECT_TRUE(file_util::PathExists(temp_file)); + EXPECT_TRUE(file_util::GetFileSize(temp_file, &file_size)); + EXPECT_EQ(test_data.size(), file_size); +} + +TEST(LoggingInstallerTest, TestMoveFailsNeedsTruncation) { + const std::string test_data(installer::kMaxInstallerLogFileSize + 1, 'a'); + + ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + + FilePath temp_file = temp_dir.path().Append(L"temp"); + EXPECT_EQ(test_data.size(), + file_util::WriteFile(temp_file, &test_data[0], test_data.size())); + ASSERT_TRUE(file_util::PathExists(temp_file)); + int64 file_size = 0; + EXPECT_TRUE(file_util::GetFileSize(temp_file, &file_size)); + EXPECT_EQ(test_data.size(), file_size); + + // Create an inconvenient, non-deletable file in the location that + // TruncateLogFileIfNeeded would like to move the log file to. + const int file_flags = base::PLATFORM_FILE_CREATE | + base::PLATFORM_FILE_READ | + base::PLATFORM_FILE_EXCLUSIVE_READ; + FilePath temp_file_move_dest(temp_file.value() + FILE_PATH_LITERAL(".tmp")); + base::win::ScopedHandle temp_move_destination_file( + base::CreatePlatformFile(temp_file_move_dest, file_flags, NULL, NULL)); + ASSERT_TRUE(temp_move_destination_file.IsValid()); + + EXPECT_EQ(installer::LOGFILE_DELETED, + installer::TruncateLogFileIfNeeded(temp_file)); + EXPECT_FALSE(file_util::PathExists(temp_file)); +} |