Common/Source/CFURLAdditions.c
author Rudy Richter
Wed Jun 24 23:00:44 2009 -0400 (2009-06-24)
changeset 4228 6febcb06621d
parent 4168 a476173fbe3f
child 5007 d9fd5792174b
permissions -rw-r--r--
fixes bug #385038
     1 //
     2 //  CFURLAdditions.c
     3 //  Growl
     4 //
     5 //  Created by Karl Adam on Fri May 28 2004.
     6 //  Copyright 2004-2006 The Growl Project. All rights reserved.
     7 //
     8 // This file is under the BSD License, refer to License.txt for details
     9 
    10 #include "CFURLAdditions.h"
    11 #include "CFGrowlAdditions.h"
    12 #include "CFMutableDictionaryAdditions.h"
    13 #include <Carbon/Carbon.h>
    14 #include <unistd.h>
    15 #include <fcntl.h>
    16 #include <sys/types.h>
    17 #include <sys/stat.h>
    18 
    19 #define _CFURLAliasDataKey  CFSTR("_CFURLAliasData")
    20 #define _CFURLStringKey     CFSTR("_CFURLString")
    21 #define _CFURLStringTypeKey CFSTR("_CFURLStringType")
    22 
    23 //'alias' as in the Alias Manager.
    24 URL_TYPE createFileURLWithAliasData(DATA_TYPE aliasData) {
    25 	if (!aliasData) {
    26 		NSLog(CFSTR("WARNING: createFileURLWithAliasData called with NULL aliasData"));
    27 		return NULL;
    28 	}
    29 
    30 	CFURLRef url = NULL;
    31 
    32 	AliasHandle alias = NULL;
    33 	OSStatus err = PtrToHand(CFDataGetBytePtr(aliasData), (Handle *)&alias, CFDataGetLength(aliasData));
    34 	if (err != noErr) {
    35 		NSLog(CFSTR("in createFileURLWithAliasData: Could not allocate an alias handle from %u bytes of alias data (data follows) because PtrToHand returned %li\n%@"), CFDataGetLength(aliasData), aliasData, (long)err);
    36 	} else {
    37 		CFStringRef path = NULL;
    38 		/*
    39 		 * FSResolveAlias mounts disk images or network shares to resolve
    40 		 * aliases, thus we resort to FSCopyAliasInfo.
    41 		 */
    42 		err = FSCopyAliasInfo(alias,
    43 							  /* targetName */ NULL,
    44 							  /* volumeName */ NULL,
    45 							  &path,
    46 							  /* whichInfo */ NULL,
    47 							  /* info */ NULL);
    48 		DisposeHandle((Handle)alias);
    49 		if (err != noErr) {
    50 			if (err != fnfErr) //ignore file-not-found; it's harmless
    51 				NSLog(CFSTR("in createFileURLWithAliasData: Could not resolve alias (alias data follows) because FSResolveAlias returned %li - will try path\n%@"), (long)err, aliasData);
    52 		} else if (path) {
    53 			url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path, kCFURLPOSIXPathStyle, true);
    54 		} else {
    55 			NSLog(CFSTR("in createFileURLWithAliasData: FSCopyAliasInfo returned a NULL path"));
    56 		}
    57 		CFRelease(path);
    58 	}
    59 
    60 	return url;
    61 }
    62 
    63 DATA_TYPE createAliasDataWithURL(URL_TYPE theURL) {
    64 	//return NULL for non-file: URLs.
    65 	CFStringRef scheme = CFURLCopyScheme(theURL);
    66 	CFComparisonResult isFileURL = CFStringCompare(scheme, CFSTR("file"), kCFCompareCaseInsensitive);
    67 	CFRelease(scheme);
    68 	if (isFileURL != kCFCompareEqualTo)
    69 		return NULL;
    70 
    71 	CFDataRef aliasData = NULL;
    72 
    73 	FSRef fsref;
    74 	if (CFURLGetFSRef(theURL, &fsref)) {
    75 		AliasHandle alias = NULL;
    76 		OSStatus    err   = FSNewAlias(/*fromFile*/ NULL, &fsref, &alias);
    77 		if (err != noErr) {
    78 			NSLog(CFSTR("in createAliasDataForURL: FSNewAlias for %@ returned %li"), theURL, (long)err);
    79 		} else {
    80 			HLock((Handle)alias);
    81 
    82 			aliasData = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)*alias, GetHandleSize((Handle)alias));
    83 
    84 			HUnlock((Handle)alias);
    85 			DisposeHandle((Handle)alias);
    86 		}
    87 	}
    88 
    89 	return aliasData;
    90 }
    91 
    92 //these are the type of external representations used by Dock.app.
    93 URL_TYPE createFileURLWithDockDescription(DICTIONARY_TYPE dict) {
    94 	CFURLRef url = NULL;
    95 
    96 	CFStringRef path      = CFDictionaryGetValue(dict, _CFURLStringKey);
    97 	CFDataRef   aliasData = CFDictionaryGetValue(dict, _CFURLAliasDataKey);
    98 
    99 	if (aliasData)
   100 		url = createFileURLWithAliasData(aliasData);
   101 
   102 	if (!url) {
   103 		if (path) {
   104 			CFNumberRef pathStyleNum = CFDictionaryGetValue(dict, _CFURLStringTypeKey);
   105 			CFURLPathStyle pathStyle = kCFURLPOSIXPathStyle;
   106 			
   107 			if (pathStyleNum)
   108 				CFNumberGetValue(pathStyleNum, kCFNumberIntType, &pathStyle);
   109 
   110 			char *filename = createFileSystemRepresentationOfString(path);
   111 			int fd = open(filename, O_RDONLY, 0);
   112 			free(filename);
   113 			if (fd != -1) {
   114 				struct stat sb;
   115 				fstat(fd, &sb);
   116 				close(fd);
   117 				url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path, pathStyle, /*isDirectory*/ (sb.st_mode & S_IFDIR));
   118 			}
   119 		}
   120 	}
   121 
   122 	return url;
   123 }
   124 
   125 DICTIONARY_TYPE createDockDescriptionWithURL(URL_TYPE theURL) {
   126 	CFMutableDictionaryRef dict;
   127 
   128 	if (!theURL) {
   129 		NSLog(CFSTR("%@"), CFSTR("in createDockDescriptionWithURL: Cannot copy Dock description for a NULL URL"));
   130 		return NULL;
   131 	}
   132 
   133 	CFStringRef path     = CFURLCopyFileSystemPath(theURL, kCFURLPOSIXPathStyle);
   134 	CFDataRef aliasData  = createAliasDataWithURL(theURL);
   135 
   136 	if (path || aliasData) {
   137 		dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
   138 
   139 		if (path) {
   140 			CFDictionarySetValue(dict, _CFURLStringKey, path);
   141 			CFRelease(path);
   142 			setIntegerForKey(dict, _CFURLStringTypeKey, kCFURLPOSIXPathStyle);
   143 		}
   144 
   145 		if (aliasData) {
   146 			CFDictionarySetValue(dict, _CFURLAliasDataKey, aliasData);
   147 			CFRelease(aliasData);
   148 		}
   149 	} else {
   150 		dict = NULL;
   151 	}
   152 
   153 	return dict;
   154 }