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"
46
#include "nsReadableUtils.h"
47
#include "nsIDirectoryEnumerator.h"
48
#include "nsISimpleEnumerator.h"
49
#include "nsITimelineService.h"
50
#include "nsVoidArray.h"
55
#include "nsHashKeys.h"
57
#include "MoreFilesX.h"
58
#include "FSCopyObject.h"
59
#include "nsAutoBuffer.h"
60
#include "nsTraceRefcntImpl.h"
63
#include <Carbon/Carbon.h>
70
#if !defined(MAC_OS_X_VERSION_10_4) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_4
71
#define GetAliasSizeFromRecord(aliasRecord) aliasRecord.aliasSize
73
#define GetAliasSizeFromRecord(aliasRecord) GetAliasSizeFromPtr(&aliasRecord)
76
#define CHECK_mBaseRef() \
79
return NS_ERROR_NOT_INITIALIZED; \
82
//*****************************************************************************
83
// Static Function Prototypes
84
//*****************************************************************************
86
static nsresult MacErrorMapper(OSErr inErr);
87
static OSErr FindRunningAppBySignature(OSType aAppSig, ProcessSerialNumber& outPsn);
88
static void CopyUTF8toUTF16NFC(const nsACString& aSrc, nsAString& aResult);
90
//*****************************************************************************
91
// Local Helper Classes
92
//*****************************************************************************
95
#pragma mark [FSRef operator==]
97
bool operator==(const FSRef& lhs, const FSRef& rhs)
99
return (::FSCompareFSRefs(&lhs, &rhs) == noErr);
103
#pragma mark [StFollowLinksState]
105
class StFollowLinksState
108
StFollowLinksState(nsLocalFile& aFile) :
111
mFile.GetFollowLinks(&mSavedState);
114
StFollowLinksState(nsLocalFile& aFile, PRBool followLinksState) :
117
mFile.GetFollowLinks(&mSavedState);
118
mFile.SetFollowLinks(followLinksState);
121
~StFollowLinksState()
123
mFile.SetFollowLinks(mSavedState);
132
#pragma mark [nsDirEnumerator]
134
class nsDirEnumerator : public nsISimpleEnumerator,
135
public nsIDirectoryEnumerator
143
mFSRefsArray(nsnull),
144
mArrayCnt(0), mArrayIndex(0)
148
nsresult Init(nsILocalFileMac* parent)
150
NS_ENSURE_ARG(parent);
156
rv = parent->GetFSRef(&parentRef);
160
mFSRefsArray = (FSRef *)nsMemory::Alloc(sizeof(FSRef)
161
* kRequestCountPerIteration);
163
return NS_ERROR_OUT_OF_MEMORY;
165
err = ::FSOpenIterator(&parentRef, kFSIterateFlat, &mIterator);
167
return MacErrorMapper(err);
172
NS_IMETHOD HasMoreElements(PRBool *result)
174
if (mNext == nsnull) {
175
if (mArrayIndex >= mArrayCnt) {
177
OSErr err = ::FSGetCatalogInfoBulk(mIterator,
178
kRequestCountPerIteration,
187
if (err == noErr || err == errFSNoMoreItems) {
188
mArrayCnt = actualCnt;
192
if (mArrayIndex < mArrayCnt) {
193
nsLocalFile *newFile = new nsLocalFile;
195
return NS_ERROR_OUT_OF_MEMORY;
196
FSRef fsRef = mFSRefsArray[mArrayIndex];
197
if (NS_FAILED(newFile->InitWithFSRef(&fsRef)))
198
return NS_ERROR_FAILURE;
203
*result = mNext != nsnull;
209
NS_IMETHOD GetNext(nsISupports **result)
211
NS_ENSURE_ARG_POINTER(result);
216
rv = HasMoreElements(&hasMore);
217
if (NS_FAILED(rv)) return rv;
219
*result = mNext; // might return nsnull
220
NS_IF_ADDREF(*result);
226
NS_IMETHOD GetNextFile(nsIFile **result)
229
PRBool hasMore = PR_FALSE;
230
nsresult rv = HasMoreElements(&hasMore);
231
if (NS_FAILED(rv) || !hasMore)
234
NS_IF_ADDREF(*result);
242
::FSCloseIterator(mIterator);
246
nsMemory::Free(mFSRefsArray);
247
mFSRefsArray = nsnull;
259
// According to Apple doc, request the number of objects
260
// per call that will fit in 4 VM pages.
262
kRequestCountPerIteration = ((4096 * 4) / sizeof(FSRef))
265
nsCOMPtr<nsILocalFileMac> mNext;
267
FSIterator mIterator;
269
PRInt32 mArrayCnt, mArrayIndex;
272
NS_IMPL_ISUPPORTS2(nsDirEnumerator, nsISimpleEnumerator, nsIDirectoryEnumerator)
275
#pragma mark [StAEDesc]
277
class StAEDesc: public AEDesc
282
descriptorType = typeNull;
288
::AEDisposeDesc(this);
292
#define FILENAME_BUFFER_SIZE 512
294
//*****************************************************************************
296
//*****************************************************************************
298
const char nsLocalFile::kPathSepChar = '/';
299
const PRUnichar nsLocalFile::kPathSepUnichar = '/';
301
// The HFS+ epoch is Jan. 1, 1904 GMT - differs from HFS in which times were local
302
// The NSPR epoch is Jan. 1, 1970 GMT
303
// 2082844800 is the difference in seconds between those dates
304
const PRInt64 nsLocalFile::kJanuaryFirst1970Seconds = 2082844800LL;
307
#pragma mark [CTORs/DTOR]
309
nsLocalFile::nsLocalFile() :
312
mCachedFSRefValid(PR_FALSE),
313
mFollowLinks(PR_TRUE),
314
mFollowLinksDirty(PR_TRUE)
318
nsLocalFile::nsLocalFile(const nsLocalFile& src) :
319
mBaseRef(src.mBaseRef),
320
mTargetRef(src.mTargetRef),
321
mCachedFSRef(src.mCachedFSRef),
322
mCachedFSRefValid(src.mCachedFSRefValid),
323
mFollowLinks(src.mFollowLinks),
324
mFollowLinksDirty(src.mFollowLinksDirty)
326
// A CFURLRef is immutable so no need to copy, just retain.
328
::CFRetain(mBaseRef);
330
::CFRetain(mTargetRef);
333
nsLocalFile::~nsLocalFile()
336
::CFRelease(mBaseRef);
338
::CFRelease(mTargetRef);
342
//*****************************************************************************
343
// nsLocalFile::nsISupports
344
//*****************************************************************************
346
#pragma mark [nsISupports]
348
NS_IMPL_THREADSAFE_ISUPPORTS4(nsLocalFile,
354
NS_METHOD nsLocalFile::nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
356
NS_ENSURE_ARG_POINTER(aInstancePtr);
357
NS_ENSURE_NO_AGGREGATION(outer);
359
nsLocalFile* inst = new nsLocalFile();
361
return NS_ERROR_OUT_OF_MEMORY;
363
nsresult rv = inst->QueryInterface(aIID, aInstancePtr);
373
//*****************************************************************************
374
// nsLocalFile::nsIFile
375
//*****************************************************************************
377
#pragma mark [nsIFile]
379
/* void append (in AString node); */
380
NS_IMETHODIMP nsLocalFile::Append(const nsAString& aNode)
382
return AppendNative(NS_ConvertUTF16toUTF8(aNode));
385
/* [noscript] void appendNative (in ACString node); */
386
NS_IMETHODIMP nsLocalFile::AppendNative(const nsACString& aNode)
388
// Check we are correctly initialized.
391
nsACString::const_iterator start, end;
392
aNode.BeginReading(start);
393
aNode.EndReading(end);
394
if (FindCharInReadable(kPathSepChar, start, end))
395
return NS_ERROR_FILE_UNRECOGNIZED_PATH;
397
CFStringRef nodeStrRef = ::CFStringCreateWithCString(kCFAllocatorDefault,
398
PromiseFlatCString(aNode).get(),
399
kCFStringEncodingUTF8);
401
CFURLRef newRef = ::CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault,
402
mBaseRef, nodeStrRef, PR_FALSE);
403
::CFRelease(nodeStrRef);
410
return NS_ERROR_FAILURE;
413
/* void normalize (); */
414
NS_IMETHODIMP nsLocalFile::Normalize()
416
// Check we are correctly initialized.
419
// CFURL doesn't doesn't seem to resolve paths containing relative
420
// components, so we'll nick the stdlib code from nsLocalFileUnix
421
UInt8 path[PATH_MAX] = "";
423
success = ::CFURLGetFileSystemRepresentation(mBaseRef, true, path, PATH_MAX);
425
return NS_ERROR_FAILURE;
427
char resolved_path[PATH_MAX] = "";
428
char *resolved_path_ptr = nsnull;
429
resolved_path_ptr = realpath((char*)path, resolved_path);
431
// if there is an error, the return is null.
432
if (!resolved_path_ptr)
433
return NSRESULT_FOR_ERRNO();
435
// Need to know whether we're a directory to create a new CFURLRef
437
nsresult rv = IsDirectory(&isDirectory);
438
NS_ENSURE_SUCCESS(rv, rv);
440
rv = NS_ERROR_FAILURE;
441
CFStringRef pathStrRef =
442
::CFStringCreateWithCString(kCFAllocatorDefault,
444
kCFStringEncodingUTF8);
447
::CFURLCreateWithFileSystemPath(kCFAllocatorDefault, pathStrRef,
448
kCFURLPOSIXPathStyle, isDirectory);
450
SetBaseRef(newURLRef);
451
::CFRelease(newURLRef);
454
::CFRelease(pathStrRef);
460
/* void create (in unsigned long type, in unsigned long permissions); */
461
NS_IMETHODIMP nsLocalFile::Create(PRUint32 type, PRUint32 permissions)
463
if (type != NORMAL_FILE_TYPE && type != DIRECTORY_TYPE)
464
return NS_ERROR_FILE_UNKNOWN_TYPE;
466
// Check we are correctly initialized.
469
nsStringArray nonExtantNodes;
470
CFURLRef pathURLRef = mBaseRef;
472
CFStringRef leafStrRef = nsnull;
473
nsAutoBuffer<UniChar, FILENAME_BUFFER_SIZE> buffer;
476
// Work backwards through the path to find the last node which
477
// exists. Place the nodes which don't exist in an array and we'll
478
// create those below.
479
while ((success = ::CFURLGetFSRef(pathURLRef, &pathFSRef)) == false) {
480
leafStrRef = ::CFURLCopyLastPathComponent(pathURLRef);
483
CFIndex leafLen = ::CFStringGetLength(leafStrRef);
484
if (!buffer.EnsureElemCapacity(leafLen + 1))
486
::CFStringGetCharacters(leafStrRef, CFRangeMake(0, leafLen), buffer.get());
487
buffer.get()[leafLen] = '\0';
488
nonExtantNodes.AppendString(nsString(nsDependentString(buffer.get())));
489
::CFRelease(leafStrRef);
492
// Get the parent of the leaf for the next go round
493
CFURLRef parent = ::CFURLCreateCopyDeletingLastPathComponent(NULL, pathURLRef);
496
if (pathURLRef != mBaseRef)
497
::CFRelease(pathURLRef);
500
if (pathURLRef != mBaseRef)
501
::CFRelease(pathURLRef);
502
if (leafStrRef != nsnull)
503
::CFRelease(leafStrRef);
505
return NS_ERROR_FAILURE;
506
PRInt32 nodesToCreate = nonExtantNodes.Count();
507
if (nodesToCreate == 0)
508
return NS_ERROR_FILE_ALREADY_EXISTS;
511
nsAutoString nextNodeName;
512
for (PRInt32 i = nodesToCreate - 1; i > 0; i--) {
513
nonExtantNodes.StringAt(i, nextNodeName);
514
err = ::FSCreateDirectoryUnicode(&pathFSRef,
515
nextNodeName.Length(),
516
(const UniChar *)nextNodeName.get(),
518
nsnull, &pathFSRef, nsnull, nsnull);
520
return MacErrorMapper(err);
522
nonExtantNodes.StringAt(0, nextNodeName);
523
if (type == NORMAL_FILE_TYPE) {
524
err = ::FSCreateFileUnicode(&pathFSRef,
525
nextNodeName.Length(),
526
(const UniChar *)nextNodeName.get(),
528
nsnull, nsnull, nsnull);
531
err = ::FSCreateDirectoryUnicode(&pathFSRef,
532
nextNodeName.Length(),
533
(const UniChar *)nextNodeName.get(),
535
nsnull, nsnull, nsnull, nsnull);
538
return MacErrorMapper(err);
541
/* attribute AString leafName; */
542
NS_IMETHODIMP nsLocalFile::GetLeafName(nsAString& aLeafName)
544
nsCAutoString nativeString;
545
nsresult rv = GetNativeLeafName(nativeString);
548
CopyUTF8toUTF16NFC(nativeString, aLeafName);
552
NS_IMETHODIMP nsLocalFile::SetLeafName(const nsAString& aLeafName)
554
return SetNativeLeafName(NS_ConvertUTF16toUTF8(aLeafName));
557
/* [noscript] attribute ACString nativeLeafName; */
558
NS_IMETHODIMP nsLocalFile::GetNativeLeafName(nsACString& aNativeLeafName)
560
// Check we are correctly initialized.
563
nsresult rv = NS_ERROR_FAILURE;
564
CFStringRef leafStrRef = ::CFURLCopyLastPathComponent(mBaseRef);
566
rv = CFStringReftoUTF8(leafStrRef, aNativeLeafName);
567
::CFRelease(leafStrRef);
572
NS_IMETHODIMP nsLocalFile::SetNativeLeafName(const nsACString& aNativeLeafName)
574
// Check we are correctly initialized.
577
nsresult rv = NS_ERROR_FAILURE;
578
CFURLRef parentURLRef = ::CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, mBaseRef);
580
CFStringRef nodeStrRef = ::CFStringCreateWithCString(kCFAllocatorDefault,
581
PromiseFlatCString(aNativeLeafName).get(),
582
kCFStringEncodingUTF8);
585
CFURLRef newURLRef = ::CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault,
586
parentURLRef, nodeStrRef, PR_FALSE);
588
SetBaseRef(newURLRef);
589
::CFRelease(newURLRef);
592
::CFRelease(nodeStrRef);
594
::CFRelease(parentURLRef);
599
/* void copyTo (in nsIFile newParentDir, in AString newName); */
600
NS_IMETHODIMP nsLocalFile::CopyTo(nsIFile *newParentDir, const nsAString& newName)
602
return CopyInternal(newParentDir, newName, PR_FALSE);
605
/* [noscrpit] void CopyToNative (in nsIFile newParentDir, in ACString newName); */
606
NS_IMETHODIMP nsLocalFile::CopyToNative(nsIFile *newParentDir, const nsACString& newName)
608
return CopyInternal(newParentDir, NS_ConvertUTF8toUTF16(newName), PR_FALSE);
611
/* void copyToFollowingLinks (in nsIFile newParentDir, in AString newName); */
612
NS_IMETHODIMP nsLocalFile::CopyToFollowingLinks(nsIFile *newParentDir, const nsAString& newName)
614
return CopyInternal(newParentDir, newName, PR_TRUE);
617
/* [noscript] void copyToFollowingLinksNative (in nsIFile newParentDir, in ACString newName); */
618
NS_IMETHODIMP nsLocalFile::CopyToFollowingLinksNative(nsIFile *newParentDir, const nsACString& newName)
620
return CopyInternal(newParentDir, NS_ConvertUTF8toUTF16(newName), PR_TRUE);
623
/* void moveTo (in nsIFile newParentDir, in AString newName); */
624
NS_IMETHODIMP nsLocalFile::MoveTo(nsIFile *newParentDir, const nsAString& newName)
626
return MoveToNative(newParentDir, NS_ConvertUTF16toUTF8(newName));
629
/* [noscript] void moveToNative (in nsIFile newParentDir, in ACString newName); */
630
NS_IMETHODIMP nsLocalFile::MoveToNative(nsIFile *newParentDir, const nsACString& newName)
632
// Check we are correctly initialized.
635
StFollowLinksState followLinks(*this, PR_FALSE);
638
nsresult rv = IsDirectory(&isDirectory);
642
// Get the source path.
643
nsCAutoString srcPath;
644
rv = GetNativePath(srcPath);
648
// Build the destination path.
649
nsCOMPtr<nsIFile> parentDir = newParentDir;
651
if (newName.IsEmpty())
652
return NS_ERROR_INVALID_ARG;
653
rv = GetParent(getter_AddRefs(parentDir));
659
rv = parentDir->Exists(&exists);
663
rv = parentDir->Create(nsIFile::DIRECTORY_TYPE, 0777);
669
nsCAutoString destPath;
670
rv = parentDir->GetNativePath(destPath);
674
if (!newName.IsEmpty())
675
destPath.Append(NS_LITERAL_CSTRING("/") + newName);
677
nsCAutoString leafName;
678
rv = GetNativeLeafName(leafName);
681
destPath.Append(NS_LITERAL_CSTRING("/") + leafName);
685
if (rename(srcPath.get(), destPath.get()) != 0) {
686
if (errno == EXDEV) {
687
// Can't move across volume (device) boundaries. Copy and remove.
688
rv = CopyToNative(parentDir, newName);
689
if (NS_SUCCEEDED(rv)) {
690
// Permit removal failure.
695
rv = NSRESULT_FOR_ERRNO();
701
// Update |this| to refer to the moved file.
702
CFURLRef newBaseRef =
703
::CFURLCreateFromFileSystemRepresentation(NULL, (UInt8*)destPath.get(),
704
destPath.Length(), isDirectory);
706
return NS_ERROR_FAILURE;
707
SetBaseRef(newBaseRef);
708
::CFRelease(newBaseRef);
713
/* void remove (in boolean recursive); */
714
NS_IMETHODIMP nsLocalFile::Remove(PRBool recursive)
716
// Check we are correctly initialized.
719
// XXX If we're an alias, never remove target
720
StFollowLinksState followLinks(*this, PR_FALSE);
723
nsresult rv = IsDirectory(&isDirectory);
727
if (recursive && isDirectory) {
729
rv = GetFSRefInternal(fsRef);
733
// Call MoreFilesX to do a recursive removal.
734
OSStatus err = ::FSDeleteContainer(&fsRef);
735
rv = MacErrorMapper(err);
739
rv = GetNativePath(path);
743
const char* pathPtr = path.get();
746
status = rmdir(pathPtr);
748
status = unlink(pathPtr);
751
rv = NSRESULT_FOR_ERRNO();
754
mCachedFSRefValid = PR_FALSE;
758
/* attribute unsigned long permissions; */
759
NS_IMETHODIMP nsLocalFile::GetPermissions(PRUint32 *aPermissions)
761
NS_ENSURE_ARG_POINTER(aPermissions);
764
nsresult rv = GetFSRefInternal(fsRef);
768
FSCatalogInfo catalogInfo;
769
OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoPermissions, &catalogInfo,
770
nsnull, nsnull, nsnull);
772
return MacErrorMapper(err);
773
FSPermissionInfo *permPtr = (FSPermissionInfo*)catalogInfo.permissions;
774
*aPermissions = permPtr->mode;
778
NS_IMETHODIMP nsLocalFile::SetPermissions(PRUint32 aPermissions)
781
nsresult rv = GetFSRefInternal(fsRef);
785
FSCatalogInfo catalogInfo;
786
OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoPermissions, &catalogInfo,
787
nsnull, nsnull, nsnull);
789
return MacErrorMapper(err);
790
FSPermissionInfo *permPtr = (FSPermissionInfo*)catalogInfo.permissions;
791
permPtr->mode = (UInt16)aPermissions;
792
err = ::FSSetCatalogInfo(&fsRef, kFSCatInfoPermissions, &catalogInfo);
793
return MacErrorMapper(err);
796
/* attribute unsigned long permissionsOfLink; */
797
NS_IMETHODIMP nsLocalFile::GetPermissionsOfLink(PRUint32 *aPermissionsOfLink)
799
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
800
return NS_ERROR_NOT_IMPLEMENTED;
803
NS_IMETHODIMP nsLocalFile::SetPermissionsOfLink(PRUint32 aPermissionsOfLink)
805
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
806
return NS_ERROR_NOT_IMPLEMENTED;
809
/* attribute PRInt64 lastModifiedTime; */
810
NS_IMETHODIMP nsLocalFile::GetLastModifiedTime(PRInt64 *aLastModifiedTime)
812
// Check we are correctly initialized.
815
NS_ENSURE_ARG_POINTER(aLastModifiedTime);
818
nsresult rv = GetFSRefInternal(fsRef);
822
FSCatalogInfo catalogInfo;
823
OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoContentMod, &catalogInfo,
824
nsnull, nsnull, nsnull);
826
return MacErrorMapper(err);
827
*aLastModifiedTime = HFSPlustoNSPRTime(catalogInfo.contentModDate);
831
NS_IMETHODIMP nsLocalFile::SetLastModifiedTime(PRInt64 aLastModifiedTime)
833
// Check we are correctly initialized.
839
FSCatalogInfo catalogInfo;
841
rv = GetFSRefInternal(fsRef);
848
/* Get the node flags, the content modification date and time, and the parent ref */
849
err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags + kFSCatInfoContentMod,
850
&catalogInfo, NULL, NULL, &parentRef);
852
return MacErrorMapper(err);
854
/* Notify the parent if this is a file */
855
notifyParent = (0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask));
857
NSPRtoHFSPlusTime(aLastModifiedTime, catalogInfo.contentModDate);
858
err = ::FSSetCatalogInfo(&fsRef, kFSCatInfoContentMod, &catalogInfo);
860
return MacErrorMapper(err);
862
/* Send a notification for the parent of the file, or for the directory */
863
err = FNNotify(notifyParent ? &parentRef : &fsRef, kFNDirectoryModifiedMessage, kNilOptions);
865
return MacErrorMapper(err);
870
/* attribute PRInt64 lastModifiedTimeOfLink; */
871
NS_IMETHODIMP nsLocalFile::GetLastModifiedTimeOfLink(PRInt64 *aLastModifiedTimeOfLink)
873
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
874
return NS_ERROR_NOT_IMPLEMENTED;
876
NS_IMETHODIMP nsLocalFile::SetLastModifiedTimeOfLink(PRInt64 aLastModifiedTimeOfLink)
878
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
879
return NS_ERROR_NOT_IMPLEMENTED;
882
/* attribute PRInt64 fileSize; */
883
NS_IMETHODIMP nsLocalFile::GetFileSize(PRInt64 *aFileSize)
885
NS_ENSURE_ARG_POINTER(aFileSize);
889
nsresult rv = GetFSRefInternal(fsRef);
893
FSCatalogInfo catalogInfo;
894
OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags + kFSCatInfoDataSizes, &catalogInfo,
895
nsnull, nsnull, nsnull);
897
return MacErrorMapper(err);
899
// FSGetCatalogInfo can return a bogus size for directories sometimes, so only
900
// rely on the answer for files
901
if ((catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) == 0)
902
*aFileSize = catalogInfo.dataLogicalSize;
906
NS_IMETHODIMP nsLocalFile::SetFileSize(PRInt64 aFileSize)
908
// Check we are correctly initialized.
912
nsresult rv = GetFSRefInternal(fsRef);
917
OSErr err = ::FSOpenFork(&fsRef, 0, nsnull, fsWrPerm, &refNum);
919
return MacErrorMapper(err);
920
err = ::FSSetForkSize(refNum, fsFromStart, aFileSize);
921
::FSCloseFork(refNum);
923
return MacErrorMapper(err);
926
/* readonly attribute PRInt64 fileSizeOfLink; */
927
NS_IMETHODIMP nsLocalFile::GetFileSizeOfLink(PRInt64 *aFileSizeOfLink)
929
// Check we are correctly initialized.
932
NS_ENSURE_ARG_POINTER(aFileSizeOfLink);
934
StFollowLinksState followLinks(*this, PR_FALSE);
935
return GetFileSize(aFileSizeOfLink);
938
/* readonly attribute AString target; */
939
NS_IMETHODIMP nsLocalFile::GetTarget(nsAString& aTarget)
941
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
942
return NS_ERROR_NOT_IMPLEMENTED;
945
/* [noscript] readonly attribute ACString nativeTarget; */
946
NS_IMETHODIMP nsLocalFile::GetNativeTarget(nsACString& aNativeTarget)
948
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
949
return NS_ERROR_NOT_IMPLEMENTED;
952
/* readonly attribute AString path; */
953
NS_IMETHODIMP nsLocalFile::GetPath(nsAString& aPath)
955
nsCAutoString nativeString;
956
nsresult rv = GetNativePath(nativeString);
959
CopyUTF8toUTF16NFC(nativeString, aPath);
963
/* [noscript] readonly attribute ACString nativePath; */
964
NS_IMETHODIMP nsLocalFile::GetNativePath(nsACString& aNativePath)
966
// Check we are correctly initialized.
969
nsresult rv = NS_ERROR_FAILURE;
970
CFStringRef pathStrRef = ::CFURLCopyFileSystemPath(mBaseRef, kCFURLPOSIXPathStyle);
972
rv = CFStringReftoUTF8(pathStrRef, aNativePath);
973
::CFRelease(pathStrRef);
978
/* boolean exists (); */
979
NS_IMETHODIMP nsLocalFile::Exists(PRBool *_retval)
981
// Check we are correctly initialized.
984
NS_ENSURE_ARG_POINTER(_retval);
988
if (NS_SUCCEEDED(GetFSRefInternal(fsRef, PR_TRUE))) {
995
/* boolean isWritable (); */
996
NS_IMETHODIMP nsLocalFile::IsWritable(PRBool *_retval)
998
// Check we are correctly initialized.
1001
NS_ENSURE_ARG_POINTER(_retval);
1002
*_retval = PR_FALSE;
1005
nsresult rv = GetFSRefInternal(fsRef);
1008
if (::FSCheckLock(&fsRef) == noErr) {
1009
PRUint32 permissions;
1010
rv = GetPermissions(&permissions);
1013
*_retval = ((permissions & S_IWUSR) != 0);
1018
/* boolean isReadable (); */
1019
NS_IMETHODIMP nsLocalFile::IsReadable(PRBool *_retval)
1021
// Check we are correctly initialized.
1024
NS_ENSURE_ARG_POINTER(_retval);
1025
*_retval = PR_FALSE;
1027
PRUint32 permissions;
1028
nsresult rv = GetPermissions(&permissions);
1031
*_retval = ((permissions & S_IRUSR) != 0);
1035
/* boolean isExecutable (); */
1036
NS_IMETHODIMP nsLocalFile::IsExecutable(PRBool *_retval)
1038
// Check we are correctly initialized.
1041
NS_ENSURE_ARG_POINTER(_retval);
1042
*_retval = PR_FALSE;
1045
nsresult rv = GetFSRefInternal(fsRef);
1049
LSRequestedInfo theInfoRequest = kLSRequestAllInfo;
1050
LSItemInfoRecord theInfo;
1051
if (::LSCopyItemInfoForRef(&fsRef, theInfoRequest, &theInfo) == noErr) {
1052
if ((theInfo.flags & kLSItemInfoIsApplication) != 0)
1058
/* boolean isHidden (); */
1059
NS_IMETHODIMP nsLocalFile::IsHidden(PRBool *_retval)
1061
NS_ENSURE_ARG_POINTER(_retval);
1062
*_retval = PR_FALSE;
1065
nsresult rv = GetFSRefInternal(fsRef);
1069
FSCatalogInfo catalogInfo;
1070
HFSUniStr255 leafName;
1071
OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoFinderInfo, &catalogInfo,
1072
&leafName, nsnull, nsnull);
1074
return MacErrorMapper(err);
1076
FileInfo *fInfoPtr = (FileInfo *)(catalogInfo.finderInfo); // Finder flags are in the same place whether we use FileInfo or FolderInfo
1077
if ((fInfoPtr->finderFlags & kIsInvisible) != 0) {
1081
// If the leaf name begins with a '.', consider it invisible
1082
if (leafName.length >= 1 && leafName.unicode[0] == UniChar('.'))
1088
/* boolean isDirectory (); */
1089
NS_IMETHODIMP nsLocalFile::IsDirectory(PRBool *_retval)
1091
NS_ENSURE_ARG_POINTER(_retval);
1092
*_retval = PR_FALSE;
1095
nsresult rv = GetFSRefInternal(fsRef, PR_FALSE);
1099
FSCatalogInfo catalogInfo;
1100
OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags, &catalogInfo,
1101
nsnull, nsnull, nsnull);
1103
return MacErrorMapper(err);
1104
*_retval = ((catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) != 0);
1108
/* boolean isFile (); */
1109
NS_IMETHODIMP nsLocalFile::IsFile(PRBool *_retval)
1111
NS_ENSURE_ARG_POINTER(_retval);
1112
*_retval = PR_FALSE;
1115
nsresult rv = GetFSRefInternal(fsRef, PR_FALSE);
1119
FSCatalogInfo catalogInfo;
1120
OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags, &catalogInfo,
1121
nsnull, nsnull, nsnull);
1123
return MacErrorMapper(err);
1124
*_retval = ((catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) == 0);
1128
/* boolean isSymlink (); */
1129
NS_IMETHODIMP nsLocalFile::IsSymlink(PRBool *_retval)
1131
// Check we are correctly initialized.
1134
NS_ENSURE_ARG(_retval);
1135
*_retval = PR_FALSE;
1137
// Check we are correctly initialized.
1141
if (::CFURLGetFSRef(mBaseRef, &fsRef)) {
1142
Boolean isAlias, isFolder;
1143
if (::FSIsAliasFile(&fsRef, &isAlias, &isFolder) == noErr)
1149
/* boolean isSpecial (); */
1150
NS_IMETHODIMP nsLocalFile::IsSpecial(PRBool *_retval)
1152
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
1153
return NS_ERROR_NOT_IMPLEMENTED;
1156
/* nsIFile clone (); */
1157
NS_IMETHODIMP nsLocalFile::Clone(nsIFile **_retval)
1159
// Just copy-construct ourselves
1160
*_retval = new nsLocalFile(*this);
1162
return NS_ERROR_OUT_OF_MEMORY;
1164
NS_ADDREF(*_retval);
1169
/* boolean equals (in nsIFile inFile); */
1170
NS_IMETHODIMP nsLocalFile::Equals(nsIFile *inFile, PRBool *_retval)
1172
return EqualsInternal(inFile, PR_TRUE, _retval);
1176
nsLocalFile::EqualsInternal(nsISupports* inFile, PRBool aUpdateCache,
1179
NS_ENSURE_ARG_POINTER(_retval);
1180
*_retval = PR_FALSE;
1182
nsCOMPtr<nsILocalFileMac> inMacFile(do_QueryInterface(inFile));
1187
NS_STATIC_CAST(nsLocalFile*, (nsILocalFileMac*) inMacFile);
1189
// If both exist, compare FSRefs
1190
FSRef thisFSRef, inFSRef;
1191
nsresult rv1 = GetFSRefInternal(thisFSRef, aUpdateCache);
1192
nsresult rv2 = inLF->GetFSRefInternal(inFSRef, aUpdateCache);
1193
if (NS_SUCCEEDED(rv1) && NS_SUCCEEDED(rv2)) {
1194
*_retval = (thisFSRef == inFSRef);
1197
// If one exists and the other doesn't, not equal
1201
// Arg, we have to get their paths and compare
1202
nsCAutoString thisPath, inPath;
1203
if (NS_FAILED(GetNativePath(thisPath)))
1204
return NS_ERROR_FAILURE;
1205
if (NS_FAILED(inMacFile->GetNativePath(inPath)))
1206
return NS_ERROR_FAILURE;
1207
*_retval = thisPath.Equals(inPath);
1212
/* boolean contains (in nsIFile inFile, in boolean recur); */
1213
NS_IMETHODIMP nsLocalFile::Contains(nsIFile *inFile, PRBool recur, PRBool *_retval)
1215
// Check we are correctly initialized.
1218
NS_ENSURE_ARG_POINTER(_retval);
1219
*_retval = PR_FALSE;
1222
nsresult rv = IsDirectory(&isDir);
1226
return NS_OK; // must be a dir to contain someone
1228
nsCAutoString thisPath, inPath;
1229
if (NS_FAILED(GetNativePath(thisPath)) || NS_FAILED(inFile->GetNativePath(inPath)))
1230
return NS_ERROR_FAILURE;
1231
size_t thisPathLen = thisPath.Length();
1232
if ((inPath.Length() > thisPathLen + 1) && (strncasecmp(thisPath.get(), inPath.get(), thisPathLen) == 0)) {
1233
// Now make sure that the |inFile|'s path has a separator at thisPathLen,
1234
// and there's at least one more character after that.
1235
if (inPath[thisPathLen] == kPathSepChar)
1241
/* readonly attribute nsIFile parent; */
1242
NS_IMETHODIMP nsLocalFile::GetParent(nsIFile * *aParent)
1244
NS_ENSURE_ARG_POINTER(aParent);
1247
// Check we are correctly initialized.
1250
nsLocalFile *newFile = nsnull;
1252
// If it can be determined without error that a file does not
1253
// have a parent, return nsnull for the parent and NS_OK as the result.
1255
nsresult rv = NS_OK;
1256
CFURLRef parentURLRef = ::CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, mBaseRef);
1258
rv = NS_ERROR_FAILURE;
1259
newFile = new nsLocalFile;
1261
rv = newFile->InitWithCFURL(parentURLRef);
1262
if (NS_SUCCEEDED(rv)) {
1263
NS_ADDREF(*aParent = newFile);
1267
::CFRelease(parentURLRef);
1272
/* readonly attribute nsISimpleEnumerator directoryEntries; */
1273
NS_IMETHODIMP nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator **aDirectoryEntries)
1275
NS_ENSURE_ARG_POINTER(aDirectoryEntries);
1276
*aDirectoryEntries = nsnull;
1280
rv = IsDirectory(&isDir);
1284
return NS_ERROR_FILE_NOT_DIRECTORY;
1286
nsDirEnumerator* dirEnum = new nsDirEnumerator;
1287
if (dirEnum == nsnull)
1288
return NS_ERROR_OUT_OF_MEMORY;
1290
rv = dirEnum->Init(this);
1291
if (NS_FAILED(rv)) {
1292
NS_RELEASE(dirEnum);
1295
*aDirectoryEntries = dirEnum;
1301
//*****************************************************************************
1302
// nsLocalFile::nsILocalFile
1303
//*****************************************************************************
1305
#pragma mark [nsILocalFile]
1307
/* void initWithPath (in AString filePath); */
1308
NS_IMETHODIMP nsLocalFile::InitWithPath(const nsAString& filePath)
1310
return InitWithNativePath(NS_ConvertUTF16toUTF8(filePath));
1313
/* [noscript] void initWithNativePath (in ACString filePath); */
1314
NS_IMETHODIMP nsLocalFile::InitWithNativePath(const nsACString& filePath)
1316
nsCAutoString fixedPath;
1317
if (Substring(filePath, 0, 2).EqualsLiteral("~/")) {
1318
nsCOMPtr<nsIFile> homeDir;
1319
nsCAutoString homePath;
1320
nsresult rv = NS_GetSpecialDirectory(NS_OS_HOME_DIR,
1321
getter_AddRefs(homeDir));
1322
NS_ENSURE_SUCCESS(rv, rv);
1323
rv = homeDir->GetNativePath(homePath);
1324
NS_ENSURE_SUCCESS(rv, rv);
1326
fixedPath = homePath + Substring(filePath, 1, filePath.Length() - 1);
1328
else if (filePath.IsEmpty() || filePath.First() != '/')
1329
return NS_ERROR_FILE_UNRECOGNIZED_PATH;
1331
fixedPath.Assign(filePath);
1333
// A path with consecutive '/'s which are not between
1334
// nodes crashes CFURLGetFSRef(). Consecutive '/'s which
1335
// are between actual nodes are OK. So, convert consecutive
1336
// '/'s to a single one.
1337
fixedPath.ReplaceSubstring("//", "/");
1339
#if 1 // bird: hack to fix RegistryLocationForSpec issues with /path/to/./components
1340
fixedPath.ReplaceSubstring("/./", "/");
1341
size_t len = fixedPath.Length();
1345
if (!strcmp(fixedPath.get() + len - 2, "/."))
1347
else if (!strcmp(fixedPath.get() + len - 1, "/"))
1351
fixedPath = StringHead(fixedPath, len - choplen);
1353
// bird: another hack for the issue with VirtualBoxVM and symlinks...
1354
char tmpBuf[PATH_MAX];
1355
if (realpath(fixedPath.get(), tmpBuf))
1359
// On 10.2, huge paths also crash CFURLGetFSRef()
1360
if (fixedPath.Length() > PATH_MAX)
1361
return NS_ERROR_FILE_NAME_TOO_LONG;
1363
CFStringRef pathAsCFString;
1364
CFURLRef pathAsCFURL;
1366
pathAsCFString = ::CFStringCreateWithCString(nsnull, fixedPath.get(), kCFStringEncodingUTF8);
1367
if (!pathAsCFString)
1368
return NS_ERROR_FAILURE;
1369
pathAsCFURL = ::CFURLCreateWithFileSystemPath(nsnull, pathAsCFString, kCFURLPOSIXPathStyle, PR_FALSE);
1371
::CFRelease(pathAsCFString);
1372
return NS_ERROR_FAILURE;
1374
SetBaseRef(pathAsCFURL);
1375
::CFRelease(pathAsCFURL);
1376
::CFRelease(pathAsCFString);
1380
/* void initWithFile (in nsILocalFile aFile); */
1381
NS_IMETHODIMP nsLocalFile::InitWithFile(nsILocalFile *aFile)
1383
NS_ENSURE_ARG(aFile);
1385
nsCOMPtr<nsILocalFileMac> aFileMac(do_QueryInterface(aFile));
1387
return NS_ERROR_UNEXPECTED;
1389
nsresult rv = aFileMac->GetCFURL(&urlRef);
1392
rv = InitWithCFURL(urlRef);
1393
::CFRelease(urlRef);
1397
/* attribute PRBool followLinks; */
1398
NS_IMETHODIMP nsLocalFile::GetFollowLinks(PRBool *aFollowLinks)
1400
NS_ENSURE_ARG_POINTER(aFollowLinks);
1402
*aFollowLinks = mFollowLinks;
1406
NS_IMETHODIMP nsLocalFile::SetFollowLinks(PRBool aFollowLinks)
1408
if (aFollowLinks != mFollowLinks) {
1409
mFollowLinks = aFollowLinks;
1415
/* [noscript] PRFileDescStar openNSPRFileDesc (in long flags, in long mode); */
1416
NS_IMETHODIMP nsLocalFile::OpenNSPRFileDesc(PRInt32 flags, PRInt32 mode, PRFileDesc **_retval)
1418
NS_ENSURE_ARG_POINTER(_retval);
1421
nsresult rv = GetPathInternal(path);
1425
*_retval = PR_Open(path.get(), flags, mode);
1427
return NS_ErrorAccordingToNSPR();
1432
/* [noscript] FILE openANSIFileDesc (in string mode); */
1433
NS_IMETHODIMP nsLocalFile::OpenANSIFileDesc(const char *mode, FILE **_retval)
1435
NS_ENSURE_ARG_POINTER(_retval);
1438
nsresult rv = GetPathInternal(path);
1442
*_retval = fopen(path.get(), mode);
1444
return NS_ERROR_FAILURE;
1449
/* [noscript] PRLibraryStar load (); */
1450
NS_IMETHODIMP nsLocalFile::Load(PRLibrary **_retval)
1452
// Check we are correctly initialized.
1455
NS_ENSURE_ARG_POINTER(_retval);
1457
NS_TIMELINE_START_TIMER("PR_LoadLibrary");
1460
nsresult rv = GetPathInternal(path);
1464
#ifdef NS_BUILD_REFCNT_LOGGING
1465
nsTraceRefcntImpl::SetActivityIsLegal(PR_FALSE);
1468
*_retval = PR_LoadLibrary(path.get());
1470
#ifdef NS_BUILD_REFCNT_LOGGING
1471
nsTraceRefcntImpl::SetActivityIsLegal(PR_TRUE);
1474
NS_TIMELINE_STOP_TIMER("PR_LoadLibrary");
1475
NS_TIMELINE_MARK_TIMER1("PR_LoadLibrary", path.get());
1478
return NS_ERROR_FAILURE;
1483
/* readonly attribute PRInt64 diskSpaceAvailable; */
1484
NS_IMETHODIMP nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable)
1486
// Check we are correctly initialized.
1489
NS_ENSURE_ARG_POINTER(aDiskSpaceAvailable);
1492
nsresult rv = GetFSRefInternal(fsRef);
1497
FSCatalogInfo catalogInfo;
1498
err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoVolume, &catalogInfo,
1499
nsnull, nsnull, nsnull);
1501
return MacErrorMapper(err);
1503
FSVolumeInfo volumeInfo;
1504
err = ::FSGetVolumeInfo(catalogInfo.volume, 0, nsnull, kFSVolInfoSizes,
1505
&volumeInfo, nsnull, nsnull);
1507
return MacErrorMapper(err);
1509
*aDiskSpaceAvailable = volumeInfo.freeBytes;
1513
/* void appendRelativePath (in AString relativeFilePath); */
1514
NS_IMETHODIMP nsLocalFile::AppendRelativePath(const nsAString& relativeFilePath)
1516
return AppendRelativeNativePath(NS_ConvertUTF16toUTF8(relativeFilePath));
1519
/* [noscript] void appendRelativeNativePath (in ACString relativeFilePath); */
1520
NS_IMETHODIMP nsLocalFile::AppendRelativeNativePath(const nsACString& relativeFilePath)
1522
if (relativeFilePath.IsEmpty())
1525
if (relativeFilePath.First() == '/')
1526
return NS_ERROR_FILE_UNRECOGNIZED_PATH;
1528
// Parse the nodes and call Append() for each
1529
nsACString::const_iterator nodeBegin, pathEnd;
1530
relativeFilePath.BeginReading(nodeBegin);
1531
relativeFilePath.EndReading(pathEnd);
1532
nsACString::const_iterator nodeEnd(nodeBegin);
1534
while (nodeEnd != pathEnd) {
1535
FindCharInReadable(kPathSepChar, nodeEnd, pathEnd);
1536
nsresult rv = AppendNative(Substring(nodeBegin, nodeEnd));
1539
if (nodeEnd != pathEnd) // If there's more left in the string, inc over the '/' nodeEnd is on.
1541
nodeBegin = nodeEnd;
1546
/* attribute ACString persistentDescriptor; */
1547
NS_IMETHODIMP nsLocalFile::GetPersistentDescriptor(nsACString& aPersistentDescriptor)
1550
nsresult rv = GetFSRefInternal(fsRef);
1555
OSErr err = ::FSNewAlias(nsnull, &fsRef, &aliasH);
1557
return MacErrorMapper(err);
1559
PRUint32 bytes = ::GetHandleSize((Handle) aliasH);
1560
::HLock((Handle) aliasH);
1561
// Passing nsnull for dest makes NULL-term string
1562
char* buf = PL_Base64Encode((const char*)*aliasH, bytes, nsnull);
1563
::DisposeHandle((Handle) aliasH);
1564
NS_ENSURE_TRUE(buf, NS_ERROR_OUT_OF_MEMORY);
1566
aPersistentDescriptor = buf;
1572
NS_IMETHODIMP nsLocalFile::SetPersistentDescriptor(const nsACString& aPersistentDescriptor)
1574
if (aPersistentDescriptor.IsEmpty())
1575
return NS_ERROR_INVALID_ARG;
1577
// Support pathnames as user-supplied descriptors if they begin with '/'
1578
// or '~'. These characters do not collide with the base64 set used for
1579
// encoding alias records.
1580
char first = aPersistentDescriptor.First();
1581
if (first == '/' || first == '~')
1582
return InitWithNativePath(aPersistentDescriptor);
1584
nsresult rv = NS_OK;
1586
PRUint32 dataSize = aPersistentDescriptor.Length();
1587
char* decodedData = PL_Base64Decode(PromiseFlatCString(aPersistentDescriptor).get(), dataSize, nsnull);
1589
NS_ERROR("SetPersistentDescriptor was given bad data");
1590
return NS_ERROR_FAILURE;
1593
// Cast to an alias record and resolve.
1594
AliasRecord aliasHeader = *(AliasPtr)decodedData;
1595
PRInt32 aliasSize = GetAliasSizeFromRecord(aliasHeader);
1596
if (aliasSize > (dataSize * 3) / 4) { // be paranoid about having too few data
1597
PR_Free(decodedData);
1598
return NS_ERROR_FAILURE;
1601
// Move the now-decoded data into the Handle.
1602
// The size of the decoded data is 3/4 the size of the encoded data. See plbase64.h
1603
Handle newHandle = nsnull;
1604
if (::PtrToHand(decodedData, &newHandle, aliasSize) != noErr)
1605
rv = NS_ERROR_OUT_OF_MEMORY;
1606
PR_Free(decodedData);
1611
FSRef resolvedFSRef;
1612
OSErr err = ::FSResolveAlias(nsnull, (AliasHandle)newHandle, &resolvedFSRef, &changed);
1614
rv = MacErrorMapper(err);
1615
DisposeHandle(newHandle);
1619
return InitWithFSRef(&resolvedFSRef);
1622
/* void reveal (); */
1623
NS_IMETHODIMP nsLocalFile::Reveal()
1625
FSRef fsRefToReveal;
1626
AppleEvent aeEvent = {0, nil};
1627
AppleEvent aeReply = {0, nil};
1628
StAEDesc aeDirDesc, listElem, myAddressDesc, fileList;
1630
ProcessSerialNumber process;
1632
nsresult rv = GetFSRefInternal(fsRefToReveal);
1636
err = ::FindRunningAppBySignature ('MACS', process);
1638
err = ::AECreateDesc(typeProcessSerialNumber, (Ptr)&process, sizeof(process), &myAddressDesc);
1640
// Create the FinderEvent
1641
err = ::AECreateAppleEvent(kAEMiscStandards, kAEMakeObjectsVisible, &myAddressDesc,
1642
kAutoGenerateReturnID, kAnyTransactionID, &aeEvent);
1644
// Create the file list
1645
err = ::AECreateList(nil, 0, false, &fileList);
1647
FSSpec fsSpecToReveal;
1648
err = ::FSRefMakeFSSpec(&fsRefToReveal, &fsSpecToReveal);
1650
err = ::AEPutPtr(&fileList, 0, typeFSS, &fsSpecToReveal, sizeof(FSSpec));
1652
err = ::AEPutParamDesc(&aeEvent, keyDirectObject, &fileList);
1654
err = ::AESend(&aeEvent, &aeReply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, nil, nil);
1656
::SetFrontProcess(&process);
1668
/* void launch (); */
1669
NS_IMETHODIMP nsLocalFile::Launch()
1672
nsresult rv = GetFSRefInternal(fsRef);
1676
OSErr err = ::LSOpenFSRef(&fsRef, NULL);
1677
return MacErrorMapper(err);
1681
//*****************************************************************************
1682
// nsLocalFile::nsILocalFileMac
1683
//*****************************************************************************
1685
#pragma mark [nsILocalFileMac]
1687
/* void initWithCFURL (in CFURLRef aCFURL); */
1688
NS_IMETHODIMP nsLocalFile::InitWithCFURL(CFURLRef aCFURL)
1690
NS_ENSURE_ARG(aCFURL);
1696
/* void initWithFSRef ([const] in FSRefPtr aFSRef); */
1697
NS_IMETHODIMP nsLocalFile::InitWithFSRef(const FSRef *aFSRef)
1699
NS_ENSURE_ARG(aFSRef);
1700
nsresult rv = NS_ERROR_FAILURE;
1702
CFURLRef newURLRef = ::CFURLCreateFromFSRef(kCFAllocatorDefault, aFSRef);
1704
SetBaseRef(newURLRef);
1705
::CFRelease(newURLRef);
1711
/* void initWithFSSpec ([const] in FSSpecPtr aFileSpec); */
1712
NS_IMETHODIMP nsLocalFile::InitWithFSSpec(const FSSpec *aFileSpec)
1714
NS_ENSURE_ARG(aFileSpec);
1717
OSErr err = ::FSpMakeFSRef(aFileSpec, &fsRef);
1719
return InitWithFSRef(&fsRef);
1720
else if (err == fnfErr) {
1722
FSSpec parentDirSpec;
1724
memset(&pBlock, 0, sizeof(CInfoPBRec));
1725
parentDirSpec.name[0] = 0;
1726
pBlock.dirInfo.ioVRefNum = aFileSpec->vRefNum;
1727
pBlock.dirInfo.ioDrDirID = aFileSpec->parID;
1728
pBlock.dirInfo.ioNamePtr = (StringPtr)parentDirSpec.name;
1729
pBlock.dirInfo.ioFDirIndex = -1; //get info on parID
1730
err = ::PBGetCatInfoSync(&pBlock);
1732
return MacErrorMapper(err);
1734
parentDirSpec.vRefNum = aFileSpec->vRefNum;
1735
parentDirSpec.parID = pBlock.dirInfo.ioDrParID;
1736
err = ::FSpMakeFSRef(&parentDirSpec, &fsRef);
1738
return MacErrorMapper(err);
1739
HFSUniStr255 unicodeName;
1740
err = ::HFSNameGetUnicodeName(aFileSpec->name, kTextEncodingUnknown, &unicodeName);
1742
return MacErrorMapper(err);
1743
nsresult rv = InitWithFSRef(&fsRef);
1746
return Append(nsDependentString(unicodeName.unicode, unicodeName.length));
1748
return MacErrorMapper(err);
1751
/* void initToAppWithCreatorCode (in OSType aAppCreator); */
1752
NS_IMETHODIMP nsLocalFile::InitToAppWithCreatorCode(OSType aAppCreator)
1755
OSErr err = ::LSFindApplicationForInfo(aAppCreator, nsnull, nsnull, &fsRef, nsnull);
1757
return MacErrorMapper(err);
1758
return InitWithFSRef(&fsRef);
1761
/* CFURLRef getCFURL (); */
1762
NS_IMETHODIMP nsLocalFile::GetCFURL(CFURLRef *_retval)
1764
NS_ENSURE_ARG_POINTER(_retval);
1765
CFURLRef whichURLRef = mFollowLinks ? mTargetRef : mBaseRef;
1767
::CFRetain(whichURLRef);
1768
*_retval = whichURLRef;
1769
return whichURLRef ? NS_OK : NS_ERROR_FAILURE;
1772
/* FSRef getFSRef (); */
1773
NS_IMETHODIMP nsLocalFile::GetFSRef(FSRef *_retval)
1775
NS_ENSURE_ARG_POINTER(_retval);
1776
return GetFSRefInternal(*_retval);
1779
/* FSSpec getFSSpec (); */
1780
NS_IMETHODIMP nsLocalFile::GetFSSpec(FSSpec *_retval)
1782
NS_ENSURE_ARG_POINTER(_retval);
1784
// Check we are correctly initialized.
1789
nsresult rv = GetFSRefInternal(fsRef);
1790
if (NS_SUCCEEDED(rv)) {
1791
// If the leaf node exists, things are simple.
1792
err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNone,
1793
nsnull, nsnull, _retval, nsnull);
1794
return MacErrorMapper(err);
1796
else if (rv == NS_ERROR_FILE_NOT_FOUND) {
1797
// If the parent of the leaf exists, make an FSSpec from that.
1798
CFURLRef parentURLRef = ::CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, mBaseRef);
1800
return NS_ERROR_FAILURE;
1803
if (::CFURLGetFSRef(parentURLRef, &fsRef)) {
1804
FSCatalogInfo catalogInfo;
1805
if ((err = ::FSGetCatalogInfo(&fsRef,
1806
kFSCatInfoVolume + kFSCatInfoNodeID + kFSCatInfoTextEncoding,
1807
&catalogInfo, nsnull, nsnull, nsnull)) == noErr) {
1808
nsAutoString leafName;
1809
if (NS_SUCCEEDED(GetLeafName(leafName))) {
1811
if ((err = ::UnicodeNameGetHFSName(leafName.Length(),
1813
catalogInfo.textEncodingHint,
1814
catalogInfo.nodeID == fsRtDirID,
1816
err = ::FSMakeFSSpec(catalogInfo.volume, catalogInfo.nodeID, hfsName, _retval);
1820
::CFRelease(parentURLRef);
1821
rv = MacErrorMapper(err);
1826
/* readonly attribute PRInt64 fileSizeWithResFork; */
1827
NS_IMETHODIMP nsLocalFile::GetFileSizeWithResFork(PRInt64 *aFileSizeWithResFork)
1829
NS_ENSURE_ARG_POINTER(aFileSizeWithResFork);
1832
nsresult rv = GetFSRefInternal(fsRef);
1836
FSCatalogInfo catalogInfo;
1837
OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoDataSizes + kFSCatInfoRsrcSizes,
1838
&catalogInfo, nsnull, nsnull, nsnull);
1840
return MacErrorMapper(err);
1842
*aFileSizeWithResFork = catalogInfo.dataLogicalSize + catalogInfo.rsrcLogicalSize;
1846
/* attribute OSType fileType; */
1847
NS_IMETHODIMP nsLocalFile::GetFileType(OSType *aFileType)
1849
NS_ENSURE_ARG_POINTER(aFileType);
1852
nsresult rv = GetFSRefInternal(fsRef);
1857
OSErr err = ::FSGetFinderInfo(&fsRef, &fInfo, nsnull, nsnull);
1859
return MacErrorMapper(err);
1860
*aFileType = fInfo.file.fileType;
1864
NS_IMETHODIMP nsLocalFile::SetFileType(OSType aFileType)
1867
nsresult rv = GetFSRefInternal(fsRef);
1871
OSErr err = ::FSChangeCreatorType(&fsRef, 0, aFileType);
1872
return MacErrorMapper(err);
1875
/* attribute OSType fileCreator; */
1876
NS_IMETHODIMP nsLocalFile::GetFileCreator(OSType *aFileCreator)
1878
NS_ENSURE_ARG_POINTER(aFileCreator);
1881
nsresult rv = GetFSRefInternal(fsRef);
1886
OSErr err = ::FSGetFinderInfo(&fsRef, &fInfo, nsnull, nsnull);
1888
return MacErrorMapper(err);
1889
*aFileCreator = fInfo.file.fileCreator;
1893
NS_IMETHODIMP nsLocalFile::SetFileCreator(OSType aFileCreator)
1896
nsresult rv = GetFSRefInternal(fsRef);
1900
OSErr err = ::FSChangeCreatorType(&fsRef, aFileCreator, 0);
1901
return MacErrorMapper(err);
1904
/* void setFileTypeAndCreatorFromMIMEType (in string aMIMEType); */
1905
NS_IMETHODIMP nsLocalFile::SetFileTypeAndCreatorFromMIMEType(const char *aMIMEType)
1907
// XXX - This should be cut from the API. Would create an evil dependency.
1908
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
1909
return NS_ERROR_NOT_IMPLEMENTED;
1912
/* void setFileTypeAndCreatorFromExtension (in string aExtension); */
1913
NS_IMETHODIMP nsLocalFile::SetFileTypeAndCreatorFromExtension(const char *aExtension)
1915
// XXX - This should be cut from the API. Would create an evil dependency.
1916
NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
1917
return NS_ERROR_NOT_IMPLEMENTED;
1920
/* void launchWithDoc (in nsILocalFile aDocToLoad, in boolean aLaunchInBackground); */
1921
NS_IMETHODIMP nsLocalFile::LaunchWithDoc(nsILocalFile *aDocToLoad, PRBool aLaunchInBackground)
1923
PRBool isExecutable;
1924
nsresult rv = IsExecutable(&isExecutable);
1928
return NS_ERROR_FILE_EXECUTION_FAILED;
1930
FSRef appFSRef, docFSRef;
1931
rv = GetFSRefInternal(appFSRef);
1936
nsCOMPtr<nsILocalFileMac> macDoc = do_QueryInterface(aDocToLoad);
1937
rv = macDoc->GetFSRef(&docFSRef);
1942
LSLaunchFlags theLaunchFlags = kLSLaunchDefaults;
1943
LSLaunchFSRefSpec thelaunchSpec;
1945
if (aLaunchInBackground)
1946
theLaunchFlags |= kLSLaunchDontSwitch;
1947
memset(&thelaunchSpec, 0, sizeof(LSLaunchFSRefSpec));
1949
thelaunchSpec.appRef = &appFSRef;
1951
thelaunchSpec.numDocs = 1;
1952
thelaunchSpec.itemRefs = &docFSRef;
1954
thelaunchSpec.launchFlags = theLaunchFlags;
1956
OSErr err = ::LSOpenFromRefSpec(&thelaunchSpec, NULL);
1958
return MacErrorMapper(err);
1963
/* void openDocWithApp (in nsILocalFile aAppToOpenWith, in boolean aLaunchInBackground); */
1964
NS_IMETHODIMP nsLocalFile::OpenDocWithApp(nsILocalFile *aAppToOpenWith, PRBool aLaunchInBackground)
1969
FSRef docFSRef, appFSRef;
1970
rv = GetFSRefInternal(docFSRef);
1974
if (aAppToOpenWith) {
1975
nsCOMPtr<nsILocalFileMac> appFileMac = do_QueryInterface(aAppToOpenWith, &rv);
1979
PRBool isExecutable;
1980
rv = appFileMac->IsExecutable(&isExecutable);
1984
return NS_ERROR_FILE_EXECUTION_FAILED;
1986
rv = appFileMac->GetFSRef(&appFSRef);
1992
rv = GetFileCreator(&fileCreator);
1996
err = ::LSFindApplicationForInfo(fileCreator, nsnull, nsnull, &appFSRef, nsnull);
1998
return MacErrorMapper(err);
2001
LSLaunchFlags theLaunchFlags = kLSLaunchDefaults;
2002
LSLaunchFSRefSpec thelaunchSpec;
2004
if (aLaunchInBackground)
2005
theLaunchFlags |= kLSLaunchDontSwitch;
2006
memset(&thelaunchSpec, 0, sizeof(LSLaunchFSRefSpec));
2008
thelaunchSpec.appRef = &appFSRef;
2009
thelaunchSpec.numDocs = 1;
2010
thelaunchSpec.itemRefs = &docFSRef;
2011
thelaunchSpec.launchFlags = theLaunchFlags;
2013
err = ::LSOpenFromRefSpec(&thelaunchSpec, NULL);
2015
return MacErrorMapper(err);
2020
/* boolean isPackage (); */
2021
NS_IMETHODIMP nsLocalFile::IsPackage(PRBool *_retval)
2023
NS_ENSURE_ARG(_retval);
2024
*_retval = PR_FALSE;
2027
nsresult rv = GetFSRefInternal(fsRef);
2031
FSCatalogInfo catalogInfo;
2032
OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags + kFSCatInfoFinderInfo,
2033
&catalogInfo, nsnull, nsnull, nsnull);
2035
return MacErrorMapper(err);
2036
if ((catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) != 0) {
2037
FileInfo *fInfoPtr = (FileInfo *)(catalogInfo.finderInfo);
2038
if ((fInfoPtr->finderFlags & kHasBundle) != 0) {
2042
// Folders ending with ".app" are also considered to
2043
// be packages, even if the top-level folder doesn't have bundle set
2045
if (NS_SUCCEEDED(rv = GetNativeLeafName(name))) {
2046
const char *extPtr = strrchr(name.get(), '.');
2048
if ((nsCRT::strcasecmp(extPtr, ".app") == 0))
2058
nsLocalFile::GetBundleDisplayName(nsAString& outBundleName)
2060
PRBool isPackage = PR_FALSE;
2061
nsresult rv = IsPackage(&isPackage);
2062
if (NS_FAILED(rv) || !isPackage)
2063
return NS_ERROR_FAILURE;
2066
rv = GetLeafName(name);
2070
PRInt32 length = name.Length();
2071
if (Substring(name, length - 4, length).EqualsLiteral(".app")) {
2072
// 4 characters in ".app"
2073
outBundleName = Substring(name, 0, length - 4);
2076
outBundleName = name;
2082
nsLocalFile::GetBundleIdentifier(nsACString& outBundleIdentifier)
2084
nsresult rv = NS_ERROR_FAILURE;
2087
if (NS_SUCCEEDED(GetCFURL(&urlRef))) {
2088
CFBundleRef bundle = ::CFBundleCreate(NULL, urlRef);
2090
CFStringRef bundleIdentifier = ::CFBundleGetIdentifier(bundle);
2091
if (bundleIdentifier)
2092
rv = CFStringReftoUTF8(bundleIdentifier, outBundleIdentifier);
2094
::CFRelease(bundle);
2096
::CFRelease(urlRef);
2103
//*****************************************************************************
2104
// nsLocalFile Methods
2105
//*****************************************************************************
2107
#pragma mark [Protected Methods]
2109
nsresult nsLocalFile::SetBaseRef(CFURLRef aCFURLRef)
2111
NS_ENSURE_ARG(aCFURLRef);
2113
::CFRetain(aCFURLRef);
2115
::CFRelease(mBaseRef);
2116
mBaseRef = aCFURLRef;
2118
mFollowLinksDirty = PR_TRUE;
2120
mCachedFSRefValid = PR_FALSE;
2124
nsresult nsLocalFile::UpdateTargetRef()
2126
// Check we are correctly initialized.
2129
if (mFollowLinksDirty) {
2131
::CFRelease(mTargetRef);
2132
mTargetRef = nsnull;
2135
mTargetRef = mBaseRef;
2136
::CFRetain(mTargetRef);
2139
if (::CFURLGetFSRef(mBaseRef, &fsRef)) {
2140
Boolean targetIsFolder, wasAliased;
2141
if (FSResolveAliasFile(&fsRef, true /*resolveAliasChains*/,
2142
&targetIsFolder, &wasAliased) == noErr && wasAliased) {
2143
::CFRelease(mTargetRef);
2144
mTargetRef = CFURLCreateFromFSRef(NULL, &fsRef);
2146
return NS_ERROR_FAILURE;
2149
mFollowLinksDirty = PR_FALSE;
2155
nsresult nsLocalFile::GetFSRefInternal(FSRef& aFSRef, PRBool bForceUpdateCache)
2157
if (bForceUpdateCache || !mCachedFSRefValid) {
2158
mCachedFSRefValid = PR_FALSE;
2159
CFURLRef whichURLRef = mFollowLinks ? mTargetRef : mBaseRef;
2160
NS_ENSURE_TRUE(whichURLRef, NS_ERROR_NULL_POINTER);
2161
if (::CFURLGetFSRef(whichURLRef, &mCachedFSRef))
2162
mCachedFSRefValid = PR_TRUE;
2164
if (mCachedFSRefValid) {
2165
aFSRef = mCachedFSRef;
2168
// CFURLGetFSRef only returns a Boolean for success,
2169
// so we have to assume what the error was. This is
2170
// the only probable cause.
2171
return NS_ERROR_FILE_NOT_FOUND;
2174
nsresult nsLocalFile::GetPathInternal(nsACString& path)
2176
nsresult rv = NS_ERROR_FAILURE;
2178
CFURLRef whichURLRef = mFollowLinks ? mTargetRef : mBaseRef;
2179
NS_ENSURE_TRUE(whichURLRef, NS_ERROR_NULL_POINTER);
2181
CFStringRef pathStrRef = ::CFURLCopyFileSystemPath(whichURLRef, kCFURLPOSIXPathStyle);
2183
rv = CFStringReftoUTF8(pathStrRef, path);
2184
::CFRelease(pathStrRef);
2189
nsresult nsLocalFile::CopyInternal(nsIFile* aParentDir,
2190
const nsAString& newName,
2193
// Check we are correctly initialized.
2196
StFollowLinksState srcFollowState(*this, followLinks);
2200
FSRef srcFSRef, newFSRef;
2202
rv = GetFSRefInternal(srcFSRef);
2206
nsCOMPtr<nsIFile> newParentDir = aParentDir;
2208
if (!newParentDir) {
2209
if (newName.IsEmpty())
2210
return NS_ERROR_INVALID_ARG;
2211
rv = GetParent(getter_AddRefs(newParentDir));
2216
// If newParentDir does not exist, create it
2218
rv = newParentDir->Exists(&exists);
2222
rv = newParentDir->Create(nsIFile::DIRECTORY_TYPE, 0777);
2228
nsCOMPtr<nsILocalFileMac> newParentDirMac(do_QueryInterface(newParentDir));
2229
if (!newParentDirMac)
2230
return NS_ERROR_NO_INTERFACE;
2231
rv = newParentDirMac->GetFSRef(&destFSRef);
2236
::FSCopyObject(&srcFSRef, &destFSRef, newName.Length(),
2237
newName.Length() ? PromiseFlatString(newName).get() : NULL,
2238
0, kFSCatInfoNone, false, false, NULL, NULL, &newFSRef);
2240
return MacErrorMapper(err);
2243
const PRInt64 kMillisecsPerSec = 1000LL;
2244
const PRInt64 kUTCDateTimeFractionDivisor = 65535LL;
2246
PRInt64 nsLocalFile::HFSPlustoNSPRTime(const UTCDateTime& utcTime)
2248
// Start with seconds since Jan. 1, 1904 GMT
2249
PRInt64 result = ((PRInt64)utcTime.highSeconds << 32) + (PRInt64)utcTime.lowSeconds;
2250
// Subtract to convert to NSPR epoch of 1970
2251
result -= kJanuaryFirst1970Seconds;
2252
// Convert to millisecs
2253
result *= kMillisecsPerSec;
2254
// Convert the fraction to millisecs and add it
2255
result += ((PRInt64)utcTime.fraction * kMillisecsPerSec) / kUTCDateTimeFractionDivisor;
2260
void nsLocalFile::NSPRtoHFSPlusTime(PRInt64 nsprTime, UTCDateTime& utcTime)
2262
PRInt64 fraction = nsprTime % kMillisecsPerSec;
2263
PRInt64 seconds = (nsprTime / kMillisecsPerSec) + kJanuaryFirst1970Seconds;
2264
utcTime.highSeconds = (UInt16)((PRUint64)seconds >> 32);
2265
utcTime.lowSeconds = (UInt32)seconds;
2266
utcTime.fraction = (UInt16)((fraction * kUTCDateTimeFractionDivisor) / kMillisecsPerSec);
2269
nsresult nsLocalFile::CFStringReftoUTF8(CFStringRef aInStrRef, nsACString& aOutStr)
2271
nsresult rv = NS_ERROR_FAILURE;
2272
CFIndex usedBufLen, inStrLen = ::CFStringGetLength(aInStrRef);
2273
CFIndex charsConverted = ::CFStringGetBytes(aInStrRef, CFRangeMake(0, inStrLen),
2274
kCFStringEncodingUTF8, 0, PR_FALSE, nsnull, 0, &usedBufLen);
2275
if (charsConverted == inStrLen) {
2276
#if 0 /* bird: too new? */
2277
aOutStr.SetLength(usedBufLen);
2278
if (aOutStr.Length() != usedBufLen)
2279
return NS_ERROR_OUT_OF_MEMORY;
2280
UInt8 *buffer = (UInt8*) aOutStr.BeginWriting();
2282
::CFStringGetBytes(aInStrRef, CFRangeMake(0, inStrLen),
2283
kCFStringEncodingUTF8, 0, false, buffer, usedBufLen, &usedBufLen);
2286
nsAutoBuffer<UInt8, FILENAME_BUFFER_SIZE> buffer;
2287
if (buffer.EnsureElemCapacity(usedBufLen + 1)) {
2288
::CFStringGetBytes(aInStrRef, CFRangeMake(0, inStrLen),
2289
kCFStringEncodingUTF8, 0, false, buffer.get(), usedBufLen, &usedBufLen);
2290
buffer.get()[usedBufLen] = '\0';
2291
aOutStr.Assign(nsDependentCString((char*)buffer.get()));
2302
nsLocalFile::Equals(nsIHashable* aOther, PRBool *aResult)
2304
return EqualsInternal(aOther, PR_FALSE, aResult);
2308
nsLocalFile::GetHashCode(PRUint32 *aResult)
2310
CFStringRef pathStrRef = ::CFURLCopyFileSystemPath(mBaseRef, kCFURLPOSIXPathStyle);
2312
CFStringReftoUTF8(pathStrRef, path);
2313
*aResult = HashString(path);
2317
//*****************************************************************************
2319
//*****************************************************************************
2321
#pragma mark [Global Functions]
2323
void nsLocalFile::GlobalInit()
2327
void nsLocalFile::GlobalShutdown()
2331
nsresult NS_NewLocalFile(const nsAString& path, PRBool followLinks, nsILocalFile* *result)
2333
nsLocalFile* file = new nsLocalFile;
2335
return NS_ERROR_OUT_OF_MEMORY;
2338
file->SetFollowLinks(followLinks);
2340
if (!path.IsEmpty()) {
2341
nsresult rv = file->InitWithPath(path);
2342
if (NS_FAILED(rv)) {
2351
nsresult NS_NewNativeLocalFile(const nsACString& path, PRBool followLinks, nsILocalFile **result)
2353
return NS_NewLocalFile(NS_ConvertUTF8toUTF16(path), followLinks, result);
2356
nsresult NS_NewLocalFileWithFSSpec(const FSSpec* inSpec, PRBool followLinks, nsILocalFileMac **result)
2358
nsLocalFile* file = new nsLocalFile();
2360
return NS_ERROR_OUT_OF_MEMORY;
2363
file->SetFollowLinks(followLinks);
2365
nsresult rv = file->InitWithFSSpec(inSpec);
2366
if (NS_FAILED(rv)) {
2374
nsresult NS_NewLocalFileWithFSRef(const FSRef* aFSRef, PRBool aFollowLinks, nsILocalFileMac** result)
2376
nsLocalFile* file = new nsLocalFile();
2378
return NS_ERROR_OUT_OF_MEMORY;
2381
file->SetFollowLinks(aFollowLinks);
2383
nsresult rv = file->InitWithFSRef(aFSRef);
2384
if (NS_FAILED(rv)) {
2392
//*****************************************************************************
2394
//*****************************************************************************
2396
static nsresult MacErrorMapper(OSErr inErr)
2407
outErr = NS_ERROR_FILE_NOT_FOUND;
2411
outErr = NS_ERROR_FILE_ALREADY_EXISTS;
2415
outErr = NS_ERROR_FILE_DISK_FULL;
2419
outErr = NS_ERROR_FILE_IS_LOCKED;
2422
// Can't find good map for some
2424
outErr = NS_ERROR_FAILURE;
2428
outErr = NS_ERROR_FAILURE;
2434
static OSErr FindRunningAppBySignature(OSType aAppSig, ProcessSerialNumber& outPsn)
2436
ProcessInfoRec info;
2439
outPsn.highLongOfPSN = 0;
2440
outPsn.lowLongOfPSN = kNoProcess;
2444
err = ::GetNextProcess(&outPsn);
2445
if (err == procNotFound)
2449
info.processInfoLength = sizeof(ProcessInfoRec);
2450
info.processName = nil;
2451
info.processAppSpec = nil;
2452
err = ::GetProcessInformation(&outPsn, &info);
2456
if (info.processSignature == aAppSig)
2459
return procNotFound;
2462
// Convert a UTF-8 string to a UTF-16 string while normalizing to
2463
// Normalization Form C (composed Unicode). We need this because
2464
// Mac OS X file system uses NFD (Normalization Form D : decomposed Unicode)
2465
// while most other OS', server-side programs usually expect NFC.
2467
typedef void (*UnicodeNormalizer) (CFMutableStringRef, CFStringNormalizationForm);
2468
static void CopyUTF8toUTF16NFC(const nsACString& aSrc, nsAString& aResult)
2470
static PRBool sChecked = PR_FALSE;
2471
static UnicodeNormalizer sUnicodeNormalizer = NULL;
2473
// CFStringNormalize was not introduced until Mac OS 10.2
2475
CFBundleRef carbonBundle =
2476
CFBundleGetBundleWithIdentifier(CFSTR("com.apple.Carbon"));
2478
sUnicodeNormalizer = (UnicodeNormalizer)
2479
::CFBundleGetFunctionPointerForName(carbonBundle,
2480
CFSTR("CFStringNormalize"));
2484
if (!sUnicodeNormalizer) { // OS X 10.2 or earlier
2485
CopyUTF8toUTF16(aSrc, aResult);
2489
const nsAFlatCString &inFlatSrc = PromiseFlatCString(aSrc);
2491
// The number of 16bit code units in a UTF-16 string will never be
2492
// larger than the number of bytes in the corresponding UTF-8 string.
2493
CFMutableStringRef inStr =
2494
::CFStringCreateMutable(NULL, inFlatSrc.Length());
2497
CopyUTF8toUTF16(aSrc, aResult);
2501
::CFStringAppendCString(inStr, inFlatSrc.get(), kCFStringEncodingUTF8);
2503
sUnicodeNormalizer(inStr, kCFStringNormalizationFormC);
2505
CFIndex length = CFStringGetLength(inStr);
2506
const UniChar* chars = CFStringGetCharactersPtr(inStr);
2509
aResult.Assign(chars, length);
2511
nsAutoBuffer<UniChar, FILENAME_BUFFER_SIZE> buffer;
2512
if (!buffer.EnsureElemCapacity(length))
2513
CopyUTF8toUTF16(aSrc, aResult);
2515
CFStringGetCharacters(inStr, CFRangeMake(0, length), buffer.get());
2516
aResult.Assign(buffer.get(), length);