]> git.saurik.com Git - apple/configd.git/blobdiff - scutil.tproj/cache.c
configd-802.20.7.tar.gz
[apple/configd.git] / scutil.tproj / cache.c
index 3739acb0cfbf650eb655083c59d31bb335ee4190..b8016e78367ddfa92c459415cecdf3616f085c59 100644 (file)
@@ -1,22 +1,23 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2005, 2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
- *
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License").  You may not use this file except in compliance with the
- * License.  Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
- *
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License.
- *
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
  * @APPLE_LICENSE_HEADER_END@
  */
 
 #include <sys/types.h>
 
 #include "scutil.h"
+#include "cache.h"
+
+
+#pragma mark -
+#pragma mark SCDynamicStore "cache"
+
+
+static Boolean                 use_cache       = FALSE;
+
+static CFMutableDictionaryRef  cached_keys     = NULL;
+static CFMutableDictionaryRef  cached_set      = NULL;
+static CFMutableArrayRef       cached_removals = NULL;
+static CFMutableArrayRef       cached_notifys  = NULL;
+
+
+static void
+cache_open(void)
+{
+       if (use_cache) {
+               // if we are already using the cache
+               cache_close();
+       }
+
+       cached_keys     = CFDictionaryCreateMutable(NULL,
+                                                   0,
+                                                   &kCFTypeDictionaryKeyCallBacks,
+                                                   &kCFTypeDictionaryValueCallBacks);
+       cached_set      = CFDictionaryCreateMutable(NULL,
+                                                   0,
+                                                   &kCFTypeDictionaryKeyCallBacks,
+                                                   &kCFTypeDictionaryValueCallBacks);
+       cached_removals = CFArrayCreateMutable(NULL,
+                                              0,
+                                              &kCFTypeArrayCallBacks);
+       cached_notifys  = CFArrayCreateMutable(NULL,
+                                              0,
+                                              &kCFTypeArrayCallBacks);
+
+       use_cache = TRUE;
+       return;
+}
+
+
+static CFPropertyListRef
+cache_SCDynamicStoreCopyValue(SCDynamicStoreRef store, CFStringRef key)
+{
+       CFPropertyListRef       value;
+
+       value = CFDictionaryGetValue(cached_set, key);
+       if (value) {
+               // if we have "set" a new value
+               return (CFRetain(value));
+       }
+
+       if (CFArrayContainsValue(cached_removals,
+                                CFRangeMake(0, CFArrayGetCount(cached_removals)),
+                                key)) {
+               // if we have "removed" the key
+               _SCErrorSet(kSCStatusNoKey);
+               return NULL;
+       }
+
+       value = CFDictionaryGetValue(cached_keys, key);
+       if (value) {
+               // if we have a cached value
+               return (CFRetain(value));
+       }
+
+       value = SCDynamicStoreCopyValue(store, key);
+       if (value) {
+               CFDictionarySetValue(cached_keys, key, value);
+       }
+
+       return value;
+}
+
+
+static void
+cache_SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFPropertyListRef value)
+{
+       CFIndex i;
+
+       i = CFArrayGetFirstIndexOfValue(cached_removals,
+                                       CFRangeMake(0, CFArrayGetCount(cached_removals)),
+                                       key);
+       if (i != kCFNotFound) {
+               // if previously "removed"
+               CFArrayRemoveValueAtIndex(cached_removals, i);
+       }
+
+       CFDictionarySetValue(cached_set, key, value);
+
+       return;
+}
+
+static void
+cache_SCDynamicStoreRemoveValue(SCDynamicStoreRef store, CFStringRef key)
+{
+       CFDictionaryRemoveValue(cached_set, key);
+
+       if (!CFArrayContainsValue(cached_removals,
+                                 CFRangeMake(0, CFArrayGetCount(cached_removals)),
+                                 key)) {
+               CFArrayAppendValue(cached_removals, key);
+       }
+
+       return;
+}
+
+
+static void
+cache_SCDynamicStoreNotifyValue(SCDynamicStoreRef store, CFStringRef key)
+{
+       if (!CFArrayContainsValue(cached_notifys,
+                                 CFRangeMake(0, CFArrayGetCount(cached_notifys)),
+                                 key)) {
+               CFArrayAppendValue(cached_notifys, key);
+       }
+
+       return;
+}
+
+
+static void
+cache_write(SCDynamicStoreRef store)
+{
+       if ((CFDictionaryGetCount(cached_set) > 0) ||
+           (CFArrayGetCount(cached_removals) > 0) ||
+           (CFArrayGetCount(cached_notifys)  > 0)) {
+               if (!SCDynamicStoreSetMultiple(store,
+                                              cached_set,
+                                              cached_removals,
+                                              cached_notifys)) {
+                       SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
+               }
+       }
+
+       return;
+}
+
+
+__private_extern__
+void
+cache_close(void)
+{
+       if (!use_cache) {
+               return;
+       }
+
+       CFRelease(cached_keys);
+       CFRelease(cached_set);
+       CFRelease(cached_removals);
+       CFRelease(cached_notifys);
+
+       use_cache = FALSE;
+       return;
+}
+
+
+#pragma mark -
+#pragma mark SCDynamicStore operations
+
+
+__private_extern__
+void
+do_block(int argc, char **argv)
+{
+       Boolean         enable  = FALSE;
+
+       if (argc >= 1) {
+               if        ((strcasecmp(argv[0], "begin") == 0) ||
+                          (strcasecmp(argv[0], "start") == 0) ||
+                          (strcasecmp(argv[0], "on"   ) == 0) ||
+                          (strcasecmp(argv[0], "1"    ) == 0)) {
+                       enable = TRUE;
+               } else if ((strcasecmp(argv[0], "end"  ) == 0) ||
+                          (strcasecmp(argv[0], "stop" ) == 0) ||
+                          (strcasecmp(argv[0], "off"  ) == 0) ||
+                          (strcasecmp(argv[0], "0"    ) == 0)) {
+                       enable = FALSE;
+               } else {
+                       SCPrint(TRUE, stdout, CFSTR("invalid value\n"));
+                       return;
+               }
+       } else {
+               enable = !use_cache;    // toggle
+       }
+
+       if (enable) {
+               // begin block of SCDynamicStore operations
+               if (use_cache) {
+                       SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(kSCStatusLocked));
+                       return;
+               }
+
+               SCPrint(TRUE, stdout, CFSTR("Begin block of SCDynamicStore operations\n"));
+
+               cache_open();
+       } else {
+               CFIndex n;
+
+               // end block of SCDynamicStore operations
+               if (!use_cache) {
+                       SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(kSCStatusNeedLock));
+                       return;
+               }
+
+               n = CFDictionaryGetCount(cached_keys) +
+                   CFArrayGetCount(cached_removals)  +
+                   CFArrayGetCount(cached_notifys);
+               SCPrint(TRUE, stdout,
+                       CFSTR("End block of SCDynamicStore operations%s\n"),
+                       (n > 0) ? ", posting changes" : "");
+               if (n > 0) {
+                       cache_write(store);
+               }
+               cache_close();
+       }
+
+       return;
+}
 
 
 static CFComparisonResult
