|
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 |
}
|