1 | /*␊ |
2 | * property_list.cpp␊ |
3 | *␊ |
4 | * Created by Rekursor on 1/17/10.␊ |
5 | *␊ |
6 | */␊ |
7 | ␊ |
8 | #import "ChameleonPropertyList.h"␊ |
9 | #include "file_util.h"␊ |
10 | #include <string.h>␊ |
11 | #include <sys/stat.h>␊ |
12 | ␊ |
13 | ␊ |
14 | //--------------------------------------------------------------------------␊ |
15 | // Simple parsing and splitting args function, does handle env. vars ␊ |
16 | //--------------------------------------------------------------------------␊ |
17 | static void parseArgs(const char * args, const char* argv[], int argvlen)␊ |
18 | {␊ |
19 | ␉// Create a list of args fron the space delimited args parameters␊ |
20 | ␉int n=0;␊ |
21 | ␉if (args && *args) ␊ |
22 | ␉{␊ |
23 | ␉␉bool skipSpaces = true;␊ |
24 | ␉␉bool prevCharwasDelim =false;␊ |
25 | ␉␉char * buf = strdup(args);␊ |
26 | ␉␉char lastPriorityDelim=' ';␊ |
27 | ␉␉␊ |
28 | ␉␉// printf("Parsing <%s>\n", args);␊ |
29 | ␉␉␊ |
30 | ␉␉int k=0;␊ |
31 | ␉␉for (int i=0; i< strlen(args); i++)␊ |
32 | ␉␉{␊ |
33 | ␉␉␉switch (args[i]) ␊ |
34 | ␉␉␉{␊ |
35 | ␉␉␉␉case ' ': case '\t':␊ |
36 | ␉␉␉␉␉if(!skipSpaces) {␊ |
37 | ␉␉␉␉␉␉buf[k++]=args[i];␊ |
38 | ␉␉␉␉␉}␊ |
39 | ␉␉␉␉␉else {␊ |
40 | ␉␉␉␉␉␉prevCharwasDelim = true; // // keep a track of delim to further split tokens␊ |
41 | ␉␉␉␉␉}␊ |
42 | ␉␉␉␉␉break;␊ |
43 | ␉␉␉␉case '\0':␊ |
44 | ␉␉␉␉case '\'': ␊ |
45 | ␉␉␉␉case '"': ␊ |
46 | ␉␉␉␉␉if (!skipSpaces &&lastPriorityDelim!=args[i])␊ |
47 | ␉␉␉␉␉{ // consider the imbricated delim as a simple char␊ |
48 | ␉␉␉␉␉␉buf[k++]=args[i];␊ |
49 | ␉␉␉␉␉␉break;␊ |
50 | ␉␉␉␉␉}␊ |
51 | ␉␉␉␉␉␊ |
52 | ␉␉␉␉␉if (!skipSpaces) // end of priority substr␊ |
53 | ␉␉␉␉␉{␊ |
54 | ␉␉␉␉␉␉skipSpaces = true;␊ |
55 | ␉␉␉␉␉␉lastPriorityDelim=' ';␊ |
56 | ␉␉␉␉␉␉buf[k]='\0'; ␊ |
57 | ␉␉␉␉␉␉argv[n++]=strdup(buf); // copy the priority substr␊ |
58 | ␉␉␉␉␉␉k=0; // reset the buf index for next token␊ |
59 | ␉␉␉␉␉␉buf[0]='\0';␊ |
60 | ␉␉␉␉␉}␊ |
61 | ␉␉␉␉␉else␊ |
62 | ␉␉␉␉␉{ // start of priority substr␊ |
63 | ␉␉␉␉␉␉skipSpaces=false;␊ |
64 | ␉␉␉␉␉␉lastPriorityDelim=args[i];␊ |
65 | ␉␉␉␉␉␉if(k>0) // previous string to store first␊ |
66 | ␉␉␉␉␉␉{␊ |
67 | ␉␉␉␉␉␉␉buf[k++]='\0'; // finish the substr␊ |
68 | ␉␉␉␉␉␉␉argv[n++]=strdup(buf); // copy the substr␊ |
69 | ␉␉␉␉␉␉␉k=0; // rest the index for next token␊ |
70 | ␉␉␉␉␉␉␉buf[0]='\0';␊ |
71 | ␉␉␉␉␉␉}␊ |
72 | ␉␉␉␉␉␉//if (args[i] !='\0') buf[k++] = args[i]; // start the new priority substr␊ |
73 | ␉␉␉␉␉}␊ |
74 | ␉␉␉␉␉break;␊ |
75 | ␉␉␉␉default: // non delimiters chars␊ |
76 | ␉␉␉␉␉if(skipSpaces && prevCharwasDelim)␊ |
77 | ␉␉␉␉␉{␊ |
78 | ␉␉␉␉␉␉if(k>0) // a previous substr was before the space␊ |
79 | ␉␉␉␉␉␉{ // store previous token␊ |
80 | ␉␉␉␉␉␉␉buf[k++]='\0'; // finish the substr␊ |
81 | ␉␉␉␉␉␉␉argv[n++]=strdup(buf); // copy the substr␊ |
82 | ␉␉␉␉␉␉␉k=0; // rest the index for next token␊ |
83 | ␉␉␉␉␉␉␉buf[0]='\0';␊ |
84 | ␉␉␉␉␉␉}␊ |
85 | ␉␉␉␉␉}␊ |
86 | ␉␉␉␉␉prevCharwasDelim = false;␊ |
87 | ␉␉␉␉␉buf[k++]=args[i];␊ |
88 | ␉␉␉␉␉break;␊ |
89 | ␉␉␉}␊ |
90 | ␉␉}␊ |
91 | ␉␉␊ |
92 | ␉␉if(*buf) ␊ |
93 | ␉␉{␊ |
94 | ␉␉␉buf[k]='\0';␊ |
95 | ␉␉␉argv[n++]=strdup(buf); // copy the last buffer␉␊ |
96 | ␉␉}␊ |
97 | ␉␉free((void*) buf);␊ |
98 | ␉}␊ |
99 | ␉argv[n]=NULL;␊ |
100 | }␊ |
101 | ␊ |
102 | //--------------------------------------------------------------------------␊ |
103 | // Execute a priviledge shell command : will wait for execution termination␊ |
104 | // by calling wait()␊ |
105 | //--------------------------------------------------------------------------␊ |
106 | bool executePrivilegedCmd(AuthorizationRef auth, ␊ |
107 | ␉␉␉␉␉␉␉␉ const char* pathToTool, ␊ |
108 | ␉␉␉␉␉␉␉␉ const char* args, ␊ |
109 | ␉␉␉␉␉␉␉␉ AuthorizationFlags flags)␊ |
110 | {␊ |
111 | ␉const char * argv[16];␊ |
112 | ␊ |
113 | ␉parseArgs(args, argv, sizeof(argv)/sizeof(const char*));␊ |
114 | ␊ |
115 | ␉// Execute Cmd␊ |
116 | ␉OSStatus status = AuthorizationExecuteWithPrivileges(auth, pathToTool,flags, (char**)argv, NULL);␊ |
117 | ␉// Wait for the child process of AEWP to terminate:␊ |
118 | ␉int wait_status=0;␊ |
119 | ␉/* pid_t pid = */␊ |
120 | ␉wait(&wait_status);␊ |
121 | ␉// usleep(10000); // 10 ms␊ |
122 | ␉␉// Cleanup mem␊ |
123 | ␉for (int i=0; argv[i]; i++) free ((void*) argv[i]);␊ |
124 | ␊ |
125 | return status ? false : true;␊ |
126 | }␊ |
127 | ␊ |
128 | //--------------------------------------------------------------------------␊ |
129 | // Execute priviledged chmod for accessing system files␊ |
130 | //--------------------------------------------------------------------------␊ |
131 | bool PropertyList::chmodFile(const char * path, const char * chmodMask,␊ |
132 | ␉␉␉␉␉␉␉ AuthorizationRef auth, AuthorizationFlags flags)␊ |
133 | {␊ |
134 | ␉if (!path || !*path) return false;␊ |
135 | ␉␊ |
136 | ␉if (auth)␊ |
137 | ␉{ // give write temporary write rights to the file␊ |
138 | ␉␉std::string args = chmodMask;␊ |
139 | ␉␉args += ' ';␊ |
140 | ␉␉args += path;␊ |
141 | ␉␉struct stat st;␊ |
142 | ␉␉if (stat(path,&st)!=0)␊ |
143 | ␉␉␉executePrivilegedCmd(auth, "/usr/bin/touch", path, flags);␊ |
144 | ␉␉if(!executePrivilegedCmd(auth, "/bin/chmod", args.c_str(), flags))␉␊ |
145 | ␉␉␉return false;␊ |
146 | ␉}␊ |
147 | ␉return true;␊ |
148 | ␉␊ |
149 | }␊ |
150 | ␊ |
151 | //--------------------------------------------------------------------------␊ |
152 | // Write a property list from a file␊ |
153 | //--------------------------------------------------------------------------␊ |
154 | bool WritePropertyListToFile( CFPropertyListRef propertyList, CFURLRef fileURL )␊ |
155 | {␊ |
156 | ␉CFDataRef xmlData;␊ |
157 | ␉Boolean status;␊ |
158 | ␉SInt32 errorCode;␊ |
159 | ␉␊ |
160 | ␉// Convert the property list into XML data.␊ |
161 | ␉xmlData = CFPropertyListCreateXMLData( kCFAllocatorDefault, propertyList );␊ |
162 | ␉␊ |
163 | ␉// Write the XML data to the file.␊ |
164 | ␉status = CFURLWriteDataAndPropertiesToResource (␊ |
165 | ␉␉␉␉␉␉␉␉␉␉␉␉␉fileURL, // URL to use␊ |
166 | ␉␉␉␉␉␉␉␉␉␉␉␉␉xmlData, // data to write␊ |
167 | ␉␉␉␉␉␉␉␉␉␉␉␉␉NULL,␊ |
168 | ␉␉␉␉␉␉␉␉␉␉␉␉␉&errorCode);␊ |
169 | ␉CFRelease(xmlData);␊ |
170 | ␉␊ |
171 | ␉return status ? true: false;␊ |
172 | }␊ |
173 | ␊ |
174 | //--------------------------------------------------------------------------␊ |
175 | // Read a property list from a file␊ |
176 | //--------------------------------------------------------------------------␊ |
177 | static CFPropertyListRef CreatePropertyListFromFile( CFURLRef fileURL, ␊ |
178 | ␉␉␉␉␉␉␉␉␉␉␉␉␉const std::string& filePath,␊ |
179 | ␉␉␉␉␉␉␉␉␉␉␉␉␉CFStringRef * errorString, ␊ |
180 | ␉␉␉␉␉␉␉␉␉␉␉␉␉bool createIfNotExist) {␊ |
181 | ␉CFPropertyListRef propertyList;␊ |
182 | ␉CFDataRef resourceData;␊ |
183 | ␉Boolean status;␊ |
184 | ␉SInt32 errorCode;␊ |
185 | ␉// ␊ |
186 | ␉if (!fileExists(filePath))␊ |
187 | ␉{␊ |
188 | ␉␉if (createIfNotExist)␊ |
189 | ␉␉{␊ |
190 | ␉␉␉CFMutableDictionaryRef dict = ␊ |
191 | ␉␉␉ CFDictionaryCreateMutable( kCFAllocatorDefault, 0,␊ |
192 | ␉␉␉␉␉␉␉␉␉␉ &kCFTypeDictionaryKeyCallBacks,␊ |
193 | ␉␉␉␉␉␉␉␉␉␉ &kCFTypeDictionaryValueCallBacks );␊ |
194 | ␉␉␉WritePropertyListToFile(dict, fileURL);␊ |
195 | ␉␉}␊ |
196 | ␉␉␊ |
197 | ␉}␊ |
198 | ␉// Read the XML file.␊ |
199 | ␉status = CFURLCreateDataAndPropertiesFromResource(␊ |
200 | ␉␉␉␉␉␉␉␉␉␉␉␉␉ kCFAllocatorDefault,␊ |
201 | ␉␉␉␉␉␉␉␉␉␉␉␉␉ fileURL,␊ |
202 | ␉␉␉␉␉␉␉␉␉␉␉␉␉ &resourceData, // place to put file data␊ |
203 | ␉␉␉␉␉␉␉␉␉␉␉␉␉ NULL,␊ |
204 | ␉␉␉␉␉␉␉␉␉␉␉␉␉ NULL,␊ |
205 | ␉␉␉␉␉␉␉␉␉␉␉␉␉ &errorCode);␊ |
206 | ␉if (!status) return NULL;␊ |
207 | ␉␊ |
208 | ␉// Reconstitute the dictionary using the XML data.␊ |
209 | ␉propertyList = CFPropertyListCreateFromXMLData( kCFAllocatorDefault,␊ |
210 | ␉␉␉␉␉␉␉␉␉␉␉␉ resourceData,␊ |
211 | ␉␉␉␉␉␉␉␉␉␉␉␉ kCFPropertyListMutableContainersAndLeaves,␊ |
212 | ␉␉␉␉␉␉␉␉␉␉␉␉ errorString);␊ |
213 | ␊ |
214 | ␉␉␉␉␉␉␊ |
215 | ␉CFRelease( resourceData );␊ |
216 | ␉return propertyList;␊ |
217 | }␊ |
218 | ␊ |
219 | //--------------------------------------------------------------------------␊ |
220 | // Always return a valid static const string, ␊ |
221 | // if the CFSTR is not valid, then we return ""␊ |
222 | //--------------------------------------------------------------------------␊ |
223 | static const char * CfsToCs(CFStringRef inRef)␊ |
224 | {␊ |
225 | ␉static char *buffer=NULL;␊ |
226 | ␉CFIndex len = CFStringGetLength(inRef);␊ |
227 | ␉if (buffer) {␊ |
228 | ␉␉delete[] buffer;␉␊ |
229 | ␉}␊ |
230 | ␉buffer = new char[len+1];␊ |
231 | ␉if(CFStringGetFileSystemRepresentation (inRef, buffer, len+1))␊ |
232 | ␉␉return buffer;␊ |
233 | ␉return "";␊ |
234 | }␊ |
235 | ␉␊ |
236 | //--------------------------------------------------------------------------␊ |
237 | // Destruct a PropertyList Instance␊ |
238 | //--------------------------------------------------------------------------␊ |
239 | PropertyList::~PropertyList()␊ |
240 | {␊ |
241 | ␉cleanup();␉␊ |
242 | }␊ |
243 | ␊ |
244 | //--------------------------------------------------------------------------␊ |
245 | // Cleanup a PropertyList Instance␊ |
246 | //--------------------------------------------------------------------------␊ |
247 | void PropertyList::cleanup()␊ |
248 | {␊ |
249 | ␉if (_CFURLRef) ␊ |
250 | ␉{␊ |
251 | ␉␉CFRelease(_CFURLRef);␊ |
252 | ␉␉_CFURLRef = NULL;␊ |
253 | ␉}␊ |
254 | ␊ |
255 | ␉if (_proplistRef) ␊ |
256 | ␉{␊ |
257 | ␉␉CFRelease(_proplistRef);␊ |
258 | ␉␉_proplistRef = NULL;␊ |
259 | ␉}␊ |
260 | ␉_propFilePath = "";␊ |
261 | }␊ |
262 | ␊ |
263 | //--------------------------------------------------------------------------␊ |
264 | // Open a property list from a path name with auth␊ |
265 | //--------------------------------------------------------------------------␊ |
266 | bool PropertyList::open(const char * path, bool createIfNotExist, AuthorizationRef auth, AuthorizationFlags flags)␊ |
267 | {␊ |
268 | ␉bool ret = false;␊ |
269 | ␉␊ |
270 | ␉cleanup();␊ |
271 | ␊ |
272 | ␉if (!path || !*path || !(createIfNotExist || fileExists(path)) ) ␊ |
273 | ␉␉return false;␊ |
274 | ␉␊ |
275 | ␉_propFilePath = path;␊ |
276 | ␉CFStringRef cfPath = CFStringCreateWithCString (kCFAllocatorDefault, path, kCFStringEncodingUTF8);␊ |
277 | ␉CFURLRef inURL = CFURLCreateWithFileSystemPath( kCFAllocatorDefault,␊ |
278 | ␉␉␉␉␉␉␉␉␉␉␉cfPath, ␊ |
279 | ␉␉␉␉␉␉␉␉␉␉␉kCFURLPOSIXPathStyle, // interpret as POSIX path␊ |
280 | ␉␉␉␉␉␉␉␉␉␉␉false ); // is it a directory?␊ |
281 | ␉CFRelease(cfPath);␊ |
282 | ␉if (_CFURLRef) CFRelease(_CFURLRef);␊ |
283 | ␉_CFURLRef = inURL;␊ |
284 | ␉␊ |
285 | ␉if (_CFURLRef) ␊ |
286 | ␉{␊ |
287 | ␉␉CFRetain(_CFURLRef);␊ |
288 | ␊ |
289 | ␉␉// give write temporary write rights to the file␊ |
290 | ␉␉if (!chmodFile(path,"0777", auth, flags)) return false;␊ |
291 | ␉␉␊ |
292 | ␉␉_proplistRef = CreatePropertyListFromFile(inURL, _propFilePath, &_errorString, createIfNotExist);␊ |
293 | ␉␉␊ |
294 | ␉␉// restore rights␊ |
295 | ␉␉ret= chmodFile(path,"0644", auth, flags);␊ |
296 | ␊ |
297 | ␉␉if (_proplistRef) {␊ |
298 | ␉␉␉CFRetain(_proplistRef);␊ |
299 | ␉␉␉ret= true;␊ |
300 | ␉␉}␊ |
301 | ␉}␊ |
302 | ␉␊ |
303 | ␉return ret;␊ |
304 | }␊ |
305 | ␊ |
306 | //--------------------------------------------------------------------------␊ |
307 | // Save the current property list␊ |
308 | //--------------------------------------------------------------------------␊ |
309 | bool PropertyList::save(AuthorizationRef auth, AuthorizationFlags flags)␊ |
310 | {␊ |
311 | ␉bool ret=false;␊ |
312 | ␉if (auth)␊ |
313 | ␉{ // give write temporary write rights to the file␊ |
314 | ␉␉std::string args = " 0777 "+ _propFilePath;␊ |
315 | ␉␉if(!executePrivilegedCmd(auth, "/bin/chmod", args.c_str(), flags))␊ |
316 | ␉␉␉return false;␊ |
317 | ␉}␊ |
318 | ␉if (_proplistRef && _CFURLRef) ␊ |
319 | ␉␉ret= WritePropertyListToFile(_proplistRef,_CFURLRef);␊ |
320 | ␉if (auth)␊ |
321 | ␉{ // give write temporary write rights to the file␊ |
322 | ␉␉std::string args = " 0644 "+ _propFilePath;␊ |
323 | ␉␉if(!executePrivilegedCmd(auth, "/bin/chmod", args.c_str(), flags))␊ |
324 | ␉␉␉return false;␊ |
325 | ␉}␊ |
326 | ␉return ret;␊ |
327 | }␊ |
328 | ␊ |
329 | //--------------------------------------------------------------------------␊ |
330 | // Get a string value from a property list key, ␊ |
331 | // value returned is not owned by caller, copy it necessary.␊ |
332 | //--------------------------------------------------------------------------␊ |
333 | const char * PropertyList::getStringForKey(const char *key)␊ |
334 | {␊ |
335 | ␉if (!_proplistRef) ␉return NULL;␊ |
336 | ␉CFStringRef cfKey = CFStringCreateWithCString (kCFAllocatorDefault, key, kCFStringEncodingUTF8);␊ |
337 | ␉CFStringRef myString;␊ |
338 | ␉␊ |
339 | ␉if (_proplistRef && CFDictionaryGetValueIfPresent((CFMutableDictionaryRef)_proplistRef, ␊ |
340 | ␉␉␉␉␉␉␉␉␉␉␉␉␉ cfKey, (const void **) &myString))␊ |
341 | ␉{␊ |
342 | ␉␉CFRelease(cfKey);␊ |
343 | ␉␉return CfsToCs(myString);␊ |
344 | ␉}␊ |
345 | ␉␊ |
346 | ␉if(cfKey) CFRelease(cfKey);␊ |
347 | ␉return NULL;␊ |
348 | }␊ |
349 | ␊ |
350 | //--------------------------------------------------------------------------␊ |
351 | // Replace or add a string value from a property list key, ␊ |
352 | // value returned is not owned by caller, copy it necessary.␊ |
353 | //--------------------------------------------------------------------------␊ |
354 | bool PropertyList::setStringForKey(const char *key, const char * value)␊ |
355 | {␊ |
356 | ␉if (!_proplistRef) ␉return false;␊ |
357 | ␉bool ret = false;␊ |
358 | ␉CFStringRef cfKey = CFStringCreateWithCString (kCFAllocatorDefault, key, kCFStringEncodingUTF8);␊ |
359 | ␉CFStringRef myString = CFStringCreateWithCString (kCFAllocatorDefault, value, kCFStringEncodingUTF8);␊ |
360 | ␉CFMutableDictionaryRef myDict = (CFMutableDictionaryRef) _proplistRef;␊ |
361 | ␉␊ |
362 | ␉if (myDict) ␊ |
363 | ␉{␊ |
364 | ␉␉CFDictionarySetValue(myDict, cfKey, myString);␊ |
365 | ␉␉ret=true;␉␊ |
366 | ␉} ␊ |
367 | ␉if(cfKey) CFRelease(cfKey);␊ |
368 | ␉if(myString) CFRelease(myString);␊ |
369 | ␉return ret;␊ |
370 | }␊ |
371 | ␊ |
372 | //--------------------------------------------------------------------------␊ |
373 | // Delete a key and its value from the dictionary␊ |
374 | //--------------------------------------------------------------------------␊ |
375 | bool PropertyList::removeKeyAndValue(const char *key)␊ |
376 | {␊ |
377 | ␉if (!_proplistRef) ␉return false;␊ |
378 | ␉bool ret = false;␊ |
379 | ␉␊ |
380 | ␉CFStringRef cfKey = CFStringCreateWithCString (kCFAllocatorDefault, key, kCFStringEncodingUTF8);␊ |
381 | ␉␊ |
382 | ␉if (_proplistRef) {␊ |
383 | ␉␉CFDictionaryRemoveValue((CFMutableDictionaryRef) _proplistRef, cfKey);␊ |
384 | ␉␉ret=true;␉␊ |
385 | ␉} ␊ |
386 | ␉if(cfKey) CFRelease(cfKey);␊ |
387 | ␉return ret;␊ |
388 | }␊ |
389 | ␊ |
390 | |