Bug 1867190 - Add prefs for PHC probablities r=glandium
[gecko.git] / xpcom / io / CocoaFileUtils.mm
blob3710be864cdcbed9f3218d0cf7b4145f2b59d354
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"
11 #include "nsDebug.h"
12 #include "nsString.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;
22   }
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;
39   }
41   nsAutoreleasePool localPool;
43   [[NSWorkspace sharedWorkspace] openURL:(NSURL*)url];
45   return NS_OK;
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;
55   }
57   nsAutoreleasePool localPool;
59   NSString* resolvedPath = [[(NSURL*)url path] stringByResolvingSymlinksInPath];
60   if (!resolvedPath) {
61     return NS_ERROR_FAILURE;
62   }
64   NSDictionary* dict =
65       [[NSFileManager defaultManager] attributesOfItemAtPath:resolvedPath
66                                                        error:nil];
67   if (!dict) {
68     return NS_ERROR_FAILURE;
69   }
71   NSNumber* creatorNum = (NSNumber*)[dict objectForKey:NSFileHFSCreatorCode];
72   if (!creatorNum) {
73     return NS_ERROR_FAILURE;
74   }
76   *creatorCode = [creatorNum unsignedLongValue];
77   return NS_OK;
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;
87   }
89   nsAutoreleasePool localPool;
91   NSDictionary* dict = [NSDictionary
92       dictionaryWithObject:[NSNumber numberWithUnsignedLong:creatorCode]
93                     forKey:NSFileHFSCreatorCode];
94   BOOL success =
95       [[NSFileManager defaultManager] setAttributes:dict
96                                        ofItemAtPath:[(NSURL*)url path]
97                                               error:nil];
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;
109   }
111   nsAutoreleasePool localPool;
113   NSString* resolvedPath = [[(NSURL*)url path] stringByResolvingSymlinksInPath];
114   if (!resolvedPath) {
115     return NS_ERROR_FAILURE;
116   }
118   NSDictionary* dict =
119       [[NSFileManager defaultManager] attributesOfItemAtPath:resolvedPath
120                                                        error:nil];
121   if (!dict) {
122     return NS_ERROR_FAILURE;
123   }
125   NSNumber* typeNum = (NSNumber*)[dict objectForKey:NSFileHFSTypeCode];
126   if (!typeNum) {
127     return NS_ERROR_FAILURE;
128   }
130   *typeCode = [typeNum unsignedLongValue];
131   return NS_OK;
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;
141   }
143   nsAutoreleasePool localPool;
145   NSDictionary* dict = [NSDictionary
146       dictionaryWithObject:[NSNumber numberWithUnsignedLong:typeCode]
147                     forKey:NSFileHFSTypeCode];
148   BOOL success =
149       [[NSFileManager defaultManager] setAttributes:dict
150                                        ofItemAtPath:[(NSURL*)url path]
151                                               error:nil];
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,
165                                               CFTypeRef);
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) {
175       return;
176     }
178     mdItemSetAttributeFunc =
179         (MDItemSetAttribute_type)::CFBundleGetFunctionPointerForName(
180             metadata_bundle, CFSTR("MDItemSetAttribute"));
181   }
182   if (!mdItemSetAttributeFunc) {
183     return;
184   }
186   MDItemRef mdItem = ::MDItemCreate(NULL, filePath);
187   if (!mdItem) {
188     return;
189   }
191   CFMutableArrayRef list = ::CFArrayCreateMutable(kCFAllocatorDefault, 2, NULL);
192   if (!list) {
193     ::CFRelease(mdItem);
194     return;
195   }
197   // The first item in the list is the source URL of the downloaded file.
198   if (sourceURL) {
199     ::CFArrayAppendValue(list, ::CFURLGetString(sourceURL));
200   }
202   // If the referrer is known, store that in the second position.
203   if (referrerURL) {
204     ::CFArrayAppendValue(list, ::CFURLGetString(referrerURL));
205   }
207   mdItemSetAttributeFunc(mdItem, kMDItemWhereFroms, list);
209   ::CFRelease(list);
210   ::CFRelease(mdItem);
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;
219   if (aCreateProps) {
220     quarantineProps = ::CFDictionaryCreate(NULL, NULL, NULL, 0,
221                                            &kCFTypeDictionaryKeyCallBacks,
222                                            &kCFTypeDictionaryValueCallBacks);
223   } else {
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) {
229       return NULL;
230     }
231   }
233   // We don't know what to do if the props aren't a dictionary.
234   if (::CFGetTypeID(quarantineProps) != ::CFDictionaryGetTypeID()) {
235     ::CFRelease(quarantineProps);
236     return NULL;
237   }
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);
262     return;
263   }
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);
271   }
273   if (!::CFDictionaryGetValue(mutQuarantineProps, kLSQuarantineOriginURLKey) &&
274       referrerURL) {
275     ::CFDictionarySetValue(mutQuarantineProps, kLSQuarantineOriginURLKey,
276                            referrerURL);
277   }
279   if (!::CFDictionaryGetValue(mutQuarantineProps, kLSQuarantineDataURLKey) &&
280       sourceURL) {
281     ::CFDictionarySetValue(mutQuarantineProps, kLSQuarantineDataURLKey,
282                            sourceURL);
283   }
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) {
305     return;
306   }
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)),
314         aReferrer);
315   }
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
327                                                             isDirectory:YES]);
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