summaryrefslogtreecommitdiffstats
path: root/chrome/installer
diff options
context:
space:
mode:
authorrobertshield@chromium.org <robertshield@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-20 21:00:45 +0000
committerrobertshield@chromium.org <robertshield@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-20 21:00:45 +0000
commit1f9e089f4335ae5487a884eba25efbdee5dc076d (patch)
tree4a09df86e95c079b9e393730030ff6fe2fa7322c /chrome/installer
parent1a6fff54665ded8a4be408f112938ad0328556dc (diff)
downloadchromium_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.cc61
-rw-r--r--chrome/installer/util/logging_installer.h32
-rw-r--r--chrome/installer/util/logging_installer_unittest.cc118
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));
+}