Bug 571193. Move Mac OS X to UNIX filesystem code shared with Linux. Also fixes bug 506812, bug 528447, bug 530188. r=benwa sr=bsmedberg CLOSED TREE
☠☠ backed out by d0d098061840 ☠ ☠
authorJosh Aas <joshmoz@gmail.com>
Fri, 16 Jul 2010 18:35:59 -0400
changeset 47841 f6c93f02146c55b55209c6ae622e15a88cb28543
parent 47840 9712aa5f77e17cbe24fd906ccadb87689af761eb
child 47842 0688052c607f8cfcf72b522028eb7c138c47067e
child 47843 d0d098061840a2d4bb25beada4dfc4f84bdc6cb5
push id14441
push userjosh@mozilla.com
push dateFri, 16 Jul 2010 22:36:13 +0000
treeherdermozilla-central@f6c93f02146c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbenwa, bsmedberg
bugs571193, 506812, 528447, 530188
milestone2.0b2pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 571193. Move Mac OS X to UNIX filesystem code shared with Linux. Also fixes bug 506812, bug 528447, bug 530188. r=benwa sr=bsmedberg CLOSED TREE
toolkit/xre/nsAppRunner.cpp
xpcom/io/CocoaFileUtils.h
xpcom/io/CocoaFileUtils.mm
xpcom/io/Makefile.in
xpcom/io/nsILocalFileMac.idl
xpcom/io/nsLocalFile.h
xpcom/io/nsLocalFileOSX.h
xpcom/io/nsLocalFileOSX.mm
xpcom/io/nsLocalFileUnix.cpp
xpcom/io/nsLocalFileUnix.h
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -1502,32 +1502,27 @@ XRE_GetBinaryPath(const char* argv0, nsI
   if (!lfm)
     return NS_ERROR_FAILURE;
 
   // Works even if we're not bundled.
   CFBundleRef appBundle = CFBundleGetMainBundle();
   if (!appBundle)
     return NS_ERROR_FAILURE;
 
-  CFURLRef bundleURL = CFBundleCopyExecutableURL(appBundle);
-  if (!bundleURL)
+  CFURLRef executableURL = CFBundleCopyExecutableURL(appBundle);
+  if (!executableURL)
     return NS_ERROR_FAILURE;
-
-  FSRef fileRef;
-  if (!CFURLGetFSRef(bundleURL, &fileRef)) {
-    CFRelease(bundleURL);
-    return NS_ERROR_FAILURE;
-  }
-
-  rv = lfm->InitWithFSRef(&fileRef);
-  CFRelease(bundleURL);
-
+  rv = lfm->InitWithCFURL(executableURL);
+  CFRelease(executableURL);
   if (NS_FAILED(rv))
     return rv;
 
+  // Callers expect a normalized path.
+  lfm->Normalize();
+
 #elif defined(XP_UNIX)
   struct stat fileStat;
   char exePath[MAXPATHLEN];
   char tmpPath[MAXPATHLEN];
 
   rv = NS_ERROR_FAILURE;
 
   // on unix, there is no official way to get the path of the current binary.
new file mode 100644
--- /dev/null
+++ b/xpcom/io/CocoaFileUtils.h
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+// vim:set ts=2 sts=2 sw=2 et cin:
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Josh Aas <josh@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// This namespace contains methods with Obj-C/Cocoa implementations. The header
+// is C/C++ for inclusion in C/C++-only files.
+
+#ifndef CocoaFileUtils_h_
+#define CocoaFileUtils_h_
+
+#include "nscore.h"
+#include <CoreFoundation/CoreFoundation.h>
+
+namespace CocoaFileUtils {
+
+nsresult RevealFileInFinder(CFURLRef url);
+nsresult OpenURL(CFURLRef url);
+nsresult GetFileCreatorCode(CFURLRef url, OSType *creatorCode);
+nsresult SetFileCreatorCode(CFURLRef url, OSType creatorCode);
+nsresult GetFileTypeCode(CFURLRef url, OSType *typeCode);
+nsresult SetFileTypeCode(CFURLRef url, OSType typeCode);
+
+} // namespace CocoaFileUtils
+
+#endif
new file mode 100644
--- /dev/null
+++ b/xpcom/io/CocoaFileUtils.mm
@@ -0,0 +1,153 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+// vim:set ts=2 sts=2 sw=2 et cin:
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Josh Aas <josh@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "CocoaFileUtils.h"
+#include <Cocoa/Cocoa.h>
+#include "nsObjCExceptions.h"
+#include "nsDebug.h"
+
+namespace CocoaFileUtils {
+
+nsresult RevealFileInFinder(CFURLRef url)
+{
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
+
+  NS_ENSURE_ARG_POINTER(url);
+
+  NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init];
+  BOOL success = [[NSWorkspace sharedWorkspace] selectFile:[(NSURL*)url path] inFileViewerRootedAtPath:@""];
+  [ap release];
+
+  return (success ? NS_OK : NS_ERROR_FAILURE);
+
+  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
+}
+
+nsresult OpenURL(CFURLRef url)
+{
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
+
+  NS_ENSURE_ARG_POINTER(url);
+
+  NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init];
+  BOOL success = [[NSWorkspace sharedWorkspace] openURL:(NSURL*)url];
+  [ap release];
+
+  return (success ? NS_OK : NS_ERROR_FAILURE);
+
+  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
+}
+
+nsresult GetFileCreatorCode(CFURLRef url, OSType *creatorCode)
+{
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
+
+  NS_ENSURE_ARG_POINTER(url);
+  NS_ENSURE_ARG_POINTER(creatorCode);
+
+  nsresult rv = NS_ERROR_FAILURE;
+
+  NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init];
+  NSDictionary* dict = [[NSFileManager defaultManager] fileAttributesAtPath:[(NSURL*)url path] traverseLink:YES];
+  NSNumber* creatorNum = (NSNumber*)[dict objectForKey:NSFileHFSCreatorCode];
+  if (creatorNum) {
+    *creatorCode = [creatorNum unsignedLongValue];
+    rv = NS_OK;
+  }
+  [ap release];
+
+  return rv;
+
+  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
+}
+
+nsresult SetFileCreatorCode(CFURLRef url, OSType creatorCode)
+{
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
+
+  NS_ENSURE_ARG_POINTER(url);
+
+  NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init];
+  NSDictionary* dict = [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedLong:creatorCode] forKey:NSFileHFSCreatorCode];
+  BOOL success = [[NSFileManager defaultManager] setAttributes:dict ofItemAtPath:[(NSURL*)url path] error:nil];
+  [ap release];
+  return (success ? NS_OK : NS_ERROR_FAILURE);
+
+  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
+}
+
+nsresult GetFileTypeCode(CFURLRef url, OSType *typeCode)
+{
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
+
+  NS_ENSURE_ARG_POINTER(url);
+  NS_ENSURE_ARG_POINTER(typeCode);
+
+  nsresult rv = NS_ERROR_FAILURE;
+
+  NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init];
+  NSDictionary* dict = [[NSFileManager defaultManager] fileAttributesAtPath:[(NSURL*)url path] traverseLink:YES];
+  NSNumber* typeNum = (NSNumber*)[dict objectForKey:NSFileHFSTypeCode];
+  if (typeNum) {
+    *typeCode = [typeNum unsignedLongValue];
+    rv = NS_OK;
+  }
+  [ap release];
+
+  return rv;
+
+  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
+}
+
+nsresult SetFileTypeCode(CFURLRef url, OSType typeCode)
+{
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
+
+  NS_ENSURE_ARG_POINTER(url);
+
+  NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init];
+  NSDictionary* dict = [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedLong:typeCode] forKey:NSFileHFSTypeCode];
+  BOOL success = [[NSFileManager defaultManager] setAttributes:dict ofItemAtPath:[(NSURL*)url path] error:nil];
+  [ap release];
+  return (success ? NS_OK : NS_ERROR_FAILURE);
+
+  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
+}
+
+} // namespace CocoaFileUtils
--- a/xpcom/io/Makefile.in
+++ b/xpcom/io/Makefile.in
@@ -72,35 +72,37 @@ CPPSRCS		= \
 		nsStorageStream.cpp \
 		nsStringStream.cpp \
 		nsUnicharInputStream.cpp \
 		nsIOUtil.cpp \
 		nsWildCard.cpp \
 		SpecialSystemDirectory.cpp \
 		$(NULL)
 
+ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
+CMMSRCS		+= \
+		CocoaFileUtils.mm \
+		$(NULL)
+endif
+
 ifndef MOZ_NO_FAST_LOAD
 CPPSRCS += \
 		nsFastLoadFile.cpp \
 		nsFastLoadService.cpp \
 		$(NULL)
 endif
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),os2)
 CPPSRCS		+= nsLocalFileOS2.cpp
 else
-ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
-CMMSRCS		= nsLocalFileOSX.mm
-else
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 CPPSRCS		+= nsLocalFileWin.cpp
 else
 CPPSRCS		+= nsLocalFileUnix.cpp
 endif # windows
-endif # mac
 endif # OS2
 
 EXPORTS		= \
 		nsAppDirectoryServiceDefs.h \
 		nsDirectoryService.h \
 		nsDirectoryServiceAtomList.h \
 		nsEscape.h \
 		nsFastLoadService.h \
@@ -113,25 +115,21 @@ EXPORTS		= \
 		nsStringStream.h \
 		nsStreamUtils.h \
 		nsWildCard.h \
 		$(NULL)			
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),os2)
 EXPORTS		+= nsLocalFileOS2.h
 else
-ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
-EXPORTS		+= nsLocalFileOSX.h
-else
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 EXPORTS		+= nsLocalFileWin.h
 else
 EXPORTS		+= nsLocalFileUnix.h
 endif # windows
-endif # cocoa
 endif # os2
 
 XPIDLSRCS	= \
 		nsIBinaryInputStream.idl \
 		nsIBinaryOutputStream.idl  \
 		nsIDirectoryEnumerator.idl \
 		nsIFastLoadFileControl.idl \
 		nsIFastLoadService.idl \
--- a/xpcom/io/nsILocalFileMac.idl
+++ b/xpcom/io/nsILocalFileMac.idl
@@ -45,17 +45,17 @@
 %}
 
       native OSType(OSType);
       native FSSpec(FSSpec);
       native FSRef(FSRef);
 [ptr] native FSRefPtr(FSRef);
       native CFURLRef(CFURLRef);
 
