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