• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Referring to file by Alias ^or^ path
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Referring to file by Alias ^or^ path


  • Subject: Re: Referring to file by Alias ^or^ path
  • From: Jerry Krinock <email@hidden>
  • Date: Wed, 3 Jun 2009 19:15:26 -0700


On 2009 Jun 03, at 17:26, Bill Monk wrote:

Given that your category depends on FSNewAliasFromPath, which is 10.5-only, both blocks of

#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4....

can be dispensed with.

Hehe. Well, like I said, my code had been "cobbled together over time from various sources". But I believe we need the "modern" block,


		Size size = GetAliasSize(aliasHandle) ;

  AliasPtr aliasPtr = *aliasHandle ;
  data = [NSData dataWithBytes:aliasPtr
                             length:size] ;

Might just as well say:

data = [NSData dataWithBytes:*aliasHandle length:size] ;

Yup.

   AliasRecord aliasHeader = *((AliasPtr)[self bytes]) ;
#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4
   AliasPtr ap = &aliasHeader ;
   AliasHandle ah = &ap ;

That sort of machination used to be known as "creating a fake handle" - as distinguished from a "real" Handle, a pointer to a pointer to relocatable block allocated by the Memory Manager . Doing that would cause various havoc and crashes. You can get away with it now because NewHandle ends up as a malloc call, and memory blocks are no longer relocatable. Still, it just looks wrong to my eye. Worse, in recent memory, fake handles could still cause trouble in OS X in certain circumstances. (When I tried to google it, I found my own post from 2005: http://www.cocoabuilder.com/archive/message/cocoa/2005/8/16/144407)


But anyway, easier to sidestep it with GetAliasSizeFromPtr. A one- liner replaces seven lines:

nBytesAliasRecord = GetAliasSizeFromPtr( (AliasPtr)[self bytes] );

Yes, looks good. But to get seven lines you need to count the comments and unnecessary #ifdefs ;)


// The full path returned by FSRefMakePath will NOT have a trailing slash UNLESS
// the path is the root, i.e. @"/". In that case it will. Thus, in order to return
// a standard result to which "/Filename.ext" should be appended, we remove that:
if ([path length] == 1)
path = @"" ;

How come?

Don't ask me. I believe I pasted in that comment (and the accompanying section of code) from some Apple Sample Code.


If the caller is correctly using stringByAppendingPathComponent:, and not stringByAppendingString", this shouldn't be a problem. The correct path for the root is @"/" and I'd think needing to return anything else here implies a problem elsewhere.

Well, you can have a convention to add trailing slashes or not add trailing slashes. Personally, I think that trailing slashes are more conventional, but apparently whoever specified FSRefMakePath() does not.


   NSLog(@"*** Tests which should fail ***") ;    ...
   ...
   ...
   TestPath(@"/") ;

That test only fails because you force it to fail, by taking steps to return @"" for the root.

Yes, if something is documented to fail, you should test that it fails :))


AliasManager returns the correct path; I'd rather see it return that, and let callers either use stringByAppendingPathComponent, or let it be their problem if they have special reasons for not using it. But maybe that's just me...

Actually, my present purpose is only regarding files, not directories. So I just tried to document what others had done, even if it's odd.


Thanks for the comments.  This code keeps looking better, and shorter!

Jerry

Here's the modified .m. The .h should have documentation added to note that it requires Mac OS 10.5.

#import "NSData+FileAlias.h"

@implementation NSData (FileAlias)

+ (NSData*)aliasRecordFromPath:(NSString*)path {
    if ([path length] == 0) {
        return nil ;
    }

    const char* pathC = [path fileSystemRepresentation] ;

    OSErr osErr ;
    AliasHandle aliasHandle = NULL ;
    osErr = FSNewAliasFromPath (
                                NULL,
                                pathC,
                                0,
                                &aliasHandle,
                                NULL
                                ) ;

    NSData* data = nil ;
    if (
        (osErr == noErr)
        // ... File exists and we have a full alias
        ||
        ((osErr == fnfErr) && (aliasHandle != NULL))
        // ... File does not exist and we have a minimal alias
        ) {

        Size size = GetAliasSize(aliasHandle) ;

        data = [NSData dataWithBytes:*aliasHandle
                              length:size] ;
    }

    return data ;
}