@@ -43,6 +265,10 @@ sort_keys(const void *p1, const void *p2, void *context) {
 }
 
 
+#define        N_QUICK 64
+
+
+__private_extern__
 void
 do_list(int argc, char **argv)
 {
@@ -54,13 +280,44 @@ do_list(int argc, char **argv)
 
        pattern = CFStringCreateWithCString(NULL,
                                            (argc >= 1) ? argv[0] : ".*",
-                                           kCFStringEncodingMacRoman);
+                                           kCFStringEncodingUTF8);
 
        list = SCDynamicStoreCopyKeyList(store, pattern);
        CFRelease(pattern);
-       if (!list) {
-               SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
-               return;
+       if (list == NULL) {
+               if (SCError() != kSCStatusOK) {
+                       SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
+                       return;
+               } else {
+                   if (!use_cache) {
+                       SCPrint(TRUE, stdout, CFSTR("  no keys.\n"));
+                       return;
+                   } else {
+                       CFIndex n;
+
+                       n = CFDictionaryGetCount(cached_set);
+                       if (n > 0) {
+                               const void *    cachedKeys_q[N_QUICK];
+                               const void **   cachedKeys      = cachedKeys_q;
+
+                               if (n > (CFIndex)(sizeof(cachedKeys_q) / sizeof(CFStringRef))) {
+                                       cachedKeys = CFAllocatorAllocate(NULL, n * sizeof(CFStringRef), 0);
+                               }
+                               CFDictionaryGetKeysAndValues(cached_set, cachedKeys, NULL);
+                               list = CFArrayCreate(NULL, cachedKeys, n, &kCFTypeArrayCallBacks);
+                               if (cachedKeys != cachedKeys_q) {
+                                       CFAllocatorDeallocate(NULL, cachedKeys);
+                               }
+                       } else {
+                               SCPrint(TRUE, stdout, CFSTR("  no keys.\n"));
+                               return;
+                       }
+                   }
+               }
+       } else if (use_cache &&
+                  ((CFDictionaryGetCount(cached_set) > 0) || (CFArrayGetCount(cached_removals) > 0))) {
+               SCPrint(TRUE, stdout,
+                       CFSTR("  Note: SCDynamicStore transactions in progress, key list (below) may be out of date.\n\n"));
        }
 
        listCnt = CFArrayGetCount(list);
@@ -72,7 +329,7 @@ do_list(int argc, char **argv)
                          NULL);
 
        if (listCnt > 0) {
-               for (i=0; i<listCnt; i++) {
+               for (i = 0; i < listCnt; i++) {
                        SCPrint(TRUE,
                                stdout,
                                CFSTR("  subKey [%d] = %@\n"),
@@ -80,7 +337,7 @@ do_list(int argc, char **argv)
                                CFArrayGetValueAtIndex(sortedList, i));
                }
        } else {
-               SCPrint(TRUE, stdout, CFSTR("  no subKey's.\n"));
+               SCPrint(TRUE, stdout, CFSTR("  no keys.\n"));
        }
        CFRelease(sortedList);
 
@@ -88,20 +345,50 @@ do_list(int argc, char **argv)
 }
 
 
