1/*
2 * Copyright (c) 2000-2006, 2009-2011, 2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 * Modification History
26 *
27 * June 1, 2001			Allan Nathanson <ajn@apple.com>
28 * - public API conversion
29 *
30 * March 24, 2000		Allan Nathanson <ajn@apple.com>
31 * - initial revision
32 */
33
34#include <mach/mach.h>
35#include <mach/mach_error.h>
36
37#include <SystemConfiguration/SystemConfiguration.h>
38#include <SystemConfiguration/SCPrivate.h>
39#include "SCDynamicStoreInternal.h"
40#include "config.h"		/* MiG generated file */
41
42
43Boolean
44SCDynamicStoreSetMultiple(SCDynamicStoreRef	store,
45			  CFDictionaryRef	keysToSet,
46			  CFArrayRef		keysToRemove,
47			  CFArrayRef		keysToNotify)
48{
49	SCDynamicStorePrivateRef	storePrivate;
50	kern_return_t			status;
51	CFDataRef			xmlSet		= NULL;	/* key/value pairs to set (XML serialized) */
52	xmlData_t			mySetRef	= NULL;	/* key/value pairs to set (serialized) */
53	CFIndex				mySetLen	= 0;
54	CFDataRef			xmlRemove	= NULL;	/* keys to remove (XML serialized) */
55	xmlData_t			myRemoveRef	= NULL;	/* keys to remove (serialized) */
56	CFIndex				myRemoveLen	= 0;
57	CFDataRef			xmlNotify	= NULL;	/* keys to notify (XML serialized) */
58	xmlData_t			myNotifyRef	= NULL;	/* keys to notify (serialized) */
59	CFIndex				myNotifyLen	= 0;
60	int				sc_status;
61
62	if (store == NULL) {
63		store = __SCDynamicStoreNullSession();
64		if (store == NULL) {
65			/* sorry, you must provide a session */
66			_SCErrorSet(kSCStatusNoStoreSession);
67			return FALSE;
68		}
69	}
70
71	storePrivate = (SCDynamicStorePrivateRef)store;
72	if (storePrivate->server == MACH_PORT_NULL) {
73		_SCErrorSet(kSCStatusNoStoreServer);
74		return FALSE;	/* you must have an open session to play */
75	}
76
77	/* serialize the key/value pairs to set*/
78	if (keysToSet != NULL) {
79		CFDictionaryRef	newInfo;
80		Boolean		ok;
81
82		newInfo = _SCSerializeMultiple(keysToSet);
83		if (newInfo == NULL) {
84			_SCErrorSet(kSCStatusInvalidArgument);
85			return FALSE;
86		}
87
88		ok = _SCSerialize(newInfo, &xmlSet, (void **)&mySetRef, &mySetLen);
89		CFRelease(newInfo);
90		if (!ok) {
91			_SCErrorSet(kSCStatusInvalidArgument);
92			return FALSE;
93		}
94	}
95
96	/* serialize the keys to remove */
97	if (keysToRemove != NULL) {
98		if (!_SCSerialize(keysToRemove, &xmlRemove, (void **)&myRemoveRef, &myRemoveLen)) {
99			if (xmlSet != NULL)	CFRelease(xmlSet);
100			_SCErrorSet(kSCStatusInvalidArgument);
101			return FALSE;
102		}
103	}
104
105	/* serialize the keys to notify */
106	if (keysToNotify != NULL) {
107		if (!_SCSerialize(keysToNotify, &xmlNotify, (void **)&myNotifyRef, &myNotifyLen)) {
108			if (xmlSet != NULL)	CFRelease(xmlSet);
109			if (xmlRemove != NULL)	CFRelease(xmlRemove);
110			_SCErrorSet(kSCStatusInvalidArgument);
111			return FALSE;
112		}
113	}
114
115    retry :
116
117	/* send the keys and patterns, fetch the associated result from the server */
118	status = configset_m(storePrivate->server,
119			     mySetRef,
120			     (mach_msg_type_number_t)mySetLen,
121			     myRemoveRef,
122			     (mach_msg_type_number_t)myRemoveLen,
123			     myNotifyRef,
124			     (mach_msg_type_number_t)myNotifyLen,
125			     (int *)&sc_status);
126
127	if (__SCDynamicStoreCheckRetryAndHandleError(store,
128						     status,
129						     &sc_status,
130						     "SCDynamicStoreSetMultiple configset_m()")) {
131		goto retry;
132	}
133
134	/* clean up */
135	if (xmlSet != NULL)	CFRelease(xmlSet);
136	if (xmlRemove != NULL)	CFRelease(xmlRemove);
137	if (xmlNotify != NULL)	CFRelease(xmlNotify);
138
139	if (sc_status != kSCStatusOK) {
140		_SCErrorSet(sc_status);
141		return FALSE;
142	}
143
144	return TRUE;
145}
146
147Boolean
148SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFPropertyListRef value)
149{
150	SCDynamicStorePrivateRef	storePrivate;
151	kern_return_t			status;
152	CFDataRef			utfKey;		/* serialized key */
153	xmlData_t			myKeyRef;
154	CFIndex				myKeyLen;
155	CFDataRef			xmlData;	/* serialized data */
156	xmlData_t			myDataRef;
157	CFIndex				myDataLen;
158	int				sc_status;
159	int				newInstance;
160
161	if (store == NULL) {
162		store = __SCDynamicStoreNullSession();
163		if (store == NULL) {
164			/* sorry, you must provide a session */
165			_SCErrorSet(kSCStatusNoStoreSession);
166			return FALSE;
167		}
168	}
169
170	storePrivate = (SCDynamicStorePrivateRef)store;
171	if (storePrivate->server == MACH_PORT_NULL) {
172		/* sorry, you must have an open session to play */
173		_SCErrorSet(kSCStatusNoStoreServer);
174		return FALSE;
175	}
176
177	/* serialize the key */
178	if (!_SCSerializeString(key, &utfKey, (void **)&myKeyRef, &myKeyLen)) {
179		_SCErrorSet(kSCStatusInvalidArgument);
180		return FALSE;
181	}
182
183	/* serialize the data */
184	if (!_SCSerialize(value, &xmlData, (void **)&myDataRef, &myDataLen)) {
185		CFRelease(utfKey);
186		_SCErrorSet(kSCStatusInvalidArgument);
187		return FALSE;
188	}
189
190    retry :
191
192	/* send the key & data to the server, get new instance id */
193	status = configset(storePrivate->server,
194			   myKeyRef,
195			   (mach_msg_type_number_t)myKeyLen,
196			   myDataRef,
197			   (mach_msg_type_number_t)myDataLen,
198			   0,
199			   &newInstance,
200			   (int *)&sc_status);
201
202	if (__SCDynamicStoreCheckRetryAndHandleError(store,
203						     status,
204						     &sc_status,
205						     "SCDynamicStoreSetValue configset()")) {
206		goto retry;
207	}
208
209	/* clean up */
210	CFRelease(utfKey);
211	CFRelease(xmlData);
212
213	if (sc_status != kSCStatusOK) {
214		_SCErrorSet(sc_status);
215		return FALSE;
216	}
217
218	return TRUE;
219}
220