- (NSString*)pathFromAliasRecord {
unsigned short nBytesAliasRecord ;
/*
In Aliases.h, note that the AliasRecord struct is opaque if
MAC_OS_X_MIN_VERSION_REQUIRED >= MAC_OS_X_VERSION_10_4. In other
words, if the "Mac OS X Deployment Target" setting for your project is
10.4 or later, the AliasRecord struct is opaque.


That's because AliasRecords, as you've noticed, get written to disk but
are also referenced in data, which means that they often have to be
big-endian even on little-endian systems. Rather than enumerate the
cases in which you'd want big- or little-endian AliasRecords, we made
the data type opaque and added new APIs which deal in native- endian
data. They're Get/SetAliasUserType and GetAliasSize, and there are
also FromPtr versions of each if you have an AliasRecord * instead of
an AliasHandle.


     Eric Albert, Apple */

    nBytesAliasRecord = GetAliasSizeFromPtr((AliasPtr)[self bytes]);

    Handle handle = NULL;
    FSRef resolvedFSRef;
    NSString* path = nil ;
    int err = 0 ;

// Move the now-decoded data into the Handle.
if (PtrToHand([self bytes], &handle, nBytesAliasRecord) != noErr) {
NSLog(@"Internal Error 589-5451. Can't allocate handle for alias") ;
err = 1 ;
}


    if (err == 0) {
        // Successfully created the handle

        // Now try and resolve the alias
        Boolean changed ;
        OSErr osErr = FSResolveAlias(NULL,
                                     (AliasHandle)handle,
                                     &resolvedFSRef,
                                     &changed) ;

        if (osErr == noErr) {
            // Alias was resolved.  Now get its path from resolvedFSRef
            char pathC[4096] ;
            OSStatus osStatus = FSRefMakePath(
                                              &resolvedFSRef,
                                              (UInt8*)pathC,
                                              sizeof(pathC)
            ) ;

if (osStatus != noErr) {
NSLog(@"Internal Error 959-2697. OSStatus %i from FSResolveAlias", osStatus) ;
err = 1 ;
}
else {
path = [NSString stringWithCString:pathC
encoding:NSUTF8StringEncoding] ;


// The full path returned by FSRefMakePath will NOT have a trailing slash UNLESS
// the path is the root, i.e. @"/". In that case it will. Thus, in order to return
// a standard result to which "/Filename.ext" should be appended, we remove that:
if ([path length] == 1)
path = @"" ;
}
}
else if (osErr == fnfErr) {
// The alias could not be resolved because the file does not exist.
// However, we can still extract the expected path from the alias.
osErr = FSCopyAliasInfo (
(AliasHandle)handle,
NULL,
NULL,
(CFStringRef*)&(path),
NULL,
NULL
) ;


// There may be a bug in the above function. If the alias is to
// that of a nonexistent directory in the root, for example,
// /Yousers
// Then the path returned will begin with two slashes.
// To work around that,
if ([path hasPrefix:@"//"]) {
path = [path substringFromIndex:1] ;
}
}
}


    if (handle)
        DisposeHandle(handle);

    return path ;
}

@end
_______________________________________________

Cocoa-dev mailing list (email@hidden)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden


References: 
 >Referring to file by Alias ^or^ path (From: Bill Monk <email@hidden>)

  • Prev by Date: Re: Scheduling an application
  • Next by Date: QTCaptureSession class reference
  • Previous by thread: Referring to file by Alias ^or^ path
  • Next by thread: CF/NSNotifications on the same thread not working.
  • Index(es):
    • Date
    • Thread