From 4c3a88d269994d867cdbcdff33a1241d39969921 Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Thu, 26 Sep 2024 13:30:09 +0200 Subject: [PATCH] Make LoopbackFS-ObjC behave like LoopbackFS-C * Implement support for all file system attributes * Implement special handling for Apple extended attributes --- LoopbackFS-ObjC/LoopbackFS/AppDelegate.h | 4 +- LoopbackFS-ObjC/LoopbackFS/AppDelegate.m | 20 +- LoopbackFS-ObjC/LoopbackFS/LoopbackFS.h | 2 +- LoopbackFS-ObjC/LoopbackFS/LoopbackFS.m | 396 +++++++++++++++++------ LoopbackFS-ObjC/LoopbackFS/main.m | 2 +- 5 files changed, 309 insertions(+), 115 deletions(-) diff --git a/LoopbackFS-ObjC/LoopbackFS/AppDelegate.h b/LoopbackFS-ObjC/LoopbackFS/AppDelegate.h index dc65176..1af8a60 100644 --- a/LoopbackFS-ObjC/LoopbackFS/AppDelegate.h +++ b/LoopbackFS-ObjC/LoopbackFS/AppDelegate.h @@ -26,8 +26,8 @@ #import "LoopbackFS.h" @interface AppDelegate : NSObject { - GMUserFileSystem* fs_; - LoopbackFS* loop_; + GMUserFileSystem *fs_; + LoopbackFS *loop_; } @end diff --git a/LoopbackFS-ObjC/LoopbackFS/AppDelegate.m b/LoopbackFS-ObjC/LoopbackFS/AppDelegate.m index ecb2feb..191c665 100644 --- a/LoopbackFS-ObjC/LoopbackFS/AppDelegate.m +++ b/LoopbackFS-ObjC/LoopbackFS/AppDelegate.m @@ -34,12 +34,12 @@ static NSString *LoopbackMountPath = @"/Volumes/loop"; - (void)mountFailed:(NSNotification *)notification { NSLog(@"Got mountFailed notification."); - NSDictionary* userInfo = [notification userInfo]; - NSError* error = [userInfo objectForKey:kGMUserFileSystemErrorKey]; + NSDictionary *userInfo = [notification userInfo]; + NSError *error = [userInfo objectForKey:kGMUserFileSystemErrorKey]; NSLog(@"kGMUserFileSystem Error: %@, userInfo=%@", error, [error userInfo]); dispatch_async(dispatch_get_main_queue(), ^{ - NSAlert* alert = [[NSAlert alloc] init]; + NSAlert *alert = [[NSAlert alloc] init]; [alert setMessageText:@"Mount Failed"]; [alert setInformativeText:[error localizedDescription] ?: @"Unknown error"]; [alert runModal]; @@ -65,24 +65,24 @@ static NSString *LoopbackMountPath = @"/Volumes/loop"; } - (void)applicationDidFinishLaunching:(NSNotification *)notification { - NSOpenPanel* panel = [NSOpenPanel openPanel]; + NSOpenPanel *panel = [NSOpenPanel openPanel]; [panel setCanChooseFiles:NO]; [panel setCanChooseDirectories:YES]; [panel setAllowsMultipleSelection:NO]; [panel setDirectoryURL:[NSURL fileURLWithPath:@"/tmp"]]; NSModalResponse ret = [panel runModal]; - if ( ret == NSModalResponseCancel ) { + if (ret == NSModalResponseCancel) { exit(0); } - NSArray* paths = [panel URLs]; - if ( [paths count] != 1 ) { + NSArray *paths = [panel URLs]; + if ([paths count] != 1) { exit(0); } - NSString* rootPath = nil; + NSString *rootPath = nil; rootPath = [[paths objectAtIndex:0] path]; - NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; [center addObserver:self selector:@selector(mountFailed:) name:kGMUserFileSystemMountFailed object:nil]; [center addObserver:self selector:@selector(didMount:) @@ -94,7 +94,7 @@ static NSString *LoopbackMountPath = @"/Volumes/loop"; fs_ = [[GMUserFileSystem alloc] initWithDelegate:loop_ isThreadSafe:NO]; - NSMutableArray* options = [NSMutableArray array]; + NSMutableArray *options = [NSMutableArray array]; // Do not use the 'native_xattr' mount-time option unless the underlying // file system supports native extended attributes. Typically, the user diff --git a/LoopbackFS-ObjC/LoopbackFS/LoopbackFS.h b/LoopbackFS-ObjC/LoopbackFS/LoopbackFS.h index 509e4ef..a0df8b5 100644 --- a/LoopbackFS-ObjC/LoopbackFS/LoopbackFS.h +++ b/LoopbackFS-ObjC/LoopbackFS/LoopbackFS.h @@ -30,7 +30,7 @@ #import @interface LoopbackFS : NSObject { - NSString* rootPath_; // The local file-system path to mount. + NSString *rootPath_; // The local file-system path to mount. } - (id)initWithRootPath:(NSString *)rootPath; diff --git a/LoopbackFS-ObjC/LoopbackFS/LoopbackFS.m b/LoopbackFS-ObjC/LoopbackFS/LoopbackFS.m index fe550a6..0d1429a 100644 --- a/LoopbackFS-ObjC/LoopbackFS/LoopbackFS.m +++ b/LoopbackFS-ObjC/LoopbackFS/LoopbackFS.m @@ -31,6 +31,7 @@ #import +#import #import #import #import @@ -61,8 +62,8 @@ error:(NSError **)error { // We use rename directly here since NSFileManager can sometimes fail to // rename and return non-posix error codes. - NSString* p_src = [rootPath_ stringByAppendingString:source]; - NSString* p_dst = [rootPath_ stringByAppendingString:destination]; + NSString *p_src = [rootPath_ stringByAppendingString:source]; + NSString *p_dst = [rootPath_ stringByAppendingString:destination]; int ret = 0; if (options == 0) { ret = rename([p_src UTF8String], [p_dst UTF8String]); @@ -76,8 +77,8 @@ } ret = renamex_np([p_src UTF8String], [p_dst UTF8String], flags); } - if ( ret < 0 ) { - if ( error ) { + if (ret < 0) { + if (error) { *error = [NSError errorWithPOSIXCode:errno]; } return NO; @@ -90,10 +91,10 @@ - (BOOL)removeDirectoryAtPath:(NSString *)path error:(NSError **)error { // We need to special-case directories here and use the bsd API since // NSFileManager will happily do a recursive remove :-( - NSString* p = [rootPath_ stringByAppendingString:path]; + NSString *p = [rootPath_ stringByAppendingString:path]; int ret = rmdir([p UTF8String]); if (ret < 0) { - if ( error ) { + if (error) { *error = [NSError errorWithPOSIXCode:errno]; } return NO; @@ -105,7 +106,7 @@ // NOTE: If removeDirectoryAtPath is commented out, then this may be called // with a directory, in which case NSFileManager will recursively remove all // subdirectories. So be careful! - NSString* p = [rootPath_ stringByAppendingString:path]; + NSString *p = [rootPath_ stringByAppendingString:path]; return [[NSFileManager defaultManager] removeItemAtPath:p error:error]; } @@ -114,7 +115,7 @@ - (BOOL)createDirectoryAtPath:(NSString *)path attributes:(NSDictionary *)attributes error:(NSError **)error { - NSString* p = [rootPath_ stringByAppendingString:path]; + NSString *p = [rootPath_ stringByAppendingString:path]; return [[NSFileManager defaultManager] createDirectoryAtPath:p withIntermediateDirectories:NO attributes:attributes @@ -126,11 +127,11 @@ flags:(int)flags userData:(id *)userData error:(NSError **)error { - NSString* p = [rootPath_ stringByAppendingString:path]; + NSString *p = [rootPath_ stringByAppendingString:path]; mode_t mode = [[attributes objectForKey:NSFilePosixPermissions] longValue]; int fd = open([p UTF8String], flags, mode); - if ( fd < 0 ) { - if ( error ) { + if (fd < 0) { + if (error) { *error = [NSError errorWithPOSIXCode:errno]; } return NO; @@ -144,14 +145,14 @@ - (BOOL)linkItemAtPath:(NSString *)path toPath:(NSString *)otherPath error:(NSError **)error { - NSString* p_path = [rootPath_ stringByAppendingString:path]; - NSString* p_otherPath = [rootPath_ stringByAppendingString:otherPath]; + NSString *p_path = [rootPath_ stringByAppendingString:path]; + NSString *p_otherPath = [rootPath_ stringByAppendingString:otherPath]; // We use link rather than the NSFileManager equivalent because it will copy // the file rather than hard link if part of the root path is a symlink. - int rc = link([p_path UTF8String], [p_otherPath UTF8String]); - if ( rc < 0 ) { - if ( error ) { + int ret = link([p_path UTF8String], [p_otherPath UTF8String]); + if (ret < 0) { + if (error) { *error = [NSError errorWithPOSIXCode:errno]; } return NO; @@ -164,7 +165,7 @@ - (BOOL)createSymbolicLinkAtPath:(NSString *)path withDestinationPath:(NSString *)otherPath error:(NSError **)error { - NSString* p_src = [rootPath_ stringByAppendingString:path]; + NSString *p_src = [rootPath_ stringByAppendingString:path]; return [[NSFileManager defaultManager] createSymbolicLinkAtPath:p_src withDestinationPath:otherPath error:error]; @@ -172,7 +173,7 @@ - (NSString *)destinationOfSymbolicLinkAtPath:(NSString *)path error:(NSError **)error { - NSString* p = [rootPath_ stringByAppendingString:path]; + NSString *p = [rootPath_ stringByAppendingString:path]; return [[NSFileManager defaultManager] destinationOfSymbolicLinkAtPath:p error:error]; } @@ -183,10 +184,10 @@ mode:(int)mode userData:(id *)userData error:(NSError **)error { - NSString* p = [rootPath_ stringByAppendingString:path]; + NSString *p = [rootPath_ stringByAppendingString:path]; int fd = open([p UTF8String], mode); - if ( fd < 0 ) { - if ( error ) { + if (fd < 0) { + if (error) { *error = [NSError errorWithPOSIXCode:errno]; } return NO; @@ -196,7 +197,7 @@ } - (void)releaseFileAtPath:(NSString *)path userData:(id)userData { - NSNumber* num = (NSNumber *)userData; + NSNumber *num = (NSNumber *)userData; int fd = [num intValue]; close(fd); } @@ -207,11 +208,11 @@ size:(size_t)size offset:(off_t)offset error:(NSError **)error { - NSNumber* num = (NSNumber *)userData; + NSNumber *num = (NSNumber *)userData; int fd = [num intValue]; size_t ret = pread(fd, buffer, size, offset); - if ( ret < 0 ) { - if ( error ) { + if (ret < 0) { + if (error) { *error = [NSError errorWithPOSIXCode:errno]; } return -1; @@ -225,11 +226,11 @@ size:(size_t)size offset:(off_t)offset error:(NSError **)error { - NSNumber* num = (NSNumber *)userData; + NSNumber *num = (NSNumber *)userData; int fd = [num intValue]; size_t ret = pwrite(fd, buffer, size, offset); - if ( ret < 0 ) { - if ( error ) { + if (ret < 0) { + if (error) { *error = [NSError errorWithPOSIXCode:errno]; } return -1; @@ -243,29 +244,29 @@ offset:(off_t)offset length:(off_t)length error:(NSError **)error { - NSNumber* num = (NSNumber *)userData; + NSNumber *num = (NSNumber *)userData; int fd = [num intValue]; fstore_t fstore; fstore.fst_flags = 0; - if ( options & ALLOCATECONTIG ) { + if (options & ALLOCATECONTIG) { fstore.fst_flags |= F_ALLOCATECONTIG; } - if ( options & ALLOCATEALL ) { + if (options & ALLOCATEALL) { fstore.fst_flags |= F_ALLOCATEALL; } - if ( options & ALLOCATEFROMPEOF ) { + if (options & ALLOCATEFROMPEOF) { fstore.fst_posmode = F_PEOFPOSMODE; - } else if ( options & ALLOCATEFROMVOL ) { + } else if (options & ALLOCATEFROMVOL) { fstore.fst_posmode = F_VOLPOSMODE; } fstore.fst_offset = offset; fstore.fst_length = length; - if ( fcntl(fd, F_PREALLOCATE, &fstore) == -1 ) { + if (fcntl(fd, F_PREALLOCATE, &fstore) == -1) { *error = [NSError errorWithPOSIXCode:errno]; return NO; } @@ -277,11 +278,11 @@ - (BOOL)exchangeDataOfItemAtPath:(NSString *)path1 withItemAtPath:(NSString *)path2 error:(NSError **)error { - NSString* p1 = [rootPath_ stringByAppendingString:path1]; - NSString* p2 = [rootPath_ stringByAppendingString:path2]; + NSString *p1 = [rootPath_ stringByAppendingString:path1]; + NSString *p2 = [rootPath_ stringByAppendingString:path2]; int ret = exchangedata([p1 UTF8String], [p2 UTF8String], 0); - if ( ret < 0 ) { - if ( error ) { + if (ret < 0) { + if (error) { *error = [NSError errorWithPOSIXCode:errno]; } return NO; @@ -294,53 +295,133 @@ #pragma mark Directory Contents - (NSArray *)contentsOfDirectoryAtPath:(NSString *)path error:(NSError **)error { - NSString* p = [rootPath_ stringByAppendingString:path]; + NSString *p = [rootPath_ stringByAppendingString:path]; return [[NSFileManager defaultManager] contentsOfDirectoryAtPath:p error:error]; } #pragma mark Getting and Setting Attributes +#define DateFromTimespec(t) \ + [NSDate dateWithTimeIntervalSince1970:((t).tv_sec + (t).tv_nsec / 1000000000.0)] + +#define TimespecFromDate(d) \ + ({ \ + NSTimeInterval _i = [(d) timeIntervalSince1970]; \ + struct timespec _t; \ + _t.tv_sec = (__darwin_time_t)_i; \ + _t.tv_nsec = (long)((_i - _t.tv_sec) * 1000000000); \ + _t; \ + }) + - (NSDictionary *)attributesOfItemAtPath:(NSString *)path userData:(id)userData error:(NSError **)error { - NSString* p = [rootPath_ stringByAppendingString:path]; - NSDictionary* attribs = + NSString *p = [rootPath_ stringByAppendingString:path]; + NSDictionary *d = [[NSFileManager defaultManager] attributesOfItemAtPath:p error:error]; - return attribs; + if (d) { + NSMutableDictionary *attribs = + [NSMutableDictionary dictionaryWithDictionary:d]; + int ret = 0; + + struct stat stbuf; + ret = lstat([p UTF8String], &stbuf); + if (ret < 0) { + if (error) { + *error = [NSError errorWithPOSIXCode:errno]; + } + return nil; + } + + struct attrlist attributes; + + attributes.bitmapcount = ATTR_BIT_MAP_COUNT; + attributes.reserved = 0; + attributes.commonattr = ATTR_CMN_BKUPTIME; + attributes.dirattr = 0; + attributes.fileattr = 0; + attributes.forkattr = 0; + attributes.volattr = 0; + + struct timeattrbuf { + uint32_t size; + struct timespec bkuptime; + } __attribute__ ((packed)); + + struct timeattrbuf timebuf; + + ret = getattrlist([p UTF8String], &attributes, &timebuf, sizeof(timebuf), + FSOPT_NOFOLLOW); + if (ret < 0) { + if (error) { + *error = [NSError errorWithPOSIXCode:errno]; + } + return nil; + } + + [attribs setObject:[NSNumber numberWithInt:stbuf.st_flags] + forKey:kGMUserFileSystemFileFlagsKey]; + [attribs setObject:DateFromTimespec(stbuf.st_atimespec) + forKey:kGMUserFileSystemFileAccessDateKey]; + [attribs setObject:DateFromTimespec(stbuf.st_ctimespec) + forKey:kGMUserFileSystemFileChangeDateKey]; + [attribs setObject:DateFromTimespec(timebuf.bkuptime) + forKey:kGMUserFileSystemFileBackupDateKey]; + [attribs setObject:[NSNumber numberWithLongLong:stbuf.st_blocks] + forKey:kGMUserFileSystemFileSizeInBlocksKey]; + [attribs setObject:[NSNumber numberWithInt:stbuf.st_blksize] + forKey:kGMUserFileSystemFileOptimalIOSizeKey]; + return attribs; + } + return nil; } - (NSDictionary *)attributesOfFileSystemForPath:(NSString *)path error:(NSError **)error { - NSString* p = [rootPath_ stringByAppendingString:path]; - NSDictionary* d = - [[NSFileManager defaultManager] attributesOfFileSystemForPath:p error:error]; + NSString *p = [rootPath_ stringByAppendingString:path]; + NSDictionary *d = + [[NSFileManager defaultManager] attributesOfFileSystemForPath:p + error:error]; if (d) { - NSMutableDictionary* attribs = [NSMutableDictionary dictionaryWithDictionary:d]; - [attribs setObject:[NSNumber numberWithBool:YES] - forKey:kGMUserFileSystemVolumeSupportsExtendedDatesKey]; + NSMutableDictionary *attribs = + [NSMutableDictionary dictionaryWithDictionary:d]; + + struct statfs stbuf; + int ret = statfs([p UTF8String], &stbuf); + if (ret < 0) { + if (error) { + *error = [NSError errorWithPOSIXCode:errno]; + } + return nil; + } NSURL *URL = [NSURL fileURLWithPath:p isDirectory:YES]; NSNumber *supportsCaseSensitiveNames = nil; - [URL getResourceValue:&supportsCaseSensitiveNames - forKey:NSURLVolumeSupportsCaseSensitiveNamesKey - error:NULL]; - if (supportsCaseSensitiveNames == nil) { + if (![URL getResourceValue:&supportsCaseSensitiveNames + forKey:NSURLVolumeSupportsCaseSensitiveNamesKey + error:error]) { + return nil; + } + if (!supportsCaseSensitiveNames) { supportsCaseSensitiveNames = [NSNumber numberWithBool:YES]; } + + [attribs setObject:[NSNumber numberWithBool:YES] + forKey:kGMUserFileSystemVolumeSupportsExtendedDatesKey]; + [attribs setObject:[NSNumber numberWithInt:255] + forKey:kGMUserFileSystemVolumeMaxFilenameLengthKey]; + [attribs setObject:[NSNumber numberWithUnsignedLong:stbuf.f_bsize] + forKey:kGMUserFileSystemVolumeFileSystemBlockSizeKey]; [attribs setObject:supportsCaseSensitiveNames forKey:kGMUserFileSystemVolumeSupportsCaseSensitiveNamesKey]; - [attribs setObject:[NSNumber numberWithBool:YES] forKey:kGMUserFileSystemVolumeSupportsSwapRenamingKey]; [attribs setObject:[NSNumber numberWithBool:YES] forKey:kGMUserFileSystemVolumeSupportsExclusiveRenamingKey]; - [attribs setObject:[NSNumber numberWithBool:YES] forKey:kGMUserFileSystemVolumeSupportsSetVolumeNameKey]; - [attribs setObject:[NSNumber numberWithBool:YES] forKey:kGMUserFileSystemVolumeSupportsReadWriteNodeLockingKey]; - return attribs; } return nil; @@ -350,30 +431,99 @@ ofItemAtPath:(NSString *)path userData:(id)userData error:(NSError **)error { - NSString* p = [rootPath_ stringByAppendingString:path]; + NSString *p = [rootPath_ stringByAppendingString:path]; - // TODO: Handle other keys not handled by NSFileManager setAttributes call. - - NSNumber* offset = [attributes objectForKey:NSFileSize]; - if ( offset ) { + NSNumber *offset = [attributes objectForKey:NSFileSize]; + if (offset) { int ret = truncate([p UTF8String], [offset longLongValue]); - if ( ret < 0 ) { - if ( error ) { + if (ret < 0) { + if (error) { *error = [NSError errorWithPOSIXCode:errno]; } return NO; } } - NSNumber* flags = [attributes objectForKey:kGMUserFileSystemFileFlagsKey]; + + NSDate *accessDate = attributes[kGMUserFileSystemFileAccessDateKey]; + if (accessDate) { + struct attrlist attributes; + + attributes.bitmapcount = ATTR_BIT_MAP_COUNT; + attributes.reserved = 0; + attributes.commonattr = ATTR_CMN_ACCTIME; + attributes.dirattr = 0; + attributes.fileattr = 0; + attributes.forkattr = 0; + attributes.volattr = 0; + + struct timespec acctime = TimespecFromDate(accessDate); + int ret = setattrlist([p UTF8String], &attributes, &acctime, + sizeof(struct timespec), FSOPT_NOFOLLOW); + if (ret < 0) { + if (error) { + *error = [NSError errorWithPOSIXCode:errno]; + } + return NO; + } + } + + NSDate *changeDate = attributes[kGMUserFileSystemFileChangeDateKey]; + if (changeDate) { + struct attrlist attributes; + + attributes.bitmapcount = ATTR_BIT_MAP_COUNT; + attributes.reserved = 0; + attributes.commonattr = ATTR_CMN_CHGTIME; + attributes.dirattr = 0; + attributes.fileattr = 0; + attributes.forkattr = 0; + attributes.volattr = 0; + + struct timespec chgtime = TimespecFromDate(changeDate); + int ret = setattrlist([p UTF8String], &attributes, &chgtime, + sizeof(struct timespec), FSOPT_NOFOLLOW); + if (ret < 0) { + if (error) { + *error = [NSError errorWithPOSIXCode:errno]; + } + return NO; + } + } + + NSDate *backupDate = attributes[kGMUserFileSystemFileBackupDateKey]; + if (backupDate) { + struct attrlist attributes; + + attributes.bitmapcount = ATTR_BIT_MAP_COUNT; + attributes.reserved = 0; + attributes.commonattr = ATTR_CMN_BKUPTIME; + attributes.dirattr = 0; + attributes.fileattr = 0; + attributes.forkattr = 0; + attributes.volattr = 0; + + struct timespec bkuptime = TimespecFromDate(backupDate); + int ret = setattrlist([p UTF8String], &attributes, &bkuptime, + sizeof(struct timespec), FSOPT_NOFOLLOW); + if (ret < 0) { + if (error) { + *error = [NSError errorWithPOSIXCode:errno]; + } + return NO; + } + } + + NSNumber *flags = [attributes objectForKey:kGMUserFileSystemFileFlagsKey]; if (flags != nil) { - int rc = chflags([p UTF8String], [flags intValue]); - if (rc < 0) { - if ( error ) { + int ret = lchflags([p UTF8String], [flags intValue]); + if (ret < 0) { + if (error) { *error = [NSError errorWithPOSIXCode:errno]; } return NO; } } + return [[NSFileManager defaultManager] setAttributes:attributes ofItemAtPath:p error:error]; @@ -387,29 +537,39 @@ #pragma mark Extended Attributes -- (NSArray *)extendedAttributesOfItemAtPath:(NSString *)path error:(NSError **)error { - NSString* p = [rootPath_ stringByAppendingString:path]; +#define G_PREFIX "org" +#define G_KAUTH_FILESEC_XATTR G_PREFIX ".apple.system.Security" +#define A_PREFIX "com" +#define A_KAUTH_FILESEC_XATTR A_PREFIX ".apple.system.Security" +#define XATTR_APPLE_PREFIX "com.apple." - ssize_t size = listxattr([p UTF8String], nil, 0, XATTR_NOFOLLOW); - if ( size < 0 ) { - if ( error ) { +- (NSArray *)extendedAttributesOfItemAtPath:(NSString *)path error:(NSError **)error { + NSString *p = [rootPath_ stringByAppendingString:path]; + + ssize_t size = listxattr([p UTF8String], NULL, 0, XATTR_NOFOLLOW); + if (size < 0) { + if (error) { *error = [NSError errorWithPOSIXCode:errno]; } return nil; } - NSMutableData* data = [NSMutableData dataWithLength:size]; + + NSMutableData *data = [NSMutableData dataWithLength:size]; size = listxattr([p UTF8String], [data mutableBytes], [data length], XATTR_NOFOLLOW); - if ( size < 0 ) { - if ( error ) { + if (size < 0) { + if (error) { *error = [NSError errorWithPOSIXCode:errno]; } return nil; } - NSMutableArray* contents = [NSMutableArray array]; - char* ptr = (char *)[data bytes]; - while ( ptr < ((char *)[data bytes] + size) ) { - NSString* s = [NSString stringWithUTF8String:ptr]; - [contents addObject:s]; + + NSMutableArray *contents = [NSMutableArray array]; + char *ptr = (char *)[data bytes]; + while (ptr < (((char *)[data bytes]) + size)) { + NSString *s = [NSString stringWithUTF8String:ptr]; + if (strcmp(ptr, G_KAUTH_FILESEC_XATTR) != 0) { + [contents addObject:s]; + } ptr += ([s length] + 1); } return contents; @@ -419,25 +579,35 @@ ofItemAtPath:(NSString *)path position:(off_t)position error:(NSError **)error { - NSString* p = [rootPath_ stringByAppendingString:path]; + NSString *p = [rootPath_ stringByAppendingString:path]; - ssize_t size = getxattr([p UTF8String], [name UTF8String], nil, 0, - (uint32_t)position, XATTR_NOFOLLOW); - if ( size < 0 ) { - if ( error ) { + const char *n = [name UTF8String]; + if (strcmp(n, A_KAUTH_FILESEC_XATTR) == 0) { + char new_name[MAXPATHLEN]; + memcpy(new_name, A_KAUTH_FILESEC_XATTR, sizeof(A_KAUTH_FILESEC_XATTR)); + memcpy(new_name, G_PREFIX, sizeof(G_PREFIX) - 1); + n = new_name; + } + + ssize_t size = getxattr([p UTF8String], n, NULL, 0, (uint32_t)position, + XATTR_NOFOLLOW); + if (size < 0) { + if (error) { *error = [NSError errorWithPOSIXCode:errno]; } return nil; } - NSMutableData* data = [NSMutableData dataWithLength:size]; - size = getxattr([p UTF8String], [name UTF8String], [data mutableBytes], - [data length], (uint32_t)position, XATTR_NOFOLLOW); - if ( size < 0 ) { - if ( error ) { + + NSMutableData *data = [NSMutableData dataWithLength:size]; + ssize_t ret = getxattr([p UTF8String], n, [data mutableBytes], [data length], + (uint32_t)position, XATTR_NOFOLLOW); + if (ret == -1) { + if (error) { *error = [NSError errorWithPOSIXCode:errno]; } return nil; } + return data; } @@ -451,31 +621,55 @@ // bits are set in the options. We need to explicitly remove them or the call // to setxattr will fail. // TODO: Why is this necessary? - options &= ~(XATTR_NOSECURITY | XATTR_NODEFAULT); - NSString* p = [rootPath_ stringByAppendingString:path]; - int ret = setxattr([p UTF8String], [name UTF8String], [value bytes], - [value length], (uint32_t)position, - options | XATTR_NOFOLLOW); - if ( ret < 0 ) { - if ( error ) { + + NSString *p = [rootPath_ stringByAppendingString:path]; + + const char *n = [name UTF8String]; + if (strcmp(n, A_KAUTH_FILESEC_XATTR) == 0) { + char new_name[MAXPATHLEN]; + memcpy(new_name, A_KAUTH_FILESEC_XATTR, sizeof(A_KAUTH_FILESEC_XATTR)); + memcpy(new_name, G_PREFIX, sizeof(G_PREFIX) - 1); + n = new_name; + } + + options |= XATTR_NOFOLLOW; + if (!strncmp(n, XATTR_APPLE_PREFIX, sizeof(XATTR_APPLE_PREFIX) - 1)) { + options &= ~(XATTR_NOSECURITY); + } + + int ret = setxattr([p UTF8String], n, [value bytes], [value length], + (uint32_t)position, options); + if (ret == -1) { + if (error) { *error = [NSError errorWithPOSIXCode:errno]; } return NO; } + return YES; } - (BOOL)removeExtendedAttribute:(NSString *)name ofItemAtPath:(NSString *)path error:(NSError **)error { - NSString* p = [rootPath_ stringByAppendingString:path]; - int ret = removexattr([p UTF8String], [name UTF8String], XATTR_NOFOLLOW); - if ( ret < 0 ) { - if ( error ) { + NSString *p = [rootPath_ stringByAppendingString:path]; + + const char *n = [name UTF8String]; + if (strcmp(n, A_KAUTH_FILESEC_XATTR) == 0) { + char new_name[MAXPATHLEN]; + memcpy(new_name, A_KAUTH_FILESEC_XATTR, sizeof(A_KAUTH_FILESEC_XATTR)); + memcpy(new_name, G_PREFIX, sizeof(G_PREFIX) - 1); + n = new_name; + } + + int res = removexattr([p UTF8String], n, XATTR_NOFOLLOW); + if (res == -1) { + if (error) { *error = [NSError errorWithPOSIXCode:errno]; } return NO; } + return YES; } diff --git a/LoopbackFS-ObjC/LoopbackFS/main.m b/LoopbackFS-ObjC/LoopbackFS/main.m index 477d5e5..b503fa1 100644 --- a/LoopbackFS-ObjC/LoopbackFS/main.m +++ b/LoopbackFS-ObjC/LoopbackFS/main.m @@ -22,7 +22,7 @@ #import -int main(int argc, const char * argv[]) { +int main(int argc, const char *argv[]) { @autoreleasepool { // Setup code that might create autoreleased objects goes here. }