Skip to content

Instantly share code, notes, and snippets.

@edenwaith
Last active February 22, 2023 09:45
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save edenwaith/99c56ef39763094a64d5d018087cf1de to your computer and use it in GitHub Desktop.
Save edenwaith/99c56ef39763094a64d5d018087cf1de to your computer and use it in GitHub Desktop.
Multiple ways to calculate the size of a file's resource fork
/*
* 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