+__private_extern__
 void
 do_add(int argc, char **argv)
 {
        CFStringRef     key;
 
-       key    = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman);
+       key    = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
 
        if (argc < 2) {
-               if (!SCDynamicStoreAddValue(store, key, value)) {
-                       SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
+               if (!use_cache) {
+                       if (!SCDynamicStoreAddValue(store, key, value)) {
+                               SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
+                       }
+               } else {
+                       CFTypeRef       val;
+
+                       val = cache_SCDynamicStoreCopyValue(store, key);
+                       if (val != NULL) {
+                               CFRelease(val);
+                               SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(kSCStatusKeyExists));
+                       } else {
+                               cache_SCDynamicStoreSetValue(store, key, value);
+                       }
                }
        } else {
-               if (!SCDynamicStoreAddTemporaryValue(store, key, value)) {
-                       SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
+               if (!use_cache) {
+                       if (!SCDynamicStoreAddTemporaryValue(store, key, value)) {
+                               SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
+                       }
+               } else {
+                       CFTypeRef       val;
+
+                       val = cache_SCDynamicStoreCopyValue(store, key);
+                       if (val != NULL) {
+                               CFRelease(val);
+                               SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(kSCStatusKeyExists));
+                       } else {
+                               if (!SCDynamicStoreAddTemporaryValue(store, key, value)) {
+                                       SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
+                               } else {
+                                       // and save the temp value in the cache too!
+                                       cache_SCDynamicStoreSetValue(store, key, value);
+                               }
+                       }
                }
        }
 
@@ -110,16 +397,21 @@ do_add(int argc, char **argv)
 }
 
 
+__private_extern__
 void
 do_get(int argc, char **argv)
 {
        CFStringRef             key;
        CFPropertyListRef       newValue;
 
-       key      = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman);
-       newValue = SCDynamicStoreCopyValue(store, key);
+       key      = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
+       if (!use_cache) {
+               newValue = SCDynamicStoreCopyValue(store, key);
+       } else {
+               newValue = cache_SCDynamicStoreCopyValue(store, key);
+       }
        CFRelease(key);
-       if (!newValue) {
+       if (newValue == NULL) {
                SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
                return;
        }
@@ -133,30 +425,85 @@ do_get(int argc, char **argv)
 }
 
 
