#include <SystemConfiguration/SystemConfiguration.h>
#include <SystemConfiguration/SCPrivate.h>
#include "SCPreferencesInternal.h"
#include <fcntl.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/errno.h>
static CFStringRef
__SCPreferencesCopyDescription(CFTypeRef cf) {
CFAllocatorRef allocator = CFGetAllocator(cf);
CFMutableStringRef result;
result = CFStringCreateMutable(allocator, 0);
CFStringAppendFormat(result, NULL, CFSTR("<SCPreferences %p [%p]> {\n"), cf, allocator);
CFStringAppendFormat(result, NULL, CFSTR("}"));
return result;
}
static void
__SCPreferencesDeallocate(CFTypeRef cf)
{
SCPreferencesPrivateRef sessionPrivate = (SCPreferencesPrivateRef)cf;
SCLog(_sc_verbose, LOG_DEBUG, CFSTR("__SCPreferencesDeallocate:"));
if (sessionPrivate->name) CFRelease(sessionPrivate->name);
if (sessionPrivate->prefsID) CFRelease(sessionPrivate->prefsID);
if (sessionPrivate->user) CFRelease(sessionPrivate->user);
if (sessionPrivate->path) CFAllocatorDeallocate(NULL, sessionPrivate->path);
if (sessionPrivate->signature) CFRelease(sessionPrivate->signature);
if (sessionPrivate->session) CFRelease(sessionPrivate->session);
if (sessionPrivate->sessionKeyLock) CFRelease(sessionPrivate->sessionKeyLock);
if (sessionPrivate->sessionKeyCommit) CFRelease(sessionPrivate->sessionKeyCommit);
if (sessionPrivate->sessionKeyApply) CFRelease(sessionPrivate->sessionKeyApply);
if (sessionPrivate->prefs) CFRelease(sessionPrivate->prefs);
return;
}
static CFTypeID __kSCPreferencesTypeID = _kCFRuntimeNotATypeID;
static const CFRuntimeClass __SCPreferencesClass = {
0, "SCPreferences", NULL, NULL, __SCPreferencesDeallocate, NULL, NULL, NULL, __SCPreferencesCopyDescription };
static pthread_once_t initialized = PTHREAD_ONCE_INIT;
static void
__SCPreferencesInitialize(void) {
__kSCPreferencesTypeID = _CFRuntimeRegisterClass(&__SCPreferencesClass);
return;
}
SCPreferencesRef
__SCPreferencesCreatePrivate(CFAllocatorRef allocator)
{
SCPreferencesPrivateRef prefs;
UInt32 size;
pthread_once(&initialized, __SCPreferencesInitialize);
size = sizeof(SCPreferencesPrivate) - sizeof(CFRuntimeBase);
prefs = (SCPreferencesPrivateRef)_CFRuntimeCreateInstance(allocator,
__kSCPreferencesTypeID,
size,
NULL);
if (!prefs) {
return NULL;
}
prefs->name = NULL;
prefs->prefsID = NULL;
prefs->perUser = FALSE;
prefs->user = NULL;
prefs->path = NULL;
prefs->signature = NULL;
prefs->session = NULL;
prefs->sessionKeyLock = NULL;
prefs->sessionKeyCommit = NULL;
prefs->sessionKeyApply = NULL;
prefs->prefs = NULL;
prefs->accessed = FALSE;
prefs->changed = FALSE;
prefs->locked = FALSE;
prefs->isRoot = (geteuid() == 0);
return (SCPreferencesRef)prefs;
}
__private_extern__ SCPreferencesRef
__SCPreferencesCreate(CFAllocatorRef allocator,
CFStringRef name,
CFStringRef prefsID,
Boolean perUser,
CFStringRef user)
{
int fd = -1;
SCPreferencesRef prefs;
SCPreferencesPrivateRef prefsPrivate;
int sc_status = kSCStatusOK;
struct stat statBuf;
CFMutableDataRef xmlData;
CFStringRef xmlError;
prefs = __SCPreferencesCreatePrivate(allocator);
if (!prefs) {
return NULL;
}
prefsPrivate = (SCPreferencesPrivateRef)prefs;
prefsPrivate->path = __SCPreferencesPath(NULL, prefsID, perUser, user);
if (prefsPrivate->path == NULL) {
sc_status = kSCStatusFailed;
goto error;
}
fd = open(prefsPrivate->path, O_RDONLY, 0644);
if (fd == -1) {
switch (errno) {
case ENOENT :
bzero(&statBuf, sizeof(statBuf));
goto create_1;
case EACCES :
sc_status = kSCStatusAccessError;
break;
default :
sc_status = kSCStatusFailed;
break;
}
SCLog(_sc_verbose, LOG_DEBUG, CFSTR("open() failed: %s"), strerror(errno));
goto error;
}
if (fstat(fd, &statBuf) == -1) {
SCLog(_sc_verbose, LOG_DEBUG, CFSTR("fstat() failed: %s"), strerror(errno));
sc_status = kSCStatusFailed;
goto error;
}
create_1 :
prefsPrivate->signature = __SCPSignatureFromStatbuf(&statBuf);
if (statBuf.st_size > 0) {
xmlData = CFDataCreateMutable(NULL, statBuf.st_size);
CFDataSetLength(xmlData, statBuf.st_size);
if (read(fd, (void *)CFDataGetBytePtr(xmlData), statBuf.st_size) != statBuf.st_size) {
SCLog(_sc_verbose, LOG_DEBUG, CFSTR("_SCPOpen read(): could not load preference data."));
CFRelease(xmlData);
xmlData = NULL;
goto create_2;
}
prefsPrivate->prefs = (CFMutableDictionaryRef)
CFPropertyListCreateFromXMLData(NULL,
xmlData,
kCFPropertyListMutableContainers,
&xmlError);
CFRelease(xmlData);
if (!prefsPrivate->prefs) {
if (xmlError) {
SCLog(_sc_verbose, LOG_DEBUG,
CFSTR("_SCPOpen CFPropertyListCreateFromXMLData(): %@"),
xmlError);
CFRelease(xmlError);
}
goto create_2;
}
if (CFGetTypeID(prefsPrivate->prefs) != CFDictionaryGetTypeID()) {
SCLog(_sc_verbose, LOG_DEBUG, CFSTR("_SCPOpen CFGetTypeID(): not a dictionary."));
CFRelease(prefsPrivate->prefs);
prefsPrivate->prefs = NULL;
goto create_2;
}
}
create_2 :
if (fd != -1) {
(void) close(fd);
fd = -1;
}
if (prefsPrivate->prefs == NULL) {
SCLog(_sc_verbose, LOG_DEBUG, CFSTR("_SCPOpen(): creating new dictionary."));
prefsPrivate->prefs = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
prefsPrivate->changed = TRUE;
}
prefsPrivate->name = CFRetain(name);
if (prefsID) {
prefsPrivate->prefsID = CFRetain(prefsID);
}
prefsPrivate->perUser = perUser;
if (user) {
prefsPrivate->user = CFRetain(user);
}
return prefs;
error :
if (fd != -1) {
(void) close(fd);
}
CFRelease(prefs);
_SCErrorSet(sc_status);
return NULL;
}
SCPreferencesRef
SCPreferencesCreate(CFAllocatorRef allocator,
CFStringRef name,
CFStringRef prefsID)
{
SCLog(_sc_verbose, LOG_DEBUG, CFSTR("SCPreferencesCreate:"));
SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" name = %@"), name);
SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" prefsID = %@"), prefsID);
return __SCPreferencesCreate(allocator, name, prefsID, FALSE, NULL);
}
SCPreferencesRef
SCUserPreferencesCreate(CFAllocatorRef allocator,
CFStringRef name,
CFStringRef prefsID,
CFStringRef user)
{
SCLog(_sc_verbose, LOG_DEBUG, CFSTR("SCUserPreferencesCreate:"));
SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" name = %@"), name);
SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" prefsID = %@"), prefsID);
SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" user = %@"), user);
return __SCPreferencesCreate(allocator, name, prefsID, TRUE, user);
}
CFTypeID
SCPreferencesGetTypeID(void) {
return __kSCPreferencesTypeID;
}