Reset sync daemon local state if the client version has changed
[pithos-macos] / pithos-macos / FileMD5Hash.c
1 /*
2  *  FileMD5Hash.c
3  *  FileMD5Hash
4  * 
5  *  Copyright © 2010 Joel Lopes Da Silva. All rights reserved.
6  *
7  *  Licensed under the Apache License, Version 2.0 (the "License");
8  *  you may not use this file except in compliance with the License.
9  *  You may obtain a copy of the License at
10  * 
11  *        http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  *  Unless required by applicable law or agreed to in writing, software
14  *  distributed under the License is distributed on an "AS IS" BASIS,
15  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *  See the License for the specific language governing permissions and
17  *  limitations under the License.
18  *
19  */
20
21 //---------------------------------------------------------
22 // Includes
23 //---------------------------------------------------------
24
25 // Header file
26 #include "FileMD5Hash.h"
27
28 // Standard library
29 #include <stdint.h>
30 #include <stdio.h>
31
32 // Core Foundation
33 #include <CoreFoundation/CoreFoundation.h>
34
35 // Cryptography
36 #include <CommonCrypto/CommonDigest.h>
37
38
39 //---------------------------------------------------------
40 // Function definition
41 //---------------------------------------------------------
42
43 CFStringRef FileMD5HashCreateWithPath(CFStringRef filePath,
44                                       size_t chunkSizeForReadingData) {
45     
46     // Declare needed variables
47     CFStringRef result = NULL;
48     CFReadStreamRef readStream = NULL;
49     
50     // Get the file URL
51     CFURLRef fileURL =
52     CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
53                                   (CFStringRef)filePath,
54                                   kCFURLPOSIXPathStyle,
55                                   (Boolean)false);
56     if (!fileURL) goto done;
57     
58     // Create and open the read stream
59     readStream = CFReadStreamCreateWithFile(kCFAllocatorDefault,
60                                             (CFURLRef)fileURL);
61     if (!readStream) goto done;
62     bool didSucceed = (bool)CFReadStreamOpen(readStream);
63     if (!didSucceed) goto done;
64     
65     // Initialize the hash object
66     CC_MD5_CTX hashObject;
67     CC_MD5_Init(&hashObject);
68     
69     // Make sure chunkSizeForReadingData is valid
70     if (!chunkSizeForReadingData) {
71         chunkSizeForReadingData = FileHashDefaultChunkSizeForReadingData;
72     }
73     
74     // Feed the data to the hash object
75     bool hasMoreData = true;
76     while (hasMoreData) {
77         uint8_t buffer[chunkSizeForReadingData];
78         CFIndex readBytesCount = CFReadStreamRead(readStream,
79                                                   (UInt8 *)buffer,
80                                                   (CFIndex)sizeof(buffer));
81         if (readBytesCount == -1) break;
82         if (readBytesCount == 0) {
83             hasMoreData = false;
84             continue;
85         }
86         CC_MD5_Update(&hashObject,
87                       (const void *)buffer,
88                       (CC_LONG)readBytesCount);
89     }
90     
91     // Check if the read operation succeeded
92     didSucceed = !hasMoreData;
93     
94     // Compute the hash digest
95     unsigned char digest[CC_MD5_DIGEST_LENGTH];
96     CC_MD5_Final(digest, &hashObject);
97     
98     // Abort if the read operation failed
99     if (!didSucceed) goto done;
100     
101     // Compute the string result
102     char hash[2 * sizeof(digest) + 1];
103     for (size_t i = 0; i < sizeof(digest); ++i) {
104         snprintf(hash + (2 * i), 3, "%02x", (int)(digest[i]));
105     }
106     result = CFStringCreateWithCString(kCFAllocatorDefault,
107                                        (const char *)hash,
108                                        kCFStringEncodingUTF8);
109     
110 done:
111     
112     if (readStream) {
113         CFReadStreamClose(readStream);
114         CFRelease(readStream);
115     }
116     if (fileURL) {
117         CFRelease(fileURL);
118     }
119     return result;
120 }