SOSGenCount.c
1 // 2 // SOSGenCount.c 3 // sec 4 // 5 // Created by Richard Murphy on 1/29/15. 6 // 7 // 8 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> 14 15 16 static CFAbsoluteTime SOSGenerationCountGetDateBits(int64_t genValue) { 17 return (uint32_t) ((((uint64_t) genValue) >> 32) << 1); 18 } 19 20 void SOSGenerationCountWithDescription(SOSGenCountRef gen, void (^operation)(CFStringRef description)) { 21 CFStringRef description = SOSGenerationCountCopyDescription(gen); 22 23 operation(description); 24 25 CFReleaseSafe(description); 26 } 27 28 CFStringRef SOSGenerationCountCopyDescription(SOSGenCountRef gen) { 29 int64_t value = SOSGetGenerationSint(gen); 30 31 CFMutableStringRef gcDecsription = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("[")); 32 33 withStringOfAbsoluteTime(SOSGenerationCountGetDateBits(value), ^(CFStringRef decription) { 34 CFStringAppend(gcDecsription, decription); 35 }); 36 37 CFStringAppendFormat(gcDecsription, NULL, CFSTR(" %u]"), (uint32_t)(value & 0xFFFFFFFF)); 38 39 return gcDecsription; 40 } 41 42 int64_t SOSGetGenerationSint(SOSGenCountRef gen) { 43 int64_t value; 44 if(!gen) return 0; 45 CFNumberGetValue(gen, kCFNumberSInt64Type, &value); 46 return value; 47 } 48 49 static int64_t sosGenerationSetHighBits(int64_t value, int32_t high_31) 50 { 51 value &= 0xFFFFFFFF; // Keep the low 32 bits. 52 value |= ((int64_t) high_31) << 32; 53 54 return value; 55 } 56 57 static SOSGenCountRef sosGenerationCreateOrIncrement(SOSGenCountRef gen) { 58 int64_t value = 0; 59 60 if(gen) { 61 value = SOSGetGenerationSint(gen); 62 } 63 64 if((value >> 32) == 0) { 65 uint32_t seconds = CFAbsoluteTimeGetCurrent(); // seconds 66 value = sosGenerationSetHighBits(value, (seconds >> 1)); 67 } 68 69 value++; 70 return CFNumberCreate(NULL, kCFNumberSInt64Type, &value); 71 } 72 73 SOSGenCountRef SOSGenerationCreate() { 74 return sosGenerationCreateOrIncrement(NULL); 75 } 76 77 78 // We need this for a circle gencount test 79 SOSGenCountRef SOSGenerationCreateWithValue(int64_t value) { 80 return CFNumberCreate(NULL, kCFNumberSInt64Type, &value); 81 } 82 83 SOSGenCountRef SOSGenerationIncrementAndCreate(SOSGenCountRef gen) { 84 return sosGenerationCreateOrIncrement(gen); 85 } 86 87 SOSGenCountRef SOSGenerationCopy(SOSGenCountRef gen) { 88 if(!gen) return NULL; 89 int64_t value = SOSGetGenerationSint(gen); 90 return CFNumberCreate(NULL, kCFNumberSInt64Type, &value); 91 } 92 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; 99 } 100 return false; 101 } 102 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; 109 } 110 return false; 111 } 112 113 114 SOSGenCountRef SOSGenerationCreateWithBaseline(SOSGenCountRef reference) { 115 SOSGenCountRef retval = SOSGenerationCreate(); 116 if(SOSGenerationIsOlderOrEqual(retval, reference)) { 117 CFReleaseNull(retval); 118 retval = SOSGenerationIncrementAndCreate(reference); 119 } 120 return retval; 121 } 122 123 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); 128 if(retval == NULL) 129 retval = SOSGenerationCreate(); 130 return retval; 131 } 132 133 size_t SOSGenCountGetDEREncodedSize(SOSGenCountRef gencount, CFErrorRef *error) { 134 return der_sizeof_number(gencount, error); 135 } 136 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); 139 } 140 141 142