5 // Created by Richard Murphy on 1/29/15.
9 #include "SOSGenCount.h"
10 #include <utilities/SecCFWrappers.h>
11 #include <CoreFoundation/CFLocale.h>
12 #include <utilities/der_plist.h>
13 #include <utilities/der_plist_internal.h>
16 static CFAbsoluteTime
SOSGenerationCountGetDateBits(int64_t genValue
) {
17 return (uint32_t) ((((uint64_t) genValue
) >> 32) << 1);
20 void SOSGenerationCountWithDescription(SOSGenCountRef gen
, void (^operation
)(CFStringRef description
)) {
21 CFStringRef description
= SOSGenerationCountCopyDescription(gen
);
23 operation(description
);
25 CFReleaseSafe(description
);
28 CFStringRef
SOSGenerationCountCopyDescription(SOSGenCountRef gen
) {
29 int64_t value
= SOSGetGenerationSint(gen
);
31 CFMutableStringRef gcDecsription
= CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, CFSTR("["));
33 withStringOfAbsoluteTime(SOSGenerationCountGetDateBits(value
), ^(CFStringRef decription
) {
34 CFStringAppend(gcDecsription
, decription
);
37 CFStringAppendFormat(gcDecsription
, NULL
, CFSTR(" %u]"), (uint32_t)(value
& 0xFFFFFFFF));
42 int64_t SOSGetGenerationSint(SOSGenCountRef gen
) {
45 CFNumberGetValue(gen
, kCFNumberSInt64Type
, &value
);
49 static int64_t sosGenerationSetHighBits(int64_t value
, int32_t high_31
)
51 value
&= 0xFFFFFFFF; // Keep the low 32 bits.
52 value
|= ((int64_t) high_31
) << 32;
57 static SOSGenCountRef
sosGenerationCreateOrIncrement(SOSGenCountRef gen
) {
61 value
= SOSGetGenerationSint(gen
);
64 if((value
>> 32) == 0) {
65 uint32_t seconds
= CFAbsoluteTimeGetCurrent(); // seconds
66 value
= sosGenerationSetHighBits(value
, (seconds
>> 1));
70 return CFNumberCreate(NULL
, kCFNumberSInt64Type
, &value
);
73 SOSGenCountRef
SOSGenerationCreate() {
74 return sosGenerationCreateOrIncrement(NULL
);
78 // We need this for a circle gencount test
79 SOSGenCountRef
SOSGenerationCreateWithValue(int64_t value
) {
80 return CFNumberCreate(NULL
, kCFNumberSInt64Type
, &value
);
83 SOSGenCountRef
SOSGenerationIncrementAndCreate(SOSGenCountRef gen
) {
84 return sosGenerationCreateOrIncrement(gen
);
87 SOSGenCountRef
SOSGenerationCopy(SOSGenCountRef gen
) {
89 int64_t value
= SOSGetGenerationSint(gen
);
90 return CFNumberCreate(NULL
, kCFNumberSInt64Type
, &value
);
93 // Is current older than proposed?
94 bool SOSGenerationIsOlder(SOSGenCountRef older
, SOSGenCountRef newer
) {
95 switch(CFNumberCompare(older
, newer
, NULL
)) {
96 case kCFCompareLessThan
: return true;
97 case kCFCompareEqualTo
: return false;
98 case kCFCompareGreaterThan
: return false;
103 // Is current older than proposed?
104 static bool SOSGenerationIsOlderOrEqual(SOSGenCountRef older
, SOSGenCountRef newer
) {
105 switch(CFNumberCompare(older
, newer
, NULL
)) {
106 case kCFCompareLessThan
: return true;
107 case kCFCompareEqualTo
: return true;
108 case kCFCompareGreaterThan
: return false;
114 SOSGenCountRef
SOSGenerationCreateWithBaseline(SOSGenCountRef reference
) {
115 SOSGenCountRef retval
= SOSGenerationCreate();
116 if(SOSGenerationIsOlderOrEqual(retval
, reference
)) {
117 CFReleaseNull(retval
);
118 retval
= SOSGenerationIncrementAndCreate(reference
);
124 SOSGenCountRef
SOSGenCountCreateFromDER(CFAllocatorRef allocator
, CFErrorRef
* error
,
125 const uint8_t** der_p
, const uint8_t *der_end
) {
126 SOSGenCountRef retval
= NULL
;
127 *der_p
= der_decode_number(allocator
, &retval
, error
, *der_p
, der_end
);
129 retval
= SOSGenerationCreate();
133 size_t SOSGenCountGetDEREncodedSize(SOSGenCountRef gencount
, CFErrorRef
*error
) {
134 return der_sizeof_number(gencount
, error
);
137 uint8_t *SOSGenCountEncodeToDER(SOSGenCountRef gencount
, CFErrorRef
* error
, const uint8_t* der
, uint8_t* der_end
) {
138 return der_encode_number(gencount
, error
, der
, der_end
);