| Index | Submit class | Submit snippet | Submission feed | List |

UKXattrMetadataStore

Language: Objective-C, Author: Uli Kusterer
License: MIT/X11

A wrapper around the MacOS X 10.4 xattr APIs for attaching metadata to files. Also offers convenience methods for dealing with UTF8 strings and property-list-objects as the metadata values.

UKXattrMetadataStore source preview

//
//  UKXattrMetadataStore.m
//  BubbleBrowser
//  LICENSE: MIT License
//
//  Created by Uli Kusterer on 12.03.06.
//  Copyright 2006 Uli Kusterer. All rights reserved.
//

#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
// -----------------------------------------------------------------------------
//  Headers:
// -----------------------------------------------------------------------------

#import "UKXattrMetadataStore.h"
#import <sys/xattr.h>


@implementation UKXattrMetadataStore

// -----------------------------------------------------------------------------
//  allKeysAtPath:traverseLink:
//    Return an NSArray of NSStrings containing all xattr names currently set
//    for the file at the specified path.
//    If travLnk == YES, it follows symlinks.
// -----------------------------------------------------------------------------

+(NSArray*)    allKeysAtPath: (NSString*)path traverseLink:(BOOL)travLnk
{
  NSMutableArray*  allKeys = [NSMutableArray array];
  size_t dataSize = listxattr( [path fileSystemRepresentation],
                NULL, ULONG_MAX,
                (travLnk ? 0 : XATTR_NOFOLLOW) );
  if( dataSize == ULONG_MAX )
    return allKeys;  // Empty list.
  NSMutableData*  listBuffer = [NSMutableData dataWithLength: dataSize];
  dataSize = listxattr( [path fileSystemRepresentation],
              [listBuffer mutableBytes], [listBuffer length],
              (travLnk ? 0 : XATTR_NOFOLLOW) );
  char*  nameStart = [listBuffer mutableBytes];
  int x;
  for( x = 0; x < dataSize; x++ )
  {
    if( ((char*)[listBuffer mutableBytes])[x] == 0 )  // End of string.
    {
      NSString*  str = [NSString stringWithUTF8String: nameStart];
      nameStart = [listBuffer mutableBytes] +x +1;
      [allKeys addObject: str];
    }
  }
  
  return allKeys;
}


// -----------------------------------------------------------------------------
//  setData:forKey:atPath:traverseLink:
//    Set the xattr with name key to a block of raw binary data.
//    path is the file whose xattr you want to set.
//    If travLnk == YES, it follows symlinks.
// -----------------------------------------------------------------------------

+(void)        setData: (NSData*)data forKey: (NSString*)key atPath: (NSString*)path traverseLink:(BOOL)travLnk
{
  setxattr( [path fileSystemRepresentation], [key UTF8String],
        [data bytes], [data length],
        0, (travLnk ? 0 : XATTR_NOFOLLOW) );
}


// -----------------------------------------------------------------------------
//  setObject:forKey:atPath:traverseLink:
//    Set the xattr with name key to an XML property list representation of
//    the specified object (or object graph).
//    path is the file whose xattr you want to set.
//    If travLnk == YES, it follows symlinks.
// -----------------------------------------------------------------------------

+(void)  setObject: (id)obj forKey: (NSString*)key atPath: (NSString*)path traverseLink:(BOOL)travLnk
{
  // Serialize our objects into a property list XML string:
  NSString*  errMsg = nil;
  NSData*    plistData = [NSPropertyListSerialization dataFromPropertyList: obj
                format: NSPropertyListXMLFormat_v1_0
                errorDescription: &errMsg];
  if( errMsg )
  {
    [errMsg autorelease];
    [NSException raise: @"UKXattrMetastoreCantSerialize" format: @"%@", errMsg];
  }
  else
    [[self class] setData: plistData forKey: key atPath: path traverseLink: travLnk];
}


// -----------------------------------------------------------------------------
//  setString:forKey:atPath:traverseLink:
//    Set the xattr with name key to an XML property list representation of
//    the specified object (or object graph).
//    path is the file whose xattr you want to set.
//    If travLnk == YES, it follows symlinks.
// -----------------------------------------------------------------------------

+(void)  setString: (NSString*)str forKey: (NSString*)key atPath: (NSString*)path traverseLink:(BOOL)travLnk
{
  NSData*    data = [str dataUsingEncoding: NSUTF8StringEncoding];
  
  if( !data )
    [NSException raise: NSCharacterConversionException format: @"Couldn't convert string to UTF8 for xattr storage."];
  
  [[self class] setData: data forKey: key atPath: path traverseLink: travLnk];
}


// -----------------------------------------------------------------------------
//  dataForKey:atPath:traverseLink:
//    Retrieve the xattr with name key as a raw block of data.
//    path is the file whose xattr you want to set.
//    If travLnk == YES, it follows symlinks.
// -----------------------------------------------------------------------------

