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

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: Address comments 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 <fcntl.h>
18 #include <unistd.h>
19 #include <uuid/uuid.h>
20
21 #include "base/logging.h"
22 #include "base/posix/eintr_wrapper.h"
23
24 namespace crashpad {
25
26 struct ALIGNAS(4) Settings::Data {
Mark Mentovai 2015/03/09 22:00:57 #include "base/compiler_specific.h"
27 static const uint16_t kSettingsVersion = 1;
28
29 Data() : version(kSettingsVersion),
30 options(),
Mark Mentovai 2015/03/09 22:00:57 Explicit 0 for uint32_t.
31 last_upload_attempt_time(0),
32 client_id() {}
33
34 enum Options : uint32_t {
35 kUploadsEnabled = 1 << 1,
Mark Mentovai 2015/03/09 22:00:58 1 << 0
36 };
37
38 uint32_t version;
39 uint32_t options;
40 uint64_t last_upload_attempt_time;
Mark Mentovai 2015/03/09 22:00:58 // time_t
41 UUID client_id;
42 };
43
44 Settings::Settings(const base::FilePath& file_path)
45 : file_path_(file_path) {
46 }
47
48 Settings::~Settings() {
49 }
50
51 bool Settings::Initialize() {
52 ScopedFileHandle handle(HANDLE_EINTR(
53 open(file_path(),
54 O_CREAT | O_EXCL | O_WRONLY | O_EXLOCK,
55 0644)));
56
57 // The file was created, so this is a new database that needs to be
58 // initialized with a client ID.
59 if (handle.is_valid()) {
60 return InitializeSettings(handle.get());
61 }
62
63 // The file wasn't created, try opening it for a write operation. If the file
64 // needs to be recovered, writing is necessary. This also ensures that the
65 // file has write permissions.
Mark Mentovai 2015/03/09 22:00:58 process has permission to write the file.
66 handle.reset(OpenForReadingAndWriting().release());
67 if (!handle.is_valid()) {
68 return false;
69 }
70
71 // Ensure that the file is valid. If it fails to read, re-initialize the
72 // settings.
73 Data settings;
74 if (!ReadSettings(handle.get(), &settings)) {
75 return RecoverSettings(handle.get(), &settings);
76 }
77
78 return true;
79 }
80
81 bool Settings::GetClientID(UUID* client_id) {
82 Data settings;
83 if (!OpenAndReadSettings(&settings)) {
84 return false;
85 }
86
87 *client_id = settings.client_id;
88 return true;
89 }
90
91 bool Settings::GetUploadsEnabled(bool* enabled) {
92 Data settings;
93 if (!OpenAndReadSettings(&settings)) {
94 return false;
95 }
96
97 *enabled = (settings.options & Data::Options::kUploadsEnabled) != 0;
98 return true;
99 }
100
101 bool Settings::SetUploadsEnabled(bool enabled) {
102 Data settings;
103 ScopedFileHandle handle = OpenForWritingAndReadSettings(&settings);
104 if (!handle.is_valid())
105 return false;
106
107 if (enabled)
108 settings.options |= Data::Options::kUploadsEnabled;
109 else
110 settings.options &= ~Data::Options::kUploadsEnabled;
111
112 return WriteSettings(handle.get(), settings);
113 }
114
115 bool Settings::GetLastUploadAttemptTime(time_t* time) {
116 Data settings;
117 if (!OpenAndReadSettings(&settings))
118 return false;
119
120 *time = settings.last_upload_attempt_time;
Mark Mentovai 2015/03/09 22:00:57 saturated_cast<time_t>()… Perhaps with a LOG(WARNI
121 return true;
122 }
123
124 bool Settings::SetLastUploadAttemptTime(time_t time) {
125 Data settings;
126 ScopedFileHandle handle = OpenForWritingAndReadSettings(&settings);
127 if (!handle.is_valid())
128 return false;
129
130 settings.last_upload_attempt_time = time;
Mark Mentovai 2015/03/09 22:00:57 satured_cast<uint64_t>(), again perhaps with a war
131
132 return WriteSettings(handle.get(), settings);
133 }
134
135 ScopedFileHandle Settings::OpenForReading() {
136 ScopedFileHandle handle(HANDLE_EINTR(open(file_path(), O_RDONLY | O_SHLOCK)));
137 PLOG_IF(ERROR, !handle.is_valid()) << "open for reading";
138 return handle.Pass();
139 }
140
141 ScopedFileHandle Settings::OpenForReadingAndWriting() {
142 ScopedFileHandle handle(HANDLE_EINTR(
143 open(file_path(), O_RDWR | O_EXLOCK | O_CREAT)));
144 PLOG_IF(ERROR, !handle.is_valid()) << "open for writing";
145 return handle.Pass();
146 }
147
148 bool Settings::OpenAndReadSettings(Data* out_data) {
149 ScopedFileHandle handle = OpenForReading();
150 if (!handle.is_valid())
151 return false;
152
153 if (ReadSettings(handle.get(), out_data))
154 return true;
155
156 // The settings file is corrupt, so reinitialize it.
157 handle.reset();
158
159 // The settings failed to be read, so re-initialize them.
160 return RecoverSettings(kInvalidFileHandle, out_data);
161 }
162
163 ScopedFileHandle Settings::OpenForWritingAndReadSettings(Data* out_data) {
164 ScopedFileHandle handle = OpenForReadingAndWriting();
165 if (!handle.is_valid())
166 return ScopedFileHandle();
167
168 if (!ReadSettings(handle.get(), out_data)) {
169 if (!RecoverSettings(handle.get(), out_data))
170 return ScopedFileHandle();
171 }
172
173 return handle.Pass();
174 }
175
176 bool Settings::ReadSettings(FileHandle handle, Data* out_data) {
177 if (LoggingSeekFile(handle, 0, SEEK_SET) != 0)
178 return false;
179
180 if (!LoggingReadFile(handle, out_data, sizeof(*out_data)))
181 return false;
182
183 if (out_data->version != Data::kSettingsVersion) {
184 LOG(ERROR) << "Settings version is not " << Data::kSettingsVersion;
185 return false;
186 }
187
188 return true;
189 }
190
191 bool Settings::WriteSettings(FileHandle handle, const Data& data) {
192 if (LoggingSeekFile(handle, 0, SEEK_SET) != 0)
193 return false;
194
195 if (HANDLE_EINTR(ftruncate(handle, 0)) != 0) {
196 PLOG(ERROR) << "ftruncate settings file";
197 return false;
198 }
199
200 return LoggingWriteFile(handle, &data, sizeof(Data));
201 }
202
203 bool Settings::RecoverSettings(FileHandle handle, Data* out_data) {
204 LOG(INFO) << "Recovering settings file " << file_path();
Mark Mentovai 2015/03/09 22:00:57 Move this to after the next conditional, since thi
205
206 ScopedFileHandle scoped_handle;
207 if (handle == kInvalidFileHandle) {
208 scoped_handle.reset(OpenForReadingAndWriting().release());
209 handle = scoped_handle.get();
210
211 // Test if the file has already been recovered.
Mark Mentovai 2015/03/09 22:00:57 The critical thing here is that the test happens u
212 if (ReadSettings(handle, out_data))
213 return true;
214 }
215
216 if (handle == kInvalidFileHandle) {
217 LOG(ERROR) << "Invalid file handle";
218 return false;
219 }
220
221 if (!InitializeSettings(handle))
222 return false;
223
224 return ReadSettings(handle, out_data);
225 }
226
227 bool Settings::InitializeSettings(FileHandle handle) {
228 uuid_t uuid;
229 uuid_generate(uuid);
230
231 Data settings;
232 settings.client_id.InitializeFromBytes(uuid);
233
234 return WriteSettings(handle, settings);
235 }
236
237 } // namespace crashpad
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698