1#include <dispatch/dispatch.h> 2#include <os/assumes.h> 3#include <errno.h> 4#include <fcntl.h> 5 6#include "commoncrypto.h" 7 8/* Generic version of libmd's *_File() functions. */ 9char * 10Digest_File(CCDigestAlg algorithm, const char *filename, char *buf) 11{ 12 static const char hex[] = "0123456789abcdef"; 13 int fd; 14 __block CCDigestCtx ctx; 15 dispatch_queue_t queue; 16 dispatch_semaphore_t sema; 17 dispatch_io_t io; 18 __block int s_error = 0; 19 uint8_t digest[32]; // SHA256 is the biggest 20 size_t i, length; 21 22 /* dispatch_io_create_with_path requires an absolute path */ 23 fd = open(filename, O_RDONLY); 24 if (fd < 0) { 25 return NULL; 26 } 27 28 (void)fcntl(fd, F_NOCACHE, 1); 29 30 (void)os_assumes_zero(CCDigestInit(algorithm, &ctx)); 31 32 queue = dispatch_queue_create("com.apple.mtree.io", NULL); 33 os_assert(queue); 34 sema = dispatch_semaphore_create(0); 35 os_assert(sema); 36 37 io = dispatch_io_create(DISPATCH_IO_STREAM, fd, queue, ^(int error) { 38 if (error != 0) { 39 s_error = error; 40 } 41 (void)close(fd); 42 (void)dispatch_semaphore_signal(sema); 43 }); 44 os_assert(io); 45 dispatch_io_read(io, 0, SIZE_MAX, queue, ^(__unused bool done, dispatch_data_t data, int error) { 46 if (data != NULL) { 47 (void)dispatch_data_apply(data, ^(__unused dispatch_data_t region, __unused size_t offset, const void *buffer, size_t size) { 48 (void)os_assumes_zero(CCDigestUpdate(&ctx, buffer, size)); 49 return (bool)true; 50 }); 51 } 52 53 if (error != 0) { 54 s_error = error; 55 } 56 }); 57 dispatch_release(io); // it will close on its own 58 59 (void)dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); 60 61 dispatch_release(queue); 62 dispatch_release(sema); 63 64 if (s_error != 0) { 65 errno = s_error; 66 return NULL; 67 } 68 69 /* Finalize and convert to hex. */ 70 (void)os_assumes_zero(CCDigestFinal(&ctx, digest)); 71 length = CCDigestOutputSize(&ctx); 72 os_assert(length <= sizeof(digest)); 73 for (i = 0; i < length; i++) { 74 buf[i+i] = hex[digest[i] >> 4]; 75 buf[i+i+1] = hex[digest[i] & 0x0f]; 76 } 77 buf[i+i] = '\0'; 78 79 return buf; 80} 81