2 * Copyright (c) 2015 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 #include <CacheDelete/CacheDelete.h>
25 #include <CoreFoundation/CoreFoundation.h>
29 /* CacheDelete ID (stored in cache delete plist). Must match suggested CacheDelete id naming conventions. */
30 #define CACHE_DELETE_ID "com.apple.activity_tracing.cache-delete"
32 #define CFSTR_FROM_DICT(dict, key) ({ \
33 void *strRef = NULL; \
35 strRef = (void *)CFDictionaryGetValue(dict, key); \
36 if ((strRef == NULL) || (CFStringGetTypeID() != CFGetTypeID(strRef))) strRef = NULL; \
38 (CFStringRef)strRef; \
41 #define INT64_FROM_DICT(dict, key) ({ \
44 void *numRef = (void *)CFDictionaryGetValue(dict, key); \
45 if (numRef && (CFNumberGetTypeID() == CFGetTypeID(numRef))) {\
46 if (!CFNumberGetValue(numRef, kCFNumberSInt64Type, &value)) value = 0; \
56 int status
= cache_delete_task(true, &psize
);
57 if (status
== 0) return (uint64_t)psize
;
62 _purge(int64_t purge_amount_bytes
, CacheDeleteUrgency urgency
)
64 size_t curr_size
, new_size
;
67 int status
= cache_delete_task(true, &curr_size
);
68 if (status
!= 0) return 0;
70 new_size
= curr_size
- purge_amount_bytes
;
72 status
= cache_delete_task(false, &new_size
);
73 if (status
== 0) return new_size
;
79 _volume_contains_cached_data(CFStringRef volume
)
85 static CFDictionaryRef
86 _handle_cache_delete_with_urgency(CFDictionaryRef info
, CacheDeleteUrgency urgency
, bool purge
)
88 xpc_transaction_begin();
90 uint64_t amount_requested
= INT64_FROM_DICT(info
, CFSTR(CACHE_DELETE_AMOUNT_KEY
));
91 CFStringRef volume_requested
= CFSTR_FROM_DICT(info
, CFSTR(CACHE_DELETE_VOLUME_KEY
));
93 CFMutableDictionaryRef result
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
98 else if (volume_requested
== NULL
)
103 /* TODO: CFStringGetCStringPtr can return NULL */
104 // debug_log(ASL_LEVEL_DEBUG, "CacheDelete request (purge=%d, urgency=%d, volume=%s, amount=%llu).", (int)urgency, CFStringGetCStringPtr(volume_requested, kCFStringEncodingUTF8), amount_requested);
106 int64_t amount_purged
= 0;
108 if (_volume_contains_cached_data(volume_requested
))
112 amount_purged
= _purge(amount_requested
, urgency
);
113 // debug_log(ASL_LEVEL_WARNING, "Purged %lld bytes.", amount_purged);
117 amount_purged
= _purgeable();
118 // debug_log(ASL_LEVEL_WARNING, "%lld bytes of purgeable space.", amount_purged);
122 CFNumberRef amount_purged_obj
= CFNumberCreate(NULL
, kCFNumberSInt64Type
, &amount_purged
);
123 if (amount_purged_obj
!= NULL
)
125 CFDictionaryAddValue(result
, CFSTR(CACHE_DELETE_AMOUNT_KEY
), amount_purged_obj
);
126 CFRelease(amount_purged_obj
);
131 xpc_transaction_end();
136 cache_delete_register(void)
138 return CacheDeleteRegisterInfoCallbacks(CFSTR(CACHE_DELETE_ID
), ^CFDictionaryRef(CacheDeleteUrgency urgency
, CFDictionaryRef info
) {
139 /* Purgeable Space Request */
140 return _handle_cache_delete_with_urgency(info
, urgency
, false);
141 }, ^CFDictionaryRef(CacheDeleteUrgency urgency
, CFDictionaryRef info
) {
143 return _handle_cache_delete_with_urgency(info
, urgency
, true);