Last active
February 22, 2023 09:45
-
-
Save edenwaith/99c56ef39763094a64d5d018087cf1de to your computer and use it in GitHub Desktop.
Multiple ways to calculate the size of a file's resource fork
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* filesize.m | |
* Description: Multiple ways to calculate the size of a file's resource fork | |
* Author: Chad Armstrong | |
* Date: 14 April 2018 (Updated 28 October 2022) | |
* To compile: gcc -w -framework Cocoa filesize.m -o filesize | |
* To run: ./filesize path/to/file | |
*/ | |
/* References: | |
* https://stackoverflow.com/questions/32003590/check-for-resource-fork-in-objective-c | |
* https://github.com/bcpierce00/unison/blob/master/src/osxsupport.c | |
* https://svn.python.org/projects/external/tcl-8.5.11.x/macosx/tclMacOSXFCmd.c | |
* https://stackoverflow.com/questions/19400043/how-to-open-and-read-resource-forks-in-obj-c | |
* http://xahlee.info/UnixResource_dir/macosx.html | |
* http://www.cocoabuilder.com/archive/cocoa/14625-carbon-only.html | |
* https://stackoverflow.com/questions/586928/how-should-i-print-types-like-off-t-and-size-t | |
*/ | |
#import <Cocoa/Cocoa.h> | |
#include <sys/attr.h> | |
#include <sys/xattr.h> // getxattr | |
#include "errno.h" | |
#pragma mark - | |
struct filesizebuf { | |
u_int32_t length; | |
off_t dataForkSize; | |
off_t rsrcForkSize; | |
off_t rsrcForkAllocSize; | |
}; | |
/* | |
struct { | |
unsigned long length; | |
char finderInfo [32]; | |
off_t rsrcLength; | |
} attrBuf; | |
*/ | |
int main (int argc, const char * argv[]) | |
{ | |
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | |
if (argc < 2) { | |
printf("Usage: %s <path_to_file>\n", argv[0]); | |
return EXIT_FAILURE; | |
} | |
const char *path = argv[1]; | |
NSString *pathToFile = [NSString stringWithFormat:@"%s", path]; | |
NSString *pathToResourceFork = [pathToFile stringByAppendingPathComponent: @"..namedfork/rsrc"]; | |
NSFileManager *fm = [NSFileManager defaultManager]; | |
NSError *error = nil; | |
if ([fm fileExistsAtPath: pathToFile] == NO) { | |
NSLog(@"Error: The file %@ does not exist.", pathToFile); | |
return EXIT_FAILURE; | |
} | |
#pragma mark - getxattr | |
// Retrieving extended attributes | |
printf("\n--- getxattr ---\n"); | |
if (getxattr(path, "com.apple.ResourceFork", NULL, 0, 0, 0) != -1) { | |
ssize_t resourceForkSize = getxattr(path, "com.apple.ResourceFork", NULL, 0, 0, 0); | |
printf("resourceForkSize:: %zu\n", resourceForkSize); | |
} else { | |
printf("The path %s does not contain a resource fork.\n", path); | |
} | |
#pragma mark - NSFileManager | |
printf("\n--- NSFileManager ---\n"); | |
// Using NSFileManager and iterating to the resource fork | |
if ([fm fileExistsAtPath: pathToResourceFork] == YES) { | |
NSLog(@"Yes, the path %@ exists", pathToResourceFork); | |
// In older versions of Mac OS X, the path to the resource fork is just /rsrc, not ..namedfork/rsrc | |
NSDictionary *fileAttr = [fm attributesOfItemAtPath: pathToResourceFork error: &error]; | |
if (error != nil) { | |
NSLog(@"Error: %@", [error localizedDescription]); | |
} else { | |
NSNumber *fileSize = [fileAttr objectForKey: NSFileSize]; | |
NSLog(@"resource fork fileSize: %@", fileSize); | |
} | |
} else { | |
NSLog(@"Cannot find the path %@", pathToResourceFork); | |
} | |
#pragma mark - getattrlist | |
// http://www.cocoabuilder.com/archive/cocoa/14625-carbon-only.html | |
printf("\n--- getattrlist ---\n"); | |
// Not working example | |
printf("\n--- Not working example:\n"); | |
int retcode = -1; | |
struct attrlist attrList; | |
struct filesizebuf fsize; | |
unsigned long options = FSOPT_NOFOLLOW | FSOPT_REPORT_FULLSIZE; //0; | |
memset(&attrList, 0, sizeof(attrList)); // some examples show using bzero, instead | |
attrList.bitmapcount = ATTR_BIT_MAP_COUNT; | |
attrList.reserved = 0; | |
attrList.commonattr = 0; // ATTR_CMN_FNDRINFO; | |
attrList.volattr = 0; /* volume attribute group */ | |
attrList.dirattr = 0; /* directory attribute group */ | |
attrList.fileattr = ATTR_FILE_DATALENGTH | ATTR_FILE_RSRCLENGTH | ATTR_FILE_RSRCALLOCSIZE; /* file attribute group */ | |
attrList.forkattr = 0; /* fork attribute group */ | |
retcode = getattrlist(path, &attrList, &fsize, sizeof(fsize), options); | |
if (retcode == -1) { | |
perror("getattrlist"); | |
} else { | |
// https://stackoverflow.com/questions/586928/how-should-i-print-types-like-off-t-and-size-t | |
printf(" Data fork length: %20qu (0x%016qX) bytes\n", fsize.dataForkSize, fsize.dataForkSize); | |
printf(" Resource fork length: %20qu (0x%016qX) bytes\n", fsize.rsrcForkSize, fsize.rsrcForkSize); | |
printf("Resource fork alloc size: %20qu\n", fsize.rsrcForkAllocSize); | |
} | |
// Working example | |
printf("\n--- Working example:\n"); | |
// https://stackoverflow.com/questions/32003590/check-for-resource-fork-in-objective-c | |
struct attrlist attrlist = {0}; | |
attrlist.bitmapcount = ATTR_BIT_MAP_COUNT; | |
attrlist.fileattr = ATTR_FILE_DATALENGTH | ATTR_FILE_RSRCLENGTH; | |
typedef struct __attribute__((__packed__)) { | |
uint32_t size; | |
off_t dataSize; | |
off_t forkSize; | |
} result_t; | |
result_t result = {0}; | |
if (getattrlist (path, &attrlist, &result, sizeof(result), 0) == 0) { | |
assert(sizeof(result)==result.size); // makes sure we got the struct right | |
// now we find the rsrc fork size in result.forkSize | |
printf(" Data fork size: %20qu\n", result.dataSize); | |
printf("Resource fork size: %20qu\n", result.forkSize); | |
} | |
#pragma mark - FSGetCatalogInfo | |
printf("\n--- FSGetCatalogInfo ---\n"); | |
// Note: A number of these methods (CFURLGetFSRefer, FSGetCatalogInfo) have been deprecated | |
unsigned long long totalSize = 0; | |
FSRef fileRef; | |
NSURL *fileURL = [NSURL fileURLWithPath: pathToFile]; | |
// WARNING: 'CFURLGetFSRef' is deprecated: first deprecated in macOS 10.9 | |
if (!CFURLGetFSRef( (CFURLRef)fileURL, &fileRef )) { | |
NSLog( @"Failed to create FSRef." ); | |
} else { | |
FSCatalogInfo fsInfo; | |
// WARNING: 'FSGetCatalogInfo' is deprecated: first deprecated in macOS 10.8 | |
if (FSGetCatalogInfo(&fileRef, kFSCatInfoDataSizes | kFSCatInfoRsrcSizes, &fsInfo, NULL, NULL, NULL) == noErr) | |
{ | |
if (fsInfo.rsrcLogicalSize > 0) | |
{ | |
totalSize += (fsInfo.dataLogicalSize + fsInfo.rsrcLogicalSize); | |
} | |
else | |
{ | |
totalSize += (fsInfo.dataLogicalSize); | |
} | |
} | |
NSLog(@"resource fork size: %llu | dataSize: %llu | totalSize: %llu", fsInfo.rsrcLogicalSize, fsInfo.dataLogicalSize, totalSize); | |
} | |
#pragma mark - NSURL | |
printf("\n--- NSURL --\n"); | |
NSNumber *fileSizeBytes; | |
NSNumber *totalFileSizeBytes; | |
[fileURL getResourceValue:&fileSizeBytes forKey:NSURLFileSizeKey error:&error]; | |
[fileURL getResourceValue:&totalFileSizeBytes forKey:NSURLTotalFileSizeKey error:&error]; | |
NSLog(@"NSURLFileSizeKey %@", fileSizeBytes); // Returns only the data size | |
NSLog(@"NSURLTotalFileSizeKey %@", totalFileSizeBytes); // Returns data + resource size | |
[pool drain]; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment