Chromium Code Reviews| 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 |