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

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: For landing 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
« no previous file with comments | « client/settings.h ('k') | client/settings_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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),
50 initialized_() {
51 }
52
53 Settings::~Settings() {
54 }
55
56 bool Settings::Initialize() {
57 INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
58
59 ScopedFileHandle handle(HANDLE_EINTR(
60 open(file_path(),
61 O_CREAT | O_EXCL | O_WRONLY | O_EXLOCK,
62 0644)));
63
64 // The file was created, so this is a new database that needs to be
65 // initialized with a client ID.
66 if (handle.is_valid()) {
67 bool initialized = InitializeSettings(handle.get());
68 if (initialized)
69 INITIALIZATION_STATE_SET_VALID(initialized_);
70 return initialized;
71 }
72
73 // The file wasn't created, try opening it for a write operation. If the file
74 // needs to be recovered, writing is necessary. This also ensures that the
75 // process has permission to write the file.
76 Data settings;
77 if (!OpenForWritingAndReadSettings(&settings).is_valid())
78 return false;
79
80 INITIALIZATION_STATE_SET_VALID(initialized_);
81 return true;
82 }
83
84 bool Settings::GetClientID(UUID* client_id) {
85 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
86
87 Data settings;
88 if (!OpenAndReadSettings(&settings))
89 return false;
90
91 *client_id = settings.client_id;
92 return true;
93 }
94
95 bool Settings::GetUploadsEnabled(bool* enabled) {
96 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
97
98 Data settings;
99 if (!OpenAndReadSettings(&settings))
100 return false;
101
102 *enabled = (settings.options & Data::Options::kUploadsEnabled) != 0;
103 return true;
104 }
105
106 bool Settings::SetUploadsEnabled(bool enabled) {
107 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
108
109 Data settings;
110 ScopedFileHandle handle = OpenForWritingAndReadSettings(&settings);
111 if (!handle.is_valid())
112 return false;
113
114 if (enabled)
115 settings.options |= Data::Options::kUploadsEnabled;
116 else
117 settings.options &= ~Data::Options::kUploadsEnabled;
118
119 return WriteSettings(handle.get(), settings);
120 }
121
122 bool Settings::GetLastUploadAttemptTime(time_t* time) {
123 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
124
125 Data settings;
126 if (!OpenAndReadSettings(&settings))
127 return false;
128
129 *time = InRangeCast<time_t>(settings.last_upload_attempt_time,
130 std::numeric_limits<time_t>::max());
131 return true;
132 }
133
134 bool Settings::SetLastUploadAttemptTime(time_t time) {
135 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
136
137 Data settings;
138 ScopedFileHandle handle = OpenForWritingAndReadSettings(&settings);
139 if (!handle.is_valid())
140 return false;
141
142 settings.last_upload_attempt_time = InRangeCast<uint64_t>(time, 0);
143
144 return WriteSettings(handle.get(), settings);
145 }
146
147 ScopedFileHandle Settings::OpenForReading() {
148 ScopedFileHandle handle(HANDLE_EINTR(open(file_path(), O_RDONLY | O_SHLOCK)));
149 PLOG_IF(ERROR, !handle.is_valid()) << "open for reading";
150 return handle.Pass();
151 }
152
153 ScopedFileHandle Settings::OpenForReadingAndWriting() {
154 ScopedFileHandle handle(HANDLE_EINTR(
155 open(file_path(), O_RDWR | O_EXLOCK | O_CREAT)));
156 PLOG_IF(ERROR, !handle.is_valid()) << "open for writing";
157 return handle.Pass();
158 }
159
160 bool Settings::OpenAndReadSettings(Data* out_data) {
161 ScopedFileHandle handle = OpenForReading();
162 if (!handle.is_valid())
163 return false;
164
165 if (ReadSettings(handle.get(), out_data))
166 return true;
167
168 // The settings file is corrupt, so reinitialize it.
169 handle.reset();
170
171 // The settings failed to be read, so re-initialize them.
172 return RecoverSettings(kInvalidFileHandle, out_data);
173 }
174
175 ScopedFileHandle Settings::OpenForWritingAndReadSettings(Data* out_data) {
176 ScopedFileHandle handle = OpenForReadingAndWriting();
177 if (!handle.is_valid())
178 return ScopedFileHandle();
179
180 if (!ReadSettings(handle.get(), out_data)) {
181 if (!RecoverSettings(handle.get(), out_data))
182 return ScopedFileHandle();
183 }
184
185 return handle.Pass();
186 }
187
188 bool Settings::ReadSettings(FileHandle handle, Data* out_data) {
189 if (LoggingSeekFile(handle, 0, SEEK_SET) != 0)
190 return false;
191
192 if (!LoggingReadFile(handle, out_data, sizeof(*out_data)))
193 return false;
194
195 if (out_data->version != Data::kSettingsVersion) {
196 LOG(ERROR) << "Settings version is not " << Data::kSettingsVersion;
197 return false;
198 }
199
200 return true;
201 }
202
203 bool Settings::WriteSettings(FileHandle handle, const Data& data) {
204 if (LoggingSeekFile(handle, 0, SEEK_SET) != 0)
205 return false;
206
207 if (HANDLE_EINTR(ftruncate(handle, 0)) != 0) {
208 PLOG(ERROR) << "ftruncate settings file";
209 return false;
210 }
211
212 return LoggingWriteFile(handle, &data, sizeof(Data));
213 }
214
215 bool Settings::RecoverSettings(FileHandle handle, Data* out_data) {
216 ScopedFileHandle scoped_handle;
217 if (handle == kInvalidFileHandle) {
218 scoped_handle.reset(OpenForReadingAndWriting().release());
219 handle = scoped_handle.get();
220
221 // Test if the file has already been recovered now that the exclusive lock
222 // is held.
223 if (ReadSettings(handle, out_data))
224 return true;
225 }
226
227 LOG(INFO) << "Recovering settings file " << file_path();
228
229 if (handle == kInvalidFileHandle) {
230 LOG(ERROR) << "Invalid file handle";
231 return false;
232 }
233
234 if (!InitializeSettings(handle))
235 return false;
236
237 return ReadSettings(handle, out_data);
238 }
239
240 bool Settings::InitializeSettings(FileHandle handle) {
241 uuid_t uuid;
242 uuid_generate(uuid);
243
244 Data settings;
245 settings.client_id.InitializeFromBytes(uuid);
246
247 return WriteSettings(handle, settings);
248 }
249
250 } // namespace crashpad
OLDNEW
« no previous file with comments | « client/settings.h ('k') | client/settings_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698