OLD | NEW |
---|---|
(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 #import "client/settings_mac.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 #include "base/strings/sys_string_conversions.h" | |
24 #include "util/misc/uuid.h" | |
25 | |
26 namespace crashpad { | |
27 namespace internal { | |
28 | |
29 namespace { | |
30 | |
31 NSString* const kClientID = @"ClientID"; | |
32 NSString* const kUploadsEnabled = @"UploadsEnabled"; | |
33 NSString* const kLastUploadAttemptTime = @"LastUploadAttemptTime"; | |
34 | |
35 } // namespace | |
36 | |
37 SettingsMac::SettingsMac(const base::FilePath& prefs_file) | |
38 : prefs_file_(prefs_file) { | |
39 } | |
40 | |
41 SettingsMac::~SettingsMac() { | |
42 } | |
43 | |
44 bool SettingsMac::Initialize() { | |
45 ScopedFileHandle fd(HANDLE_EINTR( | |
46 open(prefs_file(), | |
47 O_CREAT|O_EXCL|O_EXLOCK|O_WRONLY, | |
Mark Mentovai
2015/03/08 05:21:56
Spaces around the |s, everywhere you use bitwise O
Robert Sesek
2015/03/08 22:15:36
Done.
| |
48 0644))); | |
49 | |
50 // The file was created, so this is a new database that needs to be | |
51 // initialized with a client ID. | |
52 if (fd.is_valid()) { | |
53 uuid_t client_id; | |
54 uuid_generate(client_id); | |
55 | |
56 std::string client_id_string(UUID(client_id).ToString()); | |
57 | |
58 NSDictionary* plist = | |
59 @{ kClientID : base::SysUTF8ToNSString(client_id_string) }; | |
60 | |
61 return WritePlist(fd.get(), plist); | |
62 } | |
63 | |
64 // The file wasn't opened successfully, try opening it without creating. | |
65 fd.reset(HANDLE_EINTR(open(prefs_file(), O_RDONLY|O_SHLOCK))); | |
66 PLOG_IF(ERROR, !fd.is_valid()) << "open " << prefs_file(); | |
67 return fd.is_valid(); | |
68 } | |
69 | |
70 bool SettingsMac::GetClientID(std::string* client_id) { | |
Mark Mentovai
2015/03/08 05:21:56
These are going to be called from weird places tha
Robert Sesek
2015/03/08 22:15:36
Done. I didn't know the context of when these woul
| |
71 base::scoped_nsobject<id> value = GetSetting(kClientID); | |
72 if (!value) | |
Mark Mentovai
2015/03/08 05:21:56
If the plist couldn’t be read at any point, we sho
Robert Sesek
2015/03/08 22:15:36
Done.
Mark Mentovai
2015/03/09 14:01:23
Robert Sesek wrote:
| |
73 return false; | |
74 | |
75 if (![value isKindOfClass:[NSString class]]) { | |
Mark Mentovai
2015/03/08 05:21:56
Why not ObjCCast?
Robert Sesek
2015/03/08 22:15:36
I didn't see any advantage to using that because I
| |
76 LOG(ERROR) << [kClientID UTF8String] << " is not a NSString"; | |
77 return false; | |
78 } | |
79 | |
80 *client_id = base::SysNSStringToUTF8(value); | |
81 return true; | |
82 } | |
83 | |
84 bool SettingsMac::GetUploadsEnabled(bool* enabled) { | |
85 base::scoped_nsobject<id> value = GetSetting(kUploadsEnabled); | |
86 if (!value) | |
87 return false; | |
88 | |
89 if (![value isKindOfClass:[NSValue class]]) { | |
90 LOG(ERROR) << [kUploadsEnabled UTF8String] << " is not a NSValue"; | |
91 return false; | |
92 } | |
93 | |
94 *enabled = [value boolValue]; | |
95 return true; | |
Mark Mentovai
2015/03/08 05:21:56
With this implementation, a fresh database will re
Robert Sesek
2015/03/08 22:15:36
Done.
| |
96 } | |
97 | |
98 bool SettingsMac::SetUploadsEnabled(bool enabled) { | |
99 return SetSetting(kUploadsEnabled, [NSNumber numberWithBool:enabled]); | |
100 } | |
101 | |
102 bool SettingsMac::GetLastUploadAttemptTime(time_t* time) { | |
103 base::scoped_nsobject<id> value = GetSetting(kLastUploadAttemptTime); | |
104 if (!value) | |
105 return false; | |
106 | |
107 if (![value isKindOfClass:[NSValue class]]) { | |
108 LOG(ERROR) << [kLastUploadAttemptTime UTF8String] << " is not a NSValue"; | |
109 return false; | |
110 } | |
111 | |
112 *time = [value doubleValue]; | |
113 return true; | |
114 } | |
115 | |
116 bool SettingsMac::SetLastUploadAttemptTime(time_t time) { | |
117 return SetSetting(kLastUploadAttemptTime, [NSNumber numberWithDouble:time]); | |
118 } | |
119 | |
120 base::scoped_nsobject<NSMutableDictionary> SettingsMac::ReadPlist( | |
121 FileHandle fd) { | |
122 base::scoped_nsobject<NSMutableDictionary> plist; | |
123 | |
124 base::scoped_nsobject<NSFileHandle> file_handle( | |
125 [[NSFileHandle alloc] initWithFileDescriptor:fd closeOnDealloc:NO]); | |
126 NSData* data = nil; | |
127 @try { | |
128 data = [file_handle readDataToEndOfFile]; | |
129 } @catch (NSException* exception) { | |
130 LOG(ERROR) << "Failed to read settings: " << [exception description]; | |
131 return plist; | |
132 } | |
133 if (!data) | |
134 return plist; | |
135 | |
136 NSError* error = nil; | |
137 NSPropertyListMutabilityOptions options = NSPropertyListMutableContainers; | |
138 plist.reset( | |
139 [[NSPropertyListSerialization propertyListWithData:data | |
140 options:options | |
141 format:nullptr | |
142 error:&error] retain]); | |
143 LOG_IF(ERROR, error != nil) << "Failed to deserialize settings: " | |
144 << [error description]; | |
145 return plist; | |
146 } | |
147 | |
148 bool SettingsMac::WritePlist(FileHandle fd, NSDictionary* plist) { | |
149 NSError* error = nil; | |
150 NSPropertyListFormat format = NSPropertyListXMLFormat_v1_0; | |
Mark Mentovai
2015/03/08 05:21:56
Not the faster binary format?
Robert Sesek
2015/03/08 22:15:36
Done. The Foundation guides don't actually provide
| |
151 NSData* data = [NSPropertyListSerialization dataWithPropertyList:plist | |
152 format:format | |
153 options:0 | |
154 error:&error]; | |
155 LOG_IF(ERROR, error != nil) << "Failed to serialize settings: " | |
156 << [error description]; | |
157 if (!data) | |
158 return false; | |
159 | |
160 if (HANDLE_EINTR(ftruncate(fd, 0)) != 0) { | |
161 PLOG(ERROR) << "ftruncate failed on settings file"; | |
162 return false; | |
163 } | |
164 | |
165 if (LoggingSeekFile(fd, 0, SEEK_SET) != 0) { | |
166 return false; | |
167 } | |
168 | |
169 base::scoped_nsobject<NSFileHandle> file_handle( | |
170 [[NSFileHandle alloc] initWithFileDescriptor:fd closeOnDealloc:NO]); | |
171 @try { | |
172 [file_handle writeData:data]; | |
173 } @catch (NSException* exception) { | |
174 LOG(ERROR) << "Failed to write settings: " << [exception description]; | |
175 return false; | |
176 } | |
177 | |
178 return true; | |
179 } | |
180 | |
181 base::scoped_nsobject<id> SettingsMac::GetSetting(NSString* key) { | |
182 base::scoped_nsobject<id> value; | |
Mark Mentovai
2015/03/08 05:21:56
You don’t need to declare this ’til much later, if
Robert Sesek
2015/03/08 22:15:36
I dislike having to read and write such a verbose
| |
183 | |
184 ScopedFileHandle fd(HANDLE_EINTR(open(prefs_file(), O_RDONLY|O_SHLOCK))); | |
185 if (!fd.is_valid()) { | |
186 PLOG(ERROR) << "open for get setting"; | |
187 return value; | |
188 } | |
189 | |
190 base::scoped_nsobject<NSMutableDictionary> plist(ReadPlist(fd.get())); | |
191 if (!plist.get()) | |
192 return value; | |
193 | |
194 value.reset([[plist objectForKey:key] retain]); | |
195 return value; | |
196 } | |
197 | |
198 bool SettingsMac::SetSetting(NSString* key, NSObject* value) { | |
199 base::scoped_nsobject<NSMutableDictionary> plist; | |
200 | |
201 ScopedFileHandle fd(HANDLE_EINTR(open(prefs_file(), O_RDWR|O_EXLOCK))); | |
202 if (!fd.is_valid()) { | |
203 LOG(ERROR) << "open for set setting"; | |
Mark Mentovai
2015/03/08 05:21:56
PLOG
Robert Sesek
2015/03/08 22:15:36
Done.
| |
204 return plist; | |
205 } | |
206 | |
207 plist = ReadPlist(fd.get()); | |
208 if (!plist.get()) | |
209 return false; | |
210 | |
211 [plist setObject:value forKey:key]; | |
212 | |
213 return WritePlist(fd.get(), plist); | |
214 } | |
215 | |
216 } // namespace internal | |
217 } // namespace crashpad | |
OLD | NEW |