From c30f6fe7fb7e7bb5b4e5015fa8abbb04006ccea3 Mon Sep 17 00:00:00 2001 From: Zorg Date: Tue, 18 Jan 2022 00:04:40 -0800 Subject: [PATCH] Calculate hash of file for delta updates without using mmap (#2067) --- Autoupdate/SUBinaryDeltaCommon.m | 57 ++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/Autoupdate/SUBinaryDeltaCommon.m b/Autoupdate/SUBinaryDeltaCommon.m index 1975f923..13662464 100644 --- a/Autoupdate/SUBinaryDeltaCommon.m +++ b/Autoupdate/SUBinaryDeltaCommon.m @@ -165,7 +165,7 @@ static void _hashOfBuffer(unsigned char *hash, const char *buffer, ssize_t buffe CC_SHA1_Final(hash, &hashContext); } -static BOOL _hashOfFileContents(unsigned char *hash, FTSENT *ent) +static BOOL _hashOfFileContents(unsigned char *hash, FTSENT *ent, void *tempBuffer, size_t tempBufferSize) { if (ent->fts_info == FTS_SL) { char linkDestination[MAXPATHLEN + 1]; @@ -177,27 +177,37 @@ static BOOL _hashOfFileContents(unsigned char *hash, FTSENT *ent) _hashOfBuffer(hash, linkDestination, linkDestinationLength); } else if (ent->fts_info == FTS_F) { - int fileDescriptor = open(ent->fts_path, O_RDONLY); - if (fileDescriptor == -1) { - perror("open"); - return NO; - } - ssize_t fileSize = ent->fts_statp->st_size; - if (fileSize == 0) { + if (fileSize <= 0) { _hashOfBuffer(hash, NULL, 0); } else { - void *buffer = mmap(0, (size_t)fileSize, PROT_READ, MAP_FILE | MAP_PRIVATE, fileDescriptor, 0); - if (buffer == (void *)-1) { - close(fileDescriptor); - perror("mmap"); + FILE *file = fopen(ent->fts_path, "rb"); + if (file == NULL) { + perror("fopen"); return NO; } - - _hashOfBuffer(hash, buffer, fileSize); - munmap(buffer, (size_t)fileSize); + + CC_SHA1_CTX hashContext; + CC_SHA1_Init(&hashContext); + + size_t bytesLeft = (size_t)fileSize; + while (bytesLeft > 0) { + size_t bytesToConsume = (bytesLeft >= tempBufferSize) ? tempBufferSize : bytesLeft; + + if (fread(tempBuffer, bytesToConsume, 1, file) < 1) { + perror("fread"); + fclose(file); + return NO; + } + + CC_SHA1_Update(&hashContext, tempBuffer, (CC_LONG)bytesToConsume); + bytesLeft -= bytesToConsume; + } + + CC_SHA1_Final(hash, &hashContext); + + fclose(file); } - close(fileDescriptor); } else if (ent->fts_info == FTS_D) { memset(hash, 0xdd, CC_SHA1_DIGEST_LENGTH); } else { @@ -218,10 +228,18 @@ BOOL getRawHashOfTreeAndFileTablesWithVersion(unsigned char *hashBuffer, NSStrin return NO; } + const size_t tempBufferSize = 16384; + void *tempBuffer = calloc(1, tempBufferSize); + if (tempBuffer == NULL) { + perror("calloc"); + return NO; + } + char *const sourcePaths[] = { pathBuffer, 0 }; FTS *fts = fts_open(sourcePaths, FTS_PHYSICAL | FTS_NOCHDIR, compareFiles); if (!fts) { perror("fts_open"); + free(tempBuffer); return NO; } @@ -241,7 +259,9 @@ BOOL getRawHashOfTreeAndFileTablesWithVersion(unsigned char *hashBuffer, NSStrin continue; unsigned char fileHash[CC_SHA1_DIGEST_LENGTH]; - if (!_hashOfFileContents(fileHash, ent)) { + if (!_hashOfFileContents(fileHash, ent, tempBuffer, tempBufferSize)) { + fts_close(fts); + free(tempBuffer); return NO; } CC_SHA1_Update(&hashContext, fileHash, sizeof(fileHash)); @@ -277,6 +297,9 @@ BOOL getRawHashOfTreeAndFileTablesWithVersion(unsigned char *hashBuffer, NSStrin CC_SHA1_Update(&hashContext, &type, sizeof(type)); CC_SHA1_Update(&hashContext, &hashedPermissions, sizeof(hashedPermissions)); } + + free(tempBuffer); + fts_close(fts); CC_SHA1_Final(hashBuffer, &hashContext);