+__private_extern__
 void
 do_set(int argc, char **argv)
 {
        CFStringRef     key;
 
-       key    = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman);
-       if (!SCDynamicStoreSetValue(store, key, value)) {
-               SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
+       key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
+       if (!use_cache) {
+               if (!SCDynamicStoreSetValue(store, key, value)) {
+                       SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
+               }
+       } else {
+               cache_SCDynamicStoreSetValue(store, key, value);
        }
        CFRelease(key);
        return;
 }
 
 
+__private_extern__
 void
 do_show(int argc, char **argv)
 {
        CFStringRef             key;
        CFPropertyListRef       newValue;
 
-       key      = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman);
-       newValue = SCDynamicStoreCopyValue(store, key);
+       key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
+
+       if (argc == 1) {
+               if (!use_cache) {
+                       newValue = SCDynamicStoreCopyValue(store, key);
+               } else {
+                       newValue = cache_SCDynamicStoreCopyValue(store, key);
+               }
+       } else {
+               CFArrayRef      patterns;
+
+               patterns = CFArrayCreate(NULL, (const void **)&key, 1, &kCFTypeArrayCallBacks);
+               if (!use_cache) {
+                       newValue = SCDynamicStoreCopyMultiple(store, NULL, patterns);
+               } else {
+                       CFArrayRef              keys;
+                       CFMutableDictionaryRef  newDict;
+
+                       newDict = CFDictionaryCreateMutable(NULL,
+                                                           0,
+                                                           &kCFTypeDictionaryKeyCallBacks,
+                                                           &kCFTypeDictionaryValueCallBacks);
+                       keys = SCDynamicStoreCopyKeyList(store, key);
+                       if (keys != NULL) {
+                               CFIndex         i;
+                               CFIndex         n;
+
+                               n = CFArrayGetCount(keys);
+                               for (i = 0; i < n; i++) {
+                                       CFStringRef     storeKey;
+                                       CFTypeRef       storeVal;
+
+                                       storeKey = CFArrayGetValueAtIndex(keys, i);
+                                       storeVal = cache_SCDynamicStoreCopyValue(store, storeKey);
+                                       if (storeVal != NULL) {
+                                               CFDictionarySetValue(newDict, storeKey, storeVal);
+                                               CFRelease(storeVal);
+                                       }
+                               }
+                               CFRelease(keys);
+                       }
+
+                       if ((CFDictionaryGetCount(cached_set) > 0) || (CFArrayGetCount(cached_removals) > 0)) {
+                               SCPrint(TRUE, stdout, CFSTR("  Note: SCDynamicStore locked, keys included (below) may be out of date.\n\n"));
+                       }
+
+                       newValue = newDict;
+               }
+               CFRelease(patterns);
+       }
+
        CFRelease(key);
-       if (!newValue) {
+       if (newValue == NULL) {
                SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
                return;
        }
@@ -167,42 +514,38 @@ do_show(int argc, char **argv)
 }
 
 
+__private_extern__
 void
 do_remove(int argc, char **argv)
 {
        CFStringRef     key;
 
-       key    = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman);
-       if (!SCDynamicStoreRemoveValue(store, key)) {
-               SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
+       key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
+       if (!use_cache) {
+               if (!SCDynamicStoreRemoveValue(store, key)) {
+                       SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
+               }
+       } else {
+               cache_SCDynamicStoreRemoveValue(store, key);
        }
        CFRelease(key);
        return;
 }
 
 
+__private_extern__
 void
 do_notify(int argc, char **argv)
 {
        CFStringRef     key;
 
-       key    = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman);
-       if (!SCDynamicStoreNotifyValue(store, key)) {
-               SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
-       }
-       CFRelease(key);
-       return;
-}
-
-
-void
-do_touch(int argc, char **argv)
-{
-       CFStringRef     key;
-
-       key    = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman);
-       if (!SCDynamicStoreTouchValue(store, key)) {
-               SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
+       key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
+       if (!use_cache) {
+               if (!SCDynamicStoreNotifyValue(store, key)) {
+                       SCPrint(TRUE, stdout, CFSTR("  %s\n"), SCErrorString(SCError()));
+               }
+       } else {
+               cache_SCDynamicStoreNotifyValue(store, key);
        }
        CFRelease(key);
        return;