+(NSMutableData*)  dataForKey: (NSString*)key atPath: (NSString*)path traverseLink:(BOOL)travLnk
{
  size_t    dataSize = getxattr( [path fileSystemRepresentation], [key UTF8String],
                    NULL, ULONG_MAX, 0, (travLnk ? 0 : XATTR_NOFOLLOW) );
  if( dataSize == ULONG_MAX )
    return nil;
  NSMutableData*  data = [NSMutableData dataWithLength: dataSize];
  getxattr( [path fileSystemRepresentation], [key UTF8String],
        [data mutableBytes], [data length], 0, (travLnk ? 0 : XATTR_NOFOLLOW) );
  
  return data;
}


// -----------------------------------------------------------------------------
//  objectForKey:atPath:traverseLink:
//    Retrieve the xattr with name key, which is an XML property list
//    and unserialize it back into an object or object graph.
//    path is the file whose xattr you want to set.
//    If travLnk == YES, it follows symlinks.
// -----------------------------------------------------------------------------

+(id)  objectForKey: (NSString*)key atPath: (NSString*)path traverseLink:(BOOL)travLnk
{
  NSString*        errMsg = nil;
  NSMutableData*      data = [[self class] dataForKey: key atPath: path traverseLink: travLnk];
  NSPropertyListFormat  outFormat = NSPropertyListXMLFormat_v1_0;
  id obj = [NSPropertyListSerialization propertyListFromData: data
          mutabilityOption: NSPropertyListImmutable
          format: &outFormat
          errorDescription: &errMsg];
  if( errMsg )
  {
    [errMsg autorelease];
    [NSException raise: @"UKXattrMetastoreCantUnserialize" format: @"%@", errMsg];
  }
  
  return obj;
}


// -----------------------------------------------------------------------------
//  stringForKey:atPath:traverseLink:
//    Retrieve the xattr with name key, which is an XML property list
//    and unserialize it back into an object or object graph.
//    path is the file whose xattr you want to set.
//    If travLnk == YES, it follows symlinks.
// -----------------------------------------------------------------------------

+(id)  stringForKey: (NSString*)key atPath: (NSString*)path traverseLink:(BOOL)travLnk
{
  NSMutableData*      data = [[self class] dataForKey: key atPath: path traverseLink: travLnk];
  
  return [[[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding] autorelease];
}


@end

#endif /*MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4*/

UKXattrMetadataStore header preview

//
//  UKXattrMetadataStore.h
//  BubbleBrowser
//  LICENSE: MIT License
//
//  Created by Uli Kusterer on 12.03.06.
//  Copyright 2006 Uli Kusterer. All rights reserved.
//

// -----------------------------------------------------------------------------
//  Headers:
// -----------------------------------------------------------------------------

#import <Cocoa/Cocoa.h>

/*
  This is a wrapper around The Mac OS X 10.4 and later xattr API that lets
  you attach arbitrary metadata to a file. Currently it allows querying and
  changing the attributes of a file, as well as retrieving a list of attribute
  names.
  
  It also includes some conveniences for storing/retrieving UTF8 strings,
  and objects as XML property lists in addition to the raw data.
  
  NOTE: keys (i.e. xattr names) are strings of 127 characters or less and
  should be made like bundle identifiers, e.g. @"de.zathras.myattribute".
*/

#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
// -----------------------------------------------------------------------------
//  Class declaration:
// -----------------------------------------------------------------------------

@interface UKXattrMetadataStore : NSObject
{
  
}

+(NSArray*)    allKeysAtPath: (NSString*)path traverseLink:(BOOL)travLnk;

// Store UTF8 strings:
+(void)        setString: (NSString*)str forKey: (NSString*)key
            atPath: (NSString*)path traverseLink:(BOOL)travLnk;
+(id)        stringForKey: (NSString*)key atPath: (NSString*)path
            traverseLink:(BOOL)travLnk;

// Store raw data:
+(void)        setData: (NSData*)data forKey: (NSString*)key
            atPath: (NSString*)path traverseLink:(BOOL)travLnk;
+(NSMutableData*)  dataForKey: (NSString*)key atPath: (NSString*)path
            traverseLink:(BOOL)travLnk;

// Store objects: (Only can get/set plist-type objects for now)â
+(void)        setObject: (id)obj forKey: (NSString*)key atPath: (NSString*)path
            traverseLink:(BOOL)travLnk;
+(id)        objectForKey: (NSString*)key atPath: (NSString*)path
            traverseLink:(BOOL)travLnk;

@end

#endif /*MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4*/
Download Archive

Compatible with:


Comments

Name

Website

Do you hate spammers? (Answer "Yes")