1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 // vim:set ts=2 sts=2 sw=2 et cin:
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "CocoaFileUtils.h"
8 #include "nsCocoaUtils.h"
9 #include <Cocoa/Cocoa.h>
10 #include "nsObjCExceptions.h"
13 #include "mozilla/MacStringHelpers.h"
15 namespace CocoaFileUtils {
17 nsresult RevealFileInFinder(CFURLRef url) {
18 NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
20 if (NS_WARN_IF(!url)) {
21 return NS_ERROR_INVALID_ARG;
24 nsAutoreleasePool localPool;
26 BOOL success = [[NSWorkspace sharedWorkspace] selectFile:[(NSURL*)url path]
27 inFileViewerRootedAtPath:@""];
29 return (success ? NS_OK : NS_ERROR_FAILURE);
31 NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
34 nsresult OpenURL(CFURLRef url) {
35 NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
37 if (NS_WARN_IF(!url)) {
38 return NS_ERROR_INVALID_ARG;
41 nsAutoreleasePool localPool;
43 [[NSWorkspace sharedWorkspace] openURL:(NSURL*)url];
47 NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
50 nsresult GetFileCreatorCode(CFURLRef url, OSType* creatorCode) {
51 NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
53 if (NS_WARN_IF(!url) || NS_WARN_IF(!creatorCode)) {
54 return NS_ERROR_INVALID_ARG;
57 nsAutoreleasePool localPool;
59 NSString* resolvedPath = [[(NSURL*)url path] stringByResolvingSymlinksInPath];
61 return NS_ERROR_FAILURE;
65 [[NSFileManager defaultManager] attributesOfItemAtPath:resolvedPath
68 return NS_ERROR_FAILURE;
71 NSNumber* creatorNum = (NSNumber*)[dict objectForKey:NSFileHFSCreatorCode];
73 return NS_ERROR_FAILURE;
76 *creatorCode = [creatorNum unsignedLongValue];
79 NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
82 nsresult SetFileCreatorCode(CFURLRef url, OSType creatorCode) {
83 NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
85 if (NS_WARN_IF(!url)) {
86 return NS_ERROR_INVALID_ARG;
89 nsAutoreleasePool localPool;
91 NSDictionary* dict = [NSDictionary
92 dictionaryWithObject:[NSNumber numberWithUnsignedLong:creatorCode]
93 forKey:NSFileHFSCreatorCode];
95 [[NSFileManager defaultManager] setAttributes:dict
96 ofItemAtPath:[(NSURL*)url path]
99 return (success ? NS_OK : NS_ERROR_FAILURE);
101 NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
104 nsresult GetFileTypeCode(CFURLRef url, OSType* typeCode) {
105 NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
107 if (NS_WARN_IF(!url) || NS_WARN_IF(!typeCode)) {
108 return NS_ERROR_INVALID_ARG;
111 nsAutoreleasePool localPool;
113 NSString* resolvedPath = [[(NSURL*)url path] stringByResolvingSymlinksInPath];
115 return NS_ERROR_FAILURE;
119 [[NSFileManager defaultManager] attributesOfItemAtPath:resolvedPath
122 return NS_ERROR_FAILURE;
125 NSNumber* typeNum = (NSNumber*)[dict objectForKey:NSFileHFSTypeCode];
127 return NS_ERROR_FAILURE;
130 *typeCode = [typeNum unsignedLongValue];
133 NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
136 nsresult SetFileTypeCode(CFURLRef url, OSType typeCode) {
137 NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
139 if (NS_WARN_IF(!url)) {
140 return NS_ERROR_INVALID_ARG;
143 nsAutoreleasePool localPool;
145 NSDictionary* dict = [NSDictionary
146 dictionaryWithObject:[NSNumber numberWithUnsignedLong:typeCode]
147 forKey:NSFileHFSTypeCode];
149 [[NSFileManager defaultManager] setAttributes:dict
150 ofItemAtPath:[(NSURL*)url path]
153 return (success ? NS_OK : NS_ERROR_FAILURE);
155 NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
158 // Can be called off of the main thread.
159 void AddOriginMetadataToFile(const CFStringRef filePath,
160 const CFURLRef sourceURL,
161 const CFURLRef referrerURL) {
162 nsAutoreleasePool localPool;
164 typedef OSStatus (*MDItemSetAttribute_type)(MDItemRef, CFStringRef,
166 static MDItemSetAttribute_type mdItemSetAttributeFunc = NULL;
168 static bool did_symbol_lookup = false;
169 if (!did_symbol_lookup) {
170 did_symbol_lookup = true;
172 CFBundleRef metadata_bundle =
173 ::CFBundleGetBundleWithIdentifier(CFSTR("com.apple.Metadata"));
174 if (!metadata_bundle) {
178 mdItemSetAttributeFunc =
179 (MDItemSetAttribute_type)::CFBundleGetFunctionPointerForName(
180 metadata_bundle, CFSTR("MDItemSetAttribute"));
182 if (!mdItemSetAttributeFunc) {
186 MDItemRef mdItem = ::MDItemCreate(NULL, filePath);
191 CFMutableArrayRef list = ::CFArrayCreateMutable(kCFAllocatorDefault, 2, NULL);
197 // The first item in the list is the source URL of the downloaded file.
199 ::CFArrayAppendValue(list, ::CFURLGetString(sourceURL));
202 // If the referrer is known, store that in the second position.
204 ::CFArrayAppendValue(list, ::CFURLGetString(referrerURL));
207 mdItemSetAttributeFunc(mdItem, kMDItemWhereFroms, list);
213 // Can be called off of the main thread.
214 static CFMutableDictionaryRef CreateQuarantineDictionary(
215 const CFURLRef aFileURL, const bool aCreateProps) {
216 nsAutoreleasePool localPool;
218 CFDictionaryRef quarantineProps = NULL;
220 quarantineProps = ::CFDictionaryCreate(NULL, NULL, NULL, 0,
221 &kCFTypeDictionaryKeyCallBacks,
222 &kCFTypeDictionaryValueCallBacks);
224 Boolean success = ::CFURLCopyResourcePropertyForKey(
225 aFileURL, kCFURLQuarantinePropertiesKey, &quarantineProps, NULL);
226 // If there aren't any quarantine properties then the user probably
227 // set up an exclusion and we don't need to add metadata.
228 if (!success || !quarantineProps) {
233 // We don't know what to do if the props aren't a dictionary.
234 if (::CFGetTypeID(quarantineProps) != ::CFDictionaryGetTypeID()) {
235 ::CFRelease(quarantineProps);
239 // Make a mutable copy of the properties.
240 CFMutableDictionaryRef mutQuarantineProps = ::CFDictionaryCreateMutableCopy(
241 kCFAllocatorDefault, 0, (CFDictionaryRef)quarantineProps);
242 ::CFRelease(quarantineProps);
244 return mutQuarantineProps;
247 // Can be called off of the main thread.
248 void AddQuarantineMetadataToFile(const CFStringRef filePath,
249 const CFURLRef sourceURL,
250 const CFURLRef referrerURL,
251 const bool isFromWeb,
252 const bool createProps /* = false */) {
253 nsAutoreleasePool localPool;
255 CFURLRef fileURL = ::CFURLCreateWithFileSystemPath(
256 kCFAllocatorDefault, filePath, kCFURLPOSIXPathStyle, false);
258 CFMutableDictionaryRef mutQuarantineProps =
259 CreateQuarantineDictionary(fileURL, createProps);
260 if (!mutQuarantineProps) {
261 ::CFRelease(fileURL);
265 // Add metadata that the OS couldn't infer.
267 if (!::CFDictionaryGetValue(mutQuarantineProps, kLSQuarantineTypeKey)) {
268 CFStringRef type = isFromWeb ? kLSQuarantineTypeWebDownload
269 : kLSQuarantineTypeOtherDownload;
270 ::CFDictionarySetValue(mutQuarantineProps, kLSQuarantineTypeKey, type);
273 if (!::CFDictionaryGetValue(mutQuarantineProps, kLSQuarantineOriginURLKey) &&
275 ::CFDictionarySetValue(mutQuarantineProps, kLSQuarantineOriginURLKey,
279 if (!::CFDictionaryGetValue(mutQuarantineProps, kLSQuarantineDataURLKey) &&
281 ::CFDictionarySetValue(mutQuarantineProps, kLSQuarantineDataURLKey,
285 // Set quarantine properties on file.
286 ::CFURLSetResourcePropertyForKey(fileURL, kCFURLQuarantinePropertiesKey,
287 mutQuarantineProps, NULL);
289 ::CFRelease(fileURL);
290 ::CFRelease(mutQuarantineProps);
293 // Can be called off of the main thread.
294 void CopyQuarantineReferrerUrl(const CFStringRef aFilePath,
295 nsAString& aReferrer) {
296 nsAutoreleasePool localPool;
298 CFURLRef fileURL = ::CFURLCreateWithFileSystemPath(
299 kCFAllocatorDefault, aFilePath, kCFURLPOSIXPathStyle, false);
301 CFMutableDictionaryRef mutQuarantineProps =
302 CreateQuarantineDictionary(fileURL, false);
303 ::CFRelease(fileURL);
304 if (!mutQuarantineProps) {
308 CFTypeRef referrerRef =
309 ::CFDictionaryGetValue(mutQuarantineProps, kLSQuarantineOriginURLKey);
310 if (referrerRef && ::CFGetTypeID(referrerRef) == ::CFURLGetTypeID()) {
311 // URL string must be copied prior to releasing the dictionary.
312 mozilla::CopyCocoaStringToXPCOMString(
313 (NSString*)::CFURLGetString(static_cast<CFURLRef>(referrerRef)),
317 ::CFRelease(mutQuarantineProps);
320 CFTypeRefPtr<CFURLRef> GetTemporaryFolder() {
321 nsAutoreleasePool localPool;
323 NSString* tempDir = ::NSTemporaryDirectory();
324 return tempDir == nil ? NULL
325 : CFTypeRefPtr<CFURLRef>::WrapUnderGetRule(
326 (__bridge CFURLRef)[NSURL fileURLWithPath:tempDir
330 CFTypeRefPtr<CFURLRef> GetProductDirectory(bool aLocal) {
331 nsAutoreleasePool localPool;
333 NSSearchPathDirectory folderType =
334 aLocal ? NSCachesDirectory : NSLibraryDirectory;
335 NSFileManager* manager = [NSFileManager defaultManager];
336 return CFTypeRefPtr<CFURLRef>::WrapUnderGetRule((__bridge CFURLRef)[[manager
337 URLsForDirectory:folderType
338 inDomains:NSUserDomainMask] firstObject]);
341 } // namespace CocoaFileUtils