Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 151 lines (127 sloc) 4.458 kB
c3d8254 Add a command-line tool that can generate and apply a binary delta be…
Mark Rowe authored
1 //
2 // SUBinaryDeltaCommon.m
3 // Sparkle
4 //
5 // Created by Mark Rowe on 2009-06-01.
6 // Copyright 2009 Mark Rowe. All rights reserved.
7 //
8
9 #include "SUBinaryDeltaCommon.h"
10 #include <CommonCrypto/CommonDigest.h>
11 #include <Foundation/Foundation.h>
12 #include <fcntl.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <sys/mman.h>
16 #include <sys/param.h>
17 #include <sys/stat.h>
18
19 int compareFiles(const FTSENT **a, const FTSENT **b)
20 {
21 return strcoll((*a)->fts_name, (*b)->fts_name);
22 }
23
24 NSString *pathRelativeToDirectory(NSString *directory, NSString *path)
25 {
26 NSUInteger directoryLength = [directory length];
27 if ([path hasPrefix:directory])
28 return [path substringFromIndex:directoryLength];
29
30 return path;
31 }
32
33 NSString *temporaryFilename(NSString *base)
34 {
35 NSString *template = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.XXXXXXXXXX", base]];
36 char buffer[MAXPATHLEN];
37 strcpy(buffer, [template fileSystemRepresentation]);
38 return [NSString stringWithUTF8String:mktemp(buffer)];
39 }
40
41 static void _hashOfBuffer(unsigned char *hash, const char* buffer, size_t bufferLength)
42 {
43 assert(bufferLength <= UINT32_MAX);
44 CC_SHA1_CTX hashContext;
45 CC_SHA1_Init(&hashContext);
46 CC_SHA1_Update(&hashContext, buffer, (CC_LONG)bufferLength);
47 CC_SHA1_Final(hash, &hashContext);
48 }
49
50 static void _hashOfFile(unsigned char* hash, FTSENT *ent)
51 {
52 if (ent->fts_info == FTS_SL) {
53 char linkDestination[MAXPATHLEN + 1];
54 size_t linkDestinationLength = readlink(ent->fts_path, linkDestination, MAXPATHLEN);
55 if (linkDestinationLength < 0) {
56 perror("readlink");
57 return;
58 }
59
60 _hashOfBuffer(hash, linkDestination, linkDestinationLength);
61 return;
62 }
63
64 if (ent->fts_info == FTS_F) {
65 int fileDescriptor = open(ent->fts_path, O_RDONLY);
66 if (fileDescriptor == -1) {
67 perror("open");
68 return;
69 }
70
3ff2d82 Fix warnings and binary compatibility issues that crop up when buildi…
Mark Rowe authored
71 size_t fileSize = (size_t)ent->fts_statp->st_size;
c3d8254 Add a command-line tool that can generate and apply a binary delta be…
Mark Rowe authored
72 void *buffer = mmap(0, fileSize, PROT_READ, MAP_FILE | MAP_PRIVATE, fileDescriptor, 0);
73 if (buffer == (void*)-1) {
74 close(fileDescriptor);
75 perror("mmap");
76 return;
77 }
78
79 _hashOfBuffer(hash, buffer, fileSize);
80 munmap(buffer, fileSize);
81 close(fileDescriptor);
82 return;
83 }
84
85 if (ent->fts_info == FTS_D)
86 memset(hash, 0xdd, CC_SHA1_DIGEST_LENGTH);
87 }
88
89 NSData *hashOfFile(FTSENT *ent)
90 {
91 unsigned char fileHash[CC_SHA1_DIGEST_LENGTH];
92 _hashOfFile(fileHash, ent);
93 return [NSData dataWithBytes:fileHash length:CC_SHA1_DIGEST_LENGTH];
94 }
95
96 NSString *hashOfTree(NSString *path)
97 {
98 const char *sourcePaths[] = {[path UTF8String], 0};
99 FTS *fts = fts_open((char* const*)sourcePaths, FTS_PHYSICAL | FTS_NOCHDIR, compareFiles);
100 if (!fts) {
101 perror("fts_open");
102 return nil;
103 }
104
105 CC_SHA1_CTX hashContext;
106 CC_SHA1_Init(&hashContext);
107
108 FTSENT *ent = 0;
109 while ((ent = fts_read(fts))) {
110 if (ent->fts_info != FTS_F && ent->fts_info != FTS_SL)
111 continue;
112
113 unsigned char fileHash[CC_SHA1_DIGEST_LENGTH];
114 _hashOfFile(fileHash, ent);
115 CC_SHA1_Update(&hashContext, fileHash, sizeof(fileHash));
116
117 NSString *relativePath = pathRelativeToDirectory(path, [NSString stringWithUTF8String:ent->fts_path]);
118 NSData *relativePathBytes = [relativePath dataUsingEncoding:NSUTF8StringEncoding];
119 CC_SHA1_Update(&hashContext, [relativePathBytes bytes], (uint32_t)[relativePathBytes length]);
120 }
121 fts_close(fts);
122
123 unsigned char hash[CC_SHA1_DIGEST_LENGTH];
124 CC_SHA1_Final(hash, &hashContext);
125
126 char hexHash[CC_SHA1_DIGEST_LENGTH * 2 + 1];
127 size_t i;
128 for (i = 0; i < CC_SHA1_DIGEST_LENGTH; i++)
129 sprintf(hexHash + i * 2, "%02x", hash[i]);
130
131 return [NSString stringWithUTF8String:hexHash];
132 }
133
134 void removeTree(NSString *path)
135 {
136 #if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4
137 [[NSFileManager defaultManager] removeItemAtPath:path error:0];
138 #else
139 [[NSFileManager defaultManager] removeFileAtPath:path handler:nil];
140 #endif
141 }
142
143 void copyTree(NSString *source, NSString *dest)
144 {
145 #if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4
146 [[NSFileManager defaultManager] copyItemAtPath:source toPath:dest error:0];
147 #else
148 [[NSFileManager defaultManager] copyPath:source toPath:dest handler:nil];
149 #endif
150 }
Something went wrong with that request. Please try again.