Skip to content

Instantly share code, notes, and snippets.

@steipete
Created July 16, 2015 08:08
Show Gist options
  • Save steipete/56ead1db6c81dd8134c8 to your computer and use it in GitHub Desktop.
Save steipete/56ead1db6c81dd8134c8 to your computer and use it in GitHub Desktop.
After playing around with dispatch_io (https://gist.github.com/steipete/b22babbf3014e29c19f0), I ended up with this. Upside: Uses way less memory, controllable caching, similar performance, simpler code and supports priority donation implicitly since everything's sync.
static NSData *PSPDFCalculateSHA256FromFileURL(NSURL *fileURL, CC_LONG dataLength, NSError **error) {
NSCParameterAssert(fileURL);
NSData *shaData;
int fd = open(fileURL.path.UTF8String, O_RDONLY);
if (fd < 0) {
if (error) *error = [NSError pspdf_errorWithCode:PSPDFErrorCodeUnableToOpenPDF description:@"Failed to open file for calculating SHA256."];
return nil;
}
// Disable cache, since we only need this once.
fcntl(fd, F_NOCACHE, 1);
// Enable read-ahead so system fetches data while we calculate the SHA.
fcntl(fd, F_RDAHEAD, 1);
// Prepare SHA hash
CC_SHA256_CTX ctx;
CC_SHA256_Init(&ctx);
// Start read and block until we are done.
size_t const bufferSize = 1024*1025*4;
char *buffer;
if (!(buffer = malloc(bufferSize * sizeof(char)))) {
if (error) *error = [NSError pspdf_errorWithCode:PSPDFErrorCodeOutOfMemory description:@"Unable to allocate buffer for calculating hash."];
goto cleanup;
}
errno = 0; // just to be safe
size_t bytes = 0;
while (dataLength > 0) {
ssize_t bytes_read_max = MIN(bufferSize, dataLength);
ssize_t bytes_read = read(fd, buffer, bytes_read_max);
if (bytes_read == -1) {
if (errno == EINTR)
continue;
}
if (bytes_read <= 0) {
if (error) *error = [NSError pspdf_errorWithCode:PSPDFErrorCodeUnableToOpenPDF description:[NSString stringWithFormat:@"Failed to read data for calculating SHA256. errno: %d", errno]];
goto cleanup;
} else {
CC_SHA256_Update(&ctx, (const void *)buffer, (CC_LONG)bytes_read);
}
bytes += bytes_read;
dataLength -= bytes_read;
}
// Finalize SHA256 calculation unless there's an error.
unsigned char sha256[CC_SHA256_DIGEST_LENGTH];
CC_SHA256_Final(sha256, &ctx);
shaData = [NSData dataWithBytes:sha256 length:CC_SHA256_DIGEST_LENGTH];
cleanup:
free(buffer);
close(fd);
return shaData;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment