Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(463)

Unified Diff: third_party/crashpad/crashpad/client/settings.cc

Issue 1505213004: Copy Crashpad into the Chrome tree instead of importing it via DEPS (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address review comments, update README.chromium Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/crashpad/crashpad/client/settings.cc
diff --git a/third_party/crashpad/crashpad/client/settings.cc b/third_party/crashpad/crashpad/client/settings.cc
new file mode 100644
index 0000000000000000000000000000000000000000..e7ff2a90e7d3af274fba40dd5c1290e7870be84b
--- /dev/null
+++ b/third_party/crashpad/crashpad/client/settings.cc
@@ -0,0 +1,314 @@
+// Copyright 2015 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "client/settings.h"
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "util/stdlib/move.h"
+#include "util/numeric/in_range_cast.h"
+
+namespace crashpad {
+
+namespace internal {
+
+// static
+void ScopedLockedFileHandleTraits::Free(FileHandle handle) {
+ if (handle != kInvalidFileHandle) {
+ LoggingUnlockFile(handle);
+ CheckedCloseFile(handle);
+ }
+}
+
+} // namespace internal
+
+struct Settings::Data {
+ static const uint32_t kSettingsMagic = 'CPds';
+ static const uint32_t kSettingsVersion = 1;
+
+ enum Options : uint32_t {
+ kUploadsEnabled = 1 << 0,
+ };
+
+ Data() : magic(kSettingsMagic),
+ version(kSettingsVersion),
+ options(0),
+ padding_0(0),
+ last_upload_attempt_time(0),
+ client_id() {}
+
+ uint32_t magic;
+ uint32_t version;
+ uint32_t options;
+ uint32_t padding_0;
+ uint64_t last_upload_attempt_time; // time_t
+ UUID client_id;
+};
+
+Settings::Settings(const base::FilePath& file_path)
+ : file_path_(file_path),
+ initialized_() {
+}
+
+Settings::~Settings() {
+}
+
+bool Settings::Initialize() {
+ initialized_.set_invalid();
+
+ Data settings;
+ if (!OpenForWritingAndReadSettings(&settings).is_valid())
+ return false;
+
+ initialized_.set_valid();
+ return true;
+}
+
+bool Settings::GetClientID(UUID* client_id) {
+ DCHECK(initialized_.is_valid());
+
+ Data settings;
+ if (!OpenAndReadSettings(&settings))
+ return false;
+
+ *client_id = settings.client_id;
+ return true;
+}
+
+bool Settings::GetUploadsEnabled(bool* enabled) {
+ DCHECK(initialized_.is_valid());
+
+ Data settings;
+ if (!OpenAndReadSettings(&settings))
+ return false;
+
+ *enabled = (settings.options & Data::Options::kUploadsEnabled) != 0;
+ return true;
+}
+
+bool Settings::SetUploadsEnabled(bool enabled) {
+ DCHECK(initialized_.is_valid());
+
+ Data settings;
+ ScopedLockedFileHandle handle = OpenForWritingAndReadSettings(&settings);
+ if (!handle.is_valid())
+ return false;
+
+ if (enabled)
+ settings.options |= Data::Options::kUploadsEnabled;
+ else
+ settings.options &= ~Data::Options::kUploadsEnabled;
+
+ return WriteSettings(handle.get(), settings);
+}
+
+bool Settings::GetLastUploadAttemptTime(time_t* time) {
+ DCHECK(initialized_.is_valid());
+
+ Data settings;
+ if (!OpenAndReadSettings(&settings))
+ return false;
+
+ *time = InRangeCast<time_t>(settings.last_upload_attempt_time,
+ std::numeric_limits<time_t>::max());
+ return true;
+}
+
+bool Settings::SetLastUploadAttemptTime(time_t time) {
+ DCHECK(initialized_.is_valid());
+
+ Data settings;
+ ScopedLockedFileHandle handle = OpenForWritingAndReadSettings(&settings);
+ if (!handle.is_valid())
+ return false;
+
+ settings.last_upload_attempt_time = InRangeCast<uint64_t>(time, 0);
+
+ return WriteSettings(handle.get(), settings);
+}
+
+// static
+Settings::ScopedLockedFileHandle Settings::MakeScopedLockedFileHandle(
+ FileHandle file,
+ FileLocking locking) {
+ ScopedFileHandle scoped(file);
+ if (scoped.is_valid()) {
+ if (!LoggingLockFile(scoped.get(), locking))
+ scoped.reset();
+ }
+ return ScopedLockedFileHandle(scoped.release());
+}
+
+Settings::ScopedLockedFileHandle Settings::OpenForReading() {
+ return MakeScopedLockedFileHandle(LoggingOpenFileForRead(file_path()),
+ FileLocking::kShared);
+}
+
+Settings::ScopedLockedFileHandle Settings::OpenForReadingAndWriting(
+ FileWriteMode mode, bool log_open_error) {
+ DCHECK(mode != FileWriteMode::kTruncateOrCreate);
+
+ FileHandle handle;
+ if (log_open_error) {
+ handle = LoggingOpenFileForReadAndWrite(
+ file_path(), mode, FilePermissions::kWorldReadable);
+ } else {
+ handle = OpenFileForReadAndWrite(
+ file_path(), mode, FilePermissions::kWorldReadable);
+ }
+
+ return MakeScopedLockedFileHandle(handle, FileLocking::kExclusive);
+}
+
+bool Settings::OpenAndReadSettings(Data* out_data) {
+ ScopedLockedFileHandle handle = OpenForReading();
+ if (!handle.is_valid())
+ return false;
+
+ if (ReadSettings(handle.get(), out_data, true))
+ return true;
+
+ // The settings file is corrupt, so reinitialize it.
+ handle.reset();
+
+ // The settings failed to be read, so re-initialize them.
+ return RecoverSettings(kInvalidFileHandle, out_data);
+}
+
+Settings::ScopedLockedFileHandle Settings::OpenForWritingAndReadSettings(
+ Data* out_data) {
+ ScopedLockedFileHandle handle;
+ bool created = false;
+ if (!initialized_.is_valid()) {
+ // If this object is initializing, it hasn’t seen a settings file already,
+ // so go easy on errors. Creating a new settings file for the first time
+ // shouldn’t spew log messages.
+ //
+ // First, try to use an existing settings file.
+ handle = OpenForReadingAndWriting(FileWriteMode::kReuseOrFail, false);
+
+ if (!handle.is_valid()) {
+ // Create a new settings file if it didn’t already exist.
+ handle = OpenForReadingAndWriting(FileWriteMode::kCreateOrFail, false);
+
+ if (handle.is_valid()) {
+ created = true;
+ }
+
+ // There may have been a race to create the file, and something else may
+ // have won. There will be one more attempt to try to open or create the
+ // file below.
+ }
+ }
+
+ if (!handle.is_valid()) {
+ // Either the object is initialized, meaning it’s already seen a valid
+ // settings file, or the object is initializing and none of the above
+ // attempts to create the settings file succeeded. Either way, this is the
+ // last chance for success, so if this fails, log a message.
+ handle = OpenForReadingAndWriting(FileWriteMode::kReuseOrCreate, true);
+ }
+
+ if (!handle.is_valid())
+ return ScopedLockedFileHandle();
+
+ // Attempt reading the settings even if the file is known to have just been
+ // created. The file-create and file-lock operations don’t occur atomically,
+ // and something else may have written the settings before this invocation
+ // took the lock. If the settings file was definitely just created, though,
+ // don’t log any read errors. The expected non-race behavior in this case is a
+ // zero-length read, with ReadSettings() failing.
+ if (!ReadSettings(handle.get(), out_data, !created)) {
+ if (!RecoverSettings(handle.get(), out_data))
+ return ScopedLockedFileHandle();
+ }
+
+ return handle;
+}
+
+bool Settings::ReadSettings(FileHandle handle,
+ Data* out_data,
+ bool log_read_error) {
+ if (LoggingSeekFile(handle, 0, SEEK_SET) != 0)
+ return false;
+
+ bool read_result;
+ if (log_read_error) {
+ read_result = LoggingReadFile(handle, out_data, sizeof(*out_data));
+ } else {
+ read_result =
+ ReadFile(handle, out_data, sizeof(*out_data)) == sizeof(*out_data);
+ }
+
+ if (!read_result)
+ return false;
+
+ if (out_data->magic != Data::kSettingsMagic) {
+ LOG(ERROR) << "Settings magic is not " << Data::kSettingsMagic;
+ return false;
+ }
+
+ if (out_data->version != Data::kSettingsVersion) {
+ LOG(ERROR) << "Settings version is not " << Data::kSettingsVersion;
+ return false;
+ }
+
+ return true;
+}
+
+bool Settings::WriteSettings(FileHandle handle, const Data& data) {
+ if (LoggingSeekFile(handle, 0, SEEK_SET) != 0)
+ return false;
+
+ if (!LoggingTruncateFile(handle))
+ return false;
+
+ return LoggingWriteFile(handle, &data, sizeof(Data));
+}
+
+bool Settings::RecoverSettings(FileHandle handle, Data* out_data) {
+ ScopedLockedFileHandle scoped_handle;
+ if (handle == kInvalidFileHandle) {
+ scoped_handle =
+ OpenForReadingAndWriting(FileWriteMode::kReuseOrCreate, true);
+ handle = scoped_handle.get();
+
+ // Test if the file has already been recovered now that the exclusive lock
+ // is held.
+ if (ReadSettings(handle, out_data, true))
+ return true;
+ }
+
+ if (handle == kInvalidFileHandle) {
+ LOG(ERROR) << "Invalid file handle";
+ return false;
+ }
+
+ if (!InitializeSettings(handle))
+ return false;
+
+ return ReadSettings(handle, out_data, true);
+}
+
+bool Settings::InitializeSettings(FileHandle handle) {
+ Data settings;
+ if (!settings.client_id.InitializeWithNew())
+ return false;
+
+ return WriteSettings(handle, settings);
+}
+
+} // namespace crashpad

Powered by Google App Engine
This is Rietveld 408576698