md5: Don't symlink non working bins, setuid appropriate bins
[apple_cmds.git] / text_cmds / md5 / commoncrypto.c
1 /* Generic CommonDigest wrappers to match the semantics of libmd. */
2
3 #include <dispatch/dispatch.h>
4 #include <os/assumes.h>
5 #include <errno.h>
6 #include <fcntl.h>
7
8 #include "commoncrypto.h"
9
10 #define CHUNK_SIZE (10 * 1024 * 1024)
11
12 char *
13 Digest_End(CCDigestRef ctx, char *buf)
14 {
15 static const char hex[] = "0123456789abcdef";
16 uint8_t digest[32]; // SHA256 is the biggest
17 size_t i, length;
18
19 (void)os_assumes_zero(CCDigestFinal(ctx, digest));
20 length = CCDigestOutputSize(ctx);
21 os_assert(length <= sizeof(digest));
22 for (i = 0; i < length; i++) {
23 buf[i+i] = hex[digest[i] >> 4];
24 buf[i+i+1] = hex[digest[i] & 0x0f];
25 }
26 buf[i+i] = '\0';
27 return buf;
28 }
29
30 char *
31 Digest_Data(CCDigestAlg algorithm, const void *data, size_t len, char *buf)
32 {
33 CCDigestCtx ctx;
34
35 (void)os_assumes_zero(CCDigestInit(algorithm, &ctx));
36 (void)os_assumes_zero(CCDigestUpdate(&ctx, data, len));
37 return Digest_End(&ctx, buf);
38 }
39
40 char *
41 Digest_File(CCDigestAlg algorithm, const char *filename, char *buf)
42 {
43 int fd;
44 __block CCDigestCtx ctx;
45 dispatch_queue_t queue;
46 dispatch_semaphore_t sema;
47 dispatch_io_t io;
48 __block int s_error = 0;
49 __block bool eof = false;
50 off_t chunk_offset;
51
52 /* dispatch_io_create_with_path requires an absolute path */
53 fd = open(filename, O_RDONLY);
54 if (fd < 0) {
55 return NULL;
56 }
57
58 (void)fcntl(fd, F_NOCACHE, 1);
59
60 (void)os_assumes_zero(CCDigestInit(algorithm, &ctx));
61
62 queue = dispatch_queue_create("com.apple.mtree.io", NULL);
63 os_assert(queue);
64 sema = dispatch_semaphore_create(0);
65 os_assert(sema);
66
67 io = dispatch_io_create(DISPATCH_IO_STREAM, fd, queue, ^(int error) {
68 if (error != 0) {
69 s_error = error;
70 }
71 (void)close(fd);
72 (void)dispatch_semaphore_signal(sema);
73 });
74 os_assert(io);
75 for (chunk_offset = 0; eof == false && s_error == 0; chunk_offset += CHUNK_SIZE) {
76 dispatch_io_read(io, chunk_offset, CHUNK_SIZE, queue, ^(bool done, dispatch_data_t data, int error) {
77 if (data != NULL) {
78 (void)dispatch_data_apply(data, ^(__unused dispatch_data_t region, __unused size_t offset, const void *buffer, size_t size) {
79 (void)os_assumes_zero(CCDigestUpdate(&ctx, buffer, size));
80 return (bool)true;
81 });
82 }
83
84 if (error != 0) {
85 s_error = error;
86 }
87
88 if (done) {
89 eof = (data == dispatch_data_empty);
90 dispatch_semaphore_signal(sema);
91 }
92 });
93 dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
94 }
95 dispatch_release(io); // it will close on its own
96
97 (void)dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
98
99 dispatch_release(queue);
100 dispatch_release(sema);
101
102 if (s_error != 0) {
103 errno = s_error;
104 return NULL;
105 }
106
107 return Digest_End(&ctx, buf);
108 }