-[scriptable, uuid(86D685E5-EE3F-405A-B521-446529DB82E5)]
+[scriptable, uuid(DE4C75BE-D42B-4F8C-95D9-284C83CF29A4)]
 interface nsILocalFileMac : nsILocalFile
 {
    /**
     * initWithCFURL
     *
     * Init this object with a CFURLRef
     *
     * NOTE: Supported only for XP_MACOSX
@@ -73,28 +73,16 @@ interface nsILocalFileMac : nsILocalFile
     *
     * NOTE: Supported only for XP_MACOSX
     *
     * @param   aFSRef         the native FSRef
     *
     */
   [noscript] void initWithFSRef([const] in FSRefPtr aFSRef);
 
-   /**
-    * initToAppWithCreatorCode
-    *
-    * Init this object to point to an application having the given
-    * creator code. If this app is missing, this will fail. It will first
-    * look for running application with the given creator.
-    *
-    * @param   aAppCreator     the signature of the app
-    *
-    */
-  [noscript] void initToAppWithCreatorCode(in OSType aAppCreator);
-
     /**
     * getCFURL
     *
     * Returns the CFURLRef of the file object. The caller is
     * responsible for calling CFRelease() on it.
     *
     * NOTE: Observes the state of the followLinks attribute.
     * If the file object is an alias and followLinks is TRUE, returns
@@ -144,22 +132,17 @@ interface nsILocalFileMac : nsILocalFile
     * fileSizeWithResFork
     * 
     * Returns the combined size of both the data fork and the resource
     * fork (if present) rather than just the size of the data fork
     * as returned by GetFileSize()
     *
     */
    readonly attribute PRInt64 fileSizeWithResFork;
-    
-   /**
-    * Use with SetFileType() to specify the signature of current process
-    */
-   const unsigned long CURRENT_PROCESS_CREATOR = 0x8000000;
-    
+
    /**
     * fileType, creator
     *
     * File type and creator attributes
     *
     */
    [noscript] attribute OSType fileType;
    [noscript] attribute OSType fileCreator;
--- a/xpcom/io/nsLocalFile.h
+++ b/xpcom/io/nsLocalFile.h
@@ -67,18 +67,16 @@
 // so here we will export it.  Other users should not depend
 // on this.
 
 #include <errno.h>
 #include "nsILocalFile.h"
 
 #ifdef XP_WIN
 #include "nsLocalFileWin.h"
-#elif defined(XP_MACOSX)
-#include "nsLocalFileOSX.h"
 #elif defined(XP_UNIX) || defined(XP_BEOS)
 #include "nsLocalFileUnix.h"
 #elif defined(XP_OS2)
 #include "nsLocalFileOS2.h"
 #else
 #error NOT_IMPLEMENTED
 #endif
 
deleted file mode 100644
--- a/xpcom/io/nsLocalFileOSX.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2001, 2002
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *  Conrad Carlen <ccarlen@netscape.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef nsLocalFileMac_h_
-#define nsLocalFileMac_h_
-
-#include "nsILocalFileMac.h"
-#include "nsString.h"
-#include "nsIHashable.h"
-
-class nsDirEnumerator;
-
-// Mac OS X 10.4 does not have stat64/lstat64
-#if defined(HAVE_STAT64) && defined(HAVE_LSTAT64) && (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4)
-#define STAT stat64
-#define LSTAT lstat64
-#else
-#define STAT stat
-#define LSTAT lstat
-#endif
-
-// Mac OS X 10.4 does not have statvfs64
-#if defined(HAVE_STATVFS64) && (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4)
-#define STATVFS statvfs64
-#else
-#define STATVFS statvfs
-#endif
-
-// The native charset of this implementation is UTF-8. The Unicode used by the
-// Mac OS file system is decomposed, so "Native" versions of these routines will
-// always use decomposed Unicode (NFD). Their "non-Native" counterparts are 
-// intended to be simple wrappers which call the "Native" version and convert 
-// between UTF-8 and UTF-16. All the work is done on the "Native" side except
-// for the conversion to NFC (composed Unicode) done in "non-Native" getters.
-
-class NS_COM nsLocalFile : public nsILocalFileMac,
-                           public nsIHashable
-{
-  friend class nsDirEnumerator;
-    
-public:
-  NS_DEFINE_STATIC_CID_ACCESSOR(NS_LOCAL_FILE_CID)
-
-  nsLocalFile();
-
-  static nsresult nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr);
-
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIFILE
-  NS_DECL_NSILOCALFILE
-  NS_DECL_NSILOCALFILEMAC
-  NS_DECL_NSIHASHABLE
-
-public:
-  static void GlobalInit();
-  static void GlobalShutdown();
-
-private:
-  ~nsLocalFile();
-
-protected:
-  nsLocalFile(const nsLocalFile& src);
-  nsresult SetBaseURL(CFURLRef aCFURLRef); // retains aCFURLRef
-  nsresult GetFSRefInternal(FSRef& aFSRef);
-  nsresult GetPathInternal(nsACString& path); // Returns path respecting mFollowLinks
-  nsresult CopyInternal(nsIFile* newParentDir,
-                        const nsAString& newName,
-                        PRBool followLinks);
-  nsresult FillStatBufferInternal(struct STAT *statBuffer);
-
-protected:
-  CFURLRef     mBaseURL; // The FS object we represent
-  char         mPath[PATH_MAX]; // POSIX path, UTF-8, NULL terminated
-  PRPackedBool mFollowLinks;
-};
-
-#endif // nsLocalFileMac_h_
deleted file mode 100644
--- a/xpcom/io/nsLocalFileOSX.mm
+++ /dev/null
@@ -1,2278 +0,0 @@
-/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2001, 2002
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *  Conrad Carlen <ccarlen@netscape.com>
- *  Jungshik Shin <jshin@mailaps.org>
- *  Asaf Romano <mozilla.mano@sent.com>
- *  Mark Mentovai <mark@moxienet.com>
- *  Josh Aas <josh@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "nsLocalFile.h"
-#include "nsDirectoryServiceDefs.h"
-
-#include "nsObjCExceptions.h"
-#include "nsAutoPtr.h"
-#include "nsString.h"
-#include "nsReadableUtils.h"
-#include "nsIDirectoryEnumerator.h"
-#include "nsISimpleEnumerator.h"
-#include "nsITimelineService.h"
-#include "nsTArray.h"
-
-#include "plbase64.h"
-#include "prmem.h"
-#include "nsCRT.h"
-#include "nsHashKeys.h"
-
-#include "nsTraceRefcntImpl.h"
-
-#include <Carbon/Carbon.h>
-#import <Cocoa/Cocoa.h>
-
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/statvfs.h>
-#include <stdlib.h>
-#include <utime.h>
-
-#define CHECK_INIT()                            \
-    PR_BEGIN_MACRO                              \
-        if (!mBaseURL)                          \
-            return NS_ERROR_NOT_INITIALIZED;    \
-    PR_END_MACRO
-
-static nsresult MacErrorMapper(OSErr inErr);
-static void CopyUTF8toUTF16NFC(const nsACString& aSrc, nsAString& aResult);
-static nsresult CFStringReftoUTF8(CFStringRef aInStrRef, nsACString& aOutStr);
-
-#pragma mark -
-#pragma mark [FSRef operator==]
-
-bool operator==(const FSRef& lhs, const FSRef& rhs)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
-
-  return (::FSCompareFSRefs(&lhs, &rhs) == noErr);
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(false);
-}
-
-#pragma mark -
-#pragma mark [StFollowLinksState]
-
-class StFollowLinksState
-{
-  public:
-    StFollowLinksState(nsLocalFile& aFile) :
-        mFile(aFile)
-    {
-        mFile.GetFollowLinks(&mSavedState);
-    }
-
-    StFollowLinksState(nsLocalFile& aFile, PRBool followLinksState) :
-        mFile(aFile)
-    {
-        mFile.GetFollowLinks(&mSavedState);
-        mFile.SetFollowLinks(followLinksState);
-    }
-
-    ~StFollowLinksState()
-    {
-        mFile.SetFollowLinks(mSavedState);
-    }
-    
-  private:
-    nsLocalFile& mFile;
-    PRBool mSavedState;
-};
-
-#pragma mark -
-#pragma mark [nsDirEnumerator]
-
-class nsDirEnumerator : public nsISimpleEnumerator,
-                        public nsIDirectoryEnumerator
-{
-    public:
-
-        NS_DECL_ISUPPORTS
-
-        nsDirEnumerator() :
-          mIterator(nsnull),
-          mFSRefsArray(nsnull),
-          mArrayCnt(0), mArrayIndex(0)
-        {
-        }
-
-        nsresult Init(nsILocalFileMac* parent) 
-        {
-          NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-          NS_ENSURE_ARG(parent);
-          
-          OSErr err;
-          nsresult rv;
-          FSRef parentRef;
-          
-          rv = parent->GetFSRef(&parentRef);
-          if (NS_FAILED(rv))
-            return rv;
-          
-          mFSRefsArray = (FSRef *)nsMemory::Alloc(sizeof(FSRef)
-                                                  * kRequestCountPerIteration);
-          if (!mFSRefsArray)
-            return NS_ERROR_OUT_OF_MEMORY;
-          
-          err = ::FSOpenIterator(&parentRef, kFSIterateFlat, &mIterator);
-          if (err != noErr)
-            return MacErrorMapper(err);
-                              
-          return NS_OK;
-
-          NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-        }
-
-        NS_IMETHOD HasMoreElements(PRBool *result) 
-        {
-          NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-          if (!mIterator || !mFSRefsArray) {
-            *result = PR_FALSE;
-            return NS_OK;
-          }
-
-          if (mNext == nsnull) {
-            if (mArrayIndex >= mArrayCnt) {
-              ItemCount actualCnt;
-              OSErr err = ::FSGetCatalogInfoBulk(mIterator,
-                                           kRequestCountPerIteration,
-                                           &actualCnt,
-                                           nsnull,
-                                           kFSCatInfoNone,
-                                           nsnull,
-                                           mFSRefsArray,
-                                           nsnull,
-                                           nsnull);
-            
-              if (err == noErr || err == errFSNoMoreItems) {
-                mArrayCnt = actualCnt;
-                mArrayIndex = 0;
-              }
-            }
-
-            if (mArrayIndex < mArrayCnt) {
-              nsRefPtr<nsLocalFile> newFile = new nsLocalFile;
-              if (!newFile)
-                return NS_ERROR_OUT_OF_MEMORY;
-              FSRef fsRef = mFSRefsArray[mArrayIndex];
-              if (NS_FAILED(newFile->InitWithFSRef(&fsRef)))
-                return NS_ERROR_FAILURE;
-              mArrayIndex++;
-              mNext = newFile;
-            } 
-          }
-
-          *result = mNext != nsnull;
-          if (!*result)
-            Close();
-
-          return NS_OK;
-
-          NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-        }
-
-        NS_IMETHOD GetNext(nsISupports **result) 
-        {
-            NS_ENSURE_ARG_POINTER(result);
-            *result = nsnull;
-
-            nsresult rv;
-            PRBool hasMore;
-            rv = HasMoreElements(&hasMore);
-            if (NS_FAILED(rv)) return rv;
-
-            *result = mNext; // might return nsnull
-            NS_IF_ADDREF(*result);
-
-            mNext = nsnull;
-            return NS_OK;
-        }
-
-        NS_IMETHOD GetNextFile(nsIFile **result)
-        {
-            *result = nsnull;
-            PRBool hasMore = PR_FALSE;
-            nsresult rv = HasMoreElements(&hasMore);
-            if (NS_FAILED(rv) || !hasMore)
-                return rv;
-            *result = mNext;
-            NS_IF_ADDREF(*result);
-            mNext = nsnull;
-            return NS_OK;
-        }
-
-        NS_IMETHOD Close()
-        {
-          NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-          if (mIterator) {
-            ::FSCloseIterator(mIterator);
-            mIterator = nsnull;
-          }
-          if (mFSRefsArray) {
-            nsMemory::Free(mFSRefsArray);
-            mFSRefsArray = nsnull;
-          }
-          return NS_OK;
-
-          NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-        }
-
-    private:
-        ~nsDirEnumerator() 
-        {
-          Close();
-        }
-
-    protected:
-        // According to Apple doc, request the number of objects
-        // per call that will fit in 4 VM pages.
-        enum {
-          kRequestCountPerIteration = ((4096 * 4) / sizeof(FSRef))
-        };
-        
-        nsCOMPtr<nsILocalFileMac>   mNext;
-        
-        FSIterator              mIterator;
-        FSRef                   *mFSRefsArray;
-        PRInt32                 mArrayCnt, mArrayIndex;
-};
-
-NS_IMPL_ISUPPORTS2(nsDirEnumerator, nsISimpleEnumerator, nsIDirectoryEnumerator)
-
-const char kPathSepChar = '/';
-
-#pragma mark -
-#pragma mark [CTORs/DTOR]
-
-nsLocalFile::nsLocalFile() :
-  mBaseURL(NULL),
-  mFollowLinks(PR_TRUE)
-{
-  mPath[0] = '\0';
-}
-
-nsLocalFile::nsLocalFile(const nsLocalFile& src) :
-  mBaseURL(NULL),
-  mFollowLinks(src.mFollowLinks)
-{
-  SetBaseURL(src.mBaseURL);
-}
-
-nsLocalFile::~nsLocalFile()
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
-
-  if (mBaseURL)
-    ::CFRelease(mBaseURL);
-
-  NS_OBJC_END_TRY_ABORT_BLOCK;
-}
-
-#pragma mark -
-#pragma mark [nsISupports]
-
-NS_IMPL_THREADSAFE_ISUPPORTS4(nsLocalFile,
-                              nsILocalFileMac,
-                              nsILocalFile,
-                              nsIFile,
-                              nsIHashable)
-                              
-nsresult
-nsLocalFile::nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
-{
-  NS_ENSURE_ARG_POINTER(aInstancePtr);
-  NS_ENSURE_NO_AGGREGATION(outer);
-
-  nsLocalFile* inst = new nsLocalFile();
-  if (inst == NULL)
-    return NS_ERROR_OUT_OF_MEMORY;
-  
-  nsresult rv = inst->QueryInterface(aIID, aInstancePtr);
-  if (NS_FAILED(rv))
-  {
-    delete inst;
-    return rv;
-  }
-  return NS_OK;
-}
-
-#pragma mark -
-#pragma mark [nsIFile]
-
-NS_IMETHODIMP nsLocalFile::Append(const nsAString& aNode)
-{
-  return AppendNative(NS_ConvertUTF16toUTF8(aNode));
-}
-
-NS_IMETHODIMP nsLocalFile::AppendNative(const nsACString& aNode)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  CHECK_INIT();
-
-  nsACString::const_iterator start, end;
-  aNode.BeginReading(start);
-  aNode.EndReading(end);
-  if (FindCharInReadable(kPathSepChar, start, end))
-    return NS_ERROR_FILE_UNRECOGNIZED_PATH;
-
-  CFStringRef nodeStrRef = ::CFStringCreateWithCString(kCFAllocatorDefault,
-                                  PromiseFlatCString(aNode).get(),
-                                  kCFStringEncodingUTF8);
-  if (nodeStrRef) {
-    CFURLRef newRef = ::CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault,
-                                  mBaseURL, nodeStrRef, PR_FALSE);
-    ::CFRelease(nodeStrRef);
-    if (newRef) {
-      SetBaseURL(newRef);
-      ::CFRelease(newRef);
-      return NS_OK;
-    }
-  }
-  return NS_ERROR_FAILURE;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::Normalize()
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  CHECK_INIT();
-
-  char resolved_path[PATH_MAX] = "";
-  if (!realpath(mPath, resolved_path))
-      return NSRESULT_FOR_ERRNO();
-
-  // Need to know whether we're a directory to create a new CFURLRef
-  PRBool isDirectory;
-  nsresult rv = IsDirectory(&isDirectory);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = NS_ERROR_FAILURE;
-  CFStringRef pathStrRef = ::CFStringCreateWithCString(kCFAllocatorDefault,
-                                                       resolved_path,
-                                                       kCFStringEncodingUTF8);
-  if (pathStrRef) {
-    CFURLRef newURLRef =
-      ::CFURLCreateWithFileSystemPath(kCFAllocatorDefault, pathStrRef,
-                                      kCFURLPOSIXPathStyle, isDirectory);
-    if (newURLRef) {
-      SetBaseURL(newURLRef);
-      ::CFRelease(newURLRef);
-      rv = NS_OK;
-    }
-    ::CFRelease(pathStrRef);
-  }
-
-  return rv;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::Create(PRUint32 type, PRUint32 permissions)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  if (type != NORMAL_FILE_TYPE && type != DIRECTORY_TYPE)
-    return NS_ERROR_FILE_UNKNOWN_TYPE;
-
-  CHECK_INIT();
-  
-  nsTArray<nsString> nonExtantNodes;
-  CFURLRef pathURLRef = mBaseURL;
-  FSRef pathFSRef;
-  CFStringRef leafStrRef = nsnull;
-  nsAutoTArray<UniChar, NAME_MAX> buffer;
-  Boolean success;
-  
-  // Work backwards through the path to find the last node which
-  // exists. Place the nodes which don't exist in an array and we'll
-  // create those below.
-  while ((success = ::CFURLGetFSRef(pathURLRef, &pathFSRef)) == false) {
-    leafStrRef = ::CFURLCopyLastPathComponent(pathURLRef);
-    if (!leafStrRef)
-      break;
-    CFIndex leafLen = ::CFStringGetLength(leafStrRef);
-    if (!buffer.SetLength(leafLen + 1))
-      break;
-    ::CFStringGetCharacters(leafStrRef, CFRangeMake(0, leafLen), buffer.Elements());
-    buffer[leafLen] = '\0';
-    nonExtantNodes.AppendElement(nsString(nsDependentString(buffer.Elements())));
-    ::CFRelease(leafStrRef);
-    leafStrRef = nsnull;
-    
-    // Get the parent of the leaf for the next go round
-    CFURLRef parent = ::CFURLCreateCopyDeletingLastPathComponent(NULL, pathURLRef);
-    if (!parent)
-      break;
-    if (pathURLRef != mBaseURL)
-      ::CFRelease(pathURLRef);
-    pathURLRef = parent;
-  }
-  if (pathURLRef != mBaseURL)
-    ::CFRelease(pathURLRef);
-  if (leafStrRef != nsnull)
-    ::CFRelease(leafStrRef);
-  if (!success)
-    return NS_ERROR_FAILURE;
-  PRInt32 nodesToCreate = PRInt32(nonExtantNodes.Length());
-  if (nodesToCreate == 0)
-    return NS_ERROR_FILE_ALREADY_EXISTS;
-  
-  OSErr err;    
-  nsAutoString nextNodeName;
-  for (PRInt32 i = nodesToCreate - 1; i > 0; i--) {
-    nextNodeName = nonExtantNodes[i];
-    err = ::FSCreateDirectoryUnicode(&pathFSRef,
-                                      nextNodeName.Length(),
-                                      (const UniChar *)nextNodeName.get(),
-                                      kFSCatInfoNone,
-                                      nsnull, &pathFSRef, nsnull, nsnull);
-    if (err != noErr)
-      return MacErrorMapper(err);
-  }
-  nextNodeName = nonExtantNodes[0];
-  if (type == NORMAL_FILE_TYPE) {
-    err = ::FSCreateFileUnicode(&pathFSRef,
-                                nextNodeName.Length(),
-                                (const UniChar *)nextNodeName.get(),
-                                kFSCatInfoNone,
-                                nsnull, nsnull, nsnull);
-  }
-  else {
-    err = ::FSCreateDirectoryUnicode(&pathFSRef,
-                                    nextNodeName.Length(),
-                                    (const UniChar *)nextNodeName.get(),
-                                    kFSCatInfoNone,
-                                    nsnull, nsnull, nsnull, nsnull);
-  }
-            
-  return MacErrorMapper(err);
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::GetLeafName(nsAString& aLeafName)
-{
-  nsCAutoString nativeString;
-  nsresult rv = GetNativeLeafName(nativeString);
-  if (NS_FAILED(rv))
-    return rv;
-  CopyUTF8toUTF16NFC(nativeString, aLeafName);
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsLocalFile::SetLeafName(const nsAString& aLeafName)
-{
-  return SetNativeLeafName(NS_ConvertUTF16toUTF8(aLeafName));
-}
-
-NS_IMETHODIMP nsLocalFile::GetNativeLeafName(nsACString& aNativeLeafName)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  CHECK_INIT();
-
-  nsresult rv = NS_ERROR_FAILURE;
-  CFStringRef leafStrRef = ::CFURLCopyLastPathComponent(mBaseURL);
-  if (leafStrRef) {
-    rv = CFStringReftoUTF8(leafStrRef, aNativeLeafName);
-    ::CFRelease(leafStrRef);
-  }
-  return rv;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::SetNativeLeafName(const nsACString& aNativeLeafName)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  CHECK_INIT();
-
-  nsresult rv = NS_ERROR_FAILURE;
-  CFURLRef parentURLRef = ::CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, mBaseURL);
-  if (parentURLRef) {
-    CFStringRef nodeStrRef = ::CFStringCreateWithCString(kCFAllocatorDefault,
-                                    PromiseFlatCString(aNativeLeafName).get(),
-                                    kCFStringEncodingUTF8);
-
-    if (nodeStrRef) {
-      CFURLRef newURLRef = ::CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault,
-                                    parentURLRef, nodeStrRef, PR_FALSE);
-      if (newURLRef) {
-        SetBaseURL(newURLRef);
-        ::CFRelease(newURLRef);
-        rv = NS_OK;
-      }
-      ::CFRelease(nodeStrRef);
-    }
-    ::CFRelease(parentURLRef);
-  }
-  return rv;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::CopyTo(nsIFile *newParentDir, const nsAString& newName)
-{
-  return CopyInternal(newParentDir, newName, PR_FALSE);
-}
-
-NS_IMETHODIMP nsLocalFile::CopyToNative(nsIFile *newParentDir, const nsACString& newName)
-{
-  return CopyInternal(newParentDir, NS_ConvertUTF8toUTF16(newName), PR_FALSE);
-}
-
-NS_IMETHODIMP nsLocalFile::CopyToFollowingLinks(nsIFile *newParentDir, const nsAString& newName)
-{
-  return CopyInternal(newParentDir, newName, PR_TRUE);
-}
-
-NS_IMETHODIMP nsLocalFile::CopyToFollowingLinksNative(nsIFile *newParentDir, const nsACString& newName)
-{
-  return CopyInternal(newParentDir, NS_ConvertUTF8toUTF16(newName), PR_TRUE);
-}
-
-NS_IMETHODIMP nsLocalFile::MoveTo(nsIFile *newParentDir, const nsAString& newName)
-{
-  return MoveToNative(newParentDir, NS_ConvertUTF16toUTF8(newName));
-}
-
-NS_IMETHODIMP nsLocalFile::MoveToNative(nsIFile *newParentDir, const nsACString& newName)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  CHECK_INIT();
-
-  StFollowLinksState followLinks(*this, PR_FALSE);
-
-  PRBool isDirectory;
-  nsresult rv = IsDirectory(&isDirectory);
-  if (NS_FAILED(rv))
-    return rv;
-
-  // Build the destination path.
-  nsCOMPtr<nsIFile> parentDir = newParentDir;
-  if (!parentDir) {
-    if (newName.IsEmpty())
-      return NS_ERROR_INVALID_ARG;
-    rv = GetParent(getter_AddRefs(parentDir));
-    if (NS_FAILED(rv))
-      return rv;   
-  }
-  else {
-    PRBool exists;
-    rv = parentDir->Exists(&exists);
-    if (NS_FAILED(rv))
-      return rv;
-    if (!exists) {
-      rv = parentDir->Create(nsIFile::DIRECTORY_TYPE, 0777);
-      if (NS_FAILED(rv))
-        return rv;
-    }
-  }
-
-  nsCAutoString destPath;
-  rv = parentDir->GetNativePath(destPath);
-  if (NS_FAILED(rv))
-    return rv;
-
-  if (!newName.IsEmpty())
-    destPath.Append(NS_LITERAL_CSTRING("/") + newName);
-  else {
-    nsCAutoString leafName;
-    rv = GetNativeLeafName(leafName);
-    if (NS_FAILED(rv))
-      return rv;
-    destPath.Append(NS_LITERAL_CSTRING("/") + leafName);
-  }
-
-  // Perform the move.
-  if (rename(mPath, destPath.get()) != 0) {
-    if (errno == EXDEV) {
-      // Can't move across volume (device) boundaries.  Copy and remove.
-      rv = CopyToNative(parentDir, newName);
-      if (NS_SUCCEEDED(rv)) {
-        // Permit removal failure.
-        Remove(PR_TRUE);
-      }
-    }
-    else
-      rv = NSRESULT_FOR_ERRNO();
-
-    if (NS_FAILED(rv))
-      return rv;
-  }
-
-  // Update |this| to refer to the moved file.
-  CFURLRef newBaseRef =
-   ::CFURLCreateFromFileSystemRepresentation(NULL, (UInt8*)destPath.get(),
-                                             destPath.Length(), isDirectory);
-  if (!newBaseRef)
-    return NS_ERROR_FAILURE;
-  SetBaseURL(newBaseRef);
-  ::CFRelease(newBaseRef);
-
-  return rv;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::Remove(PRBool recursive)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  CHECK_INIT();
-
-  // if we're a symlink, never remove target
-  StFollowLinksState followLinks(*this, PR_FALSE);
-
-  PRBool isDirectory;
-  nsresult rv = IsDirectory(&isDirectory);
-  if (NS_FAILED(rv))
-    return rv;
-
-  if (recursive && isDirectory) {
-    CFURLRef urlRef;
-    rv = GetCFURL(&urlRef);
-    if (NS_SUCCEEDED(rv) && urlRef) {
-      NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init];
-      BOOL removeSuccess = [[NSFileManager defaultManager] removeFileAtPath:[(NSURL*)urlRef path] handler:nil];
-      [ap release];
-      ::CFRelease(urlRef);
-      rv = removeSuccess ? NS_OK : NS_ERROR_FAILURE;
-    }
-  }
-  else {
-    int status;
-    if (isDirectory)
-      status = rmdir(mPath);
-    else
-      status = unlink(mPath);
-
-    if (status != 0)
-      rv = NSRESULT_FOR_ERRNO();
-  }
-
-  return rv;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-// Only send back permissions bits: maybe we want to send back the whole
-// mode_t to permit checks against other file types?
-#define NORMALIZE_PERMS(mode)    ((mode)& (S_IRWXU | S_IRWXG | S_IRWXO))
-
-NS_IMETHODIMP nsLocalFile::GetPermissions(PRUint32 *aPermissions)
-{
-  NS_ENSURE_ARG_POINTER(aPermissions);
-
-  CHECK_INIT();
-
-  struct STAT buf;
-  nsresult rv = FillStatBufferInternal(&buf);
-  if (NS_FAILED(rv))
-    return NSRESULT_FOR_ERRNO();
-
-  *aPermissions = NORMALIZE_PERMS(buf.st_mode);
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsLocalFile::SetPermissions(PRUint32 aPermissions)
-{
-  CHECK_INIT();
-
-  if (chmod(mPath, aPermissions) < 0)
-    return NSRESULT_FOR_ERRNO();
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsLocalFile::GetPermissionsOfLink(PRUint32 *aPermissionsOfLink)
-{
-    NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP nsLocalFile::SetPermissionsOfLink(PRUint32 aPermissionsOfLink)
-{
-    NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP nsLocalFile::GetLastModifiedTime(PRInt64 *aLastModifiedTime)
-{
-  NS_ENSURE_ARG_POINTER(aLastModifiedTime);
-
-  nsCAutoString path;
-  nsresult rv = GetPathInternal(path);
-  if (NS_FAILED(rv))
-    return rv;
-
-  PRFileInfo64 info;
-  if (PR_GetFileInfo64(path.get(), &info) != PR_SUCCESS)
-    return NSRESULT_FOR_ERRNO();
-  PRInt64 modTime = PRInt64(info.modifyTime);
-  if (modTime == 0)
-    *aLastModifiedTime = 0;
-  else
-    *aLastModifiedTime = modTime / PRInt64(PR_USEC_PER_MSEC);
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsLocalFile::SetLastModifiedTime(PRInt64 aLastModifiedTime)
-{
-  nsCAutoString path;
-  nsresult rv = GetPathInternal(path);
-  if (NS_FAILED(rv))
-    return rv;
-
-  int result;
-  if (aLastModifiedTime != 0) {
-    struct STAT statBuf;
-    nsresult rv = FillStatBufferInternal(&statBuf);
-    if (NS_FAILED(rv))
-      return rv;
-
-    struct utimbuf ut;
-    ut.actime = statBuf.st_atime;
-
-    // convert milliseconds to seconds since the unix epoch
-    ut.modtime = (time_t)(PRFloat64(aLastModifiedTime) / PR_MSEC_PER_SEC);
-    result = utime(path.get(), &ut);
-  } else {
-    result = utime(path.get(), nsnull);
-  }
-  return NSRESULT_FOR_RETURN(result);
-}
-
-NS_IMETHODIMP nsLocalFile::GetLastModifiedTimeOfLink(PRInt64 *aLastModifiedTimeOfLink)
-{
-  NS_ENSURE_ARG(aLastModifiedTimeOfLink);
-
-  nsCAutoString path;
-  nsresult rv = GetPathInternal(path);
-  if (NS_FAILED(rv))
-    return rv;
-
-  struct STAT sbuf;
-  if (LSTAT(path.get(), &sbuf) == -1)
-    return NSRESULT_FOR_ERRNO();
-  *aLastModifiedTimeOfLink = PRInt64(sbuf.st_mtime) * PRInt64(PR_MSEC_PER_SEC);
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsLocalFile::SetLastModifiedTimeOfLink(PRInt64 aLastModifiedTimeOfLink)
-{
-  return SetLastModifiedTime(aLastModifiedTimeOfLink);
-}
-
-NS_IMETHODIMP nsLocalFile::GetFileSize(PRInt64 *aFileSize)
-{
-  NS_ENSURE_ARG_POINTER(aFileSize);
-  *aFileSize = 0;
-
-  struct STAT buf;
-  nsresult rv = FillStatBufferInternal(&buf);
-  if (NS_FAILED(rv))
-    return rv;
-
-  if (!S_ISDIR(buf.st_mode))
-    *aFileSize = (PRInt64)buf.st_size;
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsLocalFile::SetFileSize(PRInt64 aFileSize)
-{
-  CHECK_INIT();
-
-  off_t size = (off_t)aFileSize;
-  if (truncate(mPath, size) == -1)
-    return NSRESULT_FOR_ERRNO();
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsLocalFile::GetFileSizeOfLink(PRInt64 *aFileSizeOfLink)
-{
-  CHECK_INIT();
-
-  NS_ENSURE_ARG_POINTER(aFileSizeOfLink);
-  
-  StFollowLinksState followLinks(*this, PR_FALSE);
-  return GetFileSize(aFileSizeOfLink);
-}
-
-NS_IMETHODIMP nsLocalFile::GetTarget(nsAString& aTarget)
-{
-  nsCAutoString nativeString;
-  nsresult rv = GetNativeTarget(nativeString);
-  if (NS_FAILED(rv))
-    return rv;
-  CopyUTF8toUTF16NFC(nativeString, aTarget);
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsLocalFile::GetNativeTarget(nsACString& aNativeTarget)
-{
-  CHECK_INIT();
-
-  aNativeTarget.Truncate();
-  
-  struct STAT symStat;
-  if (LSTAT(mPath, &symStat) == -1)
-    return NSRESULT_FOR_ERRNO();
-  
-  if (!S_ISLNK(symStat.st_mode))
-    return NS_ERROR_FILE_INVALID_PATH;
-  
-  PRInt32 size = (PRInt32)symStat.st_size;
-  char *target = (char *)nsMemory::Alloc(size + 1);
-  if (!target)
-    return NS_ERROR_OUT_OF_MEMORY;
-  
-  if (readlink(mPath, target, (size_t)size) < 0) {
-    nsMemory::Free(target);
-    return NSRESULT_FOR_ERRNO();
-  }
-  target[size] = '\0';
-  
-  nsresult rv = NS_OK;
-  nsCOMPtr<nsIFile> self(this);
-  PRInt32 maxLinks = 40;
-  while (PR_TRUE) {
-    if (maxLinks-- == 0) {
-      rv = NS_ERROR_FILE_UNRESOLVABLE_SYMLINK;
-      break;
-    }
-    
-    if (target[0] != '/') {
-      nsCOMPtr<nsIFile> parent;
-      if (NS_FAILED(rv = self->GetParent(getter_AddRefs(parent))))
-        break;
-      nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(parent, &rv));
-      if (NS_FAILED(rv))
-        break;
-      if (NS_FAILED(rv = localFile->AppendRelativeNativePath(nsDependentCString(target))))
-        break;
-      if (NS_FAILED(rv = localFile->GetNativePath(aNativeTarget)))
-        break;
-      self = parent;
-    } else {
-      aNativeTarget = target;
-    }
-    
-    const nsPromiseFlatCString &flatRetval = PromiseFlatCString(aNativeTarget);
-    
-    // Any failure in testing the current target we'll just interpret
-    // as having reached our destiny.
-    if (LSTAT(flatRetval.get(), &symStat) == -1)
-      break;
-    
-    // And of course we're done if it isn't a symlink.
-    if (!S_ISLNK(symStat.st_mode))
-      break;
-    
-    PRInt32 newSize = (PRInt32)symStat.st_size;
-    if (newSize > size) {
-      char *newTarget = (char *)nsMemory::Realloc(target, newSize + 1);
-      if (!newTarget) {
-        rv = NS_ERROR_OUT_OF_MEMORY;
-        break;
-      }
-      target = newTarget;
-      size = newSize;
-    }
-    
-    PRInt32 linkLen = readlink(flatRetval.get(), target, size);
-    if (linkLen == -1) {
-      rv = NSRESULT_FOR_ERRNO();
-      break;
-    }
-    target[linkLen] = '\0';
-  }
-  
-  nsMemory::Free(target);
-  
-  if (NS_FAILED(rv))
-    aNativeTarget.Truncate();
-  return rv;  
-}
-
-NS_IMETHODIMP nsLocalFile::GetPath(nsAString& aPath)
-{
-  nsCAutoString nativeString;
-  nsresult rv = GetNativePath(nativeString);
-  if (NS_FAILED(rv))
-    return rv;
-  CopyUTF8toUTF16NFC(nativeString, aPath);
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsLocalFile::GetNativePath(nsACString& aNativePath)
-{
-  CHECK_INIT();
-
-  aNativePath.Assign(mPath);
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsLocalFile::Exists(PRBool *_retval)
-{
-  NS_ENSURE_ARG_POINTER(_retval);
-
-  struct STAT buf;
-  *_retval = (STAT(mPath, &buf) == 0);
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsLocalFile::IsWritable(PRBool *_retval)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  CHECK_INIT();
-
-  NS_ENSURE_ARG_POINTER(_retval);
-  *_retval = PR_FALSE;
-
-  NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init];
-  // don't bother resolving, this always traverses symbolic links
-  *_retval = (PRBool)[[NSFileManager defaultManager] isWritableFileAtPath:[(NSURL*)mBaseURL path]];
-  [ap release];
-
-  return NS_OK;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::IsReadable(PRBool *_retval)
-{
-  CHECK_INIT();
-
-  NS_ENSURE_ARG_POINTER(_retval);
-  *_retval = PR_FALSE;
-
-  PRUint32 permissions;
-  nsresult rv = GetPermissions(&permissions);
-  if (NS_FAILED(rv))
-    return rv;
-  *_retval = ((permissions & S_IRUSR) != 0);
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsLocalFile::IsExecutable(PRBool *_retval)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  CHECK_INIT();
-
-  NS_ENSURE_ARG_POINTER(_retval);
-  *_retval = PR_FALSE;
-  
-  FSRef fsRef;
-  nsresult rv = GetFSRefInternal(fsRef);
-  if (NS_FAILED(rv))
-    return rv;
-    
-  LSRequestedInfo theInfoRequest = kLSRequestAllInfo;
-  LSItemInfoRecord theInfo;
-  if (::LSCopyItemInfoForRef(&fsRef, theInfoRequest, &theInfo) == noErr) {
-    if ((theInfo.flags & kLSItemInfoIsApplication) != 0)
-    *_retval = PR_TRUE;
-  }
-  return NS_OK;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::IsHidden(PRBool *_retval)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  CHECK_INIT();
-
-  NS_ENSURE_ARG_POINTER(_retval);
-  *_retval = PR_FALSE;
-
-  // If the leaf name begins with a '.', consider it invisible
-  nsAutoString name;
-  nsresult rv = GetLeafName(name);
-  if (NS_FAILED(rv))
-    return rv;
-  if (name.Length() >= 1 && Substring(name, 0, 1).EqualsLiteral("."))
-    *_retval = PR_TRUE;
-
-  LSItemInfoRecord itemInfo;
-  LSCopyItemInfoForURL(mBaseURL, kLSRequestBasicFlagsOnly, &itemInfo);
-  *_retval = !!(itemInfo.flags & kLSItemInfoIsInvisible);
-
-  return NS_OK;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::IsDirectory(PRBool *_retval)
-{
-  NS_ENSURE_ARG_POINTER(_retval);
-  *_retval = PR_FALSE;
-
-  struct STAT buf;
-  nsresult rv = FillStatBufferInternal(&buf);
-  if (NS_FAILED(rv))
-    return rv;
-
-  *_retval = S_ISDIR(buf.st_mode);
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsLocalFile::IsFile(PRBool *_retval)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  NS_ENSURE_ARG_POINTER(_retval);
-  *_retval = PR_FALSE;
-
-  struct STAT buf;
-  nsresult rv = FillStatBufferInternal(&buf);
-  if (NS_FAILED(rv))
-    return rv;
-
-  *_retval = S_ISREG(buf.st_mode);
-
-  return NS_OK;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::IsSymlink(PRBool *_retval)
-{
-  CHECK_INIT();
-
-  NS_ENSURE_ARG(_retval);
-  *_retval = PR_FALSE;
-
-  struct stat symStat;
-  if (lstat(mPath, &symStat) < 0)
-    return NSRESULT_FOR_ERRNO();
-  *_retval = S_ISLNK(symStat.st_mode);
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsLocalFile::IsSpecial(PRBool *_retval)
-{
-  NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP nsLocalFile::Clone(nsIFile **_retval)
-{
-    // Just copy-construct ourselves
-    *_retval = new nsLocalFile(*this);
-    if (!*_retval)
-      return NS_ERROR_OUT_OF_MEMORY;
-
-    NS_ADDREF(*_retval);
-    
-    return NS_OK;
-}
-
-NS_IMETHODIMP nsLocalFile::Equals(nsIFile *inFile, PRBool *_retval)
-{
-  NS_ENSURE_ARG(inFile);
-  NS_ENSURE_ARG_POINTER(_retval);
-  *_retval = PR_FALSE;
-
-  nsCAutoString inPath;
-  nsresult rv = inFile->GetNativePath(inPath);
-  if (NS_FAILED(rv))
-    return rv;
-
-  *_retval = !strcmp(mPath, inPath.get());
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsLocalFile::Contains(nsIFile *inFile, PRBool recur, PRBool *_retval)
-{
-  CHECK_INIT();
-
-  NS_ENSURE_ARG_POINTER(_retval);
-  *_retval = PR_FALSE;
-
-  PRBool isDir;
-  nsresult rv = IsDirectory(&isDir);
-  if (NS_FAILED(rv))
-    return rv;
-  if (!isDir)
-    return NS_OK;     // must be a dir to contain someone
-
-  nsCAutoString thisPath, inPath;
-  if (NS_FAILED(GetNativePath(thisPath)) || NS_FAILED(inFile->GetNativePath(inPath)))
-    return NS_ERROR_FAILURE;
-  size_t thisPathLen = thisPath.Length();
-  if ((inPath.Length() > thisPathLen + 1) && (strncasecmp(thisPath.get(), inPath.get(), thisPathLen) == 0)) {
-    // Now make sure that the |inFile|'s path has a separator at thisPathLen,
-    // and there's at least one more character after that.
-    if (inPath[thisPathLen] == kPathSepChar)
-      *_retval = PR_TRUE;
-  }  
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsLocalFile::GetParent(nsIFile * *aParent)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  NS_ENSURE_ARG_POINTER(aParent);
-  *aParent = nsnull;
-
-  CHECK_INIT();
-
-  // If it can be determined without error that a file does not
-  // have a parent, return nsnull for the parent and NS_OK as the result.
-  // See bug 133617.
-  nsresult rv = NS_OK;
-  CFURLRef parentURLRef = ::CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, mBaseURL);
-  if (parentURLRef) {
-    // If the parent path is longer than file's path then 
-    // CFURLCreateCopyDeletingLastPathComponent must have simply added
-    // two dots at the end - in this case indicate that there is no parent.
-    // See bug 332389.
-    CFStringRef path = ::CFURLGetString(mBaseURL);
-    CFStringRef newPath = ::CFURLGetString(parentURLRef);
-    if (::CFStringGetLength(newPath) < ::CFStringGetLength(path)) {
-      rv = NS_ERROR_FAILURE;
-      nsRefPtr<nsLocalFile> newFile = new nsLocalFile;
-      if (newFile) {
-        rv = newFile->InitWithCFURL(parentURLRef);
-        if (NS_SUCCEEDED(rv)) {
-          NS_ADDREF(*aParent = newFile);
-          rv = NS_OK;
-        }
-      }
-    }
-    ::CFRelease(parentURLRef);
-  }
-  return rv;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator **aDirectoryEntries)
-{
-  NS_ENSURE_ARG_POINTER(aDirectoryEntries);
-  *aDirectoryEntries = nsnull;
-
-  nsresult rv;
-  PRBool isDir;
-  rv = IsDirectory(&isDir);
-  if (NS_FAILED(rv)) 
-    return rv;
-  if (!isDir)
-    return NS_ERROR_FILE_NOT_DIRECTORY;
-
-  nsDirEnumerator* dirEnum = new nsDirEnumerator;
-  if (dirEnum == nsnull)
-    return NS_ERROR_OUT_OF_MEMORY;
-  NS_ADDREF(dirEnum);
-  rv = dirEnum->Init(this);
-  if (NS_FAILED(rv)) {
-    NS_RELEASE(dirEnum);
-    return rv;
-  }
-  *aDirectoryEntries = dirEnum;
-  
-  return NS_OK;
-}
-
-#pragma mark -
-#pragma mark [nsILocalFile]
-
-NS_IMETHODIMP nsLocalFile::InitWithPath(const nsAString& filePath)
-{
-  return InitWithNativePath(NS_ConvertUTF16toUTF8(filePath));
-}
-
-NS_IMETHODIMP nsLocalFile::InitWithNativePath(const nsACString& filePath)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  nsCAutoString fixedPath;
-  if (Substring(filePath, 0, 2).EqualsLiteral("~/")) {
-    nsCOMPtr<nsIFile> homeDir;
-    nsCAutoString homePath;
-    nsresult rv = NS_GetSpecialDirectory(NS_OS_HOME_DIR,
-                                        getter_AddRefs(homeDir));
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = homeDir->GetNativePath(homePath);
-    NS_ENSURE_SUCCESS(rv, rv);
-    
-    fixedPath = homePath + Substring(filePath, 1, filePath.Length() - 1);
-  }
-  else if (filePath.IsEmpty() || filePath.First() != '/')
-    return NS_ERROR_FILE_UNRECOGNIZED_PATH;
-  else
-    fixedPath.Assign(filePath);
-
-  // A path with consecutive '/'s which are not between
-  // nodes crashes CFURLGetFSRef(). Consecutive '/'s which
-  // are between actual nodes are OK. So, convert consecutive
-  // '/'s to a single one.
-  fixedPath.ReplaceSubstring("//", "/");
-
-  // On 10.2, huge paths also crash CFURLGetFSRef()
-  if (fixedPath.Length() > PATH_MAX)
-    return NS_ERROR_FILE_NAME_TOO_LONG;
-
-  CFStringRef pathAsCFString;
-  CFURLRef pathAsCFURL;
-
-  pathAsCFString = ::CFStringCreateWithCString(nsnull, fixedPath.get(), kCFStringEncodingUTF8);
-  if (!pathAsCFString)
-    return NS_ERROR_FAILURE;
-  pathAsCFURL = ::CFURLCreateWithFileSystemPath(nsnull, pathAsCFString, kCFURLPOSIXPathStyle, PR_FALSE);
-  if (!pathAsCFURL) {
-    ::CFRelease(pathAsCFString);
-    return NS_ERROR_FAILURE;
-  }
-  SetBaseURL(pathAsCFURL);
-  ::CFRelease(pathAsCFURL);
-  ::CFRelease(pathAsCFString);
-  return NS_OK;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::InitWithFile(nsILocalFile *aFile)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  NS_ENSURE_ARG(aFile);
-  
-  nsCOMPtr<nsILocalFileMac> aFileMac(do_QueryInterface(aFile));
-  if (!aFileMac)
-    return NS_ERROR_UNEXPECTED;
-  CFURLRef urlRef;
-  nsresult rv = aFileMac->GetCFURL(&urlRef);
-  if (NS_FAILED(rv))
-    return rv;
-  rv = InitWithCFURL(urlRef);
-  ::CFRelease(urlRef);
-  return rv;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::GetFollowLinks(PRBool *aFollowLinks)
-{
-  NS_ENSURE_ARG_POINTER(aFollowLinks);
-  
-  *aFollowLinks = mFollowLinks;
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsLocalFile::SetFollowLinks(PRBool aFollowLinks)
-{
-  mFollowLinks = aFollowLinks;
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsLocalFile::OpenNSPRFileDesc(PRInt32 flags, PRInt32 mode, PRFileDesc **_retval)
-{
-  NS_ENSURE_ARG_POINTER(_retval);
-
-  nsCAutoString path;
-  nsresult rv = GetPathInternal(path);
-  if (NS_FAILED(rv))
-    return rv;
-    
-  *_retval = PR_Open(path.get(), flags, mode);
-  if (! *_retval)
-    return NS_ErrorAccordingToNSPR();
-
-  if (flags & DELETE_ON_CLOSE) {
-    PR_Delete(path.get());
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsLocalFile::OpenANSIFileDesc(const char *mode, FILE **_retval)
-{
-  NS_ENSURE_ARG_POINTER(_retval);
-
-  nsCAutoString path;
-  nsresult rv = GetPathInternal(path);
-  if (NS_FAILED(rv))
-    return rv;
-    
-  *_retval = fopen(path.get(), mode);
-  if (! *_retval)
-    return NS_ERROR_FAILURE;
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsLocalFile::Load(PRLibrary **_retval)
-{
-  CHECK_INIT();
-
-  NS_ENSURE_ARG_POINTER(_retval);
-
-  NS_TIMELINE_START_TIMER("PR_LoadLibrary");
-
-  nsCAutoString path;
-  nsresult rv = GetPathInternal(path);
-  if (NS_FAILED(rv))
-    return rv;
-
-#ifdef NS_BUILD_REFCNT_LOGGING
-  nsTraceRefcntImpl::SetActivityIsLegal(PR_FALSE);
-#endif
-
-  *_retval = PR_LoadLibrary(path.get());
-
-#ifdef NS_BUILD_REFCNT_LOGGING
-  nsTraceRefcntImpl::SetActivityIsLegal(PR_TRUE);
-#endif
-
-  NS_TIMELINE_STOP_TIMER("PR_LoadLibrary");
-  NS_TIMELINE_MARK_TIMER1("PR_LoadLibrary", path.get());
-
-  if (!*_retval)
-    return NS_ERROR_FAILURE;
-  
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  NS_ENSURE_ARG_POINTER(aDiskSpaceAvailable);
-
-  nsCAutoString path;
-  nsresult rv = GetPathInternal(path);
-  if (NS_FAILED(rv))
-    return rv;
-
-  struct STATVFS fs_buf;
-  if (STATVFS(path.get(), &fs_buf) < 0)
-    return NS_ERROR_FAILURE;
-  // minus one block for fuzz
-  *aDiskSpaceAvailable = (PRInt64)fs_buf.f_frsize * (fs_buf.f_bavail - 1);
-  return NS_OK;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::AppendRelativePath(const nsAString& relativeFilePath)
-{
-  return AppendRelativeNativePath(NS_ConvertUTF16toUTF8(relativeFilePath));
-}
-
-NS_IMETHODIMP nsLocalFile::AppendRelativeNativePath(const nsACString& relativeFilePath)
-{  
-  if (relativeFilePath.IsEmpty())
-    return NS_OK;
-  // No leading '/' 
-  if (relativeFilePath.First() == '/')
-    return NS_ERROR_FILE_UNRECOGNIZED_PATH;
-
-  // Parse the nodes and call Append() for each
-  nsACString::const_iterator nodeBegin, pathEnd;
-  relativeFilePath.BeginReading(nodeBegin);
-  relativeFilePath.EndReading(pathEnd);
-  nsACString::const_iterator nodeEnd(nodeBegin);
-  
-  while (nodeEnd != pathEnd) {
-    FindCharInReadable(kPathSepChar, nodeEnd, pathEnd);
-    nsresult rv = AppendNative(Substring(nodeBegin, nodeEnd));
-    if (NS_FAILED(rv))
-      return rv;
-    if (nodeEnd != pathEnd) // If there's more left in the string, inc over the '/' nodeEnd is on.
-      ++nodeEnd;
-    nodeBegin = nodeEnd;
-  }
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsLocalFile::GetPersistentDescriptor(nsACString& aPersistentDescriptor)
-{
-  return GetNativePath(aPersistentDescriptor);
-}
-
-NS_IMETHODIMP nsLocalFile::SetPersistentDescriptor(const nsACString& aPersistentDescriptor)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  if (aPersistentDescriptor.IsEmpty())
-    return NS_ERROR_INVALID_ARG;
-
-  // Support pathnames as user-supplied descriptors if they begin with '/'
-  // or '~'.  These characters do not collide with the base64 set used for
-  // encoding alias records.
-  char first = aPersistentDescriptor.First();
-  if (first == '/' || first == '~')
-    return InitWithNativePath(aPersistentDescriptor);
-
-  nsresult rv = NS_OK;
-  
-  PRUint32 dataSize = aPersistentDescriptor.Length();    
-  char* decodedData = PL_Base64Decode(PromiseFlatCString(aPersistentDescriptor).get(), dataSize, nsnull);
-  if (!decodedData) {
-    NS_ERROR("SetPersistentDescriptor was given bad data");
-    return NS_ERROR_FAILURE;
-  }
-  
-  // Cast to an alias record and resolve.
-  AliasRecord aliasHeader = *(AliasPtr)decodedData;
-  PRInt32 aliasSize = ::GetAliasSizeFromPtr(&aliasHeader);
-  if (aliasSize > ((PRInt32)dataSize * 3) / 4) { // be paranoid about having too few data
-    PR_Free(decodedData);
-    return NS_ERROR_FAILURE;
-  }
-  
-  // Move the now-decoded data into the Handle.
-  // The size of the decoded data is 3/4 the size of the encoded data. See plbase64.h
-  Handle  newHandle = nsnull;
-  if (::PtrToHand(decodedData, &newHandle, aliasSize) != noErr)
-    rv = NS_ERROR_OUT_OF_MEMORY;
-  PR_Free(decodedData);
-  if (NS_FAILED(rv))
-    return rv;
-
-  Boolean changed;
-  FSRef resolvedFSRef;
-  OSErr err = ::FSResolveAlias(nsnull, (AliasHandle)newHandle, &resolvedFSRef, &changed);
-    
-  rv = MacErrorMapper(err);
-  DisposeHandle(newHandle);
-  if (NS_FAILED(rv))
-    return rv;
- 
-  return InitWithFSRef(&resolvedFSRef);
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::Reveal()
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  BOOL success = NO;
-
-  CFURLRef urlRef;
-  if (NS_SUCCEEDED(GetCFURL(&urlRef)) && urlRef) {
-    NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init];
-    success = [[NSWorkspace sharedWorkspace] selectFile:[(NSURL*)urlRef path] inFileViewerRootedAtPath:@""];
-    [ap release];
-
-    ::CFRelease(urlRef);
-  }
-
-  return (success ? NS_OK : NS_ERROR_FAILURE);
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::Launch()
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  BOOL success = NO;
-
-  CFURLRef urlRef;
-  if (NS_SUCCEEDED(GetCFURL(&urlRef)) && urlRef) {
-    NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init];
-    success = [[NSWorkspace sharedWorkspace] openURL:(NSURL*)urlRef];
-    [ap release];
-
-    ::CFRelease(urlRef);
-  }
-
-  return (success ? NS_OK : NS_ERROR_FAILURE);
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-#pragma mark -
-#pragma mark [nsILocalFileMac]
-
-NS_IMETHODIMP nsLocalFile::InitWithCFURL(CFURLRef aCFURL)
-{
-  NS_ENSURE_ARG(aCFURL);
-  
-  SetBaseURL(aCFURL);
-  return NS_OK;
-}
-
-NS_IMETHODIMP nsLocalFile::InitWithFSRef(const FSRef *aFSRef)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  NS_ENSURE_ARG(aFSRef);
-  nsresult rv = NS_ERROR_FAILURE;
-  
-  CFURLRef newURLRef = ::CFURLCreateFromFSRef(kCFAllocatorDefault, aFSRef);
-  if (newURLRef) {
-    SetBaseURL(newURLRef);
-    ::CFRelease(newURLRef);
-    rv = NS_OK;
-  }
-  return rv;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::InitToAppWithCreatorCode(OSType aAppCreator)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  FSRef fsRef;
-  OSErr err = ::LSFindApplicationForInfo(aAppCreator, nsnull, nsnull, &fsRef, nsnull);
-  if (err != noErr)
-    return MacErrorMapper(err);
-  return InitWithFSRef(&fsRef);
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::GetCFURL(CFURLRef *_retval)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  CHECK_INIT();
-
-  if (mFollowLinks) {
-    nsCAutoString nativePath;
-    nsresult rv = GetNativeTarget(nativePath);
-    if (NS_SUCCEEDED(rv)) {
-      // This is a symlink if we can get a target path.
-      // We can assume this is not a directory if we know it is a symlink.
-      // I'll say this anyway because it is so dangerous: Do not call IsDirectory
-      // here because that ultimately ends up calling GetCFURL and you get a loop.
-      CFURLRef targetURL = ::CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
-                                                                     (UInt8*)nativePath.BeginWriting(),
-                                                                     nativePath.Length(),
-                                                                     false);
-      if (!targetURL)
-        return NS_ERROR_FAILURE;
-      *_retval = targetURL;
-      return NS_OK;
-    }
-  }
-
-  ::CFRetain(mBaseURL);
-  *_retval = mBaseURL;
-
-  return NS_OK;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::GetFSRef(FSRef *_retval)
-{
-  NS_ENSURE_ARG_POINTER(_retval);
-  return GetFSRefInternal(*_retval);
-}
-
-NS_IMETHODIMP nsLocalFile::GetFSSpec(FSSpec *_retval)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  NS_ENSURE_ARG_POINTER(_retval);
-  CHECK_INIT();
-
-  FSRef fsRef;
-  nsresult rv = GetFSRefInternal(fsRef);
-  if (NS_SUCCEEDED(rv)) {
-    OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNone, nsnull, nsnull, _retval, nsnull);
-    return MacErrorMapper(err); 
-  }
-  return rv;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::GetFileSizeWithResFork(PRInt64 *aFileSizeWithResFork)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  NS_ENSURE_ARG_POINTER(aFileSizeWithResFork);
-  
-  FSRef fsRef;
-  nsresult rv = GetFSRefInternal(fsRef);
-  if (NS_FAILED(rv))
-    return rv;
-      
-  FSCatalogInfo catalogInfo;
-  OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoDataSizes + kFSCatInfoRsrcSizes,
-                                 &catalogInfo, nsnull, nsnull, nsnull);
-  if (err != noErr)
-    return MacErrorMapper(err);
-    
-  *aFileSizeWithResFork = catalogInfo.dataLogicalSize + catalogInfo.rsrcLogicalSize;
-  return NS_OK;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::GetFileType(OSType *aFileType)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  NS_ENSURE_ARG_POINTER(aFileType);
-
-  CHECK_INIT();
-  
-  nsresult rv = NS_ERROR_FAILURE;
-
-  NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init];
-  NSDictionary* dict = [[NSFileManager defaultManager] fileAttributesAtPath:[(NSURL*)mBaseURL path] traverseLink:YES];
-  NSNumber* typeNum = (NSNumber*)[dict objectForKey:NSFileHFSTypeCode];
-  if (typeNum) {
-    *aFileType = [typeNum unsignedLongValue];
-    rv = NS_OK;
-  }
-  [ap release];
-
-  return rv;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::SetFileType(OSType aFileType)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  CHECK_INIT();
-
-  NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init];
-  NSDictionary* dict = [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedLong:aFileType] forKey:NSFileHFSTypeCode];
-  BOOL success = [[NSFileManager defaultManager] changeFileAttributes:dict atPath:[(NSURL*)mBaseURL path]];
-  [ap release];
-  return (success ? NS_OK : NS_ERROR_FAILURE);
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::GetFileCreator(OSType *aFileCreator)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  NS_ENSURE_ARG_POINTER(aFileCreator);
-
-  CHECK_INIT();
-
-  nsresult rv = NS_ERROR_FAILURE;
-
-  NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init];
-  NSDictionary* dict = [[NSFileManager defaultManager] fileAttributesAtPath:[(NSURL*)mBaseURL path] traverseLink:YES];
-  id creatorNum = (NSNumber*)[dict objectForKey:NSFileHFSCreatorCode];
-  if (creatorNum) {
-    *aFileCreator = [creatorNum unsignedLongValue];
-    rv = NS_OK;
-  }
-  [ap release];
-
-  return rv;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::SetFileCreator(OSType aFileCreator)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  CHECK_INIT();
-
-  NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init];
-  NSDictionary* dict = [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedLong:aFileCreator] forKey:NSFileHFSCreatorCode];
-  BOOL success = [[NSFileManager defaultManager] changeFileAttributes:dict atPath:[(NSURL*)mBaseURL path]];
-  [ap release];
-  return (success ? NS_OK : NS_ERROR_FAILURE);
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::LaunchWithDoc(nsILocalFile *aDocToLoad, PRBool aLaunchInBackground)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  PRBool isExecutable;
-  nsresult rv = IsExecutable(&isExecutable);
-  if (NS_FAILED(rv))
-    return rv;
-  if (!isExecutable)
-    return NS_ERROR_FILE_EXECUTION_FAILED;
-
-  FSRef appFSRef, docFSRef;
-  rv = GetFSRefInternal(appFSRef);
-  if (NS_FAILED(rv))
-    return rv;
-
-  if (aDocToLoad) {
-    nsCOMPtr<nsILocalFileMac> macDoc = do_QueryInterface(aDocToLoad);
-    rv = macDoc->GetFSRef(&docFSRef);
-    if (NS_FAILED(rv))
-      return rv;
-  }
-  
-  LSLaunchFlags       theLaunchFlags = kLSLaunchDefaults;
-  LSLaunchFSRefSpec   thelaunchSpec;
-
-  if (aLaunchInBackground)
-    theLaunchFlags |= kLSLaunchDontSwitch;
-  memset(&thelaunchSpec, 0, sizeof(LSLaunchFSRefSpec));
-
-  thelaunchSpec.appRef = &appFSRef;
-  if (aDocToLoad) {
-    thelaunchSpec.numDocs = 1;
-    thelaunchSpec.itemRefs = &docFSRef;
-  }
-  thelaunchSpec.launchFlags = theLaunchFlags;
-
-  OSErr err = ::LSOpenFromRefSpec(&thelaunchSpec, NULL);
-  if (err != noErr)
-    return MacErrorMapper(err);
-
-  return NS_OK;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::OpenDocWithApp(nsILocalFile *aAppToOpenWith, PRBool aLaunchInBackground)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  nsresult rv;
-  OSErr err;
-
-  FSRef docFSRef, appFSRef;
-  rv = GetFSRefInternal(docFSRef);
-  if (NS_FAILED(rv))
-    return rv;
-
-  if (aAppToOpenWith) {
-    nsCOMPtr<nsILocalFileMac> appFileMac = do_QueryInterface(aAppToOpenWith, &rv);
-    if (!appFileMac)
-      return rv;
-
-    PRBool isExecutable;
-    rv = appFileMac->IsExecutable(&isExecutable);
-    if (NS_FAILED(rv))
-      return rv;
-    if (!isExecutable)
-      return NS_ERROR_FILE_EXECUTION_FAILED;
-    
-    rv = appFileMac->GetFSRef(&appFSRef);
-    if (NS_FAILED(rv))
-      return rv;
-  }
-  else {
-    OSType  fileCreator;
-    rv = GetFileCreator(&fileCreator);
-    if (NS_FAILED(rv))
-      return rv;
-
-    err = ::LSFindApplicationForInfo(fileCreator, nsnull, nsnull, &appFSRef, nsnull);
-    if (err != noErr)
-      return MacErrorMapper(err);
-  }
-  
-  LSLaunchFlags       theLaunchFlags = kLSLaunchDefaults;
-  LSLaunchFSRefSpec   thelaunchSpec;
-
-  if (aLaunchInBackground)
-  theLaunchFlags |= kLSLaunchDontSwitch;
-  memset(&thelaunchSpec, 0, sizeof(LSLaunchFSRefSpec));
-
-  thelaunchSpec.appRef = &appFSRef;
-  thelaunchSpec.numDocs = 1;
-  thelaunchSpec.itemRefs = &docFSRef;
-  thelaunchSpec.launchFlags = theLaunchFlags;
-
-  err = ::LSOpenFromRefSpec(&thelaunchSpec, NULL);
-  if (err != noErr)
-    return MacErrorMapper(err);
-
-  return NS_OK;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP nsLocalFile::IsPackage(PRBool *_retval)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  NS_ENSURE_ARG(_retval);
-  *_retval = PR_FALSE;
-  
-  CFURLRef urlRef;
-  if (NS_SUCCEEDED(GetCFURL(&urlRef)) && urlRef) {
-    *_retval = [[NSWorkspace sharedWorkspace] isFilePackageAtPath:[(NSURL *)urlRef path]];
-    ::CFRelease(urlRef);
-    
-    return NS_OK;
-  }
-  
-  return NS_ERROR_FAILURE;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-NS_IMETHODIMP
-nsLocalFile::GetBundleDisplayName(nsAString& outBundleName)
-{
-  PRBool isPackage = PR_FALSE;
-  nsresult rv = IsPackage(&isPackage);
-  if (NS_FAILED(rv) || !isPackage)
-    return NS_ERROR_FAILURE;
-  
-  nsAutoString name;
-  rv = GetLeafName(name);
-  if (NS_FAILED(rv))
-    return rv;
-  
-  PRInt32 length = name.Length();
-  if (Substring(name, length - 4, length).EqualsLiteral(".app")) {
-    // 4 characters in ".app"
-    outBundleName = Substring(name, 0, length - 4);
-  }
-  else
-    outBundleName = name;
-  
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsLocalFile::GetBundleIdentifier(nsACString& outBundleIdentifier)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  nsresult rv = NS_ERROR_FAILURE;
-
-  CFURLRef urlRef;
-  if (NS_SUCCEEDED(GetCFURL(&urlRef))) {
-    CFBundleRef bundle = ::CFBundleCreate(NULL, urlRef);
-    if (bundle) {
-      CFStringRef bundleIdentifier = ::CFBundleGetIdentifier(bundle);
-      if (bundleIdentifier)
-        rv = CFStringReftoUTF8(bundleIdentifier, outBundleIdentifier);
-
-      ::CFRelease(bundle);
-    }
-    ::CFRelease(urlRef);
-  }
-
-  return rv;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-#pragma mark -
-#pragma mark [Protected Methods]
-
-nsresult nsLocalFile::SetBaseURL(CFURLRef aCFURLRef)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  NS_ENSURE_ARG(aCFURLRef);
-
-  ::CFRetain(aCFURLRef);
-  if (mBaseURL)
-    ::CFRelease(mBaseURL);
-  mBaseURL = aCFURLRef;
-
-  if (!::CFURLGetFileSystemRepresentation(mBaseURL, NO, (UInt8*)mPath, PATH_MAX))
-    return NS_ERROR_FAILURE;
-
-  return NS_OK;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-nsresult nsLocalFile::GetFSRefInternal(FSRef& aFSRef)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  CHECK_INIT();
-
-  return (::CFURLGetFSRef(mBaseURL, &aFSRef) ? NS_OK : NS_ERROR_FAILURE);
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-nsresult nsLocalFile::GetPathInternal(nsACString& path)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  CHECK_INIT();
-
-  CFURLRef urlRef;
-  nsresult rv = GetCFURL(&urlRef);
-  if (NS_FAILED(rv))
-    return rv;
-
-  path.SetLength(PATH_MAX);
-  if (path.Length() != (unsigned int)PATH_MAX) {
-    ::CFRelease(urlRef);
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-  Boolean gotPath = ::CFURLGetFileSystemRepresentation(urlRef, true, (UInt8*)path.BeginWriting(), PATH_MAX);
-  ::CFRelease(urlRef);
-
-  return (gotPath ? NS_OK : NS_ERROR_FAILURE);
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-nsresult nsLocalFile::CopyInternal(nsIFile* aParentDir,
-                                   const nsAString& newName,
-                                   PRBool followLinks)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  CHECK_INIT();
-
-  StFollowLinksState srcFollowState(*this, followLinks);
-
-  nsresult rv;
-  OSErr err;
-  FSRef srcFSRef;
-
-  rv = GetFSRefInternal(srcFSRef);
-  if (NS_FAILED(rv))
-    return rv;
-
-  nsCOMPtr<nsIFile> newParentDir = aParentDir;
-
-  if (!newParentDir) {
-    if (newName.IsEmpty())
-      return NS_ERROR_INVALID_ARG;
-    rv = GetParent(getter_AddRefs(newParentDir));
-    if (NS_FAILED(rv))
-      return rv;    
-  }
-
-  // If newParentDir does not exist, create it
-  PRBool exists;
-  rv = newParentDir->Exists(&exists);
-  if (NS_FAILED(rv))
-    return rv;
-  if (!exists) {
-    rv = newParentDir->Create(nsIFile::DIRECTORY_TYPE, 0777);
-    if (NS_FAILED(rv))
-      return rv;
-  }
-
-  FSRef destFSRef;
-  nsCOMPtr<nsILocalFileMac> newParentDirMac(do_QueryInterface(newParentDir));
-  if (!newParentDirMac)
-    return NS_ERROR_NO_INTERFACE;
-  rv = newParentDirMac->GetFSRef(&destFSRef);
-  if (NS_FAILED(rv))
-    return rv;
-
-  CFStringRef destNameStr = NULL;
-  if (newName.Length() > 0) {
-    destNameStr = ::CFStringCreateWithCharacters(kCFAllocatorDefault,
-                                                 PromiseFlatString(newName).get(),
-                                                 newName.Length());
-  }
-  err = ::FSCopyObjectSync(&srcFSRef, &destFSRef, destNameStr, NULL, kFSFileOperationDefaultOptions);
-  if (destNameStr)
-    ::CFRelease(destNameStr);
-
-  return MacErrorMapper(err);
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-nsresult nsLocalFile::FillStatBufferInternal(struct STAT *statBuffer)
-{
-  CHECK_INIT();
-
-  if (STAT(mPath, statBuffer) == -1) {
-    if (LSTAT(mPath, statBuffer) == -1)
-      return NSRESULT_FOR_ERRNO();
-  }
-
-  return NS_OK;
-}
-
-// nsIHashable
-
-NS_IMETHODIMP
-nsLocalFile::Equals(nsIHashable* aOther, PRBool *aResult)
-{
-  nsCOMPtr<nsIFile> otherFile(do_QueryInterface(aOther));
-  if (!otherFile) {
-    *aResult = PR_FALSE;
-    return NS_OK;
-  }
-
-  return Equals(otherFile, aResult);
-}
-
-NS_IMETHODIMP
-nsLocalFile::GetHashCode(PRUint32 *aResult)
-{
-    NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-    CFStringRef pathStrRef = ::CFURLCopyFileSystemPath(mBaseURL, kCFURLPOSIXPathStyle);
-    nsCAutoString path;
-    CFStringReftoUTF8(pathStrRef, path);
-    ::CFRelease(pathStrRef);
-    *aResult = HashString(path);
-    return NS_OK;
-
-    NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
-
-#pragma mark -
-#pragma mark [Global Functions]
-
-void nsLocalFile::GlobalInit()
-{
-}
-
-void nsLocalFile::GlobalShutdown()
-{
-}
-
-nsresult NS_NewLocalFile(const nsAString& path, PRBool followLinks, nsILocalFile* *result)
-{
-    nsLocalFile* file = new nsLocalFile;
-    if (file == nsnull)
-        return NS_ERROR_OUT_OF_MEMORY;
-    NS_ADDREF(file);
-
-    file->SetFollowLinks(followLinks);
-
-    if (!path.IsEmpty()) {
-        nsresult rv = file->InitWithPath(path);
-        if (NS_FAILED(rv)) {
-            NS_RELEASE(file);
-            return rv;
-        }
-    }
-    *result = file;
-    return NS_OK;
-}
-
-nsresult NS_NewNativeLocalFile(const nsACString& path, PRBool followLinks, nsILocalFile **result)
-{
-    return NS_NewLocalFile(NS_ConvertUTF8toUTF16(path), followLinks, result);
-}
-
-nsresult NS_NewLocalFileWithFSRef(const FSRef* aFSRef, PRBool aFollowLinks, nsILocalFileMac** result)
-{
-    nsLocalFile* file = new nsLocalFile();
-    if (file == nsnull)
-        return NS_ERROR_OUT_OF_MEMORY;
-    NS_ADDREF(file);
-
-    file->SetFollowLinks(aFollowLinks);
-
-    nsresult rv = file->InitWithFSRef(aFSRef);
-    if (NS_FAILED(rv)) {
-        NS_RELEASE(file);
-        return rv;
-    }
-    *result = file;
-    return NS_OK;
-}
-
-nsresult NS_NewLocalFileWithCFURL(const CFURLRef aURL, PRBool aFollowLinks, nsILocalFileMac** result)
-{
-  nsLocalFile* file = new nsLocalFile();
-  if (file == nsnull)
-    return NS_ERROR_OUT_OF_MEMORY;
-  NS_ADDREF(file);
-
-  file->SetFollowLinks(aFollowLinks);
-
-  nsresult rv = file->InitWithCFURL(aURL);
-  if (NS_FAILED(rv)) {
-    NS_RELEASE(file);
-    return rv;
-  }
-  *result = file;
-  return NS_OK;
-}
-
-#pragma mark -
-#pragma mark [Static Functions]
-
-static nsresult MacErrorMapper(OSErr inErr)
-{
-    nsresult outErr;
-    
-    switch (inErr)
-    {
-        case noErr:
-            outErr = NS_OK;
-            break;
-
-        case fnfErr:
-        case afpObjectNotFound:
-        case afpDirNotFound:
-            outErr = NS_ERROR_FILE_NOT_FOUND;
-            break;
-
-        case dupFNErr:
-        case afpObjectExists:
-            outErr = NS_ERROR_FILE_ALREADY_EXISTS;
-            break;
-        
-        case dskFulErr:
-        case afpDiskFull:
-            outErr = NS_ERROR_FILE_DISK_FULL;
-            break;
-        
-        case fLckdErr:
-        case afpVolLocked:
-            outErr = NS_ERROR_FILE_IS_LOCKED;
-            break;
-        
-        case afpAccessDenied:
-            outErr = NS_ERROR_FILE_ACCESS_DENIED;
-            break;
-
-        case afpDirNotEmpty:
-            outErr = NS_ERROR_FILE_DIR_NOT_EMPTY;
-            break;
-            
-        // Can't find good map for some
-        case bdNamErr:
-            outErr = NS_ERROR_FAILURE;
-            break;
-
-        default:    
-            outErr = NS_ERROR_FAILURE;
-            break;
-    }
-    return outErr;
-}
-
-// Convert a UTF-8 string to a UTF-16 string while normalizing to
-// Normalization Form C (composed Unicode). We need this because
-// Mac OS X file system uses NFD (Normalization Form D : decomposed Unicode)
-// while most other OS', server-side programs usually expect NFC.
-static void CopyUTF8toUTF16NFC(const nsACString& aSrc, nsAString& aResult)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
-
-  const nsAFlatCString &inFlatSrc = PromiseFlatCString(aSrc);
-
-  // The number of 16bit code units in a UTF-16 string will never be
-  // larger than the number of bytes in the corresponding UTF-8 string.
-  CFMutableStringRef inStr = ::CFStringCreateMutable(NULL, inFlatSrc.Length());
-
-  if (!inStr) {
-    CopyUTF8toUTF16(aSrc, aResult);
-    return;
-  }
-
-  ::CFStringAppendCString(inStr, inFlatSrc.get(), kCFStringEncodingUTF8);
-
-  ::CFStringNormalize(inStr, kCFStringNormalizationFormC);
-
-  CFIndex length = ::CFStringGetLength(inStr);
-  const UniChar* chars = ::CFStringGetCharactersPtr(inStr);
-
-  if (chars) {
-    aResult.Assign(chars, length);
-  }
-  else {
-    nsAutoTArray<UniChar, PATH_MAX> buffer;
-    if (!buffer.SetLength(length)) {
-      CopyUTF8toUTF16(aSrc, aResult);
-    }
-    else {
-      ::CFStringGetCharacters(inStr, ::CFRangeMake(0, length), buffer.Elements());
-      aResult.Assign(buffer.Elements(), length);
-    }
-  }
-  ::CFRelease(inStr);
-
-  NS_OBJC_END_TRY_ABORT_BLOCK;
-}
-
-nsresult CFStringReftoUTF8(CFStringRef aInStrRef, nsACString& aOutStr)
-{
-  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
-
-  // first see if the conversion would succeed and find the length of the result
-  CFIndex usedBufLen, inStrLen = ::CFStringGetLength(aInStrRef);
-  CFIndex charsConverted = ::CFStringGetBytes(aInStrRef, CFRangeMake(0, inStrLen),
-                                              kCFStringEncodingUTF8, 0, PR_FALSE,
-                                              NULL, 0, &usedBufLen);
-  if (charsConverted == inStrLen) {
-    // all characters converted, do the actual conversion
-    aOutStr.SetLength(usedBufLen);
-    if (aOutStr.Length() != (unsigned int)usedBufLen)
-      return NS_ERROR_OUT_OF_MEMORY;
-    UInt8 *buffer = (UInt8*)aOutStr.BeginWriting();
-    ::CFStringGetBytes(aInStrRef, CFRangeMake(0, inStrLen), kCFStringEncodingUTF8,
-                       0, false, buffer, usedBufLen, &usedBufLen);
-    return NS_OK;
-  }
-  return NS_ERROR_FAILURE;
-
-  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
-}
--- a/xpcom/io/nsLocalFileUnix.cpp
+++ b/xpcom/io/nsLocalFileUnix.cpp
@@ -41,17 +41,17 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 /**
- * Implementation of nsIFile for ``Unixy'' systems.
+ * Implementation of nsIFile for "unixy" systems.
  */
 
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <utime.h>
@@ -87,16 +87,21 @@
 #include "nsISimpleEnumerator.h"
 #include "nsITimelineService.h"
 
 #ifdef MOZ_WIDGET_GTK2
 #include "nsIGIOService.h"
 #include "nsIGnomeVFSService.h"
 #endif
 
+#ifdef XP_MACOSX
+#include <Carbon/Carbon.h>
+#include "CocoaFileUtils.h"
+#endif
+
 #if (MOZ_PLATFORM_MAEMO == 5)
 #include <glib.h>
 #include <hildon-uri.h>
 #include <hildon-mime.h>
 #include <libosso.h>
 #endif
 
 #ifdef ANDROID
@@ -255,20 +260,28 @@ nsLocalFile::nsLocalFile()
 {
 }
 
 nsLocalFile::nsLocalFile(const nsLocalFile& other)
   : mPath(other.mPath)
 {
 }
 
-NS_IMPL_THREADSAFE_ISUPPORTS3(nsLocalFile,
+#ifdef XP_MACOSX
+NS_IMPL_THREADSAFE_ISUPPORTS4(nsLocalFile,
+                              nsILocalFileMac,
+                              nsILocalFile,
                               nsIFile,
+                              nsIHashable)
+#else
+NS_IMPL_THREADSAFE_ISUPPORTS3(nsLocalFile,
                               nsILocalFile,
+                              nsIFile,
                               nsIHashable)
+#endif
 
 nsresult
 nsLocalFile::nsLocalFileConstructor(nsISupports *outer, 
                                     const nsIID &aIID,
                                     void **aInstancePtr)
 {
     NS_ENSURE_ARG_POINTER(aInstancePtr);
     NS_ENSURE_NO_AGGREGATION(outer);
@@ -1282,29 +1295,29 @@ nsLocalFile::GetDiskSpaceAvailable(PRInt
 
 }
 
 NS_IMETHODIMP
 nsLocalFile::GetParent(nsIFile **aParent)
 {
     CHECK_mPath();
     NS_ENSURE_ARG_POINTER(aParent);
-    *aParent       = nsnull;
+    *aParent = nsnull;
 
     // if '/' we are at the top of the volume, return null
     if (mPath.Equals("/"))
         return  NS_OK;
  
     // <brendan, after jband> I promise to play nice
     char *buffer   = mPath.BeginWriting(),
          *slashp   = buffer;
 
     // find the last significant slash in buffer
     slashp = strrchr(buffer, '/');
-    NS_ASSERTION(slashp, "non-canonical mPath?");
+    NS_ASSERTION(slashp, "non-canonical path?");
     if (!slashp)
         return NS_ERROR_FILE_INVALID_PATH;
 
     // for the case where we are at '/'
     if (slashp == buffer)
         slashp++;
 
     // temporarily terminate buffer at the last significant slash
@@ -1635,17 +1648,16 @@ nsLocalFile::GetNativeTarget(nsACString 
 
     nsMemory::Free(target);
 
     if (NS_FAILED(rv))
         _retval.Truncate();
     return rv;
 }
 
-/* attribute PRBool followLinks; */
 NS_IMETHODIMP
 nsLocalFile::GetFollowLinks(PRBool *aFollowLinks)
 {
     *aFollowLinks = PR_TRUE;
     return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -1768,16 +1780,24 @@ nsLocalFile::Reveal()
         if (NS_FAILED(parentDir->GetNativePath(dirPath)))
             return NS_ERROR_FAILURE;
 
         if (giovfs)
             return giovfs->ShowURIForInput(dirPath);
         else 
             return gnomevfs->ShowURIForInput(dirPath);        
     }
+#elif defined(XP_MACOSX)
+    CFURLRef url;
+    if (NS_SUCCEEDED(GetCFURL(&url))) {
+      nsresult rv = CocoaFileUtils::RevealFileInFinder(url);
+      ::CFRelease(url);
+      return rv;
+    }
+    return NS_ERROR_FAILURE;
 #else
     return NS_ERROR_FAILURE;
 #endif
 }
 
 NS_IMETHODIMP
 nsLocalFile::Launch()
 {
@@ -1818,30 +1838,40 @@ nsLocalFile::Launch()
     nsCOMPtr<nsIMIMEService> mimeService(do_GetService("@mozilla.org/mime;1", &rv));
     if (NS_SUCCEEDED(rv))
         rv = mimeService->GetTypeFromFile(this, type);
 
     nsDependentCString fileUri = NS_LITERAL_CSTRING("file://");
     fileUri.Append(mPath);
     mozilla::AndroidBridge* bridge = mozilla::AndroidBridge::Bridge();
     return bridge->OpenUriExternal(fileUri, type) ? NS_OK : NS_ERROR_FAILURE;
+#elif defined(XP_MACOSX)
+    CFURLRef url;
+    if (NS_SUCCEEDED(GetCFURL(&url))) {
+        nsresult rv = CocoaFileUtils::OpenURL(url);
+        ::CFRelease(url);
+        return rv;
+    }
+    return NS_ERROR_FAILURE;
 #else
     return NS_ERROR_FAILURE;
 #endif
 }
 #endif
 
 nsresult
 NS_NewNativeLocalFile(const nsACString &path, PRBool followSymlinks, nsILocalFile **result)
 {
     nsLocalFile *file = new nsLocalFile();
     if (!file)
         return NS_ERROR_OUT_OF_MEMORY;
     NS_ADDREF(file);
 
+    file->SetFollowLinks(followSymlinks);
+
     if (!path.IsEmpty()) {
         nsresult rv = file->InitWithNativePath(path);
         if (NS_FAILED(rv)) {
             NS_RELEASE(file);
             return rv;
         }
     }
     *result = file;
@@ -1969,8 +1999,434 @@ void
 nsLocalFile::GlobalInit()
 {
 }
 
 void
 nsLocalFile::GlobalShutdown()
 {
 }
+
+// nsILocalFileMac
+
+#ifdef XP_MACOSX
+
+static nsresult MacErrorMapper(OSErr inErr)
+{
+  nsresult outErr;
+
+  switch (inErr)
+  {
+    case noErr:
+      outErr = NS_OK;
+      break;
+
+    case fnfErr:
+    case afpObjectNotFound:
+    case afpDirNotFound:
+      outErr = NS_ERROR_FILE_NOT_FOUND;
+      break;
+
+    case dupFNErr:
+    case afpObjectExists:
+      outErr = NS_ERROR_FILE_ALREADY_EXISTS;
+      break;
+
+    case dskFulErr:
+    case afpDiskFull:
+      outErr = NS_ERROR_FILE_DISK_FULL;
+      break;
+
+    case fLckdErr:
+    case afpVolLocked:
+      outErr = NS_ERROR_FILE_IS_LOCKED;
+      break;
+
+    case afpAccessDenied:
+      outErr = NS_ERROR_FILE_ACCESS_DENIED;
+      break;
+
+    case afpDirNotEmpty:
+      outErr = NS_ERROR_FILE_DIR_NOT_EMPTY;
+      break;
+
+    // Can't find good map for some
+    case bdNamErr:
+      outErr = NS_ERROR_FAILURE;
+      break;
+
+    default:
+      outErr = NS_ERROR_FAILURE;
+      break;
+  }
+
+  return outErr;
+}
+
+static nsresult CFStringReftoUTF8(CFStringRef aInStrRef, nsACString& aOutStr)
+{
+  // first see if the conversion would succeed and find the length of the result
+  CFIndex usedBufLen, inStrLen = ::CFStringGetLength(aInStrRef);
+  CFIndex charsConverted = ::CFStringGetBytes(aInStrRef, CFRangeMake(0, inStrLen),
+                                              kCFStringEncodingUTF8, 0, PR_FALSE,
+                                              NULL, 0, &usedBufLen);
+  if (charsConverted == inStrLen) {
+    // all characters converted, do the actual conversion
+    aOutStr.SetLength(usedBufLen);
+    if (aOutStr.Length() != (unsigned int)usedBufLen)
+      return NS_ERROR_OUT_OF_MEMORY;
+    UInt8 *buffer = (UInt8*)aOutStr.BeginWriting();
+    ::CFStringGetBytes(aInStrRef, CFRangeMake(0, inStrLen), kCFStringEncodingUTF8,
+                       0, false, buffer, usedBufLen, &usedBufLen);
+    return NS_OK;
+  }
+
+  return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsLocalFile::InitWithCFURL(CFURLRef aCFURL)
+{
+  UInt8 path[PATH_MAX];
+  if (::CFURLGetFileSystemRepresentation(aCFURL, false, path, PATH_MAX)) {
+    nsDependentCString nativePath((char*)path);
+    return InitWithNativePath(nativePath);
+  }
+
+  return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsLocalFile::InitWithFSRef(const FSRef *aFSRef)
+{
+  NS_ENSURE_ARG(aFSRef);
+
+  CFURLRef newURLRef = ::CFURLCreateFromFSRef(kCFAllocatorDefault, aFSRef);
+  if (newURLRef) {
+    nsresult rv = InitWithCFURL(newURLRef);
+    ::CFRelease(newURLRef);
+    return rv;
+  }
+
+  return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsLocalFile::GetCFURL(CFURLRef *_retval)
+{
+  CHECK_mPath();
+
+  PRBool isDir;
+  IsDirectory(&isDir);
+  *_retval = ::CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
+                                                       (UInt8*)mPath.get(),
+                                                       mPath.Length(),
+                                                       isDir);
+
+  return (*_retval ? NS_OK : NS_ERROR_FAILURE);
+}
+
+NS_IMETHODIMP
+nsLocalFile::GetFSRef(FSRef *_retval)
+{
+  NS_ENSURE_ARG_POINTER(_retval);
+
+  nsresult rv = NS_ERROR_FAILURE;
+
+  CFURLRef url = NULL;
+  if (NS_SUCCEEDED(GetCFURL(&url))) {
+    if (::CFURLGetFSRef(url, _retval)) {
+      rv = NS_OK;
+    }
+    ::CFRelease(url);
+  }
+
+  return rv;
+}
+
+NS_IMETHODIMP
+nsLocalFile::GetFSSpec(FSSpec *_retval)
+{
+  NS_ENSURE_ARG_POINTER(_retval);
+
+  FSRef fsRef;
+  nsresult rv = GetFSRef(&fsRef);
+  if (NS_SUCCEEDED(rv)) {
+    OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNone, nsnull, nsnull, _retval, nsnull);
+    return MacErrorMapper(err);
+  }
+
+  return rv;
+}
+
+NS_IMETHODIMP
+nsLocalFile::GetFileSizeWithResFork(PRInt64 *aFileSizeWithResFork)
+{
+  NS_ENSURE_ARG_POINTER(aFileSizeWithResFork);
+
+  FSRef fsRef;
+  nsresult rv = GetFSRef(&fsRef);
+  if (NS_FAILED(rv))
+    return rv;
+
+  FSCatalogInfo catalogInfo;
+  OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoDataSizes + kFSCatInfoRsrcSizes,
+                                 &catalogInfo, nsnull, nsnull, nsnull);
+  if (err != noErr)
+    return MacErrorMapper(err);
+
+  *aFileSizeWithResFork = catalogInfo.dataLogicalSize + catalogInfo.rsrcLogicalSize;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsLocalFile::GetFileType(OSType *aFileType)
+{
+  CFURLRef url;
+  if (NS_SUCCEEDED(GetCFURL(&url))) {
+    nsresult rv = CocoaFileUtils::GetFileTypeCode(url, aFileType);
+    ::CFRelease(url);
+    return rv;
+  }
+  return NS_ERROR_FAILURE;
+}
+  
+NS_IMETHODIMP
+nsLocalFile::SetFileType(OSType aFileType)
+{
+  CFURLRef url;
+  if (NS_SUCCEEDED(GetCFURL(&url))) {
+    nsresult rv = CocoaFileUtils::SetFileTypeCode(url, aFileType);
+    ::CFRelease(url);
+    return rv;
+  }
+  return NS_ERROR_FAILURE;
+}
+  
+NS_IMETHODIMP
+nsLocalFile::GetFileCreator(OSType *aFileCreator)
+{
+  CFURLRef url;
+  if (NS_SUCCEEDED(GetCFURL(&url))) {
+    nsresult rv = CocoaFileUtils::GetFileCreatorCode(url, aFileCreator);
+    ::CFRelease(url);
+    return rv;
+  }
+  return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsLocalFile::SetFileCreator(OSType aFileCreator)
+{
+  CFURLRef url;
+  if (NS_SUCCEEDED(GetCFURL(&url))) {
+    nsresult rv = CocoaFileUtils::SetFileCreatorCode(url, aFileCreator);
+    ::CFRelease(url);
+    return rv;
+  }
+  return NS_ERROR_FAILURE;
+}
+  
+NS_IMETHODIMP
+nsLocalFile::LaunchWithDoc(nsILocalFile *aDocToLoad, PRBool aLaunchInBackground)
+{    
+  PRBool isExecutable;
+  nsresult rv = IsExecutable(&isExecutable);
+  if (NS_FAILED(rv))
+    return rv;
+  if (!isExecutable)
+    return NS_ERROR_FILE_EXECUTION_FAILED;
+
+  FSRef appFSRef, docFSRef;
+  rv = GetFSRef(&appFSRef);
+  if (NS_FAILED(rv))
+    return rv;
+
+  if (aDocToLoad) {
+    nsCOMPtr<nsILocalFileMac> macDoc = do_QueryInterface(aDocToLoad);
+    rv = macDoc->GetFSRef(&docFSRef);
+    if (NS_FAILED(rv))
+      return rv;
+  }
+
+  LSLaunchFlags theLaunchFlags = kLSLaunchDefaults;
+  LSLaunchFSRefSpec thelaunchSpec;
+
+  if (aLaunchInBackground)
+    theLaunchFlags |= kLSLaunchDontSwitch;
+  memset(&thelaunchSpec, 0, sizeof(LSLaunchFSRefSpec));
+
+  thelaunchSpec.appRef = &appFSRef;
+  if (aDocToLoad) {
+    thelaunchSpec.numDocs = 1;
+    thelaunchSpec.itemRefs = &docFSRef;
+  }
+  thelaunchSpec.launchFlags = theLaunchFlags;
+
+  OSErr err = ::LSOpenFromRefSpec(&thelaunchSpec, NULL);
+  if (err != noErr)
+    return MacErrorMapper(err);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsLocalFile::OpenDocWithApp(nsILocalFile *aAppToOpenWith, PRBool aLaunchInBackground)
+{
+  FSRef docFSRef;
+  nsresult rv = GetFSRef(&docFSRef);
+  if (NS_FAILED(rv))
+    return rv;
+
+  if (!aAppToOpenWith) {
+    OSErr err = ::LSOpenFSRef(&docFSRef, NULL);
+    return MacErrorMapper(err);
+  }
+
+  nsCOMPtr<nsILocalFileMac> appFileMac = do_QueryInterface(aAppToOpenWith, &rv);
+  if (!appFileMac)
+    return rv;
+
+  PRBool isExecutable;
+  rv = appFileMac->IsExecutable(&isExecutable);
+  if (NS_FAILED(rv))
+    return rv;
+  if (!isExecutable)
+    return NS_ERROR_FILE_EXECUTION_FAILED;
+
+  FSRef appFSRef;
+  rv = appFileMac->GetFSRef(&appFSRef);
+  if (NS_FAILED(rv))
+    return rv;
+
+  LSLaunchFlags theLaunchFlags = kLSLaunchDefaults;
+  LSLaunchFSRefSpec thelaunchSpec;
+
+  if (aLaunchInBackground)
+    theLaunchFlags |= kLSLaunchDontSwitch;
+  memset(&thelaunchSpec, 0, sizeof(LSLaunchFSRefSpec));
+
+  thelaunchSpec.appRef = &appFSRef;
+  thelaunchSpec.numDocs = 1;
+  thelaunchSpec.itemRefs = &docFSRef;
+  thelaunchSpec.launchFlags = theLaunchFlags;
+
+  OSErr err = ::LSOpenFromRefSpec(&thelaunchSpec, NULL);
+  if (err != noErr)
+    return MacErrorMapper(err);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsLocalFile::IsPackage(PRBool *_retval)
+{
+  NS_ENSURE_ARG(_retval);
+  *_retval = PR_FALSE;
+
+  CFURLRef url;
+  nsresult rv = GetCFURL(&url);
+  if (NS_SUCCEEDED(rv)) {
+    CFBundleRef bundle = ::CFBundleCreate(kCFAllocatorDefault, url);
+    if (bundle) {
+      *_retval = PR_TRUE;
+      ::CFRelease(bundle);
+    }
+  }
+  return rv;
+}
+
+NS_IMETHODIMP
+nsLocalFile::GetBundleDisplayName(nsAString& outBundleName)
+{
+  PRBool isPackage = PR_FALSE;
+  nsresult rv = IsPackage(&isPackage);
+  if (NS_FAILED(rv) || !isPackage)
+    return NS_ERROR_FAILURE;
+
+  nsAutoString name;
+  rv = GetLeafName(name);
+  if (NS_FAILED(rv))
+    return rv;
+
+  PRInt32 length = name.Length();
+  if (Substring(name, length - 4, length).EqualsLiteral(".app")) {
+    // 4 characters in ".app"
+    outBundleName = Substring(name, 0, length - 4);
+  }
+  else {
+    outBundleName = name;
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsLocalFile::GetBundleIdentifier(nsACString& outBundleIdentifier)
+{
+  nsresult rv = NS_ERROR_FAILURE;
+
+  CFURLRef urlRef;
+  if (NS_SUCCEEDED(GetCFURL(&urlRef))) {
+    CFBundleRef bundle = ::CFBundleCreate(NULL, urlRef);
+    if (bundle) {
+      CFStringRef bundleIdentifier = ::CFBundleGetIdentifier(bundle);
+      if (bundleIdentifier)
+        rv = CFStringReftoUTF8(bundleIdentifier, outBundleIdentifier);
+      ::CFRelease(bundle);
+    }
+    ::CFRelease(urlRef);
+  }
+
+  return rv;
+}
+
+NS_IMETHODIMP nsLocalFile::InitWithFile(nsILocalFile *aFile)
+{
+  NS_ENSURE_ARG(aFile);
+
+  nsCAutoString nativePath;
+  nsresult rv = aFile->GetNativePath(nativePath);
+  if (NS_FAILED(rv))
+    return rv;
+
+  return InitWithNativePath(nativePath);
+}
+
+nsresult
+NS_NewLocalFileWithFSRef(const FSRef* aFSRef, PRBool aFollowLinks, nsILocalFileMac** result)
+{
+  nsLocalFile* file = new nsLocalFile();
+  if (file == nsnull)
+    return NS_ERROR_OUT_OF_MEMORY;
+  NS_ADDREF(file);
+
+  file->SetFollowLinks(aFollowLinks);
+
+  nsresult rv = file->InitWithFSRef(aFSRef);
+  if (NS_FAILED(rv)) {
+    NS_RELEASE(file);
+    return rv;
+  }
+  *result = file;
+  return NS_OK;
+}
+
+nsresult
+NS_NewLocalFileWithCFURL(const CFURLRef aURL, PRBool aFollowLinks, nsILocalFileMac** result)
+{
+  nsLocalFile* file = new nsLocalFile();
+  if (!file)
+    return NS_ERROR_OUT_OF_MEMORY;
+  NS_ADDREF(file);
+
+  file->SetFollowLinks(aFollowLinks);
+
+  nsresult rv = file->InitWithCFURL(aURL);
+  if (NS_FAILED(rv)) {
+    NS_RELEASE(file);
+    return rv;
+  }
+  *result = file;
+  return NS_OK;
+}
+
+#endif
--- a/xpcom/io/nsLocalFileUnix.h
+++ b/xpcom/io/nsLocalFileUnix.h
@@ -48,16 +48,19 @@
 #include <sys/types.h>
 #include <unistd.h>
 
 #include "nscore.h"
 #include "nsString.h"
 #include "nsReadableUtils.h"
 #include "nsIHashable.h"
 #include "nsIClassInfoImpl.h"
+#ifdef XP_MACOSX
+#include "nsILocalFileMac.h"
+#endif
 
 /** 
  *  we need these for statfs()
  */
 #ifdef HAVE_SYS_STATVFS_H
     #if defined(__osf__) && defined(__DECCXX)
         extern "C" int statvfs(const char *, struct statvfs *);
     #endif
@@ -96,49 +99,50 @@
     #define LSTAT lstat64
     #define HAVE_STATS64 1
 #else
     #define STAT stat
     #define LSTAT lstat
 #endif
 
 
-class NS_COM nsLocalFile : public nsILocalFile,
+class NS_COM nsLocalFile :
+#ifdef XP_MACOSX
+                           public nsILocalFileMac,
+#else
+                           public nsILocalFile,
+#endif
                            public nsIHashable
 {
 public:
     NS_DEFINE_STATIC_CID_ACCESSOR(NS_LOCAL_FILE_CID)
     
     nsLocalFile();
 
     static nsresult nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr);
 
-    // nsISupports
     NS_DECL_ISUPPORTS
-
-    // nsIFile
     NS_DECL_NSIFILE
-
-    // nsILocalFile
     NS_DECL_NSILOCALFILE
-
-    // nsIHashable
+#ifdef XP_MACOSX
+    NS_DECL_NSILOCALFILEMAC
+#endif
     NS_DECL_NSIHASHABLE
 
 public:
     static void GlobalInit();
     static void GlobalShutdown();
 
 private:
     nsLocalFile(const nsLocalFile& other);
     ~nsLocalFile() {}
 
 protected:
-// This stat cache holds the *last stat* - it does not invalidate.
-// Call "FillStatCache" whenever you want to stat our file.
+    // This stat cache holds the *last stat* - it does not invalidate.
+    // Call "FillStatCache" whenever you want to stat our file.
     struct STAT  mCachedStat;
     nsCString    mPath;
 
     void LocateNativeLeafName(nsACString::const_iterator &,
                               nsACString::const_iterator &);
 
     nsresult CopyDirectoryTo(nsIFile *newParent);
     nsresult CreateAllAncestors(PRUint32 permissions);