1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 2001, 2002
20 * the Initial Developer. All Rights Reserved.
23 * Conrad Carlen <ccarlen@netscape.com>
24 * Jungshik Shin <jshin@mailaps.org>
25 * Asaf Romano <mozilla.mano@sent.com>
26 * Mark Mentovai <mark@moxienet.com>
28 * Alternatively, the contents of this file may be used under the terms of
29 * either the GNU General Public License Version 2 or later (the "GPL"), or
30 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 * in which case the provisions of the GPL or the LGPL are applicable instead
32 * of those above. If you wish to allow use of your version of this file only
33 * under the terms of either the GPL or the LGPL, and not to allow others to
34 * use your version of this file under the terms of the MPL, indicate your
35 * decision by deleting the provisions above and replace them with the notice
36 * and other provisions required by the GPL or the LGPL. If you do not delete
37 * the provisions above, a recipient may use your version of this file under
38 * the terms of any one of the MPL, the GPL or the LGPL.
40 * ***** END LICENSE BLOCK ***** */
42 #include "nsLocalFile.h"
43 #include "nsDirectoryServiceDefs.h"
45 #include "nsObjCExceptions.h"
47 #include "nsReadableUtils.h"
48 #include "nsIDirectoryEnumerator.h"
49 #include "nsISimpleEnumerator.h"
50 #include "nsITimelineService.h"
51 #include "nsVoidArray.h"
56 #include "nsHashKeys.h"
58 #include "MoreFilesX.h"
59 #include "FSCopyObject.h"
61 #include "nsTraceRefcntImpl.h"
64 #include <Carbon/Carbon.h>
65 #import <Cocoa/Cocoa.h>
72 #if !defined(MAC_OS_X_VERSION_10_4) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_4
73 #define GetAliasSizeFromRecord(aliasRecord) aliasRecord.aliasSize
75 #define GetAliasSizeFromRecord(aliasRecord) GetAliasSizeFromPtr(&aliasRecord)
78 #define CHECK_mBaseRef() \
81 return NS_ERROR_NOT_INITIALIZED; \
84 //*****************************************************************************
85 // Static Function Prototypes
86 //*****************************************************************************
88 static nsresult MacErrorMapper(OSErr inErr);
89 static OSErr FindRunningAppBySignature(OSType aAppSig, ProcessSerialNumber& outPsn);
90 static void CopyUTF8toUTF16NFC(const nsACString& aSrc, nsAString& aResult);
92 //*****************************************************************************
93 // Local Helper Classes
94 //*****************************************************************************
97 #pragma mark [FSRef operator==]
99 bool operator==(const FSRef& lhs, const FSRef& rhs)
101 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
103 return (::FSCompareFSRefs(&lhs, &rhs) == noErr);
105 NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(false);
109 #pragma mark [StFollowLinksState]
111 class StFollowLinksState
114 StFollowLinksState(nsLocalFile& aFile) :
117 mFile.GetFollowLinks(&mSavedState);
120 StFollowLinksState(nsLocalFile& aFile, PRBool followLinksState) :
123 mFile.GetFollowLinks(&mSavedState);
124 mFile.SetFollowLinks(followLinksState);
127 ~StFollowLinksState()
129 mFile.SetFollowLinks(mSavedState);
138 #pragma mark [nsDirEnumerator]
140 class nsDirEnumerator : public nsISimpleEnumerator,
141 public nsIDirectoryEnumerator
149 mFSRefsArray(nsnull),
150 mArrayCnt(0), mArrayIndex(0)
154 nsresult Init(nsILocalFileMac* parent)
156 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
158 NS_ENSURE_ARG(parent);
164 rv = parent->GetFSRef(&parentRef);
168 mFSRefsArray = (FSRef *)nsMemory::Alloc(sizeof(FSRef)
169 * kRequestCountPerIteration);
171 return NS_ERROR_OUT_OF_MEMORY;
173 err = ::FSOpenIterator(&parentRef, kFSIterateFlat, &mIterator);
175 return MacErrorMapper(err);
179 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
182 NS_IMETHOD HasMoreElements(PRBool *result)
184 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
186 if (!mIterator || !mFSRefsArray) {
191 if (mNext == nsnull) {
192 if (mArrayIndex >= mArrayCnt) {
194 OSErr err = ::FSGetCatalogInfoBulk(mIterator,
195 kRequestCountPerIteration,
204 if (err == noErr || err == errFSNoMoreItems) {
205 mArrayCnt = actualCnt;
210 if (mArrayIndex < mArrayCnt) {
211 nsLocalFile *newFile = new nsLocalFile;
213 return NS_ERROR_OUT_OF_MEMORY;
214 FSRef fsRef = mFSRefsArray[mArrayIndex];
215 if (NS_FAILED(newFile->InitWithFSRef(&fsRef)))
216 return NS_ERROR_FAILURE;
222 *result = mNext != nsnull;
228 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
231 NS_IMETHOD GetNext(nsISupports **result)
233 NS_ENSURE_ARG_POINTER(result);
238 rv = HasMoreElements(&hasMore);
239 if (NS_FAILED(rv)) return rv;
241 *result = mNext; // might return nsnull
242 NS_IF_ADDREF(*result);
248 NS_IMETHOD GetNextFile(nsIFile **result)
251 PRBool hasMore = PR_FALSE;
252 nsresult rv = HasMoreElements(&hasMore);
253 if (NS_FAILED(rv) || !hasMore)
256 NS_IF_ADDREF(*result);
263 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
266 ::FSCloseIterator(mIterator);
270 nsMemory::Free(mFSRefsArray);
271 mFSRefsArray = nsnull;
275 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
285 // According to Apple doc, request the number of objects
286 // per call that will fit in 4 VM pages.
288 kRequestCountPerIteration = ((4096 * 4) / sizeof(FSRef))
291 nsCOMPtr<nsILocalFileMac> mNext;
293 FSIterator mIterator;
295 PRInt32 mArrayCnt, mArrayIndex;
298 NS_IMPL_ISUPPORTS2(nsDirEnumerator, nsISimpleEnumerator, nsIDirectoryEnumerator)
301 #pragma mark [StAEDesc]
303 class StAEDesc: public AEDesc
308 descriptorType = typeNull;
314 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
316 ::AEDisposeDesc(this);
318 NS_OBJC_END_TRY_ABORT_BLOCK;
322 #define FILENAME_BUFFER_SIZE 512
324 //*****************************************************************************
326 //*****************************************************************************
328 const char nsLocalFile::kPathSepChar = '/';
329 const PRUnichar nsLocalFile::kPathSepUnichar = '/';
331 // The HFS+ epoch is Jan. 1, 1904 GMT - differs from HFS in which times were local
332 // The NSPR epoch is Jan. 1, 1970 GMT
333 // 2082844800 is the difference in seconds between those dates
334 const PRInt64 nsLocalFile::kJanuaryFirst1970Seconds = 2082844800LL;
337 #pragma mark [CTORs/DTOR]
339 nsLocalFile::nsLocalFile() :
342 mCachedFSRefValid(PR_FALSE),
343 mFollowLinks(PR_TRUE),
344 mFollowLinksDirty(PR_TRUE)
348 nsLocalFile::nsLocalFile(const nsLocalFile& src) :
349 mBaseRef(src.mBaseRef),
350 mTargetRef(src.mTargetRef),
351 mCachedFSRef(src.mCachedFSRef),
352 mCachedFSRefValid(src.mCachedFSRefValid),
353 mFollowLinks(src.mFollowLinks),
354 mFollowLinksDirty(src.mFollowLinksDirty)
356 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
358 // A CFURLRef is immutable so no need to copy, just retain.
360 ::CFRetain(mBaseRef);
362 ::CFRetain(mTargetRef);
364 NS_OBJC_END_TRY_ABORT_BLOCK;
367 nsLocalFile::~nsLocalFile()
369 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
372 ::CFRelease(mBaseRef);
374 ::CFRelease(mTargetRef);
376 NS_OBJC_END_TRY_ABORT_BLOCK;
380 //*****************************************************************************
381 // nsLocalFile::nsISupports
382 //*****************************************************************************
384 #pragma mark [nsISupports]
386 NS_IMPL_THREADSAFE_ISUPPORTS4(nsLocalFile,
392 NS_IMETHODIMP nsLocalFile::nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
394 NS_ENSURE_ARG_POINTER(aInstancePtr);
395 NS_ENSURE_NO_AGGREGATION(outer);
397 nsLocalFile* inst = new nsLocalFile();
399 return NS_ERROR_OUT_OF_MEMORY;
401 nsresult rv = inst->QueryInterface(aIID, aInstancePtr);
411 //*****************************************************************************
412 // nsLocalFile::nsIFile
413 //*****************************************************************************
415 #pragma mark [nsIFile]
417 /* void append (in AString node); */
418 NS_IMETHODIMP nsLocalFile::Append(const nsAString& aNode)
420 return AppendNative(NS_ConvertUTF16toUTF8(aNode));
423 /* [noscript] void appendNative (in ACString node); */
424 NS_IMETHODIMP nsLocalFile::AppendNative(const nsACString& aNode)
426 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
428 // Check we are correctly initialized.
431 nsACString::const_iterator start, end;
432 aNode.BeginReading(start);
433 aNode.EndReading(end);
434 if (FindCharInReadable(kPathSepChar, start, end))
435 return NS_ERROR_FILE_UNRECOGNIZED_PATH;
437 CFStringRef nodeStrRef = ::CFStringCreateWithCString(kCFAllocatorDefault,
438 PromiseFlatCString(aNode).get(),
439 kCFStringEncodingUTF8);
441 CFURLRef newRef = ::CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault,
442 mBaseRef, nodeStrRef, PR_FALSE);
443 ::CFRelease(nodeStrRef);
450 return NS_ERROR_FAILURE;
452 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
455 /* void normalize (); */
456 NS_IMETHODIMP nsLocalFile::Normalize()
458 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
460 // Check we are correctly initialized.
463 // CFURL doesn't doesn't seem to resolve paths containing relative
464 // components, so we'll nick the stdlib code from nsLocalFileUnix
465 UInt8 path[PATH_MAX] = "";
467 success = ::CFURLGetFileSystemRepresentation(mBaseRef, true, path, PATH_MAX);
469 return NS_ERROR_FAILURE;
471 char resolved_path[PATH_MAX] = "";
472 char *resolved_path_ptr = nsnull;
473 resolved_path_ptr = realpath((char*)path, resolved_path);
475 // if there is an error, the return is null.
476 if (!resolved_path_ptr)
477 return NSRESULT_FOR_ERRNO();
479 // Need to know whether we're a directory to create a new CFURLRef
481 nsresult rv = IsDirectory(&isDirectory);
482 NS_ENSURE_SUCCESS(rv, rv);
484 rv = NS_ERROR_FAILURE;
485 CFStringRef pathStrRef =
486 ::CFStringCreateWithCString(kCFAllocatorDefault,
488 kCFStringEncodingUTF8);
491 ::CFURLCreateWithFileSystemPath(kCFAllocatorDefault, pathStrRef,
492 kCFURLPOSIXPathStyle, isDirectory);
494 SetBaseRef(newURLRef);
495 ::CFRelease(newURLRef);
498 ::CFRelease(pathStrRef);
503 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
506 /* void create (in unsigned long type, in unsigned long permissions); */
507 NS_IMETHODIMP nsLocalFile::Create(PRUint32 type, PRUint32 permissions)
509 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
511 if (type != NORMAL_FILE_TYPE && type != DIRECTORY_TYPE)
512 return NS_ERROR_FILE_UNKNOWN_TYPE;
514 // Check we are correctly initialized.
517 nsStringArray nonExtantNodes;
518 CFURLRef pathURLRef = mBaseRef;
520 CFStringRef leafStrRef = nsnull;
521 nsAutoTArray<UniChar, FILENAME_BUFFER_SIZE> buffer;
524 // Work backwards through the path to find the last node which
525 // exists. Place the nodes which don't exist in an array and we'll
526 // create those below.
527 while ((success = ::CFURLGetFSRef(pathURLRef, &pathFSRef)) == false) {
528 leafStrRef = ::CFURLCopyLastPathComponent(pathURLRef);
531 CFIndex leafLen = ::CFStringGetLength(leafStrRef);
532 if (!buffer.SetLength(leafLen + 1))
534 ::CFStringGetCharacters(leafStrRef, CFRangeMake(0, leafLen), buffer.Elements());
535 buffer[leafLen] = '\0';
536 nonExtantNodes.AppendString(nsString(nsDependentString(buffer.Elements())));
537 ::CFRelease(leafStrRef);
540 // Get the parent of the leaf for the next go round
541 CFURLRef parent = ::CFURLCreateCopyDeletingLastPathComponent(NULL, pathURLRef);
544 if (pathURLRef != mBaseRef)
545 ::CFRelease(pathURLRef);
548 if (pathURLRef != mBaseRef)
549 ::CFRelease(pathURLRef);
550 if (leafStrRef != nsnull)
551 ::CFRelease(leafStrRef);
553 return NS_ERROR_FAILURE;
554 PRInt32 nodesToCreate = nonExtantNodes.Count();
555 if (nodesToCreate == 0)
556 return NS_ERROR_FILE_ALREADY_EXISTS;
559 nsAutoString nextNodeName;
560 for (PRInt32 i = nodesToCreate - 1; i > 0; i--) {
561 nonExtantNodes.StringAt(i, nextNodeName);
562 err = ::FSCreateDirectoryUnicode(&pathFSRef,
563 nextNodeName.Length(),
564 (const UniChar *)nextNodeName.get(),
566 nsnull, &pathFSRef, nsnull, nsnull);
568 return MacErrorMapper(err);
570 nonExtantNodes.StringAt(0, nextNodeName);
571 if (type == NORMAL_FILE_TYPE) {
572 err = ::FSCreateFileUnicode(&pathFSRef,
573 nextNodeName.Length(),
574 (const UniChar *)nextNodeName.get(),
576 nsnull, nsnull, nsnull);
579 err = ::FSCreateDirectoryUnicode(&pathFSRef,
580 nextNodeName.Length(),
581 (const UniChar *)nextNodeName.get(),
583 nsnull, nsnull, nsnull, nsnull);
586 return MacErrorMapper(err);
588 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
591 /* attribute AString leafName; */
592 NS_IMETHODIMP nsLocalFile::GetLeafName(nsAString& aLeafName)
594 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
596 nsCAutoString nativeString;
597 nsresult rv = GetNativeLeafName(nativeString);
600 CopyUTF8toUTF16NFC(nativeString, aLeafName);
603 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
606 NS_IMETHODIMP nsLocalFile::SetLeafName(const nsAString& aLeafName)
608 return SetNativeLeafName(NS_ConvertUTF16toUTF8(aLeafName));
611 /* [noscript] attribute ACString nativeLeafName; */
612 NS_IMETHODIMP nsLocalFile::GetNativeLeafName(nsACString& aNativeLeafName)
614 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
616 // Check we are correctly initialized.
619 nsresult rv = NS_ERROR_FAILURE;
620 CFStringRef leafStrRef = ::CFURLCopyLastPathComponent(mBaseRef);
622 rv = CFStringReftoUTF8(leafStrRef, aNativeLeafName);
623 ::CFRelease(leafStrRef);
627 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
630 NS_IMETHODIMP nsLocalFile::SetNativeLeafName(const nsACString& aNativeLeafName)
632 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
634 // Check we are correctly initialized.
637 nsresult rv = NS_ERROR_FAILURE;
638 CFURLRef parentURLRef = ::CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, mBaseRef);
640 CFStringRef nodeStrRef = ::CFStringCreateWithCString(kCFAllocatorDefault,
641 PromiseFlatCString(aNativeLeafName).get(),
642 kCFStringEncodingUTF8);
645 CFURLRef newURLRef = ::CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault,
646 parentURLRef, nodeStrRef, PR_FALSE);
648 SetBaseRef(newURLRef);
649 ::CFRelease(newURLRef);
652 ::CFRelease(nodeStrRef);
654 ::CFRelease(parentURLRef);
658 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
661 /* void copyTo (in nsIFile newParentDir, in AString newName); */
662 NS_IMETHODIMP nsLocalFile::CopyTo(nsIFile *newParentDir, const nsAString& newName)
664 return CopyInternal(newParentDir, newName, PR_FALSE);
667 /* [noscrpit] void CopyToNative (in nsIFile newParentDir, in ACString newName); */
668 NS_IMETHODIMP nsLocalFile::CopyToNative(nsIFile *newParentDir, const nsACString& newName)
670 return CopyInternal(newParentDir, NS_ConvertUTF8toUTF16(newName), PR_FALSE);
673 /* void copyToFollowingLinks (in nsIFile newParentDir, in AString newName); */
674 NS_IMETHODIMP nsLocalFile::CopyToFollowingLinks(nsIFile *newParentDir, const nsAString& newName)
676 return CopyInternal(newParentDir, newName, PR_TRUE);
679 /* [noscript] void copyToFollowingLinksNative (in nsIFile newParentDir, in ACString newName); */
680 NS_IMETHODIMP nsLocalFile::CopyToFollowingLinksNative(nsIFile *newParentDir, const nsACString& newName)
682 return CopyInternal(newParentDir, NS_ConvertUTF8toUTF16(newName), PR_TRUE);
685 /* void moveTo (in nsIFile newParentDir, in AString newName); */
686 NS_IMETHODIMP nsLocalFile::MoveTo(nsIFile *newParentDir, const nsAString& newName)
688 return MoveToNative(newParentDir, NS_ConvertUTF16toUTF8(newName));
691 /* [noscript] void moveToNative (in nsIFile newParentDir, in ACString newName); */
692 NS_IMETHODIMP nsLocalFile::MoveToNative(nsIFile *newParentDir, const nsACString& newName)
694 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
696 // Check we are correctly initialized.
699 StFollowLinksState followLinks(*this, PR_FALSE);
702 nsresult rv = IsDirectory(&isDirectory);
706 // Get the source path.
707 nsCAutoString srcPath;
708 rv = GetNativePath(srcPath);
712 // Build the destination path.
713 nsCOMPtr<nsIFile> parentDir = newParentDir;
715 if (newName.IsEmpty())
716 return NS_ERROR_INVALID_ARG;
717 rv = GetParent(getter_AddRefs(parentDir));
723 rv = parentDir->Exists(&exists);
727 rv = parentDir->Create(nsIFile::DIRECTORY_TYPE, 0777);
733 nsCAutoString destPath;
734 rv = parentDir->GetNativePath(destPath);
738 if (!newName.IsEmpty())
739 destPath.Append(NS_LITERAL_CSTRING("/") + newName);
741 nsCAutoString leafName;
742 rv = GetNativeLeafName(leafName);
745 destPath.Append(NS_LITERAL_CSTRING("/") + leafName);
749 if (rename(srcPath.get(), destPath.get()) != 0) {
750 if (errno == EXDEV) {
751 // Can't move across volume (device) boundaries. Copy and remove.
752 rv = CopyToNative(parentDir, newName);
753 if (NS_SUCCEEDED(rv)) {
754 // Permit removal failure.
759 rv = NSRESULT_FOR_ERRNO();
765 // Update |this| to refer to the moved file.
766 CFURLRef newBaseRef =
767 ::CFURLCreateFromFileSystemRepresentation(NULL, (UInt8*)destPath.get(),
768 destPath.Length(), isDirectory);
770 return NS_ERROR_FAILURE;
771 SetBaseRef(newBaseRef);
772 ::CFRelease(newBaseRef);
776 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
779 /* void remove (in boolean recursive); */
780 NS_IMETHODIMP nsLocalFile::Remove(PRBool recursive)
782 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
784 // Check we are correctly initialized.
787 // XXX If we're an alias, never remove target
788 StFollowLinksState followLinks(*this, PR_FALSE);
791 nsresult rv = IsDirectory(&isDirectory);
795 if (recursive && isDirectory) {
797 rv = GetFSRefInternal(fsRef);
801 // Call MoreFilesX to do a recursive removal.
802 OSStatus err = ::FSDeleteContainer(&fsRef);
803 rv = MacErrorMapper(err);
807 rv = GetNativePath(path);
811 const char* pathPtr = path.get();
814 status = rmdir(pathPtr);
816 status = unlink(pathPtr);
819 rv = NSRESULT_FOR_ERRNO();
822 mCachedFSRefValid = PR_FALSE;
825 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
828 /* attribute unsigned long permissions; */
829 NS_IMETHODIMP nsLocalFile::GetPermissions(PRUint32 *aPermissions)
831 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
833 NS_ENSURE_ARG_POINTER(aPermissions);
836 nsresult rv = GetFSRefInternal(fsRef);
840 FSCatalogInfo catalogInfo;
841 OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoPermissions, &catalogInfo,
842 nsnull, nsnull, nsnull);
844 return MacErrorMapper(err);
845 FSPermissionInfo *permPtr = (FSPermissionInfo*)catalogInfo.permissions;
846 *aPermissions = permPtr->mode;
849 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
852 NS_IMETHODIMP nsLocalFile::SetPermissions(PRUint32 aPermissions)
854 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
857 nsresult rv = GetFSRefInternal(fsRef);
861 FSCatalogInfo catalogInfo;
862 OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoPermissions, &catalogInfo,
863 nsnull, nsnull, nsnull);
865 return MacErrorMapper(err);
866 FSPermissionInfo *permPtr = (FSPermissionInfo*)catalogInfo.permissions;
867 permPtr->mode = (UInt16)aPermissions;
868 err = ::FSSetCatalogInfo(&fsRef, kFSCatInfoPermissions, &catalogInfo);
869 return MacErrorMapper(err);
871 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
874 /* attribute unsigned long permissionsOfLink; */
875 NS_IMETHODIMP nsLocalFile::GetPermissionsOfLink(PRUint32 *aPermissionsOfLink)
877 NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
878 return NS_ERROR_NOT_IMPLEMENTED;
881 NS_IMETHODIMP nsLocalFile::SetPermissionsOfLink(PRUint32 aPermissionsOfLink)
883 NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
884 return NS_ERROR_NOT_IMPLEMENTED;
887 /* attribute PRInt64 lastModifiedTime; */
888 NS_IMETHODIMP nsLocalFile::GetLastModifiedTime(PRInt64 *aLastModifiedTime)
890 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
892 // Check we are correctly initialized.
895 NS_ENSURE_ARG_POINTER(aLastModifiedTime);
898 nsresult rv = GetFSRefInternal(fsRef);
902 FSCatalogInfo catalogInfo;
903 OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoContentMod, &catalogInfo,
904 nsnull, nsnull, nsnull);
906 return MacErrorMapper(err);
907 *aLastModifiedTime = HFSPlustoNSPRTime(catalogInfo.contentModDate);
910 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
913 NS_IMETHODIMP nsLocalFile::SetLastModifiedTime(PRInt64 aLastModifiedTime)
915 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
917 // Check we are correctly initialized.
923 FSCatalogInfo catalogInfo;
925 rv = GetFSRefInternal(fsRef);
932 /* Get the node flags, the content modification date and time, and the parent ref */
933 err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags + kFSCatInfoContentMod,
934 &catalogInfo, NULL, NULL, &parentRef);
936 return MacErrorMapper(err);
938 /* Notify the parent if this is a file */
939 notifyParent = (0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask));
941 NSPRtoHFSPlusTime(aLastModifiedTime, catalogInfo.contentModDate);
942 err = ::FSSetCatalogInfo(&fsRef, kFSCatInfoContentMod, &catalogInfo);
944 return MacErrorMapper(err);
946 /* Send a notification for the parent of the file, or for the directory */
947 err = FNNotify(notifyParent ? &parentRef : &fsRef, kFNDirectoryModifiedMessage, kNilOptions);
949 return MacErrorMapper(err);
953 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
956 /* attribute PRInt64 lastModifiedTimeOfLink; */
957 NS_IMETHODIMP nsLocalFile::GetLastModifiedTimeOfLink(PRInt64 *aLastModifiedTimeOfLink)
959 NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
960 return NS_ERROR_NOT_IMPLEMENTED;
962 NS_IMETHODIMP nsLocalFile::SetLastModifiedTimeOfLink(PRInt64 aLastModifiedTimeOfLink)
964 NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
965 return NS_ERROR_NOT_IMPLEMENTED;
968 /* attribute PRInt64 fileSize; */
969 NS_IMETHODIMP nsLocalFile::GetFileSize(PRInt64 *aFileSize)
971 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
973 NS_ENSURE_ARG_POINTER(aFileSize);
977 nsresult rv = GetFSRefInternal(fsRef);
981 FSCatalogInfo catalogInfo;
982 OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags + kFSCatInfoDataSizes, &catalogInfo,
983 nsnull, nsnull, nsnull);
985 return MacErrorMapper(err);
987 // FSGetCatalogInfo can return a bogus size for directories sometimes, so only
988 // rely on the answer for files
989 if ((catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) == 0)
990 *aFileSize = catalogInfo.dataLogicalSize;
993 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
996 NS_IMETHODIMP nsLocalFile::SetFileSize(PRInt64 aFileSize)
998 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
1000 // Check we are correctly initialized.
1004 nsresult rv = GetFSRefInternal(fsRef);
1009 OSErr err = ::FSOpenFork(&fsRef, 0, nsnull, fsWrPerm, &refNum);
1011 return MacErrorMapper(err);
1012 err = ::FSSetForkSize(refNum, fsFromStart, aFileSize);
1013 ::FSCloseFork(refNum);
1015 return MacErrorMapper(err);
1017 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
1020 /* readonly attribute PRInt64 fileSizeOfLink; */
1021 NS_IMETHODIMP nsLocalFile::GetFileSizeOfLink(PRInt64 *aFileSizeOfLink)
1023 // Check we are correctly initialized.
1026 NS_ENSURE_ARG_POINTER(aFileSizeOfLink);
1028 StFollowLinksState followLinks(*this, PR_FALSE);
1029 return GetFileSize(aFileSizeOfLink);
1032 /* readonly attribute AString target; */
1033 NS_IMETHODIMP nsLocalFile::GetTarget(nsAString& aTarget)
1035 nsCAutoString nativeString;
1036 nsresult rv = GetNativeTarget(nativeString);
1039 CopyUTF8toUTF16NFC(nativeString, aTarget);
1043 /* [noscript] readonly attribute ACString nativeTarget; */
1044 NS_IMETHODIMP nsLocalFile::GetNativeTarget(nsACString& aNativeTarget)
1046 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
1049 return NS_ERROR_NOT_INITIALIZED;
1050 nsresult rv = NS_ERROR_FAILURE;
1051 CFStringRef pathStrRef = ::CFURLCopyFileSystemPath(mTargetRef, kCFURLPOSIXPathStyle);
1053 rv = CFStringReftoUTF8(pathStrRef, aNativeTarget);
1054 ::CFRelease(pathStrRef);
1058 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
1061 /* readonly attribute AString path; */
1062 NS_IMETHODIMP nsLocalFile::GetPath(nsAString& aPath)
1064 nsCAutoString nativeString;
1065 nsresult rv = GetNativePath(nativeString);
1068 CopyUTF8toUTF16NFC(nativeString, aPath);
1072 /* [noscript] readonly attribute ACString nativePath; */
1073 NS_IMETHODIMP nsLocalFile::GetNativePath(nsACString& aNativePath)
1075 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
1077 // Check we are correctly initialized.
1080 nsresult rv = NS_ERROR_FAILURE;
1081 CFStringRef pathStrRef = ::CFURLCopyFileSystemPath(mBaseRef, kCFURLPOSIXPathStyle);
1083 rv = CFStringReftoUTF8(pathStrRef, aNativePath);
1084 ::CFRelease(pathStrRef);
1088 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
1091 /* boolean exists (); */
1092 NS_IMETHODIMP nsLocalFile::Exists(PRBool *_retval)
1094 // Check we are correctly initialized.
1097 NS_ENSURE_ARG_POINTER(_retval);
1098 *_retval = PR_FALSE;
1101 if (NS_SUCCEEDED(GetFSRefInternal(fsRef, PR_TRUE))) {
1108 /* boolean isWritable (); */
1109 NS_IMETHODIMP nsLocalFile::IsWritable(PRBool *_retval)
1111 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
1113 // Check we are correctly initialized.
1116 NS_ENSURE_ARG_POINTER(_retval);
1117 *_retval = PR_FALSE;
1120 nsresult rv = GetFSRefInternal(fsRef);
1123 if (::FSCheckLock(&fsRef) == noErr) {
1124 PRUint32 permissions;
1125 rv = GetPermissions(&permissions);
1128 *_retval = ((permissions & S_IWUSR) != 0);
1132 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
1135 /* boolean isReadable (); */
1136 NS_IMETHODIMP nsLocalFile::IsReadable(PRBool *_retval)
1138 // Check we are correctly initialized.
1141 NS_ENSURE_ARG_POINTER(_retval);
1142 *_retval = PR_FALSE;
1144 PRUint32 permissions;
1145 nsresult rv = GetPermissions(&permissions);
1148 *_retval = ((permissions & S_IRUSR) != 0);
1152 /* boolean isExecutable (); */
1153 NS_IMETHODIMP nsLocalFile::IsExecutable(PRBool *_retval)
1155 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
1157 // Check we are correctly initialized.
1160 NS_ENSURE_ARG_POINTER(_retval);
1161 *_retval = PR_FALSE;
1164 nsresult rv = GetFSRefInternal(fsRef);
1168 LSRequestedInfo theInfoRequest = kLSRequestAllInfo;
1169 LSItemInfoRecord theInfo;
1170 if (::LSCopyItemInfoForRef(&fsRef, theInfoRequest, &theInfo) == noErr) {
1171 if ((theInfo.flags & kLSItemInfoIsApplication) != 0)
1176 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
1179 /* boolean isHidden (); */
1180 NS_IMETHODIMP nsLocalFile::IsHidden(PRBool *_retval)
1182 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
1184 NS_ENSURE_ARG_POINTER(_retval);
1185 *_retval = PR_FALSE;
1188 nsresult rv = GetFSRefInternal(fsRef);
1192 FSCatalogInfo catalogInfo;
1193 HFSUniStr255 leafName;
1194 OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoFinderInfo, &catalogInfo,
1195 &leafName, nsnull, nsnull);
1197 return MacErrorMapper(err);
1199 FileInfo *fInfoPtr = (FileInfo *)(catalogInfo.finderInfo); // Finder flags are in the same place whether we use FileInfo or FolderInfo
1200 if ((fInfoPtr->finderFlags & kIsInvisible) != 0) {
1204 // If the leaf name begins with a '.', consider it invisible
1205 if (leafName.length >= 1 && leafName.unicode[0] == UniChar('.'))
1210 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
1213 /* boolean isDirectory (); */
1214 NS_IMETHODIMP nsLocalFile::IsDirectory(PRBool *_retval)
1216 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
1218 NS_ENSURE_ARG_POINTER(_retval);
1219 *_retval = PR_FALSE;
1222 nsresult rv = GetFSRefInternal(fsRef, PR_FALSE);
1226 FSCatalogInfo catalogInfo;
1227 OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags, &catalogInfo,
1228 nsnull, nsnull, nsnull);
1230 return MacErrorMapper(err);
1231 *_retval = ((catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) != 0);
1234 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
1237 /* boolean isFile (); */
1238 NS_IMETHODIMP nsLocalFile::IsFile(PRBool *_retval)
1240 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
1242 NS_ENSURE_ARG_POINTER(_retval);
1243 *_retval = PR_FALSE;
1246 nsresult rv = GetFSRefInternal(fsRef, PR_FALSE);
1250 FSCatalogInfo catalogInfo;
1251 OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags, &catalogInfo,
1252 nsnull, nsnull, nsnull);
1254 return MacErrorMapper(err);
1255 *_retval = ((catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) == 0);
1258 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
1261 /* boolean isSymlink (); */
1262 NS_IMETHODIMP nsLocalFile::IsSymlink(PRBool *_retval)
1264 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
1266 // Check we are correctly initialized.
1269 NS_ENSURE_ARG(_retval);
1270 *_retval = PR_FALSE;
1272 // Check we are correctly initialized.
1276 if (::CFURLGetFSRef(mBaseRef, &fsRef)) {
1277 Boolean isAlias, isFolder;
1278 if (::FSIsAliasFile(&fsRef, &isAlias, &isFolder) == noErr)
1283 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
1286 /* boolean isSpecial (); */
1287 NS_IMETHODIMP nsLocalFile::IsSpecial(PRBool *_retval)
1289 NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
1290 return NS_ERROR_NOT_IMPLEMENTED;
1293 /* nsIFile clone (); */
1294 NS_IMETHODIMP nsLocalFile::Clone(nsIFile **_retval)
1296 // Just copy-construct ourselves
1297 *_retval = new nsLocalFile(*this);
1299 return NS_ERROR_OUT_OF_MEMORY;
1301 NS_ADDREF(*_retval);
1306 /* boolean equals (in nsIFile inFile); */
1307 NS_IMETHODIMP nsLocalFile::Equals(nsIFile *inFile, PRBool *_retval)
1309 return EqualsInternal(inFile, PR_TRUE, _retval);
1313 nsLocalFile::EqualsInternal(nsISupports* inFile, PRBool aUpdateCache,
1316 NS_ENSURE_ARG_POINTER(_retval);
1317 *_retval = PR_FALSE;
1319 nsCOMPtr<nsILocalFileMac> inMacFile(do_QueryInterface(inFile));
1324 static_cast<nsLocalFile*>((nsILocalFileMac*) inMacFile);
1326 // If both exist, compare FSRefs
1327 FSRef thisFSRef, inFSRef;
1328 nsresult rv1 = GetFSRefInternal(thisFSRef, aUpdateCache);
1329 nsresult rv2 = inLF->GetFSRefInternal(inFSRef, aUpdateCache);
1330 if (NS_SUCCEEDED(rv1) && NS_SUCCEEDED(rv2)) {
1331 *_retval = (thisFSRef == inFSRef);
1334 // If one exists and the other doesn't, not equal
1338 // Arg, we have to get their paths and compare
1339 nsCAutoString thisPath, inPath;
1340 if (NS_FAILED(GetNativePath(thisPath)))
1341 return NS_ERROR_FAILURE;
1342 if (NS_FAILED(inMacFile->GetNativePath(inPath)))
1343 return NS_ERROR_FAILURE;
1344 *_retval = thisPath.Equals(inPath);
1349 /* boolean contains (in nsIFile inFile, in boolean recur); */
1350 NS_IMETHODIMP nsLocalFile::Contains(nsIFile *inFile, PRBool recur, PRBool *_retval)
1352 // Check we are correctly initialized.
1355 NS_ENSURE_ARG_POINTER(_retval);
1356 *_retval = PR_FALSE;
1359 nsresult rv = IsDirectory(&isDir);
1363 return NS_OK; // must be a dir to contain someone
1365 nsCAutoString thisPath, inPath;
1366 if (NS_FAILED(GetNativePath(thisPath)) || NS_FAILED(inFile->GetNativePath(inPath)))
1367 return NS_ERROR_FAILURE;
1368 size_t thisPathLen = thisPath.Length();
1369 if ((inPath.Length() > thisPathLen + 1) && (strncasecmp(thisPath.get(), inPath.get(), thisPathLen) == 0)) {
1370 // Now make sure that the |inFile|'s path has a separator at thisPathLen,
1371 // and there's at least one more character after that.
1372 if (inPath[thisPathLen] == kPathSepChar)
1378 /* readonly attribute nsIFile parent; */
1379 NS_IMETHODIMP nsLocalFile::GetParent(nsIFile * *aParent)
1381 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
1383 NS_ENSURE_ARG_POINTER(aParent);
1386 // Check we are correctly initialized.
1389 nsLocalFile *newFile = nsnull;
1391 // If it can be determined without error that a file does not
1392 // have a parent, return nsnull for the parent and NS_OK as the result.
1394 nsresult rv = NS_OK;
1395 CFURLRef parentURLRef = ::CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, mBaseRef);
1397 // If the parent path is longer than file's path then
1398 // CFURLCreateCopyDeletingLastPathComponent must have simply added
1399 // two dots at the end - in this case indicate that there is no parent.
1401 CFStringRef path = ::CFURLGetString(mBaseRef);
1402 CFStringRef newPath = ::CFURLGetString(parentURLRef);
1403 if (::CFStringGetLength(newPath) < ::CFStringGetLength(path)) {
1404 rv = NS_ERROR_FAILURE;
1405 newFile = new nsLocalFile;
1407 rv = newFile->InitWithCFURL(parentURLRef);
1408 if (NS_SUCCEEDED(rv)) {
1409 NS_ADDREF(*aParent = newFile);
1414 ::CFRelease(parentURLRef);
1418 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
1421 /* readonly attribute nsISimpleEnumerator directoryEntries; */
1422 NS_IMETHODIMP nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator **aDirectoryEntries)
1424 NS_ENSURE_ARG_POINTER(aDirectoryEntries);
1425 *aDirectoryEntries = nsnull;
1429 rv = IsDirectory(&isDir);
1433 return NS_ERROR_FILE_NOT_DIRECTORY;
1435 nsDirEnumerator* dirEnum = new nsDirEnumerator;
1436 if (dirEnum == nsnull)
1437 return NS_ERROR_OUT_OF_MEMORY;
1439 rv = dirEnum->Init(this);
1440 if (NS_FAILED(rv)) {
1441 NS_RELEASE(dirEnum);
1444 *aDirectoryEntries = dirEnum;
1450 //*****************************************************************************
1451 // nsLocalFile::nsILocalFile
1452 //*****************************************************************************
1454 #pragma mark [nsILocalFile]
1456 /* void initWithPath (in AString filePath); */
1457 NS_IMETHODIMP nsLocalFile::InitWithPath(const nsAString& filePath)
1459 return InitWithNativePath(NS_ConvertUTF16toUTF8(filePath));
1462 /* [noscript] void initWithNativePath (in ACString filePath); */
1463 NS_IMETHODIMP nsLocalFile::InitWithNativePath(const nsACString& filePath)
1465 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
1467 nsCAutoString fixedPath;
1468 if (Substring(filePath, 0, 2).EqualsLiteral("~/")) {
1469 nsCOMPtr<nsIFile> homeDir;
1470 nsCAutoString homePath;
1471 nsresult rv = NS_GetSpecialDirectory(NS_OS_HOME_DIR,
1472 getter_AddRefs(homeDir));
1473 NS_ENSURE_SUCCESS(rv, rv);
1474 rv = homeDir->GetNativePath(homePath);
1475 NS_ENSURE_SUCCESS(rv, rv);
1477 fixedPath = homePath + Substring(filePath, 1, filePath.Length() - 1);
1479 else if (filePath.IsEmpty() || filePath.First() != '/')
1480 return NS_ERROR_FILE_UNRECOGNIZED_PATH;
1482 fixedPath.Assign(filePath);
1484 // A path with consecutive '/'s which are not between
1485 // nodes crashes CFURLGetFSRef(). Consecutive '/'s which
1486 // are between actual nodes are OK. So, convert consecutive
1487 // '/'s to a single one.
1488 fixedPath.ReplaceSubstring("//", "/");
1490 // On 10.2, huge paths also crash CFURLGetFSRef()
1491 if (fixedPath.Length() > PATH_MAX)
1492 return NS_ERROR_FILE_NAME_TOO_LONG;
1494 CFStringRef pathAsCFString;
1495 CFURLRef pathAsCFURL;
1497 pathAsCFString = ::CFStringCreateWithCString(nsnull, fixedPath.get(), kCFStringEncodingUTF8);
1498 if (!pathAsCFString)
1499 return NS_ERROR_FAILURE;
1500 pathAsCFURL = ::CFURLCreateWithFileSystemPath(nsnull, pathAsCFString, kCFURLPOSIXPathStyle, PR_FALSE);
1502 ::CFRelease(pathAsCFString);
1503 return NS_ERROR_FAILURE;
1505 SetBaseRef(pathAsCFURL);
1506 ::CFRelease(pathAsCFURL);
1507 ::CFRelease(pathAsCFString);
1510 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
1513 /* void initWithFile (in nsILocalFile aFile); */
1514 NS_IMETHODIMP nsLocalFile::InitWithFile(nsILocalFile *aFile)
1516 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
1518 NS_ENSURE_ARG(aFile);
1520 nsCOMPtr<nsILocalFileMac> aFileMac(do_QueryInterface(aFile));
1522 return NS_ERROR_UNEXPECTED;
1524 nsresult rv = aFileMac->GetCFURL(&urlRef);
1527 rv = InitWithCFURL(urlRef);
1528 ::CFRelease(urlRef);
1531 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
1534 /* attribute PRBool followLinks; */
1535 NS_IMETHODIMP nsLocalFile::GetFollowLinks(PRBool *aFollowLinks)
1537 NS_ENSURE_ARG_POINTER(aFollowLinks);
1539 *aFollowLinks = mFollowLinks;
1543 NS_IMETHODIMP nsLocalFile::SetFollowLinks(PRBool aFollowLinks)
1545 if (aFollowLinks != mFollowLinks) {
1546 mFollowLinks = aFollowLinks;
1552 /* [noscript] PRFileDescStar openNSPRFileDesc (in long flags, in long mode); */
1553 NS_IMETHODIMP nsLocalFile::OpenNSPRFileDesc(PRInt32 flags, PRInt32 mode, PRFileDesc **_retval)
1555 NS_ENSURE_ARG_POINTER(_retval);
1558 nsresult rv = GetPathInternal(path);
1562 *_retval = PR_Open(path.get(), flags, mode);
1564 return NS_ErrorAccordingToNSPR();
1569 /* [noscript] FILE openANSIFileDesc (in string mode); */
1570 NS_IMETHODIMP nsLocalFile::OpenANSIFileDesc(const char *mode, FILE **_retval)
1572 NS_ENSURE_ARG_POINTER(_retval);
1575 nsresult rv = GetPathInternal(path);
1579 *_retval = fopen(path.get(), mode);
1581 return NS_ERROR_FAILURE;
1586 /* [noscript] PRLibraryStar load (); */
1587 NS_IMETHODIMP nsLocalFile::Load(PRLibrary **_retval)
1589 // Check we are correctly initialized.
1592 NS_ENSURE_ARG_POINTER(_retval);
1594 NS_TIMELINE_START_TIMER("PR_LoadLibrary");
1597 nsresult rv = GetPathInternal(path);
1601 #ifdef NS_BUILD_REFCNT_LOGGING
1602 nsTraceRefcntImpl::SetActivityIsLegal(PR_FALSE);
1605 *_retval = PR_LoadLibrary(path.get());
1607 #ifdef NS_BUILD_REFCNT_LOGGING
1608 nsTraceRefcntImpl::SetActivityIsLegal(PR_TRUE);
1611 NS_TIMELINE_STOP_TIMER("PR_LoadLibrary");
1612 NS_TIMELINE_MARK_TIMER1("PR_LoadLibrary", path.get());
1615 return NS_ERROR_FAILURE;
1620 /* readonly attribute PRInt64 diskSpaceAvailable; */
1621 NS_IMETHODIMP nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable)
1623 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
1625 // Check we are correctly initialized.
1628 NS_ENSURE_ARG_POINTER(aDiskSpaceAvailable);
1631 nsresult rv = GetFSRefInternal(fsRef);
1636 FSCatalogInfo catalogInfo;
1637 err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoVolume, &catalogInfo,
1638 nsnull, nsnull, nsnull);
1640 return MacErrorMapper(err);
1642 FSVolumeInfo volumeInfo;
1643 err = ::FSGetVolumeInfo(catalogInfo.volume, 0, nsnull, kFSVolInfoSizes,
1644 &volumeInfo, nsnull, nsnull);
1646 return MacErrorMapper(err);
1648 *aDiskSpaceAvailable = volumeInfo.freeBytes;
1651 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
1654 /* void appendRelativePath (in AString relativeFilePath); */
1655 NS_IMETHODIMP nsLocalFile::AppendRelativePath(const nsAString& relativeFilePath)
1657 return AppendRelativeNativePath(NS_ConvertUTF16toUTF8(relativeFilePath));
1660 /* [noscript] void appendRelativeNativePath (in ACString relativeFilePath); */
1661 NS_IMETHODIMP nsLocalFile::AppendRelativeNativePath(const nsACString& relativeFilePath)
1663 if (relativeFilePath.IsEmpty())
1666 if (relativeFilePath.First() == '/')
1667 return NS_ERROR_FILE_UNRECOGNIZED_PATH;
1669 // Parse the nodes and call Append() for each
1670 nsACString::const_iterator nodeBegin, pathEnd;
1671 relativeFilePath.BeginReading(nodeBegin);
1672 relativeFilePath.EndReading(pathEnd);
1673 nsACString::const_iterator nodeEnd(nodeBegin);
1675 while (nodeEnd != pathEnd) {
1676 FindCharInReadable(kPathSepChar, nodeEnd, pathEnd);
1677 nsresult rv = AppendNative(Substring(nodeBegin, nodeEnd));
1680 if (nodeEnd != pathEnd) // If there's more left in the string, inc over the '/' nodeEnd is on.
1682 nodeBegin = nodeEnd;
1687 /* attribute ACString persistentDescriptor; */
1688 NS_IMETHODIMP nsLocalFile::GetPersistentDescriptor(nsACString& aPersistentDescriptor)
1690 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
1693 nsresult rv = GetFSRefInternal(fsRef);
1698 OSErr err = ::FSNewAlias(nsnull, &fsRef, &aliasH);
1700 return MacErrorMapper(err);
1702 PRUint32 bytes = ::GetHandleSize((Handle) aliasH);
1703 ::HLock((Handle) aliasH);
1704 // Passing nsnull for dest makes NULL-term string
1705 char* buf = PL_Base64Encode((const char*)*aliasH, bytes, nsnull);
1706 ::DisposeHandle((Handle) aliasH);
1707 NS_ENSURE_TRUE(buf, NS_ERROR_OUT_OF_MEMORY);
1709 aPersistentDescriptor = buf;
1714 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
1717 NS_IMETHODIMP nsLocalFile::SetPersistentDescriptor(const nsACString& aPersistentDescriptor)
1719 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
1721 if (aPersistentDescriptor.IsEmpty())
1722 return NS_ERROR_INVALID_ARG;
1724 // Support pathnames as user-supplied descriptors if they begin with '/'
1725 // or '~'. These characters do not collide with the base64 set used for
1726 // encoding alias records.
1727 char first = aPersistentDescriptor.First();
1728 if (first == '/' || first == '~')
1729 return InitWithNativePath(aPersistentDescriptor);
1731 nsresult rv = NS_OK;
1733 PRUint32 dataSize = aPersistentDescriptor.Length();
1734 char* decodedData = PL_Base64Decode(PromiseFlatCString(aPersistentDescriptor).get(), dataSize, nsnull);
1736 NS_ERROR("SetPersistentDescriptor was given bad data");
1737 return NS_ERROR_FAILURE;
1740 // Cast to an alias record and resolve.
1741 AliasRecord aliasHeader = *(AliasPtr)decodedData;
1742 PRInt32 aliasSize = GetAliasSizeFromRecord(aliasHeader);
1743 if (aliasSize > ((PRInt32)dataSize * 3) / 4) { // be paranoid about having too few data
1744 PR_Free(decodedData);
1745 return NS_ERROR_FAILURE;
1748 // Move the now-decoded data into the Handle.
1749 // The size of the decoded data is 3/4 the size of the encoded data. See plbase64.h
1750 Handle newHandle = nsnull;
1751 if (::PtrToHand(decodedData, &newHandle, aliasSize) != noErr)
1752 rv = NS_ERROR_OUT_OF_MEMORY;
1753 PR_Free(decodedData);
1758 FSRef resolvedFSRef;
1759 OSErr err = ::FSResolveAlias(nsnull, (AliasHandle)newHandle, &resolvedFSRef, &changed);
1761 rv = MacErrorMapper(err);
1762 DisposeHandle(newHandle);
1766 return InitWithFSRef(&resolvedFSRef);
1768 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
1771 /* void reveal (); */
1772 NS_IMETHODIMP nsLocalFile::Reveal()
1774 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
1776 FSRef fsRefToReveal;
1777 AppleEvent aeEvent = {0, nil};
1778 AppleEvent aeReply = {0, nil};
1779 StAEDesc aeDirDesc, listElem, myAddressDesc, fileList;
1781 ProcessSerialNumber process;
1783 nsresult rv = GetFSRefInternal(fsRefToReveal);
1787 err = ::FindRunningAppBySignature ('MACS', process);
1789 err = ::AECreateDesc(typeProcessSerialNumber, (Ptr)&process, sizeof(process), &myAddressDesc);
1791 // Create the FinderEvent
1792 err = ::AECreateAppleEvent(kAEMiscStandards, kAEMakeObjectsVisible, &myAddressDesc,
1793 kAutoGenerateReturnID, kAnyTransactionID, &aeEvent);
1795 // Create the file list
1796 err = ::AECreateList(nil, 0, false, &fileList);
1798 FSSpec fsSpecToReveal;
1799 err = ::FSRefMakeFSSpec(&fsRefToReveal, &fsSpecToReveal);
1801 err = ::AEPutPtr(&fileList, 0, typeFSS, &fsSpecToReveal, sizeof(FSSpec));
1803 err = ::AEPutParamDesc(&aeEvent, keyDirectObject, &fileList);
1805 err = ::AESend(&aeEvent, &aeReply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, nil, nil);
1807 ::SetFrontProcess(&process);
1818 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
1821 /* void launch (); */
1822 NS_IMETHODIMP nsLocalFile::Launch()
1824 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
1827 nsresult rv = GetFSRefInternal(fsRef);
1831 OSErr err = ::LSOpenFSRef(&fsRef, NULL);
1832 return MacErrorMapper(err);
1834 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
1838 //*****************************************************************************
1839 // nsLocalFile::nsILocalFileMac
1840 //*****************************************************************************
1842 #pragma mark [nsILocalFileMac]
1844 /* void initWithCFURL (in CFURLRef aCFURL); */
1845 NS_IMETHODIMP nsLocalFile::InitWithCFURL(CFURLRef aCFURL)
1847 NS_ENSURE_ARG(aCFURL);
1853 /* void initWithFSRef ([const] in FSRefPtr aFSRef); */
1854 NS_IMETHODIMP nsLocalFile::InitWithFSRef(const FSRef *aFSRef)
1856 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
1858 NS_ENSURE_ARG(aFSRef);
1859 nsresult rv = NS_ERROR_FAILURE;
1861 CFURLRef newURLRef = ::CFURLCreateFromFSRef(kCFAllocatorDefault, aFSRef);
1863 SetBaseRef(newURLRef);
1864 ::CFRelease(newURLRef);
1869 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
1872 /* void initWithFSSpec ([const] in FSSpecPtr aFileSpec); */
1873 NS_IMETHODIMP nsLocalFile::InitWithFSSpec(const FSSpec *aFileSpec)
1875 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
1877 NS_ENSURE_ARG(aFileSpec);
1880 OSErr err = ::FSpMakeFSRef(aFileSpec, &fsRef);
1882 return InitWithFSRef(&fsRef);
1883 else if (err == fnfErr) {
1885 FSSpec parentDirSpec;
1887 memset(&pBlock, 0, sizeof(CInfoPBRec));
1888 parentDirSpec.name[0] = 0;
1889 pBlock.dirInfo.ioVRefNum = aFileSpec->vRefNum;
1890 pBlock.dirInfo.ioDrDirID = aFileSpec->parID;
1891 pBlock.dirInfo.ioNamePtr = (StringPtr)parentDirSpec.name;
1892 pBlock.dirInfo.ioFDirIndex = -1; //get info on parID
1893 err = ::PBGetCatInfoSync(&pBlock);
1895 return MacErrorMapper(err);
1897 parentDirSpec.vRefNum = aFileSpec->vRefNum;
1898 parentDirSpec.parID = pBlock.dirInfo.ioDrParID;
1899 err = ::FSpMakeFSRef(&parentDirSpec, &fsRef);
1901 return MacErrorMapper(err);
1902 HFSUniStr255 unicodeName;
1903 err = ::HFSNameGetUnicodeName(aFileSpec->name, kTextEncodingUnknown, &unicodeName);
1905 return MacErrorMapper(err);
1906 nsresult rv = InitWithFSRef(&fsRef);
1909 return Append(nsDependentString(unicodeName.unicode, unicodeName.length));
1911 return MacErrorMapper(err);
1913 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
1916 /* void initToAppWithCreatorCode (in OSType aAppCreator); */
1917 NS_IMETHODIMP nsLocalFile::InitToAppWithCreatorCode(OSType aAppCreator)
1919 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
1922 OSErr err = ::LSFindApplicationForInfo(aAppCreator, nsnull, nsnull, &fsRef, nsnull);
1924 return MacErrorMapper(err);
1925 return InitWithFSRef(&fsRef);
1927 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
1930 /* CFURLRef getCFURL (); */
1931 NS_IMETHODIMP nsLocalFile::GetCFURL(CFURLRef *_retval)
1933 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
1935 NS_ENSURE_ARG_POINTER(_retval);
1936 CFURLRef whichURLRef = mFollowLinks ? mTargetRef : mBaseRef;
1938 ::CFRetain(whichURLRef);
1939 *_retval = whichURLRef;
1940 return whichURLRef ? NS_OK : NS_ERROR_FAILURE;
1942 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
1945 /* FSRef getFSRef (); */
1946 NS_IMETHODIMP nsLocalFile::GetFSRef(FSRef *_retval)
1948 NS_ENSURE_ARG_POINTER(_retval);
1949 return GetFSRefInternal(*_retval);
1952 /* FSSpec getFSSpec (); */
1953 NS_IMETHODIMP nsLocalFile::GetFSSpec(FSSpec *_retval)
1955 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
1957 NS_ENSURE_ARG_POINTER(_retval);
1959 // Check we are correctly initialized.
1964 nsresult rv = GetFSRefInternal(fsRef);
1965 if (NS_SUCCEEDED(rv)) {
1966 // If the leaf node exists, things are simple.
1967 err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNone,
1968 nsnull, nsnull, _retval, nsnull);
1969 return MacErrorMapper(err);
1971 else if (rv == NS_ERROR_FILE_NOT_FOUND) {
1972 // If the parent of the leaf exists, make an FSSpec from that.
1973 CFURLRef parentURLRef = ::CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, mBaseRef);
1975 return NS_ERROR_FAILURE;
1978 if (::CFURLGetFSRef(parentURLRef, &fsRef)) {
1979 FSCatalogInfo catalogInfo;
1980 if ((err = ::FSGetCatalogInfo(&fsRef,
1981 kFSCatInfoVolume + kFSCatInfoNodeID + kFSCatInfoTextEncoding,
1982 &catalogInfo, nsnull, nsnull, nsnull)) == noErr) {
1983 nsAutoString leafName;
1984 if (NS_SUCCEEDED(GetLeafName(leafName))) {
1986 if ((err = ::UnicodeNameGetHFSName(leafName.Length(),
1988 catalogInfo.textEncodingHint,
1989 catalogInfo.nodeID == fsRtDirID,
1991 err = ::FSMakeFSSpec(catalogInfo.volume, catalogInfo.nodeID, hfsName, _retval);
1995 ::CFRelease(parentURLRef);
1996 rv = MacErrorMapper(err);
2000 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
2003 /* readonly attribute PRInt64 fileSizeWithResFork; */
2004 NS_IMETHODIMP nsLocalFile::GetFileSizeWithResFork(PRInt64 *aFileSizeWithResFork)
2006 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
2008 NS_ENSURE_ARG_POINTER(aFileSizeWithResFork);
2011 nsresult rv = GetFSRefInternal(fsRef);
2015 FSCatalogInfo catalogInfo;
2016 OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoDataSizes + kFSCatInfoRsrcSizes,
2017 &catalogInfo, nsnull, nsnull, nsnull);
2019 return MacErrorMapper(err);
2021 *aFileSizeWithResFork = catalogInfo.dataLogicalSize + catalogInfo.rsrcLogicalSize;
2024 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
2027 /* attribute OSType fileType; */
2028 NS_IMETHODIMP nsLocalFile::GetFileType(OSType *aFileType)
2030 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
2032 NS_ENSURE_ARG_POINTER(aFileType);
2035 nsresult rv = GetFSRefInternal(fsRef);
2040 OSErr err = ::FSGetFinderInfo(&fsRef, &fInfo, nsnull, nsnull);
2042 return MacErrorMapper(err);
2043 *aFileType = fInfo.file.fileType;
2046 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
2049 NS_IMETHODIMP nsLocalFile::SetFileType(OSType aFileType)
2051 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
2054 nsresult rv = GetFSRefInternal(fsRef);
2058 OSErr err = ::FSChangeCreatorType(&fsRef, 0, aFileType);
2059 return MacErrorMapper(err);
2061 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
2064 /* attribute OSType fileCreator; */
2065 NS_IMETHODIMP nsLocalFile::GetFileCreator(OSType *aFileCreator)
2067 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
2069 NS_ENSURE_ARG_POINTER(aFileCreator);
2072 nsresult rv = GetFSRefInternal(fsRef);
2077 OSErr err = ::FSGetFinderInfo(&fsRef, &fInfo, nsnull, nsnull);
2079 return MacErrorMapper(err);
2080 *aFileCreator = fInfo.file.fileCreator;
2083 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
2086 NS_IMETHODIMP nsLocalFile::SetFileCreator(OSType aFileCreator)
2088 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
2091 nsresult rv = GetFSRefInternal(fsRef);
2095 OSErr err = ::FSChangeCreatorType(&fsRef, aFileCreator, 0);
2096 return MacErrorMapper(err);
2098 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
2101 /* void setFileTypeAndCreatorFromMIMEType (in string aMIMEType); */
2102 NS_IMETHODIMP nsLocalFile::SetFileTypeAndCreatorFromMIMEType(const char *aMIMEType)
2104 // XXX - This should be cut from the API. Would create an evil dependency.
2105 NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
2106 return NS_ERROR_NOT_IMPLEMENTED;
2109 /* void setFileTypeAndCreatorFromExtension (in string aExtension); */
2110 NS_IMETHODIMP nsLocalFile::SetFileTypeAndCreatorFromExtension(const char *aExtension)
2112 // XXX - This should be cut from the API. Would create an evil dependency.
2113 NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
2114 return NS_ERROR_NOT_IMPLEMENTED;
2117 /* void launchWithDoc (in nsILocalFile aDocToLoad, in boolean aLaunchInBackground); */
2118 NS_IMETHODIMP nsLocalFile::LaunchWithDoc(nsILocalFile *aDocToLoad, PRBool aLaunchInBackground)
2120 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
2122 PRBool isExecutable;
2123 nsresult rv = IsExecutable(&isExecutable);
2127 return NS_ERROR_FILE_EXECUTION_FAILED;
2129 FSRef appFSRef, docFSRef;
2130 rv = GetFSRefInternal(appFSRef);
2135 nsCOMPtr<nsILocalFileMac> macDoc = do_QueryInterface(aDocToLoad);
2136 rv = macDoc->GetFSRef(&docFSRef);
2141 LSLaunchFlags theLaunchFlags = kLSLaunchDefaults;
2142 LSLaunchFSRefSpec thelaunchSpec;
2144 if (aLaunchInBackground)
2145 theLaunchFlags |= kLSLaunchDontSwitch;
2146 memset(&thelaunchSpec, 0, sizeof(LSLaunchFSRefSpec));
2148 thelaunchSpec.appRef = &appFSRef;
2150 thelaunchSpec.numDocs = 1;
2151 thelaunchSpec.itemRefs = &docFSRef;
2153 thelaunchSpec.launchFlags = theLaunchFlags;
2155 OSErr err = ::LSOpenFromRefSpec(&thelaunchSpec, NULL);
2157 return MacErrorMapper(err);
2161 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
2164 /* void openDocWithApp (in nsILocalFile aAppToOpenWith, in boolean aLaunchInBackground); */
2165 NS_IMETHODIMP nsLocalFile::OpenDocWithApp(nsILocalFile *aAppToOpenWith, PRBool aLaunchInBackground)
2167 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
2172 FSRef docFSRef, appFSRef;
2173 rv = GetFSRefInternal(docFSRef);
2177 if (aAppToOpenWith) {
2178 nsCOMPtr<nsILocalFileMac> appFileMac = do_QueryInterface(aAppToOpenWith, &rv);
2182 PRBool isExecutable;
2183 rv = appFileMac->IsExecutable(&isExecutable);
2187 return NS_ERROR_FILE_EXECUTION_FAILED;
2189 rv = appFileMac->GetFSRef(&appFSRef);
2195 rv = GetFileCreator(&fileCreator);
2199 err = ::LSFindApplicationForInfo(fileCreator, nsnull, nsnull, &appFSRef, nsnull);
2201 return MacErrorMapper(err);
2204 LSLaunchFlags theLaunchFlags = kLSLaunchDefaults;
2205 LSLaunchFSRefSpec thelaunchSpec;
2207 if (aLaunchInBackground)
2208 theLaunchFlags |= kLSLaunchDontSwitch;
2209 memset(&thelaunchSpec, 0, sizeof(LSLaunchFSRefSpec));
2211 thelaunchSpec.appRef = &appFSRef;
2212 thelaunchSpec.numDocs = 1;
2213 thelaunchSpec.itemRefs = &docFSRef;
2214 thelaunchSpec.launchFlags = theLaunchFlags;
2216 err = ::LSOpenFromRefSpec(&thelaunchSpec, NULL);
2218 return MacErrorMapper(err);
2222 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
2225 /* boolean isPackage (); */
2226 NS_IMETHODIMP nsLocalFile::IsPackage(PRBool *_retval)
2228 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
2230 NS_ENSURE_ARG(_retval);
2231 *_retval = PR_FALSE;
2234 nsresult rv = GetFSRefInternal(fsRef);
2238 FSCatalogInfo catalogInfo;
2239 OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags + kFSCatInfoFinderInfo,
2240 &catalogInfo, nsnull, nsnull, nsnull);
2242 return MacErrorMapper(err);
2243 if ((catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) != 0) {
2244 FileInfo *fInfoPtr = (FileInfo *)(catalogInfo.finderInfo);
2245 if ((fInfoPtr->finderFlags & kHasBundle) != 0) {
2249 // Folders ending with ".app" are also considered to
2250 // be packages, even if the top-level folder doesn't have bundle set
2252 if (NS_SUCCEEDED(rv = GetNativeLeafName(name))) {
2253 const char *extPtr = strrchr(name.get(), '.');
2255 if ((nsCRT::strcasecmp(extPtr, ".app") == 0))
2263 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
2267 nsLocalFile::GetBundleDisplayName(nsAString& outBundleName)
2269 PRBool isPackage = PR_FALSE;
2270 nsresult rv = IsPackage(&isPackage);
2271 if (NS_FAILED(rv) || !isPackage)
2272 return NS_ERROR_FAILURE;
2275 rv = GetLeafName(name);
2279 PRInt32 length = name.Length();
2280 if (Substring(name, length - 4, length).EqualsLiteral(".app")) {
2281 // 4 characters in ".app"
2282 outBundleName = Substring(name, 0, length - 4);
2285 outBundleName = name;
2291 nsLocalFile::GetBundleIdentifier(nsACString& outBundleIdentifier)
2293 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
2295 nsresult rv = NS_ERROR_FAILURE;
2298 if (NS_SUCCEEDED(GetCFURL(&urlRef))) {
2299 CFBundleRef bundle = ::CFBundleCreate(NULL, urlRef);
2301 CFStringRef bundleIdentifier = ::CFBundleGetIdentifier(bundle);
2302 if (bundleIdentifier)
2303 rv = CFStringReftoUTF8(bundleIdentifier, outBundleIdentifier);
2305 ::CFRelease(bundle);
2307 ::CFRelease(urlRef);
2312 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
2316 //*****************************************************************************
2317 // nsLocalFile Methods
2318 //*****************************************************************************
2320 #pragma mark [Protected Methods]
2322 nsresult nsLocalFile::SetBaseRef(CFURLRef aCFURLRef)
2324 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
2326 NS_ENSURE_ARG(aCFURLRef);
2328 ::CFRetain(aCFURLRef);
2330 ::CFRelease(mBaseRef);
2331 mBaseRef = aCFURLRef;
2333 mFollowLinksDirty = PR_TRUE;
2335 mCachedFSRefValid = PR_FALSE;
2338 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
2341 nsresult nsLocalFile::UpdateTargetRef()
2343 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
2345 // Check we are correctly initialized.
2348 if (mFollowLinksDirty) {
2350 ::CFRelease(mTargetRef);
2351 mTargetRef = nsnull;
2354 mTargetRef = mBaseRef;
2355 ::CFRetain(mTargetRef);
2358 if (::CFURLGetFSRef(mBaseRef, &fsRef)) {
2359 Boolean targetIsFolder, wasAliased;
2360 if (FSResolveAliasFile(&fsRef, true /*resolveAliasChains*/,
2361 &targetIsFolder, &wasAliased) == noErr && wasAliased) {
2362 ::CFRelease(mTargetRef);
2363 mTargetRef = CFURLCreateFromFSRef(NULL, &fsRef);
2365 return NS_ERROR_FAILURE;
2368 mFollowLinksDirty = PR_FALSE;
2373 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
2376 nsresult nsLocalFile::GetFSRefInternal(FSRef& aFSRef, PRBool bForceUpdateCache)
2378 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
2380 if (bForceUpdateCache || !mCachedFSRefValid) {
2381 mCachedFSRefValid = PR_FALSE;
2382 CFURLRef whichURLRef = mFollowLinks ? mTargetRef : mBaseRef;
2383 NS_ENSURE_TRUE(whichURLRef, NS_ERROR_NULL_POINTER);
2384 if (::CFURLGetFSRef(whichURLRef, &mCachedFSRef))
2385 mCachedFSRefValid = PR_TRUE;
2387 if (mCachedFSRefValid) {
2388 aFSRef = mCachedFSRef;
2391 // CFURLGetFSRef only returns a Boolean for success,
2392 // so we have to assume what the error was. This is
2393 // the only probable cause.
2394 return NS_ERROR_FILE_NOT_FOUND;
2396 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
2399 nsresult nsLocalFile::GetPathInternal(nsACString& path)
2401 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
2403 nsresult rv = NS_ERROR_FAILURE;
2405 CFURLRef whichURLRef = mFollowLinks ? mTargetRef : mBaseRef;
2406 NS_ENSURE_TRUE(whichURLRef, NS_ERROR_NULL_POINTER);
2408 CFStringRef pathStrRef = ::CFURLCopyFileSystemPath(whichURLRef, kCFURLPOSIXPathStyle);
2410 rv = CFStringReftoUTF8(pathStrRef, path);
2411 ::CFRelease(pathStrRef);
2415 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
2418 nsresult nsLocalFile::CopyInternal(nsIFile* aParentDir,
2419 const nsAString& newName,
2422 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
2424 // Check we are correctly initialized.
2427 StFollowLinksState srcFollowState(*this, followLinks);
2431 FSRef srcFSRef, newFSRef;
2433 rv = GetFSRefInternal(srcFSRef);
2437 nsCOMPtr<nsIFile> newParentDir = aParentDir;
2439 if (!newParentDir) {
2440 if (newName.IsEmpty())
2441 return NS_ERROR_INVALID_ARG;
2442 rv = GetParent(getter_AddRefs(newParentDir));
2447 // If newParentDir does not exist, create it
2449 rv = newParentDir->Exists(&exists);
2453 rv = newParentDir->Create(nsIFile::DIRECTORY_TYPE, 0777);
2459 nsCOMPtr<nsILocalFileMac> newParentDirMac(do_QueryInterface(newParentDir));
2460 if (!newParentDirMac)
2461 return NS_ERROR_NO_INTERFACE;
2462 rv = newParentDirMac->GetFSRef(&destFSRef);
2467 ::FSCopyObject(&srcFSRef, &destFSRef, newName.Length(),
2468 newName.Length() ? PromiseFlatString(newName).get() : NULL,
2469 0, kFSCatInfoNone, false, false, NULL, NULL, &newFSRef);
2471 return MacErrorMapper(err);
2473 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
2476 const PRInt64 kMillisecsPerSec = 1000LL;
2477 const PRInt64 kUTCDateTimeFractionDivisor = 65535LL;
2479 PRInt64 nsLocalFile::HFSPlustoNSPRTime(const UTCDateTime& utcTime)
2481 // Start with seconds since Jan. 1, 1904 GMT
2482 PRInt64 result = ((PRInt64)utcTime.highSeconds << 32) + (PRInt64)utcTime.lowSeconds;
2483 // Subtract to convert to NSPR epoch of 1970
2484 result -= kJanuaryFirst1970Seconds;
2485 // Convert to millisecs
2486 result *= kMillisecsPerSec;
2487 // Convert the fraction to millisecs and add it
2488 result += ((PRInt64)utcTime.fraction * kMillisecsPerSec) / kUTCDateTimeFractionDivisor;
2493 void nsLocalFile::NSPRtoHFSPlusTime(PRInt64 nsprTime, UTCDateTime& utcTime)
2495 PRInt64 fraction = nsprTime % kMillisecsPerSec;
2496 PRInt64 seconds = (nsprTime / kMillisecsPerSec) + kJanuaryFirst1970Seconds;
2497 utcTime.highSeconds = (UInt16)((PRUint64)seconds >> 32);
2498 utcTime.lowSeconds = (UInt32)seconds;
2499 utcTime.fraction = (UInt16)((fraction * kUTCDateTimeFractionDivisor) / kMillisecsPerSec);
2502 nsresult nsLocalFile::CFStringReftoUTF8(CFStringRef aInStrRef, nsACString& aOutStr)
2504 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
2506 nsresult rv = NS_ERROR_FAILURE;
2507 CFIndex usedBufLen, inStrLen = ::CFStringGetLength(aInStrRef);
2508 CFIndex charsConverted = ::CFStringGetBytes(aInStrRef, CFRangeMake(0, inStrLen),
2509 kCFStringEncodingUTF8, 0, PR_FALSE, nsnull, 0, &usedBufLen);
2510 if (charsConverted == inStrLen) {
2511 aOutStr.SetLength(usedBufLen);
2512 if (aOutStr.Length() != (unsigned int)usedBufLen)
2513 return NS_ERROR_OUT_OF_MEMORY;
2514 UInt8 *buffer = (UInt8*) aOutStr.BeginWriting();
2516 ::CFStringGetBytes(aInStrRef, CFRangeMake(0, inStrLen),
2517 kCFStringEncodingUTF8, 0, false, buffer, usedBufLen, &usedBufLen);
2522 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
2528 nsLocalFile::Equals(nsIHashable* aOther, PRBool *aResult)
2530 return EqualsInternal(aOther, PR_FALSE, aResult);
2534 nsLocalFile::GetHashCode(PRUint32 *aResult)
2536 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
2538 CFStringRef pathStrRef = ::CFURLCopyFileSystemPath(mBaseRef, kCFURLPOSIXPathStyle);
2540 CFStringReftoUTF8(pathStrRef, path);
2541 ::CFRelease(pathStrRef);
2542 *aResult = HashString(path);
2545 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
2548 //*****************************************************************************
2550 //*****************************************************************************
2552 #pragma mark [Global Functions]
2554 void nsLocalFile::GlobalInit()
2558 void nsLocalFile::GlobalShutdown()
2562 nsresult NS_NewLocalFile(const nsAString& path, PRBool followLinks, nsILocalFile* *result)
2564 nsLocalFile* file = new nsLocalFile;
2566 return NS_ERROR_OUT_OF_MEMORY;
2569 file->SetFollowLinks(followLinks);
2571 if (!path.IsEmpty()) {
2572 nsresult rv = file->InitWithPath(path);
2573 if (NS_FAILED(rv)) {
2582 nsresult NS_NewNativeLocalFile(const nsACString& path, PRBool followLinks, nsILocalFile **result)
2584 return NS_NewLocalFile(NS_ConvertUTF8toUTF16(path), followLinks, result);
2587 nsresult NS_NewLocalFileWithFSSpec(const FSSpec* inSpec, PRBool followLinks, nsILocalFileMac **result)
2589 nsLocalFile* file = new nsLocalFile();
2591 return NS_ERROR_OUT_OF_MEMORY;
2594 file->SetFollowLinks(followLinks);
2596 nsresult rv = file->InitWithFSSpec(inSpec);
2597 if (NS_FAILED(rv)) {
2605 nsresult NS_NewLocalFileWithFSRef(const FSRef* aFSRef, PRBool aFollowLinks, nsILocalFileMac** result)
2607 nsLocalFile* file = new nsLocalFile();
2609 return NS_ERROR_OUT_OF_MEMORY;
2612 file->SetFollowLinks(aFollowLinks);
2614 nsresult rv = file->InitWithFSRef(aFSRef);
2615 if (NS_FAILED(rv)) {
2623 //*****************************************************************************
2625 //*****************************************************************************
2627 static nsresult MacErrorMapper(OSErr inErr)
2638 case afpObjectNotFound:
2639 case afpDirNotFound:
2640 outErr = NS_ERROR_FILE_NOT_FOUND;
2644 case afpObjectExists:
2645 outErr = NS_ERROR_FILE_ALREADY_EXISTS;
2650 outErr = NS_ERROR_FILE_DISK_FULL;
2655 outErr = NS_ERROR_FILE_IS_LOCKED;
2658 case afpAccessDenied:
2659 outErr = NS_ERROR_FILE_ACCESS_DENIED;
2662 case afpDirNotEmpty:
2663 outErr = NS_ERROR_FILE_DIR_NOT_EMPTY;
2666 // Can't find good map for some
2668 outErr = NS_ERROR_FAILURE;
2672 outErr = NS_ERROR_FAILURE;
2678 static OSErr FindRunningAppBySignature(OSType aAppSig, ProcessSerialNumber& outPsn)
2680 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
2682 ProcessInfoRec info;
2685 outPsn.highLongOfPSN = 0;
2686 outPsn.lowLongOfPSN = kNoProcess;
2690 err = ::GetNextProcess(&outPsn);
2691 if (err == procNotFound)
2695 info.processInfoLength = sizeof(ProcessInfoRec);
2696 info.processName = nil;
2697 info.processAppSpec = nil;
2698 err = ::GetProcessInformation(&outPsn, &info);
2702 if (info.processSignature == aAppSig)
2705 return procNotFound;
2707 NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(procNotFound);
2710 // Convert a UTF-8 string to a UTF-16 string while normalizing to
2711 // Normalization Form C (composed Unicode). We need this because
2712 // Mac OS X file system uses NFD (Normalization Form D : decomposed Unicode)
2713 // while most other OS', server-side programs usually expect NFC.
2715 typedef void (*UnicodeNormalizer) (CFMutableStringRef, CFStringNormalizationForm);
2716 static void CopyUTF8toUTF16NFC(const nsACString& aSrc, nsAString& aResult)
2718 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
2720 static PRBool sChecked = PR_FALSE;
2721 static UnicodeNormalizer sUnicodeNormalizer = NULL;
2723 // CFStringNormalize was not introduced until Mac OS 10.2
2725 CFBundleRef carbonBundle =
2726 CFBundleGetBundleWithIdentifier(CFSTR("com.apple.Carbon"));
2728 sUnicodeNormalizer = (UnicodeNormalizer)
2729 ::CFBundleGetFunctionPointerForName(carbonBundle,
2730 CFSTR("CFStringNormalize"));
2734 if (!sUnicodeNormalizer) { // OS X 10.2 or earlier
2735 CopyUTF8toUTF16(aSrc, aResult);
2739 const nsAFlatCString &inFlatSrc = PromiseFlatCString(aSrc);
2741 // The number of 16bit code units in a UTF-16 string will never be
2742 // larger than the number of bytes in the corresponding UTF-8 string.
2743 CFMutableStringRef inStr =
2744 ::CFStringCreateMutable(NULL, inFlatSrc.Length());
2747 CopyUTF8toUTF16(aSrc, aResult);
2751 ::CFStringAppendCString(inStr, inFlatSrc.get(), kCFStringEncodingUTF8);
2753 sUnicodeNormalizer(inStr, kCFStringNormalizationFormC);
2755 CFIndex length = CFStringGetLength(inStr);
2756 const UniChar* chars = CFStringGetCharactersPtr(inStr);
2759 aResult.Assign(chars, length);
2761 nsAutoTArray<UniChar, FILENAME_BUFFER_SIZE> buffer;
2762 if (!buffer.SetLength(length))
2763 CopyUTF8toUTF16(aSrc, aResult);
2765 CFStringGetCharacters(inStr, CFRangeMake(0, length), buffer.Elements());
2766 aResult.Assign(buffer.Elements(), length);
2771 NS_OBJC_END_TRY_ABORT_BLOCK;