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

Side by Side Diff: client/settings.cc

Issue 988063003: Define the Settings interface for a CrashReportDatabase and provide a Mac implementation. (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: INITIALIZATION_STATE_DCHECK Created 5 years, 9 months 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "client/settings.h"
16
17 #include <limits>
18
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <uuid/uuid.h>
22
23 #include "base/compiler_specific.h"
24 #include "base/logging.h"
25 #include "base/posix/eintr_wrapper.h"
26 #include "util/numeric/in_range_cast.h"
27
28 namespace crashpad {
29
30 struct ALIGNAS(4) Settings::Data {
31 static const uint16_t kSettingsVersion = 1;
32
33 Data() : version(kSettingsVersion),
34 options(0),
35 last_upload_attempt_time(0),
36 client_id() {}
37
38 enum Options : uint32_t {
39 kUploadsEnabled = 1 << 0,
40 };
41
42 uint32_t version;
43 uint32_t options;
44 uint64_t last_upload_attempt_time; // time_t
45 UUID client_id;
46 };
47
48 Settings::Settings(const base::FilePath& file_path)
49 : file_path_(file_path) {
Mark Mentovai 2015/03/09 22:41:34 , initialized_()
Robert Sesek 2015/03/09 22:44:39 Done.
50 }
51
52 Settings::~Settings() {
53 }
54
55 bool Settings::Initialize() {
56 INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
57
58 ScopedFileHandle handle(HANDLE_EINTR(
59 open(file_path(),
60 O_CREAT | O_EXCL | O_WRONLY | O_EXLOCK,
61 0644)));
62
63 // The file was created, so this is a new database that needs to be
64 // initialized with a client ID.
65 if (handle.is_valid()) {
66 bool initialized = InitializeSettings(handle.get());
67 if (initialized)
68 INITIALIZATION_STATE_SET_VALID(initialized_);
69 return initialized;
70 }
71
72 // The file wasn't created, try opening it for a write operation. If the file
73 // needs to be recovered, writing is necessary. This also ensures that the
74 // process has permission to write the file.
75 Data settings;
76 if (!OpenForWritingAndReadSettings(&settings).is_valid())
77 return false;
78
79 INITIALIZATION_STATE_SET_VALID(initialized_);
80 return true;
81 }
82
83 bool Settings::GetClientID(UUID* client_id) {
84 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
85
86 Data settings;
87 if (!OpenAndReadSettings(&settings))
88 return false;
89
90 *client_id = settings.client_id;
91 return true;
92 }
93
94 bool Settings::GetUploadsEnabled(bool* enabled) {
95 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
96
97 Data settings;
98 if (!OpenAndReadSettings(&settings))
99 return false;
100
101 *enabled = (settings.options & Data::Options::kUploadsEnabled) != 0;
102 return true;
103 }
104
105 bool Settings::SetUploadsEnabled(bool enabled) {
106 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
107
108 Data settings;
109 ScopedFileHandle handle = OpenForWritingAndReadSettings(&settings);
110 if (!handle.is_valid())
111 return false;
112
113 if (enabled)
114 settings.options |= Data::Options::kUploadsEnabled;
115 else
116 settings.options &= ~Data::Options::kUploadsEnabled;
117
118 return WriteSettings(handle.get(), settings);
119 }
120
121 bool Settings::GetLastUploadAttemptTime(time_t* time) {
122 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
123
124 Data settings;
125 if (!OpenAndReadSettings(&settings))
126 return false;
127
128 *time = InRangeCast<time_t>(settings.last_upload_attempt_time,
129 std::numeric_limits<time_t>::max());
130 return true;
131 }
132
133 bool Settings::SetLastUploadAttemptTime(time_t time) {
134 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
135
136 Data settings;
137 ScopedFileHandle handle = OpenForWritingAndReadSettings(&settings);
138 if (!handle.is_valid())
139 return false;
140
141 settings.last_upload_attempt_time = InRangeCast<uint64_t>(time, 0);
142
143 return WriteSettings(handle.get(), settings);
144 }
145
146 ScopedFileHandle Settings::OpenForReading() {
147 ScopedFileHandle handle(HANDLE_EINTR(open(file_path(), O_RDONLY | O_SHLOCK)));
148 PLOG_IF(ERROR, !handle.is_valid()) << "open for reading";
149 return handle.Pass();
150 }
151
152 ScopedFileHandle Settings::OpenForReadingAndWriting() {
153 ScopedFileHandle handle(HANDLE_EINTR(
154 open(file_path(), O_RDWR | O_EXLOCK | O_CREAT)));
155 PLOG_IF(ERROR, !handle.is_valid()) << "open for writing";
156 return handle.Pass();
157 }
158
159 bool Settings::OpenAndReadSettings(Data* out_data) {
160 ScopedFileHandle handle = OpenForReading();
161 if (!handle.is_valid())
162 return false;
163
164 if (ReadSettings(handle.get(), out_data))
165 return true;
166
167 // The settings file is corrupt, so reinitialize it.
168 handle.reset();
169
170 // The settings failed to be read, so re-initialize them.
171 return RecoverSettings(kInvalidFileHandle, out_data);
172 }
173
174 ScopedFileHandle Settings::OpenForWritingAndReadSettings(Data* out_data) {
175 ScopedFileHandle handle = OpenForReadingAndWriting();
176 if (!handle.is_valid())
177 return ScopedFileHandle();
178
179 if (!ReadSettings(handle.get(), out_data)) {
180 if (!RecoverSettings(handle.get(), out_data))
181 return ScopedFileHandle();
182 }
183
184 return handle.Pass();
185 }
186
187 bool Settings::ReadSettings(FileHandle handle, Data* out_data) {
188 if (LoggingSeekFile(handle, 0, SEEK_SET) != 0)
189 return false;
190
191 if (!LoggingReadFile(handle, out_data, sizeof(*out_data)))
192 return false;
193
194 if (out_data->version != Data::kSettingsVersion) {
195 LOG(ERROR) << "Settings version is not " << Data::kSettingsVersion;
196 return false;
197 }
198
199 return true;
200 }
201
202 bool Settings::WriteSettings(FileHandle handle, const Data& data) {
203 if (LoggingSeekFile(handle, 0, SEEK_SET) != 0)
204 return false;
205
206 if (HANDLE_EINTR(ftruncate(handle, 0)) != 0) {
207 PLOG(ERROR) << "ftruncate settings file";
208 return false;
209 }
210
211 return LoggingWriteFile(handle, &data, sizeof(Data));
212 }
213
214 bool Settings::RecoverSettings(FileHandle handle, Data* out_data) {
215 ScopedFileHandle scoped_handle;
216 if (handle == kInvalidFileHandle) {
217 scoped_handle.reset(OpenForReadingAndWriting().release());
218 handle = scoped_handle.get();
219
220 // Test if the file has already been recovered now that the exclusive lock
221 // is held.
222 if (ReadSettings(handle, out_data))
223 return true;
224 }
225
226 LOG(INFO) << "Recovering settings file " << file_path();
227
228 if (handle == kInvalidFileHandle) {
229 LOG(ERROR) << "Invalid file handle";
230 return false;
231 }
232
233 if (!InitializeSettings(handle))
234 return false;
235
236 return ReadSettings(handle, out_data);
237 }
238
239 bool Settings::InitializeSettings(FileHandle handle) {
240 uuid_t uuid;
241 uuid_generate(uuid);
242
243 Data settings;
244 settings.client_id.InitializeFromBytes(uuid);
245
246 return WriteSettings(handle, settings);
247 }
248
249 } // namespace crashpad
OLDNEW
« no previous file with comments | « client/settings.h ('k') | client/settings_test.cc » ('j') | client/settings_test.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698