Getting and Setting a File's Extended Attributes

One last code snippet....

This'll let you get and set the extended attributes on a file in OS X. It uses setxattr() / getxattr() / listxattr(), but it's all wrapped up in ARC-dependent Objective-C. When setting a value you can pass in either an NSString or an NSData.

Enjoy.

#import <errno.h>
#import <stdio.h>
#import <sys/xattr.h>

+ (BOOL)setValue:(NSObject *)value forName:(NSString *)name onFile:(NSString *)filePath
{
  int err;
  const void *bytes = NULL;
  size_t length = 0;
  
  if ([value isKindOfClass:[NSString class]]) {
    bytes = [(NSString *)value UTF8String];
    length = [(NSString *)value lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
  }
  else if ([value isKindOfClass:[NSData class]]) {
    bytes = [(NSData *)value bytes];
    length = [(NSData *)value length];
  }
  else {
    NSLog(@"%s.. unsupported data type, %@", __PRETTY_FUNCTION__, NSStringFromClass([value class]));
    return FALSE;
  }
  
  if (0 != (err = setxattr([filePath UTF8String], [name UTF8String], bytes, length, 0, 0))) {
    NSLog(@"%s.. failed to setxattr(%@), %s", __PRETTY_FUNCTION__, filePath, strerror(errno));
  }
  
  return TRUE;
}

+ (NSData *)getDataValueForName:(NSString *)name onFile:(NSString *)filePath
{
  ssize_t size;
  void *buffer[4096];
  
  if (0 > (size = getxattr([filePath UTF8String], [name UTF8String], buffer, sizeof(buffer), 0, 0)) || size > sizeof(buffer)) {
    NSLog(@"%s.. failed to getxattr(%@), %s", __PRETTY_FUNCTION__, filePath, strerror(errno));
    return nil;
  }
  
  return [[NSData alloc] initWithBytes:buffer length:size];
}

+ (NSDictionary *)getAllValuesOnFile:(NSString *)filePath
{
  ssize_t size;
  char buffer[4096], *bufferPtr;
  NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init];
  
  if (0 > (size = listxattr([filePath UTF8String], buffer, sizeof(buffer), 00)) || size > sizeof(buffer)) {
    NSLog(@"%s.. failed to listxattr(%@), %s", __PRETTY_FUNCTION__, filePath, strerror(errno));
    return nil;
  }
  
  bufferPtr = buffer;
  
  for (ssize_t bufferNdx = 0; bufferNdx < size; ) {
    NSString *name = [NSString stringWithCString:bufferPtr encoding:NSUTF8StringEncoding];
    NSData *value = [self getDataValueForName:name onFile:filePath];
    unsigned long namelen = strlen(bufferPtr);
    
    if (name && value)
      [attributes setValue:value forKey:name];
    
    bufferPtr += namelen + 1;
    bufferNdx += namelen + 1;
  }
  
  return attributes;
}

Subscribe to A garage sale for your mind

Don’t miss out on the latest posts. Sign up now to get access to the library of members-only posts.
[email protected]
Subscribe