Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
CFPreferences_SharedAppValue.c
// |
// File: CFPreferences_SharedAppValues.c |
// |
// Contains: CFPreferences by design only allows write access to the kCFPreferencesAnyUser domain by a user |
// with admin privileges. But occasionally developers have had the need to store user preferences |
// that are both readable and writable by all users. This sample demonstrates how this may be |
// achieved utilizing Core Foundation API's. |
// |
// Version: 1.0 |
// |
// Created: 8/31/06 |
// |
// Copyright: Copyright 2006 Apple Computer, Inc., All Rights Reserved |
// |
// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ( "Apple" ) in |
// consideration of your agreement to the following terms, and your use, installation, modification |
// or redistribution of this Apple software constitutes acceptance of these terms. If you do |
// not agree with these terms, please do not use, install, modify or redistribute this Apple |
// software. |
// |
// In consideration of your agreement to abide by the following terms, and subject to these terms, |
// Apple grants you a personal, non - exclusive license, under Apple's copyrights in this |
// original Apple software ( the "Apple Software" ), to use, reproduce, modify and redistribute the |
// Apple Software, with or without modifications, in source and / or binary forms; provided that if you |
// redistribute the Apple Software in its entirety and without modifications, you must retain this |
// notice and the following text and disclaimers in all such redistributions of the Apple Software. |
// Neither the name, trademarks, service marks or logos of Apple Computer, Inc. may be used to |
// endorse or promote products derived from the Apple Software without specific prior written |
// permission from Apple. Except as expressly stated in this notice, no other rights or |
// licenses, express or implied, are granted by Apple herein, including but not limited to any |
// patent rights that may be infringed by your derivative works or by other works in which the |
// Apple Software may be incorporated. |
// |
// The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, EXPRESS OR |
// IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON - INFRINGEMENT, MERCHANTABILITY |
// AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE |
// OR IN COMBINATION WITH YOUR PRODUCTS. |
// |
// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL |
// DAMAGES ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) ARISING IN ANY WAY OUT OF THE USE, |
// REPRODUCTION, MODIFICATION AND / OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER |
// UNDER THEORY OF CONTRACT, TORT ( INCLUDING NEGLIGENCE ), STRICT LIABILITY OR OTHERWISE, EVEN |
// IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
// |
// |
// *************************************************** |
#pragma mark * complation directives * |
//---------------------------------------------------- |
// *************************************************** |
#pragma mark - |
#pragma mark * includes & imports * |
//---------------------------------------------------- |
#include <Carbon/Carbon.h> |
#include <stdio.h> // printf, fprinf, stderr |
#include <fcntl.h> // open |
#include <unistd.h> // close |
#include <sys/stat.h> // umask, chmod |
#include "CFPreferences_SharedAppValue.h" |
// *************************************************** |
#pragma mark - |
#pragma mark * typedef's, struct's, enums, defines, etc. * |
//---------------------------------------------------- |
// *************************************************** |
#pragma mark - |
#pragma mark * local ( static ) function prototypes * |
//---------------------------------------------------- |
static CFURLRef CFPreferences_CopySharedCFURLRef( CFStringRef inApplicationID ); |
static SInt32 CFProperty_SaveToXMLFile( CFPropertyListRef inCFPRef, CFURLRef inCFURLRef ); |
static CFPropertyListRef CFProperty_CreateFromXMLFile( CFURLRef inCFURLRef, CFOptionFlags inMutabilityOption ); |
// *************************************************** |
#pragma mark - |
#pragma mark * exported globals * |
//---------------------------------------------------- |
// *************************************************** |
#pragma mark - |
#pragma mark * local ( static ) globals * |
//---------------------------------------------------- |
// *************************************************** |
#pragma mark - |
#pragma mark * exported function implementations * |
//---------------------------------------------------- |
// **************************************************** |
// |
// CFPreferences_CopySharedAppValue( inKey, inApplicationID ) |
// |
// Purpose: This is a special version of CFPreferences_CopyAppValue that acesses |
// preferences stored in a shared location that writeable by non - admin users |
// ( /Users / Shared / Library / Preferences ). |
// |
// Inputs: inKey - the key, must not be null |
// inApplicationID - the Application ID |
// |
// Returns: CFPropertyListRef - the CFProperty list, Null if key not found |
// |
// Notes: If not null then Caller must release the returned value |
// |
CFPropertyListRef CFPreferences_CopySharedAppValue( CFStringRef inKey, CFStringRef inApplicationID ) |
{ |
CFPropertyListRef tCFPropertyListRef = NULL; |
if ( inKey ) { // if the input key is valid |
// create a URL to the shared preferences file |
CFURLRef tCFURLRef = CFPreferences_CopySharedCFURLRef( inApplicationID ); |
if ( tCFURLRef ) { // if that succedded ... |
// load the existing preferences from the file |
CFDictionaryRef tCFDictionaryRef = ( CFDictionaryRef ) |
CFProperty_CreateFromXMLFile( tCFURLRef, kCFPropertyListImmutable ); |
// if this was successful and of the correct type ... |
if ( tCFDictionaryRef && ( CFDictionaryGetTypeID( ) == CFGetTypeID( tCFDictionaryRef ) ) ) { |
// look for our preference in the dictionary |
if ( CFDictionaryGetValueIfPresent( tCFDictionaryRef, inKey, ( const void * * ) &tCFPropertyListRef ) ) { |
CFRetain( tCFPropertyListRef ); |
} |
CFRelease( tCFDictionaryRef ); |
} |
} |
CFRelease( tCFURLRef ); |
} |
// if the shared location doesn't have the preference then try the other domains |
if ( !tCFPropertyListRef ) { |
tCFPropertyListRef = CFPreferencesCopyAppValue( inKey, inApplicationID ); |
} |
return tCFPropertyListRef; |
} // CFPreferences_CopySharedAppValue |
// **************************************************** |
// |
// CFPreferences_SetSharedAppValue( inKey, inValue, inApplicationID ) |
// |
// Purpose: This is a special version of CFPreferences_SetAppValue that stores preferences in a |
// location that is writeable by non - admin users ( /Users / Shared / Library / Preferences ). |
// |
// Inputs: inKey - the key, must not be null |
// inValue - the value to be saved |
// inApplicationID - the Application ID |
// |
// Returns: Boolean - TRUE if successful |
// |
Boolean CFPreferences_SetSharedAppValue( CFStringRef inKey, CFPropertyListRef inValue, CFStringRef inApplicationID ) |
{ |
Boolean result = FALSE; // assume failure ( pessimist! ) |
// create a URL to the shared preferences file |
CFURLRef tCFURLRef = CFPreferences_CopySharedCFURLRef( inApplicationID ); |
if ( tCFURLRef ) { // if that succedded ... |
// load the existing preferences from the file |
CFMutableDictionaryRef tCFMutableDictionaryRef = ( CFMutableDictionaryRef ) |
CFProperty_CreateFromXMLFile( tCFURLRef, kCFPropertyListMutableContainers ); |
// if this failed or was of the wrong type ... |
if ( !tCFMutableDictionaryRef || ( CFDictionaryGetTypeID( ) != CFGetTypeID( tCFMutableDictionaryRef ) ) ) { |
if ( tCFMutableDictionaryRef ) { |
CFRelease( tCFMutableDictionaryRef ); |
} |
tCFMutableDictionaryRef = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); |
} |
// if we have a dictionary now ... |
if ( tCFMutableDictionaryRef ) { |
if ( inValue ) { // then set our value |
CFDictionarySetValue( tCFMutableDictionaryRef, inKey, inValue ); |
} else { |
CFDictionaryRemoveValue( tCFMutableDictionaryRef, inKey ); |
} |
// and save our preferences back out to the file |
SInt32 status = CFProperty_SaveToXMLFile( tCFMutableDictionaryRef, tCFURLRef ); |
result = ( noErr == status ); |
CFRelease( tCFMutableDictionaryRef ); |
} |
CFRelease( tCFURLRef ); |
} |
return result; |
} // CFPreferences_SetSharedAppValue |
// *************************************************** |
#pragma mark - |
#pragma mark * local ( static ) function implementations * |
//---------------------------------------------------- |
// ***************************************************** |
// |
// CFPreferences_CopySharedCFURLRef( inApplicationID ) |
// |
// Purpose: return the URL for the shared preferences file for this application |
// |
// Inputs: inApplicationID - the application ID |
// |
// Returns: CFURLRef - the URL |
// |
static CFURLRef CFPreferences_CopySharedCFURLRef( CFStringRef inApplicationID ) |
{ |
CFURLRef result = NULL; |
OSStatus status = noErr; |
// if kCFPreferencesCurrentApplication is used as the inApplicationID ... |
// ... convert that to the identifier of the current application. |
if ( CFEqual( inApplicationID, kCFPreferencesCurrentApplication ) ) { |
inApplicationID = CFBundleGetIdentifier( CFBundleGetMainBundle( ) ); |
if ( !inApplicationID ) { |
status = coreFoundationUnknownErr; |
} |
} |
// the inApplicationID is used as the file name ( sans extension ) |
char fileName[PATH_MAX]; |
if ( noErr == status ) { |
if ( !CFStringGetCString( inApplicationID, fileName, sizeof( fileName ), kCFStringEncodingUTF8 ) ) { |
status = coreFoundationUnknownErr; |
} |
} |
// Locate the shared user data folder ... |
FSRef usersSharedFSRef; |
if ( noErr == status ) { |
status = FSFindFolder( kOnAppropriateDisk, kSharedUserDataFolderType, TRUE, &usersSharedFSRef ); |
} |
// ... and convert that to a C string. |
char usersSharedPath[PATH_MAX]; |
if ( noErr == status ) { |
status = FSRefMakePath( &usersSharedFSRef, ( UInt8 * ) usersSharedPath, sizeof( usersSharedPath ) ); |
} |
// Locate the users preference folder ... |
FSRef prefsFSRef; |
if ( noErr == status ) { |
status = FSFindFolder( kUserDomain, kPreferencesFolderType, TRUE, &prefsFSRef ); |
} |
// ... and convert that to a C string. |
char prefsPath[PATH_MAX]; |
if ( noErr == status ) { |
status = FSRefMakePath( &prefsFSRef, ( UInt8 * ) prefsPath, sizeof( prefsPath ) ); |
} |
// Locate the users home directory |
FSRef homeFSRef; |
if ( noErr == status ) { |
status = FSFindFolder( kUserDomain, kDomainTopLevelFolderType, TRUE, &homeFSRef ); |
} |
// ... and convert that to a C string. |
char homePath[PATH_MAX]; |
if ( noErr == status ) { |
status = FSRefMakePath( &homeFSRef, ( UInt8 * ) homePath, sizeof( homePath ) ); |
} |
// The result path will be the shared user data folder (</Users/Shared>) plus ... |
// ... the part of the prefs path that's after the users home directory ... |
// ( </Users/xxxxx/Library/Preferences> - </Users/xxxxx/> => <Library/Preferences> ) |
// ... plus the filename, plus the extension (".plist"). |
if ( noErr == status ) { |
assert( strlen( prefsPath ) > strlen( homePath ) ); |
assert( strncmp( prefsPath, homePath, strlen( homePath ) ) == 0 ); |
char resultPath[PATH_MAX]; |
snprintf( resultPath, sizeof( resultPath ), "%s/%s/%s.plist", usersSharedPath, prefsPath + strlen( homePath ) + 1, fileName ); |
// convert the result path to a CFURL |
result = CFURLCreateFromFileSystemRepresentation( NULL, ( const UInt8 * ) resultPath, strlen( resultPath ), false ); |
if ( !result ) { |
status = coreFoundationUnknownErr; |
} |
} |
assert( ( noErr == status ) == ( NULL != result ) ); |
return result; |
} // CFPreferences_CopySharedCFURLRef |
// ***************************************************** |
// |
// CFProperty_SaveToXMLFile( inCFPRef, inCFURLRef ) |
// |
// Purpose: saves CFProperty list into an XML file |
// |
// Inputs: inCFPRef - the CFProperty list to save |
// inCFURLRef - the file to save it to |
// |
// Returns: SInt32 - error code ( 0 == no error ) |
// |
static SInt32 CFProperty_SaveToXMLFile( CFPropertyListRef inCFPRef, CFURLRef inCFURLRef ) |
{ |
SInt32 result = noErr; |
mode_t oldMode = umask( 0 ); |
char urlPath[PATH_MAX]; |
if ( !CFURLGetFileSystemRepresentation( inCFURLRef, TRUE, ( UInt8 * ) urlPath, PATH_MAX ) ) { |
result = coreFoundationUnknownErr; |
} |
// Create any directories leading up to the file. |
// CFURLWriteDataAndPropertiesToResource will create the file itself, if necessary. |
if ( noErr == result ) { |
char * cursor = urlPath + 1; // start after leading slash |
while ( TRUE ) { |
cursor = strchr( cursor, '/' ); // look for the next slash |
if ( !cursor ) { // no next slash, we've reached the last component |
result = noErr; |
break; |
} |
*cursor = 0; // terminate string at the slash |
result = mkdir( urlPath, ALLPERMS ); |
if ( result < 0 ) { |
result = errno; |
if ( errno != EEXIST ) { |
break; |
} |
} |
*cursor = '/'; // restore the slash |
cursor += 1; // skip over the slash |
} |
} |
// Convert the property list into XML data. |
CFDataRef xmlCFDataRef = NULL; |
if ( noErr == result ) { |
xmlCFDataRef = CFPropertyListCreateXMLData( kCFAllocatorDefault, inCFPRef ); |
if ( !xmlCFDataRef ) { |
result = coreFoundationUnknownErr; |
} |
} |
// Write the XML data to the file. |
if ( noErr == result ) { |
if ( CFURLWriteDataAndPropertiesToResource( inCFURLRef, xmlCFDataRef, NULL, &result ) ) { |
result = noErr; |
} |
} |
( void ) umask( oldMode ); |
if ( xmlCFDataRef ) { |
CFRelease( xmlCFDataRef ); |
} |
return result; |
} // CFProperty_SaveToXMLFile |
// ***************************************************** |
// |
// CFProperty_CreateFromXMLFile( inCFURLRef, inMutabilityOption ) |
// |
// Purpose: loads a CFProperty list from an XML file |
// |
// Inputs: inCFURLRef - the file to load it from |
// inMutabilityOption - the mutability option |
// |
// Returns: inCFPRef - the CFProperty list |
// |
static CFPropertyListRef CFProperty_CreateFromXMLFile( CFURLRef inCFURLRef, CFOptionFlags inMutabilityOption ) |
{ |
CFDataRef xmlCFDataRef; |
CFPropertyListRef myCFPropertyListRef = NULL; |
// Read the XML file. |
if ( CFURLCreateDataAndPropertiesFromResource( kCFAllocatorDefault, inCFURLRef, &xmlCFDataRef, NULL, NULL, NULL ) ) { |
// Reconstitute the dictionary using the XML data. |
myCFPropertyListRef = CFPropertyListCreateFromXMLData( kCFAllocatorDefault, xmlCFDataRef, inMutabilityOption, NULL ); |
// Release the XML data |
CFRelease( xmlCFDataRef ); |
} |
return myCFPropertyListRef; |
} // CFProperty_CreateFromXMLFile |
Copyright © 2006 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2006-10-09