-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathNSFileManager+ZKAdditions.m
185 lines (167 loc) · 6.46 KB
/
NSFileManager+ZKAdditions.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
//
// NSFileManager+ZKAdditions.m
// ZipKit
//
// Created by Karl Moskowski on 01/04/09.
//
#import "NSFileManager+ZKAdditions.h"
#import "NSData+ZKAdditions.h"
#import "NSDictionary+ZKAdditions.h"
#if ZK_TARGET_OS_MAC
#import "GMAppleDouble+ZKAdditions.h"
#endif
const NSUInteger ZKMaxEntriesPerFetch = 40;
@implementation NSFileManager (ZKAdditions)
- (BOOL) zk_isSymLinkAtPath:(NSString *) path {
return [[[self attributesOfItemAtPath:path error:nil] fileType] isEqualToString:NSFileTypeSymbolicLink];
}
- (BOOL) zk_isDirAtPath:(NSString *) path {
BOOL isDir;
BOOL pathExists = [self fileExistsAtPath:path isDirectory:&isDir];
return pathExists && isDir;
}
- (unsigned long long) zk_dataSizeAtFilePath:(NSString *) path {
return [[self attributesOfItemAtPath:path error:nil] fileSize];
}
#if ZK_TARGET_OS_MAC
- (void) totalsAtDirectoryFSRef:(FSRef*) fsRef usingResourceFork:(BOOL) rfFlag
totalSize:(unsigned long long *) size
itemCount:(unsigned long long *) count {
FSIterator iterator;
OSErr fsErr = FSOpenIterator(fsRef, kFSIterateFlat, &iterator);
if (fsErr == noErr) {
ItemCount actualFetched;
FSRef fetchedRefs[ZKMaxEntriesPerFetch];
FSCatalogInfo fetchedInfos[ZKMaxEntriesPerFetch];
while (fsErr == noErr) {
fsErr = FSGetCatalogInfoBulk(iterator, ZKMaxEntriesPerFetch, &actualFetched, NULL,
kFSCatInfoDataSizes | kFSCatInfoRsrcSizes | kFSCatInfoNodeFlags,
fetchedInfos, fetchedRefs, NULL, NULL);
if ((fsErr == noErr) || (fsErr == errFSNoMoreItems)) {
(*count) += actualFetched;
for (ItemCount i = 0; i < actualFetched; i++) {
if (fetchedInfos[i].nodeFlags & kFSNodeIsDirectoryMask)
[self totalsAtDirectoryFSRef:&fetchedRefs[i] usingResourceFork:rfFlag totalSize:size itemCount:count];
else
(*size) += fetchedInfos [i].dataLogicalSize + (rfFlag ? fetchedInfos [i].rsrcLogicalSize : 0);
}
}
}
FSCloseIterator(iterator);
}
return ;
}
#endif
- (NSDictionary *) zkTotalSizeAndItemCountAtPath:(NSString *) path usingResourceFork:(BOOL) rfFlag {
unsigned long long size = 0;
unsigned long long count = 0;
#if ZK_TARGET_OS_MAC
FSRef fsRef;
Boolean isDirectory;
OSStatus status = FSPathMakeRef((const unsigned char*)[path fileSystemRepresentation], &fsRef, &isDirectory);
if (status != noErr)
return nil;
if (isDirectory) {
[self totalsAtDirectoryFSRef:&fsRef usingResourceFork:rfFlag totalSize:&size itemCount:&count];
} else {
count = 1;
FSCatalogInfo info;
OSErr fsErr = FSGetCatalogInfo(&fsRef, kFSCatInfoDataSizes | kFSCatInfoRsrcSizes, &info, NULL, NULL, NULL);
if (fsErr == noErr)
size = info.dataLogicalSize + (rfFlag ? info.rsrcLogicalSize : 0);
}
#else
// TODO: maybe fix this for non-Mac targets
size = 0;
count = 0;
#endif
return [NSDictionary zk_totalSizeAndCountDictionaryWithSize:size andItemCount:count];
}
#if ZK_TARGET_OS_MAC
- (void) zk_combineAppleDoubleInDirectory:(NSString *) path {
if (![self zk_isDirAtPath:path])
return;
NSArray *dirContents = [self contentsOfDirectoryAtPath:path error:nil];
for (NSString *entry in dirContents) {
NSString *subPath = [path stringByAppendingPathComponent:entry];
if (![self zk_isSymLinkAtPath:subPath]) {
if ([self zk_isDirAtPath:subPath])
[self zk_combineAppleDoubleInDirectory:subPath];
else {
// if the file is an AppleDouble file (i.e., it begins with "._") in the __MACOSX hierarchy,
// find its corresponding data fork and combine them
if ([subPath rangeOfString:ZKMacOSXDirectory].location != NSNotFound) {
NSString *fileName = [subPath lastPathComponent];
NSRange ZKDotUnderscoreRange = [fileName rangeOfString:ZKDotUnderscore];
if (ZKDotUnderscoreRange.location == 0 && ZKDotUnderscoreRange.length == 2) {
NSMutableArray *pathComponents =
(NSMutableArray *)[[[subPath stringByDeletingLastPathComponent] stringByAppendingPathComponent:
[fileName substringFromIndex:2]] pathComponents];
for (NSString *pathComponent in pathComponents) {
if ([ZKMacOSXDirectory isEqualToString:pathComponent]) {
[pathComponents removeObject:pathComponent];
break;
}
}
NSData *appleDoubleData = [NSData dataWithContentsOfFile:subPath];
[GMAppleDouble zk_restoreAppleDoubleData:appleDoubleData toPath:[NSString pathWithComponents:pathComponents]];
}
}
}
}
}
}
#endif
- (NSDate *) zk_modificationDateForPath:(NSString *) path {
return [[self attributesOfItemAtPath:path error:nil] fileModificationDate];
}
- (NSUInteger) zk_posixPermissionsAtPath:(NSString *) path {
return [[self attributesOfItemAtPath:path error:nil] filePosixPermissions];
}
- (NSUInteger) zk_externalFileAttributesAtPath:(NSString *) path {
return [self zk_externalFileAttributesFor:[self attributesOfItemAtPath:path error:nil]];
}
- (NSUInteger) zk_externalFileAttributesFor:(NSDictionary *) fileAttributes {
NSUInteger externalFileAttributes = 0;
@try {
BOOL isSymLink = [[fileAttributes fileType] isEqualToString:NSFileTypeSymbolicLink];
BOOL isDir = [[fileAttributes fileType] isEqualToString:NSFileTypeDirectory];
NSUInteger posixPermissions = [fileAttributes filePosixPermissions];
externalFileAttributes = posixPermissions << 16 | (isSymLink ? 0xA0004000 : (isDir ? 0x40004000 : 0x80004000));
} @catch(NSException * e) {
externalFileAttributes = 0;
}
return externalFileAttributes;
}
- (NSUInteger) zk_crcForPath:(NSString *) path {
return [self zk_crcForPath:path invoker:nil throttleThreadSleepTime:0.0];
}
- (NSUInteger) zk_crcForPath:(NSString *) path invoker:(id)invoker {
return [self zk_crcForPath:path invoker:invoker throttleThreadSleepTime:0.0];
}
- (NSUInteger) zk_crcForPath:(NSString *)path invoker:(id)invoker throttleThreadSleepTime:(NSTimeInterval) throttleThreadSleepTime {
NSUInteger crc32 = 0;
path = [path stringByExpandingTildeInPath];
BOOL isDirectory;
if ([self fileExistsAtPath:path isDirectory:&isDirectory] && !isDirectory) {
BOOL irtsIsCancelled = [invoker respondsToSelector:@selector(isCancelled)];
const NSUInteger crcBlockSize = 1048576;
NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:path];
NSData *block = [fileHandle readDataOfLength:crcBlockSize] ;
while ([block length] > 0) {
crc32 = [block zk_crc32:crc32];
if (irtsIsCancelled) {
if ([invoker isCancelled]) {
[fileHandle closeFile];
return 0;
}
}
block = [fileHandle readDataOfLength:crcBlockSize];
[NSThread sleepForTimeInterval:throttleThreadSleepTime];
}
[fileHandle closeFile];
} else
crc32 = 0;
return crc32;
}
@end