VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/xpcom/io/nsLocalFileOSX.cpp@ 1

最後變更 在這個檔案從1是 1,由 vboxsync 提交於 55 年 前

import

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 62.9 KB
 
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
4 *
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/
9 *
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
13 * License.
14 *
15 * The Original Code is mozilla.org code.
16 *
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.
21 *
22 * Contributor(s):
23 * Conrad Carlen <ccarlen@netscape.com>
24 * Jungshik Shin <jshin@mailaps.org>
25 *
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
37 *
38 * ***** END LICENSE BLOCK ***** */
39
40#include "nsLocalFile.h"
41
42#include "nsString.h"
43#include "nsReadableUtils.h"
44#include "nsISimpleEnumerator.h"
45#include "nsITimelineService.h"
46#include "nsVoidArray.h"
47
48#include "plbase64.h"
49#include "prmem.h"
50#include "nsCRT.h"
51
52#include "MoreFilesX.h"
53#include "FSCopyObject.h"
54#include "nsAutoBuffer.h"
55
56// Mac Includes
57#include <Aliases.h>
58#include <Gestalt.h>
59#include <AppleEvents.h>
60#include <AEDataModel.h>
61#include <Processes.h>
62#include <Carbon/Carbon.h>
63
64// Unix Includes
65#include <sys/stat.h>
66
67//*****************************************************************************
68// Static Function Prototypes
69//*****************************************************************************
70
71static nsresult MacErrorMapper(OSErr inErr);
72static OSErr FindRunningAppBySignature(OSType aAppSig, ProcessSerialNumber& outPsn);
73static void CopyUTF8toUTF16NFC(const nsACString& aSrc, nsAString& aResult);
74
75//*****************************************************************************
76// Local Helper Classes
77//*****************************************************************************
78
79#pragma mark -
80#pragma mark [FSRef operator==]
81
82bool operator==(const FSRef& lhs, const FSRef& rhs)
83{
84 return (::FSCompareFSRefs(&lhs, &rhs) == noErr);
85}
86
87#pragma mark -
88#pragma mark [StFollowLinksState]
89
90class StFollowLinksState
91{
92 public:
93 StFollowLinksState(nsLocalFile& aFile) :
94 mFile(aFile)
95 {
96 mFile.GetFollowLinks(&mSavedState);
97 }
98
99 StFollowLinksState(nsLocalFile& aFile, PRBool followLinksState) :
100 mFile(aFile)
101 {
102 mFile.GetFollowLinks(&mSavedState);
103 mFile.SetFollowLinks(followLinksState);
104 }
105
106 ~StFollowLinksState()
107 {
108 mFile.SetFollowLinks(mSavedState);
109 }
110
111 private:
112 nsLocalFile& mFile;
113 PRBool mSavedState;
114};
115
116#pragma mark -
117#pragma mark [nsDirEnumerator]
118
119class nsDirEnumerator : public nsISimpleEnumerator
120{
121 public:
122
123 NS_DECL_ISUPPORTS
124
125 nsDirEnumerator() :
126 mIterator(nsnull),
127 mFSRefsArray(nsnull),
128 mArrayCnt(0), mArrayIndex(0)
129 {
130 }
131
132 nsresult Init(nsILocalFileMac* parent)
133 {
134 NS_ENSURE_ARG(parent);
135
136 OSErr err;
137 nsresult rv;
138 FSRef parentRef;
139
140 rv = parent->GetFSRef(&parentRef);
141 if (NS_FAILED(rv))
142 return rv;
143
144 mFSRefsArray = (FSRef *)nsMemory::Alloc(sizeof(FSRef)
145 * kRequestCountPerIteration);
146 if (!mFSRefsArray)
147 return NS_ERROR_OUT_OF_MEMORY;
148
149 err = ::FSOpenIterator(&parentRef, kFSIterateFlat, &mIterator);
150 if (err != noErr)
151 return MacErrorMapper(err);
152
153 return NS_OK;
154 }
155
156 NS_IMETHOD HasMoreElements(PRBool *result)
157 {
158 if (mNext == nsnull) {
159 if (mArrayIndex >= mArrayCnt) {
160 ItemCount actualCnt;
161 OSErr err = ::FSGetCatalogInfoBulk(mIterator,
162 kRequestCountPerIteration,
163 &actualCnt,
164 nsnull,
165 kFSCatInfoNone,
166 nsnull,
167 mFSRefsArray,
168 nsnull,
169 nsnull);
170
171 if (err == noErr || err == errFSNoMoreItems) {
172 mArrayCnt = actualCnt;
173 mArrayIndex = 0;
174 }
175 }
176 if (mArrayIndex < mArrayCnt) {
177 nsLocalFile *newFile = new nsLocalFile;
178 if (!newFile)
179 return NS_ERROR_OUT_OF_MEMORY;
180 FSRef fsRef = mFSRefsArray[mArrayIndex];
181 if (NS_FAILED(newFile->InitWithFSRef(&fsRef)))
182 return NS_ERROR_FAILURE;
183 mArrayIndex++;
184 mNext = newFile;
185 }
186 }
187 *result = mNext != nsnull;
188 return NS_OK;
189 }
190
191 NS_IMETHOD GetNext(nsISupports **result)
192 {
193 NS_ENSURE_ARG_POINTER(result);
194 *result = nsnull;
195
196 nsresult rv;
197 PRBool hasMore;
198 rv = HasMoreElements(&hasMore);
199 if (NS_FAILED(rv)) return rv;
200
201 *result = mNext; // might return nsnull
202 NS_IF_ADDREF(*result);
203
204 mNext = nsnull;
205 return NS_OK;
206 }
207
208 private:
209 ~nsDirEnumerator()
210 {
211 if (mIterator)
212 ::FSCloseIterator(mIterator);
213 if (mFSRefsArray)
214 nsMemory::Free(mFSRefsArray);
215 }
216
217 protected:
218 // According to Apple doc, request the number of objects
219 // per call that will fit in 4 VM pages.
220 enum {
221 kRequestCountPerIteration = ((4096 * 4) / sizeof(FSRef))
222 };
223
224 nsCOMPtr<nsILocalFileMac> mNext;
225
226 FSIterator mIterator;
227 FSRef *mFSRefsArray;
228 PRInt32 mArrayCnt, mArrayIndex;
229};
230
231NS_IMPL_ISUPPORTS1(nsDirEnumerator, nsISimpleEnumerator)
232
233#pragma mark -
234#pragma mark [StAEDesc]
235
236class StAEDesc: public AEDesc
237{
238public:
239 StAEDesc()
240 {
241 descriptorType = typeNull;
242 dataHandle = nil;
243 }
244
245 ~StAEDesc()
246 {
247 ::AEDisposeDesc(this);
248 }
249};
250
251#define FILENAME_BUFFER_SIZE 512
252
253//*****************************************************************************
254// nsLocalFile
255//*****************************************************************************
256
257const char nsLocalFile::kPathSepChar = '/';
258const PRUnichar nsLocalFile::kPathSepUnichar = '/';
259
260// The HFS+ epoch is Jan. 1, 1904 GMT - differs from HFS in which times were local
261// The NSPR epoch is Jan. 1, 1970 GMT
262// 2082844800 is the difference in seconds between those dates
263const PRInt64 nsLocalFile::kJanuaryFirst1970Seconds = 2082844800LL;
264
265#pragma mark -
266#pragma mark [CTORs/DTOR]
267
268nsLocalFile::nsLocalFile() :
269 mBaseRef(nsnull),
270 mTargetRef(nsnull),
271 mCachedFSRefValid(PR_FALSE),
272 mFollowLinks(PR_TRUE),
273 mFollowLinksDirty(PR_TRUE)
274{
275}
276
277nsLocalFile::nsLocalFile(const nsLocalFile& src) :
278 mBaseRef(src.mBaseRef),
279 mTargetRef(src.mTargetRef),
280 mCachedFSRef(src.mCachedFSRef),
281 mCachedFSRefValid(src.mCachedFSRefValid),
282 mFollowLinks(src.mFollowLinks),
283 mFollowLinksDirty(src.mFollowLinksDirty)
284{
285 // A CFURLRef is immutable so no need to copy, just retain.
286 if (mBaseRef)
287 ::CFRetain(mBaseRef);
288 if (mTargetRef)
289 ::CFRetain(mTargetRef);
290}
291
292nsLocalFile::~nsLocalFile()
293{
294 if (mBaseRef)
295 ::CFRelease(mBaseRef);
296 if (mTargetRef)
297 ::CFRelease(mTargetRef);
298}
299
300
301//*****************************************************************************
302// nsLocalFile::nsISupports
303//*****************************************************************************
304#pragma mark -
305#pragma mark [nsISupports]
306
307NS_IMPL_THREADSAFE_ISUPPORTS3(nsLocalFile,
308 nsILocalFileMac,
309 nsILocalFile,
310 nsIFile)
311
312NS_METHOD nsLocalFile::nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
313{
314 NS_ENSURE_ARG_POINTER(aInstancePtr);
315 NS_ENSURE_NO_AGGREGATION(outer);
316
317 nsLocalFile* inst = new nsLocalFile();
318 if (inst == NULL)
319 return NS_ERROR_OUT_OF_MEMORY;
320
321 nsresult rv = inst->QueryInterface(aIID, aInstancePtr);
322 if (NS_FAILED(rv))
323 {
324 delete inst;
325 return rv;
326 }
327 return NS_OK;
328}
329
330
331//*****************************************************************************
332// nsLocalFile::nsIFile
333//*****************************************************************************
334#pragma mark -
335#pragma mark [nsIFile]
336
337/* void append (in AString node); */
338NS_IMETHODIMP nsLocalFile::Append(const nsAString& aNode)
339{
340 return AppendNative(NS_ConvertUCS2toUTF8(aNode));
341}
342
343/* [noscript] void appendNative (in ACString node); */
344NS_IMETHODIMP nsLocalFile::AppendNative(const nsACString& aNode)
345{
346 if (!mBaseRef)
347 return NS_ERROR_NOT_INITIALIZED;
348
349 nsACString::const_iterator start, end;
350 aNode.BeginReading(start);
351 aNode.EndReading(end);
352 if (FindCharInReadable(kPathSepChar, start, end))
353 return NS_ERROR_FILE_UNRECOGNIZED_PATH;
354
355 CFStringRef nodeStrRef = ::CFStringCreateWithCString(kCFAllocatorDefault,
356 PromiseFlatCString(aNode).get(),
357 kCFStringEncodingUTF8);
358 if (nodeStrRef) {
359 CFURLRef newRef = ::CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault,
360 mBaseRef, nodeStrRef, PR_FALSE);
361 ::CFRelease(nodeStrRef);
362 if (newRef) {
363 SetBaseRef(newRef);
364 ::CFRelease(newRef);
365 return NS_OK;
366 }
367 }
368 return NS_ERROR_FAILURE;
369}
370
371/* void normalize (); */
372NS_IMETHODIMP nsLocalFile::Normalize()
373{
374 return NS_OK;
375}
376
377/* void create (in unsigned long type, in unsigned long permissions); */
378NS_IMETHODIMP nsLocalFile::Create(PRUint32 type, PRUint32 permissions)
379{
380 if (type != NORMAL_FILE_TYPE && type != DIRECTORY_TYPE)
381 return NS_ERROR_FILE_UNKNOWN_TYPE;
382 if (!mBaseRef)
383 return NS_ERROR_NOT_INITIALIZED;
384
385 nsStringArray nonExtantNodes;
386 CFURLRef pathURLRef = mBaseRef;
387 FSRef pathFSRef;
388 CFStringRef leafStrRef = nsnull;
389 nsAutoBuffer<UniChar, FILENAME_BUFFER_SIZE> buffer;
390 Boolean success;
391
392 // Work backwards through the path to find the last node which
393 // exists. Place the nodes which don't exist in an array and we'll
394 // create those below.
395 while ((success = ::CFURLGetFSRef(pathURLRef, &pathFSRef)) == false) {
396 leafStrRef = ::CFURLCopyLastPathComponent(pathURLRef);
397 if (!leafStrRef)
398 break;
399 CFIndex leafLen = ::CFStringGetLength(leafStrRef);
400 if (!buffer.EnsureElemCapacity(leafLen + 1))
401 break;
402 ::CFStringGetCharacters(leafStrRef, CFRangeMake(0, leafLen), buffer.get());
403 buffer.get()[leafLen] = '\0';
404 nonExtantNodes.AppendString(nsString(nsDependentString(buffer.get())));
405 ::CFRelease(leafStrRef);
406 leafStrRef = nsnull;
407
408 // Get the parent of the leaf for the next go round
409 CFURLRef parent = ::CFURLCreateCopyDeletingLastPathComponent(NULL, pathURLRef);
410 if (!parent)
411 break;
412 if (pathURLRef != mBaseRef)
413 ::CFRelease(pathURLRef);
414 pathURLRef = parent;
415 }
416 if (pathURLRef != mBaseRef)
417 ::CFRelease(pathURLRef);
418 if (leafStrRef != nsnull)
419 ::CFRelease(leafStrRef);
420 if (!success)
421 return NS_ERROR_FAILURE;
422 PRInt32 nodesToCreate = nonExtantNodes.Count();
423 if (nodesToCreate == 0)
424 return NS_ERROR_FILE_ALREADY_EXISTS;
425
426 OSErr err;
427 nsAutoString nextNodeName;
428 for (PRInt32 i = nodesToCreate - 1; i > 0; i--) {
429 nonExtantNodes.StringAt(i, nextNodeName);
430 err = ::FSCreateDirectoryUnicode(&pathFSRef,
431 nextNodeName.Length(),
432 (const UniChar *)nextNodeName.get(),
433 kFSCatInfoNone,
434 nsnull, &pathFSRef, nsnull, nsnull);
435 if (err != noErr)
436 return MacErrorMapper(err);
437 }
438 nonExtantNodes.StringAt(0, nextNodeName);
439 if (type == NORMAL_FILE_TYPE) {
440 err = ::FSCreateFileUnicode(&pathFSRef,
441 nextNodeName.Length(),
442 (const UniChar *)nextNodeName.get(),
443 kFSCatInfoNone,
444 nsnull, nsnull, nsnull);
445 }
446 else {
447 err = ::FSCreateDirectoryUnicode(&pathFSRef,
448 nextNodeName.Length(),
449 (const UniChar *)nextNodeName.get(),
450 kFSCatInfoNone,
451 nsnull, nsnull, nsnull, nsnull);
452 }
453
454 return MacErrorMapper(err);
455}
456
457/* attribute AString leafName; */
458NS_IMETHODIMP nsLocalFile::GetLeafName(nsAString& aLeafName)
459{
460 nsCAutoString nativeString;
461 nsresult rv = GetNativeLeafName(nativeString);
462 if (NS_FAILED(rv))
463 return rv;
464 CopyUTF8toUTF16NFC(nativeString, aLeafName);
465 return NS_OK;
466}
467
468NS_IMETHODIMP nsLocalFile::SetLeafName(const nsAString& aLeafName)
469{
470 return SetNativeLeafName(NS_ConvertUCS2toUTF8(aLeafName));
471}
472
473/* [noscript] attribute ACString nativeLeafName; */
474NS_IMETHODIMP nsLocalFile::GetNativeLeafName(nsACString& aNativeLeafName)
475{
476 if (!mBaseRef)
477 return NS_ERROR_NOT_INITIALIZED;
478 nsresult rv = NS_ERROR_FAILURE;
479 CFStringRef leafStrRef = ::CFURLCopyLastPathComponent(mBaseRef);
480 if (leafStrRef) {
481 rv = CFStringReftoUTF8(leafStrRef, aNativeLeafName);
482 ::CFRelease(leafStrRef);
483 }
484 return rv;
485}
486
487NS_IMETHODIMP nsLocalFile::SetNativeLeafName(const nsACString& aNativeLeafName)
488{
489 if (!mBaseRef)
490 return NS_ERROR_NOT_INITIALIZED;
491 nsresult rv = NS_ERROR_FAILURE;
492 CFURLRef parentURLRef = ::CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, mBaseRef);
493 if (parentURLRef) {
494 CFStringRef nodeStrRef = ::CFStringCreateWithCString(kCFAllocatorDefault,
495 PromiseFlatCString(aNativeLeafName).get(),
496 kCFStringEncodingUTF8);
497
498 if (nodeStrRef) {
499 CFURLRef newURLRef = ::CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault,
500 parentURLRef, nodeStrRef, PR_FALSE);
501 if (newURLRef) {
502 SetBaseRef(newURLRef);
503 ::CFRelease(newURLRef);
504 rv = NS_OK;
505 }
506 ::CFRelease(nodeStrRef);
507 }
508 ::CFRelease(parentURLRef);
509 }
510 return rv;
511}
512
513/* void copyTo (in nsIFile newParentDir, in AString newName); */
514NS_IMETHODIMP nsLocalFile::CopyTo(nsIFile *newParentDir, const nsAString& newName)
515{
516 return MoveCopy(newParentDir, newName, PR_TRUE, PR_FALSE);
517}
518
519/* [noscrpit] void CopyToNative (in nsIFile newParentDir, in ACString newName); */
520NS_IMETHODIMP nsLocalFile::CopyToNative(nsIFile *newParentDir, const nsACString& newName)
521{
522 return MoveCopy(newParentDir, NS_ConvertUTF8toUCS2(newName), PR_TRUE, PR_FALSE);
523}
524
525/* void copyToFollowingLinks (in nsIFile newParentDir, in AString newName); */
526NS_IMETHODIMP nsLocalFile::CopyToFollowingLinks(nsIFile *newParentDir, const nsAString& newName)
527{
528 return MoveCopy(newParentDir, newName, PR_TRUE, PR_TRUE);
529}
530
531/* [noscript] void copyToFollowingLinksNative (in nsIFile newParentDir, in ACString newName); */
532NS_IMETHODIMP nsLocalFile::CopyToFollowingLinksNative(nsIFile *newParentDir, const nsACString& newName)
533{
534 return MoveCopy(newParentDir, NS_ConvertUTF8toUCS2(newName), PR_TRUE, PR_TRUE);
535}
536
537/* void moveTo (in nsIFile newParentDir, in AString newName); */
538NS_IMETHODIMP nsLocalFile::MoveTo(nsIFile *newParentDir, const nsAString& newName)
539{
540 return MoveCopy(newParentDir, newName, FALSE, FALSE);
541}
542
543/* [noscript] void moveToNative (in nsIFile newParentDir, in ACString newName); */
544NS_IMETHODIMP nsLocalFile::MoveToNative(nsIFile *newParentDir, const nsACString& newName)
545{
546 return MoveCopy(newParentDir, NS_ConvertUTF8toUCS2(newName), FALSE, FALSE);
547}
548
549/* void remove (in boolean recursive); */
550NS_IMETHODIMP nsLocalFile::Remove(PRBool recursive)
551{
552 StFollowLinksState followLinks(*this, PR_FALSE); // XXX If we're an alias, never remove target
553
554 FSRef fsRef;
555 nsresult rv = GetFSRefInternal(fsRef);
556 if (NS_FAILED(rv))
557 return rv;
558
559 PRBool isDir;
560 rv = IsDirectory(&isDir);
561 if (NS_FAILED(rv))
562 return rv;
563
564 OSErr err;
565 if (recursive && isDir)
566 err = ::FSDeleteContainer(&fsRef);
567 else
568 err = ::FSDeleteObject(&fsRef);
569
570 mCachedFSRefValid = PR_FALSE;
571 return MacErrorMapper(err);
572}
573
574/* attribute unsigned long permissions; */
575NS_IMETHODIMP nsLocalFile::GetPermissions(PRUint32 *aPermissions)
576{
577 NS_ENSURE_ARG_POINTER(aPermissions);
578
579 FSRef fsRef;
580 nsresult rv = GetFSRefInternal(fsRef);
581 if (NS_FAILED(rv))
582 return rv;
583
584 FSCatalogInfo catalogInfo;
585 OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoPermissions, &catalogInfo,
586 nsnull, nsnull, nsnull);
587 if (err != noErr)
588 return MacErrorMapper(err);
589 FSPermissionInfo *permPtr = (FSPermissionInfo*)catalogInfo.permissions;
590 *aPermissions = permPtr->mode;
591 return NS_OK;
592}
593
594NS_IMETHODIMP nsLocalFile::SetPermissions(PRUint32 aPermissions)
595{
596 FSRef fsRef;
597 nsresult rv = GetFSRefInternal(fsRef);
598 if (NS_FAILED(rv))
599 return rv;
600
601 FSCatalogInfo catalogInfo;
602 OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoPermissions, &catalogInfo,
603 nsnull, nsnull, nsnull);
604 if (err != noErr)
605 return MacErrorMapper(err);
606 FSPermissionInfo *permPtr = (FSPermissionInfo*)catalogInfo.permissions;
607 permPtr->mode = (UInt16)aPermissions;
608 err = ::FSSetCatalogInfo(&fsRef, kFSCatInfoPermissions, &catalogInfo);
609 return MacErrorMapper(err);
610}
611
612/* attribute unsigned long permissionsOfLink; */
613NS_IMETHODIMP nsLocalFile::GetPermissionsOfLink(PRUint32 *aPermissionsOfLink)
614{
615 NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
616 return NS_ERROR_NOT_IMPLEMENTED;
617}
618
619NS_IMETHODIMP nsLocalFile::SetPermissionsOfLink(PRUint32 aPermissionsOfLink)
620{
621 NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
622 return NS_ERROR_NOT_IMPLEMENTED;
623}
624
625/* attribute PRInt64 lastModifiedTime; */
626NS_IMETHODIMP nsLocalFile::GetLastModifiedTime(PRInt64 *aLastModifiedTime)
627{
628 NS_ENSURE_ARG_POINTER(aLastModifiedTime);
629
630 FSRef fsRef;
631 nsresult rv = GetFSRefInternal(fsRef);
632 if (NS_FAILED(rv))
633 return rv;
634
635 FSCatalogInfo catalogInfo;
636 OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoContentMod, &catalogInfo,
637 nsnull, nsnull, nsnull);
638 if (err != noErr)
639 return MacErrorMapper(err);
640 *aLastModifiedTime = HFSPlustoNSPRTime(catalogInfo.contentModDate);
641 return NS_OK;
642}
643
644NS_IMETHODIMP nsLocalFile::SetLastModifiedTime(PRInt64 aLastModifiedTime)
645{
646 OSErr err;
647 nsresult rv;
648 FSRef fsRef;
649 FSCatalogInfo catalogInfo;
650
651 rv = GetFSRefInternal(fsRef);
652 if (NS_FAILED(rv))
653 return rv;
654
655 FSRef parentRef;
656 PRBool notifyParent;
657
658 /* Get the node flags, the content modification date and time, and the parent ref */
659 err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags + kFSCatInfoContentMod,
660 &catalogInfo, NULL, NULL, &parentRef);
661 if (err != noErr)
662 return MacErrorMapper(err);
663
664 /* Notify the parent if this is a file */
665 notifyParent = (0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask));
666
667 NSPRtoHFSPlusTime(aLastModifiedTime, catalogInfo.contentModDate);
668 err = ::FSSetCatalogInfo(&fsRef, kFSCatInfoContentMod, &catalogInfo);
669 if (err != noErr)
670 return MacErrorMapper(err);
671
672 /* Send a notification for the parent of the file, or for the directory */
673 err = FNNotify(notifyParent ? &parentRef : &fsRef, kFNDirectoryModifiedMessage, kNilOptions);
674 if (err != noErr)
675 return MacErrorMapper(err);
676
677 return NS_OK;
678}
679
680/* attribute PRInt64 lastModifiedTimeOfLink; */
681NS_IMETHODIMP nsLocalFile::GetLastModifiedTimeOfLink(PRInt64 *aLastModifiedTimeOfLink)
682{
683 NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
684 return NS_ERROR_NOT_IMPLEMENTED;
685}
686NS_IMETHODIMP nsLocalFile::SetLastModifiedTimeOfLink(PRInt64 aLastModifiedTimeOfLink)
687{
688 NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
689 return NS_ERROR_NOT_IMPLEMENTED;
690}
691
692/* attribute PRInt64 fileSize; */
693NS_IMETHODIMP nsLocalFile::GetFileSize(PRInt64 *aFileSize)
694{
695 NS_ENSURE_ARG_POINTER(aFileSize);
696 *aFileSize = 0;
697
698 FSRef fsRef;
699 nsresult rv = GetFSRefInternal(fsRef);
700 if (NS_FAILED(rv))
701 return rv;
702
703 FSCatalogInfo catalogInfo;
704 OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags + kFSCatInfoDataSizes, &catalogInfo,
705 nsnull, nsnull, nsnull);
706 if (err != noErr)
707 return MacErrorMapper(err);
708
709 // FSGetCatalogInfo can return a bogus size for directories sometimes, so only
710 // rely on the answer for files
711 if ((catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) == 0)
712 *aFileSize = catalogInfo.dataLogicalSize;
713 return NS_OK;
714}
715
716NS_IMETHODIMP nsLocalFile::SetFileSize(PRInt64 aFileSize)
717{
718 FSRef fsRef;
719 nsresult rv = GetFSRefInternal(fsRef);
720 if (NS_FAILED(rv))
721 return rv;
722
723 SInt16 refNum;
724 OSErr err = ::FSOpenFork(&fsRef, 0, nsnull, fsWrPerm, &refNum);
725 if (err != noErr)
726 return MacErrorMapper(err);
727 err = ::FSSetForkSize(refNum, fsFromStart, aFileSize);
728 ::FSCloseFork(refNum);
729
730 return MacErrorMapper(err);
731}
732
733/* readonly attribute PRInt64 fileSizeOfLink; */
734NS_IMETHODIMP nsLocalFile::GetFileSizeOfLink(PRInt64 *aFileSizeOfLink)
735{
736 NS_ENSURE_ARG_POINTER(aFileSizeOfLink);
737
738 StFollowLinksState followLinks(*this, PR_FALSE);
739 return GetFileSize(aFileSizeOfLink);
740}
741
742/* readonly attribute AString target; */
743NS_IMETHODIMP nsLocalFile::GetTarget(nsAString& aTarget)
744{
745 NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
746 return NS_ERROR_NOT_IMPLEMENTED;
747}
748
749/* [noscript] readonly attribute ACString nativeTarget; */
750NS_IMETHODIMP nsLocalFile::GetNativeTarget(nsACString& aNativeTarget)
751{
752 NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
753 return NS_ERROR_NOT_IMPLEMENTED;
754}
755
756/* readonly attribute AString path; */
757NS_IMETHODIMP nsLocalFile::GetPath(nsAString& aPath)
758{
759 nsCAutoString nativeString;
760 nsresult rv = GetNativePath(nativeString);
761 if (NS_FAILED(rv))
762 return rv;
763 CopyUTF8toUTF16NFC(nativeString, aPath);
764 return NS_OK;
765}
766
767/* [noscript] readonly attribute ACString nativePath; */
768NS_IMETHODIMP nsLocalFile::GetNativePath(nsACString& aNativePath)
769{
770 if (!mBaseRef)
771 return NS_ERROR_NOT_INITIALIZED;
772 nsresult rv = NS_ERROR_FAILURE;
773 CFStringRef pathStrRef = ::CFURLCopyFileSystemPath(mBaseRef, kCFURLPOSIXPathStyle);
774 if (pathStrRef) {
775 rv = CFStringReftoUTF8(pathStrRef, aNativePath);
776 ::CFRelease(pathStrRef);
777 }
778 return rv;
779}
780
781/* boolean exists (); */
782NS_IMETHODIMP nsLocalFile::Exists(PRBool *_retval)
783{
784 NS_ENSURE_ARG_POINTER(_retval);
785 *_retval = PR_FALSE;
786
787 FSRef fsRef;
788 if (NS_SUCCEEDED(GetFSRefInternal(fsRef, PR_TRUE))) {
789 *_retval = PR_TRUE;
790 }
791
792 return NS_OK;
793}
794
795/* boolean isWritable (); */
796NS_IMETHODIMP nsLocalFile::IsWritable(PRBool *_retval)
797{
798 NS_ENSURE_ARG_POINTER(_retval);
799 *_retval = PR_FALSE;
800
801 FSRef fsRef;
802 nsresult rv = GetFSRefInternal(fsRef);
803 if (NS_FAILED(rv))
804 return rv;
805 if (::FSCheckLock(&fsRef) == noErr) {
806 PRUint32 permissions;
807 rv = GetPermissions(&permissions);
808 if (NS_FAILED(rv))
809 return rv;
810 *_retval = ((permissions & S_IWUSR) != 0);
811 }
812 return NS_OK;
813}
814
815/* boolean isReadable (); */
816NS_IMETHODIMP nsLocalFile::IsReadable(PRBool *_retval)
817{
818 NS_ENSURE_ARG_POINTER(_retval);
819 *_retval = PR_FALSE;
820
821 PRUint32 permissions;
822 nsresult rv = GetPermissions(&permissions);
823 if (NS_FAILED(rv))
824 return rv;
825 *_retval = ((permissions & S_IRUSR) != 0);
826 return NS_OK;
827}
828
829/* boolean isExecutable (); */
830NS_IMETHODIMP nsLocalFile::IsExecutable(PRBool *_retval)
831{
832 NS_ENSURE_ARG_POINTER(_retval);
833 *_retval = PR_FALSE;
834
835 FSRef fsRef;
836 nsresult rv = GetFSRefInternal(fsRef);
837 if (NS_FAILED(rv))
838 return rv;
839
840 LSRequestedInfo theInfoRequest = kLSRequestAllInfo;
841 LSItemInfoRecord theInfo;
842 if (::LSCopyItemInfoForRef(&fsRef, theInfoRequest, &theInfo) == noErr) {
843 if ((theInfo.flags & kLSItemInfoIsApplication) != 0)
844 *_retval = PR_TRUE;
845 }
846 return NS_OK;
847}
848
849/* boolean isHidden (); */
850NS_IMETHODIMP nsLocalFile::IsHidden(PRBool *_retval)
851{
852 NS_ENSURE_ARG_POINTER(_retval);
853 *_retval = PR_FALSE;
854
855 FSRef fsRef;
856 nsresult rv = GetFSRefInternal(fsRef);
857 if (NS_FAILED(rv))
858 return rv;
859
860 FSCatalogInfo catalogInfo;
861 HFSUniStr255 leafName;
862 OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags, &catalogInfo,
863 &leafName, nsnull, nsnull);
864 if (err != noErr)
865 return MacErrorMapper(err);
866
867 FileInfo *fInfoPtr = (FileInfo *)(catalogInfo.finderInfo); // Finder flags are in the same place whether we use FileInfo or FolderInfo
868 if ((fInfoPtr->finderFlags & kIsInvisible) != 0) {
869 *_retval = PR_TRUE;
870 }
871 else {
872 // If the leaf name begins with a '.', consider it invisible
873 if (leafName.length >= 1 && leafName.unicode[0] == UniChar('.'))
874 *_retval = PR_TRUE;
875 }
876 return NS_OK;
877}
878
879/* boolean isDirectory (); */
880NS_IMETHODIMP nsLocalFile::IsDirectory(PRBool *_retval)
881{
882 NS_ENSURE_ARG_POINTER(_retval);
883 *_retval = PR_FALSE;
884
885 FSRef fsRef;
886 nsresult rv = GetFSRefInternal(fsRef, PR_FALSE);
887 if (NS_FAILED(rv))
888 return rv;
889
890 FSCatalogInfo catalogInfo;
891 OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags, &catalogInfo,
892 nsnull, nsnull, nsnull);
893 if (err != noErr)
894 return MacErrorMapper(err);
895 *_retval = ((catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) != 0);
896 return NS_OK;
897}
898
899/* boolean isFile (); */
900NS_IMETHODIMP nsLocalFile::IsFile(PRBool *_retval)
901{
902 NS_ENSURE_ARG_POINTER(_retval);
903 *_retval = PR_FALSE;
904
905 FSRef fsRef;
906 nsresult rv = GetFSRefInternal(fsRef, PR_FALSE);
907 if (NS_FAILED(rv))
908 return rv;
909
910 FSCatalogInfo catalogInfo;
911 OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags, &catalogInfo,
912 nsnull, nsnull, nsnull);
913 if (err != noErr)
914 return MacErrorMapper(err);
915 *_retval = ((catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) == 0);
916 return NS_OK;
917}
918
919/* boolean isSymlink (); */
920NS_IMETHODIMP nsLocalFile::IsSymlink(PRBool *_retval)
921{
922 NS_ENSURE_ARG(_retval);
923 *_retval = PR_FALSE;
924 if (!mBaseRef)
925 return NS_ERROR_NOT_INITIALIZED;
926
927 FSRef fsRef;
928 if (::CFURLGetFSRef(mBaseRef, &fsRef)) {
929 Boolean isAlias, isFolder;
930 if (::FSIsAliasFile(&fsRef, &isAlias, &isFolder) == noErr)
931 *_retval = isAlias;
932 }
933 return NS_OK;
934}
935
936/* boolean isSpecial (); */
937NS_IMETHODIMP nsLocalFile::IsSpecial(PRBool *_retval)
938{
939 NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
940 return NS_ERROR_NOT_IMPLEMENTED;
941}
942
943/* nsIFile clone (); */
944NS_IMETHODIMP nsLocalFile::Clone(nsIFile **_retval)
945{
946 // Just copy-construct ourselves
947 *_retval = new nsLocalFile(*this);
948 if (!*_retval)
949 return NS_ERROR_OUT_OF_MEMORY;
950
951 NS_ADDREF(*_retval);
952
953 return NS_OK;
954}
955
956/* boolean equals (in nsIFile inFile); */
957NS_IMETHODIMP nsLocalFile::Equals(nsIFile *inFile, PRBool *_retval)
958{
959 NS_ENSURE_ARG_POINTER(_retval);
960 *_retval = PR_FALSE;
961
962 nsCOMPtr<nsILocalFileMac> inMacFile(do_QueryInterface(inFile));
963 if (!inFile)
964 return NS_OK;
965
966 // If both exist, compare FSRefs
967 FSRef thisFSRef, inFSRef;
968 nsresult rv1 = GetFSRef(&thisFSRef);
969 nsresult rv2 = inMacFile->GetFSRef(&inFSRef);
970 if (NS_SUCCEEDED(rv1) && NS_SUCCEEDED(rv2)) {
971 *_retval = (thisFSRef == inFSRef);
972 return NS_OK;
973 }
974 // If one exists and the other doesn't, not equal
975 if (rv1 != rv2)
976 return NS_OK;
977
978 // Arg, we have to get their paths and compare
979 nsCAutoString thisPath, inPath;
980 if (NS_FAILED(GetNativePath(thisPath)))
981 return NS_ERROR_FAILURE;
982 if (NS_FAILED(inMacFile->GetNativePath(inPath)))
983 return NS_ERROR_FAILURE;
984 *_retval = thisPath.Equals(inPath);
985
986 return NS_OK;
987}
988
989/* boolean contains (in nsIFile inFile, in boolean recur); */
990NS_IMETHODIMP nsLocalFile::Contains(nsIFile *inFile, PRBool recur, PRBool *_retval)
991{
992 NS_ENSURE_ARG_POINTER(_retval);
993 *_retval = PR_FALSE;
994
995 PRBool isDir;
996 nsresult rv = IsDirectory(&isDir);
997 if (NS_FAILED(rv))
998 return rv;
999 if (!isDir)
1000 return NS_OK; // must be a dir to contain someone
1001
1002 nsCAutoString thisPath, inPath;
1003 if (NS_FAILED(GetNativePath(thisPath)) || NS_FAILED(inFile->GetNativePath(inPath)))
1004 return NS_ERROR_FAILURE;
1005 size_t thisPathLen = thisPath.Length();
1006 if ((inPath.Length() > thisPathLen + 1) && (strncasecmp(thisPath.get(), inPath.get(), thisPathLen) == 0)) {
1007 // Now make sure that the |inFile|'s path has a separator at thisPathLen,
1008 // and there's at least one more character after that.
1009 if (inPath[thisPathLen] == kPathSepChar)
1010 *_retval = PR_TRUE;
1011 }
1012 return NS_OK;
1013}
1014
1015/* readonly attribute nsIFile parent; */
1016NS_IMETHODIMP nsLocalFile::GetParent(nsIFile * *aParent)
1017{
1018 NS_ENSURE_ARG_POINTER(aParent);
1019 *aParent = nsnull;
1020 if (!mBaseRef)
1021 return NS_ERROR_NOT_INITIALIZED;
1022
1023 nsLocalFile *newFile = nsnull;
1024
1025 // If it can be determined without error that a file does not
1026 // have a parent, return nsnull for the parent and NS_OK as the result.
1027 // See bug 133617.
1028 nsresult rv = NS_OK;
1029 CFURLRef parentURLRef = ::CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, mBaseRef);
1030 if (parentURLRef) {
1031 rv = NS_ERROR_FAILURE;
1032 newFile = new nsLocalFile;
1033 if (newFile) {
1034 rv = newFile->InitWithCFURL(parentURLRef);
1035 if (NS_SUCCEEDED(rv)) {
1036 NS_ADDREF(*aParent = newFile);
1037 rv = NS_OK;
1038 }
1039 }
1040 ::CFRelease(parentURLRef);
1041 }
1042 return rv;
1043}
1044
1045/* readonly attribute nsISimpleEnumerator directoryEntries; */
1046NS_IMETHODIMP nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator **aDirectoryEntries)
1047{
1048 NS_ENSURE_ARG_POINTER(aDirectoryEntries);
1049 *aDirectoryEntries = nsnull;
1050
1051 nsresult rv;
1052 PRBool isDir;
1053 rv = IsDirectory(&isDir);
1054 if (NS_FAILED(rv))
1055 return rv;
1056 if (!isDir)
1057 return NS_ERROR_FILE_NOT_DIRECTORY;
1058
1059 nsDirEnumerator* dirEnum = new nsDirEnumerator;
1060 if (dirEnum == nsnull)
1061 return NS_ERROR_OUT_OF_MEMORY;
1062 NS_ADDREF(dirEnum);
1063 rv = dirEnum->Init(this);
1064 if (NS_FAILED(rv)) {
1065 NS_RELEASE(dirEnum);
1066 return rv;
1067 }
1068 *aDirectoryEntries = dirEnum;
1069
1070 return NS_OK;
1071}
1072
1073
1074//*****************************************************************************
1075// nsLocalFile::nsILocalFile
1076//*****************************************************************************
1077#pragma mark -
1078#pragma mark [nsILocalFile]
1079
1080/* void initWithPath (in AString filePath); */
1081NS_IMETHODIMP nsLocalFile::InitWithPath(const nsAString& filePath)
1082{
1083 return InitWithNativePath(NS_ConvertUCS2toUTF8(filePath));
1084}
1085
1086/* [noscript] void initWithNativePath (in ACString filePath); */
1087NS_IMETHODIMP nsLocalFile::InitWithNativePath(const nsACString& filePath)
1088{
1089 if (filePath.IsEmpty() || filePath.First() != '/')
1090 return NS_ERROR_FILE_UNRECOGNIZED_PATH;
1091 // On 10.2, huge paths crash CFURLGetFSRef()
1092 if (filePath.Length() > PATH_MAX)
1093 return NS_ERROR_FILE_NAME_TOO_LONG;
1094 // And, a path with consecutive '/'s which are not between
1095 // nodes also crashes CFURLGetFSRef(). Consecutive '/'s which
1096 // are between actual nodes are OK. So, convert consecutive
1097 // '/'s to a single one.
1098 nsCAutoString fixedPath;
1099 fixedPath.Assign(filePath);
1100 fixedPath.ReplaceSubstring("//", "/");
1101
1102 CFStringRef pathAsCFString;
1103 CFURLRef pathAsCFURL;
1104
1105 pathAsCFString = ::CFStringCreateWithCString(nsnull, fixedPath.get(), kCFStringEncodingUTF8);
1106 if (!pathAsCFString)
1107 return NS_ERROR_FAILURE;
1108 pathAsCFURL = ::CFURLCreateWithFileSystemPath(nsnull, pathAsCFString, kCFURLPOSIXPathStyle, PR_FALSE);
1109 if (!pathAsCFURL) {
1110 ::CFRelease(pathAsCFString);
1111 return NS_ERROR_FAILURE;
1112 }
1113 SetBaseRef(pathAsCFURL);
1114 ::CFRelease(pathAsCFURL);
1115 return NS_OK;
1116}
1117
1118/* void initWithFile (in nsILocalFile aFile); */
1119NS_IMETHODIMP nsLocalFile::InitWithFile(nsILocalFile *aFile)
1120{
1121 NS_ENSURE_ARG(aFile);
1122
1123 nsCOMPtr<nsILocalFileMac> aFileMac(do_QueryInterface(aFile));
1124 if (!aFileMac)
1125 return NS_ERROR_UNEXPECTED;
1126 CFURLRef urlRef;
1127 nsresult rv = aFileMac->GetCFURL(&urlRef);
1128 if (NS_FAILED(rv))
1129 return rv;
1130 rv = InitWithCFURL(urlRef);
1131 ::CFRelease(urlRef);
1132 return rv;
1133}
1134
1135/* attribute PRBool followLinks; */
1136NS_IMETHODIMP nsLocalFile::GetFollowLinks(PRBool *aFollowLinks)
1137{
1138 NS_ENSURE_ARG_POINTER(aFollowLinks);
1139
1140 *aFollowLinks = mFollowLinks;
1141 return NS_OK;
1142}
1143
1144NS_IMETHODIMP nsLocalFile::SetFollowLinks(PRBool aFollowLinks)
1145{
1146 if (aFollowLinks != mFollowLinks) {
1147 mFollowLinks = aFollowLinks;
1148 UpdateTargetRef();
1149 }
1150 return NS_OK;
1151}
1152
1153/* [noscript] PRFileDescStar openNSPRFileDesc (in long flags, in long mode); */
1154NS_IMETHODIMP nsLocalFile::OpenNSPRFileDesc(PRInt32 flags, PRInt32 mode, PRFileDesc **_retval)
1155{
1156 NS_ENSURE_ARG_POINTER(_retval);
1157
1158 nsCAutoString path;
1159 nsresult rv = GetPathInternal(path);
1160 if (NS_FAILED(rv))
1161 return rv;
1162
1163 *_retval = PR_Open(path.get(), flags, mode);
1164 if (! *_retval)
1165 return NS_ErrorAccordingToNSPR();
1166
1167 return NS_OK;
1168}
1169
1170/* [noscript] FILE openANSIFileDesc (in string mode); */
1171NS_IMETHODIMP nsLocalFile::OpenANSIFileDesc(const char *mode, FILE **_retval)
1172{
1173 NS_ENSURE_ARG_POINTER(_retval);
1174
1175 nsCAutoString path;
1176 nsresult rv = GetPathInternal(path);
1177 if (NS_FAILED(rv))
1178 return rv;
1179
1180 *_retval = fopen(path.get(), mode);
1181 if (! *_retval)
1182 return NS_ERROR_FAILURE;
1183
1184 return NS_OK;
1185}
1186
1187/* [noscript] PRLibraryStar load (); */
1188NS_IMETHODIMP nsLocalFile::Load(PRLibrary **_retval)
1189{
1190 NS_ENSURE_ARG_POINTER(_retval);
1191
1192 NS_TIMELINE_START_TIMER("PR_LoadLibrary");
1193
1194 nsCAutoString path;
1195 nsresult rv = GetPathInternal(path);
1196 if (NS_FAILED(rv))
1197 return rv;
1198
1199 *_retval = PR_LoadLibrary(path.get());
1200
1201 NS_TIMELINE_STOP_TIMER("PR_LoadLibrary");
1202 NS_TIMELINE_MARK_TIMER1("PR_LoadLibrary", path.get());
1203
1204 if (!*_retval)
1205 return NS_ERROR_FAILURE;
1206
1207 return NS_OK;
1208}
1209
1210/* readonly attribute PRInt64 diskSpaceAvailable; */
1211NS_IMETHODIMP nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable)
1212{
1213 NS_ENSURE_ARG_POINTER(aDiskSpaceAvailable);
1214
1215 FSRef fsRef;
1216 nsresult rv = GetFSRefInternal(fsRef);
1217 if (NS_FAILED(rv))
1218 return rv;
1219
1220 OSErr err;
1221 FSCatalogInfo catalogInfo;
1222 err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoVolume, &catalogInfo,
1223 nsnull, nsnull, nsnull);
1224 if (err != noErr)
1225 return MacErrorMapper(err);
1226
1227 FSVolumeInfo volumeInfo;
1228 err = ::FSGetVolumeInfo(catalogInfo.volume, 0, nsnull, kFSVolInfoSizes,
1229 &volumeInfo, nsnull, nsnull);
1230 if (err != noErr)
1231 return MacErrorMapper(err);
1232
1233 *aDiskSpaceAvailable = volumeInfo.freeBytes;
1234 return NS_OK;
1235}
1236
1237/* void appendRelativePath (in AString relativeFilePath); */
1238NS_IMETHODIMP nsLocalFile::AppendRelativePath(const nsAString& relativeFilePath)
1239{
1240 return AppendRelativeNativePath(NS_ConvertUCS2toUTF8(relativeFilePath));
1241}
1242
1243/* [noscript] void appendRelativeNativePath (in ACString relativeFilePath); */
1244NS_IMETHODIMP nsLocalFile::AppendRelativeNativePath(const nsACString& relativeFilePath)
1245{
1246 if (relativeFilePath.IsEmpty())
1247 return NS_OK;
1248 // No leading '/'
1249 if (relativeFilePath.First() == '/')
1250 return NS_ERROR_FILE_UNRECOGNIZED_PATH;
1251
1252 // Parse the nodes and call Append() for each
1253 nsACString::const_iterator nodeBegin, pathEnd;
1254 relativeFilePath.BeginReading(nodeBegin);
1255 relativeFilePath.EndReading(pathEnd);
1256 nsACString::const_iterator nodeEnd(nodeBegin);
1257
1258 while (nodeEnd != pathEnd) {
1259 FindCharInReadable(kPathSepChar, nodeEnd, pathEnd);
1260 nsresult rv = AppendNative(Substring(nodeBegin, nodeEnd));
1261 if (NS_FAILED(rv))
1262 return rv;
1263 if (nodeEnd != pathEnd) // If there's more left in the string, inc over the '/' nodeEnd is on.
1264 ++nodeEnd;
1265 nodeBegin = nodeEnd;
1266 }
1267 return NS_OK;
1268}
1269
1270/* attribute ACString persistentDescriptor; */
1271NS_IMETHODIMP nsLocalFile::GetPersistentDescriptor(nsACString& aPersistentDescriptor)
1272{
1273 FSRef fsRef;
1274 nsresult rv = GetFSRefInternal(fsRef);
1275 if (NS_FAILED(rv))
1276 return rv;
1277
1278 AliasHandle aliasH;
1279 OSErr err = ::FSNewAlias(nsnull, &fsRef, &aliasH);
1280 if (err != noErr)
1281 return MacErrorMapper(err);
1282
1283 PRUint32 bytes = ::GetHandleSize((Handle) aliasH);
1284 ::HLock((Handle) aliasH);
1285 // Passing nsnull for dest makes NULL-term string
1286 char* buf = PL_Base64Encode((const char*)*aliasH, bytes, nsnull);
1287 ::DisposeHandle((Handle) aliasH);
1288 NS_ENSURE_TRUE(buf, NS_ERROR_OUT_OF_MEMORY);
1289
1290 aPersistentDescriptor = buf;
1291 PR_Free(buf);
1292
1293 return NS_OK;
1294}
1295
1296NS_IMETHODIMP nsLocalFile::SetPersistentDescriptor(const nsACString& aPersistentDescriptor)
1297{
1298 if (aPersistentDescriptor.IsEmpty())
1299 return NS_ERROR_INVALID_ARG;
1300
1301 nsresult rv = NS_OK;
1302
1303 PRUint32 dataSize = aPersistentDescriptor.Length();
1304 char* decodedData = PL_Base64Decode(PromiseFlatCString(aPersistentDescriptor).get(), dataSize, nsnull);
1305 if (!decodedData) {
1306 NS_ERROR("SetPersistentDescriptor was given bad data");
1307 return NS_ERROR_FAILURE;
1308 }
1309
1310 // Cast to an alias record and resolve.
1311 PRInt32 aliasSize = (dataSize * 3) / 4;
1312 AliasRecord aliasHeader = *(AliasPtr)decodedData;
1313 if (aliasHeader.aliasSize > aliasSize) { // be paranoid about having too few data
1314 PR_Free(decodedData);
1315 return NS_ERROR_FAILURE;
1316 }
1317
1318 aliasSize = aliasHeader.aliasSize;
1319
1320 // Move the now-decoded data into the Handle.
1321 // The size of the decoded data is 3/4 the size of the encoded data. See plbase64.h
1322 Handle newHandle = nsnull;
1323 if (::PtrToHand(decodedData, &newHandle, aliasSize) != noErr)
1324 rv = NS_ERROR_OUT_OF_MEMORY;
1325 PR_Free(decodedData);
1326 if (NS_FAILED(rv))
1327 return rv;
1328
1329 Boolean changed;
1330 FSRef resolvedFSRef;
1331 OSErr err = ::FSResolveAlias(nsnull, (AliasHandle)newHandle, &resolvedFSRef, &changed);
1332
1333 rv = MacErrorMapper(err);
1334 DisposeHandle(newHandle);
1335 if (NS_FAILED(rv))
1336 return rv;
1337
1338 return InitWithFSRef(&resolvedFSRef);
1339}
1340
1341/* void reveal (); */
1342NS_IMETHODIMP nsLocalFile::Reveal()
1343{
1344 FSRef fsRefToReveal;
1345 AppleEvent aeEvent = {0, nil};
1346 AppleEvent aeReply = {0, nil};
1347 StAEDesc aeDirDesc, listElem, myAddressDesc, fileList;
1348 OSErr err;
1349 ProcessSerialNumber process;
1350
1351 nsresult rv = GetFSRefInternal(fsRefToReveal);
1352 if (NS_FAILED(rv))
1353 return rv;
1354
1355 err = ::FindRunningAppBySignature ('MACS', process);
1356 if (err == noErr) {
1357 err = ::AECreateDesc(typeProcessSerialNumber, (Ptr)&process, sizeof(process), &myAddressDesc);
1358 if (err == noErr) {
1359 // Create the FinderEvent
1360 err = ::AECreateAppleEvent(kAEMiscStandards, kAEMakeObjectsVisible, &myAddressDesc,
1361 kAutoGenerateReturnID, kAnyTransactionID, &aeEvent);
1362 if (err == noErr) {
1363 // Create the file list
1364 err = ::AECreateList(nil, 0, false, &fileList);
1365 if (err == noErr) {
1366 FSSpec fsSpecToReveal;
1367 err = ::FSRefMakeFSSpec(&fsRefToReveal, &fsSpecToReveal);
1368 if (err == noErr) {
1369 err = ::AEPutPtr(&fileList, 0, typeFSS, &fsSpecToReveal, sizeof(FSSpec));
1370 if (err == noErr) {
1371 err = ::AEPutParamDesc(&aeEvent, keyDirectObject, &fileList);
1372 if (err == noErr) {
1373 err = ::AESend(&aeEvent, &aeReply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, nil, nil);
1374 if (err == noErr)
1375 ::SetFrontProcess(&process);
1376 }
1377 }
1378 }
1379 }
1380 }
1381 }
1382 }
1383
1384 return NS_OK;
1385}
1386
1387/* void launch (); */
1388NS_IMETHODIMP nsLocalFile::Launch()
1389{
1390 FSRef fsRef;
1391 nsresult rv = GetFSRefInternal(fsRef);
1392 if (NS_FAILED(rv))
1393 return rv;
1394
1395 OSErr err = ::LSOpenFSRef(&fsRef, NULL);
1396 return MacErrorMapper(err);
1397}
1398
1399
1400//*****************************************************************************
1401// nsLocalFile::nsILocalFileMac
1402//*****************************************************************************
1403#pragma mark -
1404#pragma mark [nsILocalFileMac]
1405
1406/* void initWithCFURL (in CFURLRef aCFURL); */
1407NS_IMETHODIMP nsLocalFile::InitWithCFURL(CFURLRef aCFURL)
1408{
1409 NS_ENSURE_ARG(aCFURL);
1410
1411 SetBaseRef(aCFURL);
1412 return NS_OK;
1413}
1414
1415/* void initWithFSRef ([const] in FSRefPtr aFSRef); */
1416NS_IMETHODIMP nsLocalFile::InitWithFSRef(const FSRef *aFSRef)
1417{
1418 NS_ENSURE_ARG(aFSRef);
1419 nsresult rv = NS_ERROR_FAILURE;
1420
1421 CFURLRef newURLRef = ::CFURLCreateFromFSRef(kCFAllocatorDefault, aFSRef);
1422 if (newURLRef) {
1423 SetBaseRef(newURLRef);
1424 ::CFRelease(newURLRef);
1425 rv = NS_OK;
1426 }
1427 return rv;
1428}
1429
1430/* void initWithFSSpec ([const] in FSSpecPtr aFileSpec); */
1431NS_IMETHODIMP nsLocalFile::InitWithFSSpec(const FSSpec *aFileSpec)
1432{
1433 NS_ENSURE_ARG(aFileSpec);
1434
1435 FSRef fsRef;
1436 OSErr err = ::FSpMakeFSRef(aFileSpec, &fsRef);
1437 if (err == noErr)
1438 return InitWithFSRef(&fsRef);
1439 else if (err == fnfErr) {
1440 CInfoPBRec pBlock;
1441 FSSpec parentDirSpec;
1442
1443 memset(&pBlock, 0, sizeof(CInfoPBRec));
1444 parentDirSpec.name[0] = 0;
1445 pBlock.dirInfo.ioVRefNum = aFileSpec->vRefNum;
1446 pBlock.dirInfo.ioDrDirID = aFileSpec->parID;
1447 pBlock.dirInfo.ioNamePtr = (StringPtr)parentDirSpec.name;
1448 pBlock.dirInfo.ioFDirIndex = -1; //get info on parID
1449 err = ::PBGetCatInfoSync(&pBlock);
1450 if (err != noErr)
1451 return MacErrorMapper(err);
1452
1453 parentDirSpec.vRefNum = aFileSpec->vRefNum;
1454 parentDirSpec.parID = pBlock.dirInfo.ioDrParID;
1455 err = ::FSpMakeFSRef(&parentDirSpec, &fsRef);
1456 if (err != noErr)
1457 return MacErrorMapper(err);
1458 HFSUniStr255 unicodeName;
1459 err = ::HFSNameGetUnicodeName(aFileSpec->name, kTextEncodingUnknown, &unicodeName);
1460 if (err != noErr)
1461 return MacErrorMapper(err);
1462 nsresult rv = InitWithFSRef(&fsRef);
1463 if (NS_FAILED(rv))
1464 return rv;
1465 return Append(nsDependentString(unicodeName.unicode, unicodeName.length));
1466 }
1467 return MacErrorMapper(err);
1468}
1469
1470/* void initToAppWithCreatorCode (in OSType aAppCreator); */
1471NS_IMETHODIMP nsLocalFile::InitToAppWithCreatorCode(OSType aAppCreator)
1472{
1473 FSRef fsRef;
1474 OSErr err = ::LSFindApplicationForInfo(aAppCreator, nsnull, nsnull, &fsRef, nsnull);
1475 if (err != noErr)
1476 return MacErrorMapper(err);
1477 return InitWithFSRef(&fsRef);
1478}
1479
1480/* CFURLRef getCFURL (); */
1481NS_IMETHODIMP nsLocalFile::GetCFURL(CFURLRef *_retval)
1482{
1483 NS_ENSURE_ARG_POINTER(_retval);
1484 CFURLRef whichURLRef = mFollowLinks ? mTargetRef : mBaseRef;
1485 if (whichURLRef)
1486 ::CFRetain(whichURLRef);
1487 *_retval = whichURLRef;
1488 return whichURLRef ? NS_OK : NS_ERROR_FAILURE;
1489}
1490
1491/* FSRef getFSRef (); */
1492NS_IMETHODIMP nsLocalFile::GetFSRef(FSRef *_retval)
1493{
1494 NS_ENSURE_ARG_POINTER(_retval);
1495 return GetFSRefInternal(*_retval);
1496}
1497
1498/* FSSpec getFSSpec (); */
1499NS_IMETHODIMP nsLocalFile::GetFSSpec(FSSpec *_retval)
1500{
1501 NS_ENSURE_ARG_POINTER(_retval);
1502 if (!mBaseRef)
1503 return NS_ERROR_NOT_INITIALIZED;
1504
1505 OSErr err;
1506 FSRef fsRef;
1507 nsresult rv = GetFSRefInternal(fsRef);
1508 if (NS_SUCCEEDED(rv)) {
1509 // If the leaf node exists, things are simple.
1510 err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNone,
1511 nsnull, nsnull, _retval, nsnull);
1512 return MacErrorMapper(err);
1513 }
1514 else if (rv == NS_ERROR_FILE_NOT_FOUND) {
1515 // If the parent of the leaf exists, make an FSSpec from that.
1516 CFURLRef parentURLRef = ::CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, mBaseRef);
1517 if (!parentURLRef)
1518 return NS_ERROR_FAILURE;
1519
1520 err = fnfErr;
1521 if (::CFURLGetFSRef(parentURLRef, &fsRef)) {
1522 FSCatalogInfo catalogInfo;
1523 if ((err = ::FSGetCatalogInfo(&fsRef,
1524 kFSCatInfoVolume + kFSCatInfoNodeID + kFSCatInfoTextEncoding,
1525 &catalogInfo, nsnull, nsnull, nsnull)) == noErr) {
1526 nsAutoString leafName;
1527 if (NS_SUCCEEDED(GetLeafName(leafName))) {
1528 Str31 hfsName;
1529 if ((err = ::UnicodeNameGetHFSName(leafName.Length(),
1530 leafName.get(),
1531 catalogInfo.textEncodingHint,
1532 catalogInfo.nodeID == fsRtDirID,
1533 hfsName)) == noErr)
1534 err = ::FSMakeFSSpec(catalogInfo.volume, catalogInfo.nodeID, hfsName, _retval);
1535 }
1536 }
1537 }
1538 ::CFRelease(parentURLRef);
1539 rv = MacErrorMapper(err);
1540 }
1541 return rv;
1542}
1543
1544/* readonly attribute PRInt64 fileSizeWithResFork; */
1545NS_IMETHODIMP nsLocalFile::GetFileSizeWithResFork(PRInt64 *aFileSizeWithResFork)
1546{
1547 NS_ENSURE_ARG_POINTER(aFileSizeWithResFork);
1548
1549 FSRef fsRef;
1550 nsresult rv = GetFSRefInternal(fsRef);
1551 if (NS_FAILED(rv))
1552 return rv;
1553
1554 FSCatalogInfo catalogInfo;
1555 OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoDataSizes + kFSCatInfoRsrcSizes,
1556 &catalogInfo, nsnull, nsnull, nsnull);
1557 if (err != noErr)
1558 return MacErrorMapper(err);
1559
1560 *aFileSizeWithResFork = catalogInfo.dataLogicalSize + catalogInfo.rsrcLogicalSize;
1561 return NS_OK;
1562}
1563
1564/* attribute OSType fileType; */
1565NS_IMETHODIMP nsLocalFile::GetFileType(OSType *aFileType)
1566{
1567 NS_ENSURE_ARG_POINTER(aFileType);
1568
1569 FSRef fsRef;
1570 nsresult rv = GetFSRefInternal(fsRef);
1571 if (NS_FAILED(rv))
1572 return rv;
1573
1574 FinderInfo fInfo;
1575 OSErr err = ::FSGetFinderInfo(&fsRef, &fInfo, nsnull, nsnull);
1576 if (err != noErr)
1577 return MacErrorMapper(err);
1578 *aFileType = fInfo.file.fileType;
1579 return NS_OK;
1580}
1581
1582NS_IMETHODIMP nsLocalFile::SetFileType(OSType aFileType)
1583{
1584 FSRef fsRef;
1585 nsresult rv = GetFSRefInternal(fsRef);
1586 if (NS_FAILED(rv))
1587 return rv;
1588
1589 OSErr err = ::FSChangeCreatorType(&fsRef, 0, aFileType);
1590 return MacErrorMapper(err);
1591}
1592
1593/* attribute OSType fileCreator; */
1594NS_IMETHODIMP nsLocalFile::GetFileCreator(OSType *aFileCreator)
1595{
1596 NS_ENSURE_ARG_POINTER(aFileCreator);
1597
1598 FSRef fsRef;
1599 nsresult rv = GetFSRefInternal(fsRef);
1600 if (NS_FAILED(rv))
1601 return rv;
1602
1603 FinderInfo fInfo;
1604 OSErr err = ::FSGetFinderInfo(&fsRef, &fInfo, nsnull, nsnull);
1605 if (err != noErr)
1606 return MacErrorMapper(err);
1607 *aFileCreator = fInfo.file.fileCreator;
1608 return NS_OK;
1609}
1610
1611NS_IMETHODIMP nsLocalFile::SetFileCreator(OSType aFileCreator)
1612{
1613 FSRef fsRef;
1614 nsresult rv = GetFSRefInternal(fsRef);
1615 if (NS_FAILED(rv))
1616 return rv;
1617
1618 OSErr err = ::FSChangeCreatorType(&fsRef, aFileCreator, 0);
1619 return MacErrorMapper(err);
1620}
1621
1622/* void setFileTypeAndCreatorFromMIMEType (in string aMIMEType); */
1623NS_IMETHODIMP nsLocalFile::SetFileTypeAndCreatorFromMIMEType(const char *aMIMEType)
1624{
1625 // XXX - This should be cut from the API. Would create an evil dependency.
1626 NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
1627 return NS_ERROR_NOT_IMPLEMENTED;
1628}
1629
1630/* void setFileTypeAndCreatorFromExtension (in string aExtension); */
1631NS_IMETHODIMP nsLocalFile::SetFileTypeAndCreatorFromExtension(const char *aExtension)
1632{
1633 // XXX - This should be cut from the API. Would create an evil dependency.
1634 NS_ERROR("NS_ERROR_NOT_IMPLEMENTED");
1635 return NS_ERROR_NOT_IMPLEMENTED;
1636}
1637
1638/* void launchWithDoc (in nsILocalFile aDocToLoad, in boolean aLaunchInBackground); */
1639NS_IMETHODIMP nsLocalFile::LaunchWithDoc(nsILocalFile *aDocToLoad, PRBool aLaunchInBackground)
1640{
1641 PRBool isExecutable;
1642 nsresult rv = IsExecutable(&isExecutable);
1643 if (NS_FAILED(rv))
1644 return rv;
1645 if (!isExecutable)
1646 return NS_ERROR_FILE_EXECUTION_FAILED;
1647
1648 FSRef appFSRef, docFSRef;
1649 rv = GetFSRefInternal(appFSRef);
1650 if (NS_FAILED(rv))
1651 return rv;
1652
1653 if (aDocToLoad) {
1654 nsCOMPtr<nsILocalFileMac> macDoc = do_QueryInterface(aDocToLoad);
1655 rv = macDoc->GetFSRef(&docFSRef);
1656 if (NS_FAILED(rv))
1657 return rv;
1658 }
1659
1660 LSLaunchFlags theLaunchFlags = kLSLaunchDefaults;
1661 LSLaunchFSRefSpec thelaunchSpec;
1662
1663 if (aLaunchInBackground)
1664 theLaunchFlags |= kLSLaunchDontSwitch;
1665 memset(&thelaunchSpec, 0, sizeof(LSLaunchFSRefSpec));
1666
1667 thelaunchSpec.appRef = &appFSRef;
1668 if (aDocToLoad) {
1669 thelaunchSpec.numDocs = 1;
1670 thelaunchSpec.itemRefs = &docFSRef;
1671 }
1672 thelaunchSpec.launchFlags = theLaunchFlags;
1673
1674 OSErr err = ::LSOpenFromRefSpec(&thelaunchSpec, NULL);
1675 if (err != noErr)
1676 return MacErrorMapper(err);
1677
1678 return NS_OK;
1679}
1680
1681/* void openDocWithApp (in nsILocalFile aAppToOpenWith, in boolean aLaunchInBackground); */
1682NS_IMETHODIMP nsLocalFile::OpenDocWithApp(nsILocalFile *aAppToOpenWith, PRBool aLaunchInBackground)
1683{
1684 nsresult rv;
1685 OSErr err;
1686
1687 FSRef docFSRef, appFSRef;
1688 rv = GetFSRefInternal(docFSRef);
1689 if (NS_FAILED(rv))
1690 return rv;
1691
1692 if (aAppToOpenWith) {
1693 nsCOMPtr<nsILocalFileMac> appFileMac = do_QueryInterface(aAppToOpenWith, &rv);
1694 if (!appFileMac)
1695 return rv;
1696
1697 PRBool isExecutable;
1698 rv = appFileMac->IsExecutable(&isExecutable);
1699 if (NS_FAILED(rv))
1700 return rv;
1701 if (!isExecutable)
1702 return NS_ERROR_FILE_EXECUTION_FAILED;
1703
1704 rv = appFileMac->GetFSRef(&appFSRef);
1705 if (NS_FAILED(rv))
1706 return rv;
1707 }
1708 else {
1709 OSType fileCreator;
1710 rv = GetFileCreator(&fileCreator);
1711 if (NS_FAILED(rv))
1712 return rv;
1713
1714 err = ::LSFindApplicationForInfo(fileCreator, nsnull, nsnull, &appFSRef, nsnull);
1715 if (err != noErr)
1716 return MacErrorMapper(err);
1717 }
1718
1719 LSLaunchFlags theLaunchFlags = kLSLaunchDefaults;
1720 LSLaunchFSRefSpec thelaunchSpec;
1721
1722 if (aLaunchInBackground)
1723 theLaunchFlags |= kLSLaunchDontSwitch;
1724 memset(&thelaunchSpec, 0, sizeof(LSLaunchFSRefSpec));
1725
1726 thelaunchSpec.appRef = &appFSRef;
1727 thelaunchSpec.numDocs = 1;
1728 thelaunchSpec.itemRefs = &docFSRef;
1729 thelaunchSpec.launchFlags = theLaunchFlags;
1730
1731 err = ::LSOpenFromRefSpec(&thelaunchSpec, NULL);
1732 if (err != noErr)
1733 return MacErrorMapper(err);
1734
1735 return NS_OK;
1736}
1737
1738/* boolean isPackage (); */
1739NS_IMETHODIMP nsLocalFile::IsPackage(PRBool *_retval)
1740{
1741 NS_ENSURE_ARG(_retval);
1742 *_retval = PR_FALSE;
1743
1744 FSRef fsRef;
1745 nsresult rv = GetFSRefInternal(fsRef);
1746 if (NS_FAILED(rv))
1747 return rv;
1748
1749 FSCatalogInfo catalogInfo;
1750 OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags + kFSCatInfoFinderInfo,
1751 &catalogInfo, nsnull, nsnull, nsnull);
1752 if (err != noErr)
1753 return MacErrorMapper(err);
1754 if ((catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) != 0) {
1755 FileInfo *fInfoPtr = (FileInfo *)(catalogInfo.finderInfo);
1756 if ((fInfoPtr->finderFlags & kHasBundle) != 0) {
1757 *_retval = PR_TRUE;
1758 }
1759 else {
1760 // Folders ending with ".app" are also considered to
1761 // be packages, even if the top-level folder doesn't have bundle set
1762 nsCAutoString name;
1763 if (NS_SUCCEEDED(rv = GetNativeLeafName(name))) {
1764 const char *extPtr = strrchr(name.get(), '.');
1765 if (extPtr) {
1766 if ((nsCRT::strcasecmp(extPtr, ".app") == 0))
1767 *_retval = PR_TRUE;
1768 }
1769 }
1770 }
1771 }
1772 return NS_OK;
1773}
1774
1775
1776//*****************************************************************************
1777// nsLocalFile Methods
1778//*****************************************************************************
1779#pragma mark -
1780#pragma mark [Protected Methods]
1781
1782nsresult nsLocalFile::SetBaseRef(CFURLRef aCFURLRef)
1783{
1784 NS_ENSURE_ARG(aCFURLRef);
1785
1786 ::CFRetain(aCFURLRef);
1787 if (mBaseRef)
1788 ::CFRelease(mBaseRef);
1789 mBaseRef = aCFURLRef;
1790
1791 mFollowLinksDirty = PR_TRUE;
1792 UpdateTargetRef();
1793 mCachedFSRefValid = PR_FALSE;
1794 return NS_OK;
1795}
1796
1797nsresult nsLocalFile::UpdateTargetRef()
1798{
1799 if (!mBaseRef)
1800 return NS_ERROR_NOT_INITIALIZED;
1801
1802 if (mFollowLinksDirty) {
1803 if (mTargetRef) {
1804 ::CFRelease(mTargetRef);
1805 mTargetRef = nsnull;
1806 }
1807 if (mFollowLinks) {
1808 mTargetRef = mBaseRef;
1809 ::CFRetain(mTargetRef);
1810
1811 FSRef fsRef;
1812 if (::CFURLGetFSRef(mBaseRef, &fsRef)) {
1813 Boolean targetIsFolder, wasAliased;
1814 if (FSResolveAliasFile(&fsRef, true /*resolveAliasChains*/,
1815 &targetIsFolder, &wasAliased) == noErr && wasAliased) {
1816 ::CFRelease(mTargetRef);
1817 mTargetRef = CFURLCreateFromFSRef(NULL, &fsRef);
1818 if (!mTargetRef)
1819 return NS_ERROR_FAILURE;
1820 }
1821 }
1822 mFollowLinksDirty = PR_FALSE;
1823 }
1824 }
1825 return NS_OK;
1826}
1827
1828nsresult nsLocalFile::GetFSRefInternal(FSRef& aFSRef, PRBool bForceUpdateCache)
1829{
1830 if (bForceUpdateCache || !mCachedFSRefValid) {
1831 mCachedFSRefValid = PR_FALSE;
1832 CFURLRef whichURLRef = mFollowLinks ? mTargetRef : mBaseRef;
1833 NS_ENSURE_TRUE(whichURLRef, NS_ERROR_NULL_POINTER);
1834 if (::CFURLGetFSRef(whichURLRef, &mCachedFSRef))
1835 mCachedFSRefValid = PR_TRUE;
1836 }
1837 if (mCachedFSRefValid) {
1838 aFSRef = mCachedFSRef;
1839 return NS_OK;
1840 }
1841 // CFURLGetFSRef only returns a Boolean for success,
1842 // so we have to assume what the error was. This is
1843 // the only probable cause.
1844 return NS_ERROR_FILE_NOT_FOUND;
1845}
1846
1847nsresult nsLocalFile::GetPathInternal(nsACString& path)
1848{
1849 nsresult rv = NS_ERROR_FAILURE;
1850
1851 CFURLRef whichURLRef = mFollowLinks ? mTargetRef : mBaseRef;
1852 NS_ENSURE_TRUE(whichURLRef, NS_ERROR_NULL_POINTER);
1853
1854 CFStringRef pathStrRef = ::CFURLCopyFileSystemPath(whichURLRef, kCFURLPOSIXPathStyle);
1855 if (pathStrRef) {
1856 rv = CFStringReftoUTF8(pathStrRef, path);
1857 ::CFRelease(pathStrRef);
1858 }
1859 return rv;
1860}
1861
1862nsresult nsLocalFile::MoveCopy(nsIFile* aParentDir, const nsAString& newName, PRBool isCopy, PRBool followLinks)
1863{
1864 StFollowLinksState srcFollowState(*this, followLinks);
1865
1866 nsresult rv;
1867 OSErr err;
1868 FSRef srcFSRef, newFSRef;
1869
1870 rv = GetFSRefInternal(srcFSRef);
1871 if (NS_FAILED(rv))
1872 return rv;
1873
1874 nsCOMPtr<nsIFile> newParentDir = aParentDir;
1875 CFURLRef newBaseURLRef;
1876
1877 if (!newParentDir) {
1878 if (newName.IsEmpty())
1879 return NS_ERROR_INVALID_ARG;
1880 rv = GetParent(getter_AddRefs(newParentDir));
1881 if (NS_FAILED(rv))
1882 return rv;
1883 }
1884
1885 // If newParentDir does not exist, create it
1886 PRBool exists;
1887 rv = newParentDir->Exists(&exists);
1888 if (NS_FAILED(rv))
1889 return rv;
1890 if (!exists) {
1891 rv = newParentDir->Create(nsIFile::DIRECTORY_TYPE, 0666);
1892 if (NS_FAILED(rv))
1893 return rv;
1894 }
1895
1896 FSRef destFSRef;
1897 nsCOMPtr<nsILocalFileMac> newParentDirMac(do_QueryInterface(newParentDir));
1898 if (!newParentDirMac)
1899 return NS_ERROR_NO_INTERFACE;
1900 rv = newParentDirMac->GetFSRef(&destFSRef);
1901 if (NS_FAILED(rv))
1902 return rv;
1903
1904 if (isCopy) {
1905 err = ::FSCopyObject(&srcFSRef, &destFSRef,
1906 newName.Length(), newName.Length() ? PromiseFlatString(newName).get() : nsnull,
1907 0, kFSCatInfoNone, false, false, nsnull, nsnull, &newFSRef);
1908 // don't update ourselves on a copy
1909 }
1910 else {
1911 // According to the API: "If 'this' is a file, and the destination file already
1912 // exists, moveTo will replace the old file."
1913 FSCatalogInfo catalogInfo;
1914 HFSUniStr255 leafName;
1915 err = ::FSGetCatalogInfo(&srcFSRef, kFSCatInfoNodeFlags, &catalogInfo,
1916 newName.IsEmpty() ? &leafName : nsnull, nsnull, nsnull);
1917 if (err == noErr) {
1918 if (!(catalogInfo.nodeFlags & kFSNodeIsDirectoryMask)) {
1919 FSRef oldFileRef;
1920 if (newName.IsEmpty())
1921 err = ::FSMakeFSRefUnicode(&destFSRef, leafName.length, leafName.unicode,
1922 kTextEncodingUnknown, &oldFileRef);
1923 else
1924 err = ::FSMakeFSRefUnicode(&destFSRef, newName.Length(), PromiseFlatString(newName).get(),
1925 kTextEncodingUnknown, &oldFileRef);
1926 if (err == noErr)
1927 ::FSDeleteObject(&oldFileRef);
1928 }
1929 }
1930 // First, try the quick way which works only within the same volume
1931 err = ::FSMoveRenameObjectUnicode(&srcFSRef, &destFSRef,
1932 newName.Length(), newName.Length() ? PromiseFlatString(newName).get() : nsnull,
1933 kTextEncodingUnknown, &newFSRef);
1934
1935 if (err == diffVolErr) {
1936 // If on different volumes, resort to copy & delete
1937 err = ::FSCopyObject(&srcFSRef, &destFSRef,
1938 newName.Length(), newName.Length() ? PromiseFlatString(newName).get() : nsnull,
1939 0, kFSCatInfoNone, false, false, nsnull, nsnull, &newFSRef);
1940 ::FSDeleteObjects(&srcFSRef);
1941 }
1942 if (err == noErr) {
1943 newBaseURLRef = ::CFURLCreateFromFSRef(kCFAllocatorDefault, &newFSRef);
1944 if (!newBaseURLRef)
1945 return NS_ERROR_FAILURE;
1946 SetBaseRef(newBaseURLRef);
1947 ::CFRelease(newBaseURLRef);
1948 }
1949 }
1950 return MacErrorMapper(err);
1951}
1952
1953const PRInt64 kMilisecsPerSec = 1000LL;
1954const PRInt64 kUTCDateTimeFractionDivisor = 65535LL;
1955
1956PRInt64 nsLocalFile::HFSPlustoNSPRTime(const UTCDateTime& utcTime)
1957{
1958 // Start with seconds since Jan. 1, 1904 GMT
1959 PRInt64 result = ((PRInt64)utcTime.highSeconds << 32) + (PRInt64)utcTime.lowSeconds;
1960 // Subtract to convert to NSPR epoch of 1970
1961 result -= kJanuaryFirst1970Seconds;
1962 // Convert to milisecs
1963 result *= kMilisecsPerSec;
1964 // Convert the fraction to milisecs and add it
1965 result += ((PRInt64)utcTime.fraction * kMilisecsPerSec) / kUTCDateTimeFractionDivisor;
1966
1967 return result;
1968}
1969
1970void nsLocalFile::NSPRtoHFSPlusTime(PRInt64 nsprTime, UTCDateTime& utcTime)
1971{
1972 PRInt64 fraction = nsprTime % kMilisecsPerSec;
1973 PRInt64 seconds = (nsprTime / kMilisecsPerSec) + kJanuaryFirst1970Seconds;
1974 utcTime.highSeconds = (UInt16)((PRUint64)seconds >> 32);
1975 utcTime.lowSeconds = (UInt32)seconds;
1976 utcTime.fraction = (UInt16)((fraction * kUTCDateTimeFractionDivisor) / kMilisecsPerSec);
1977}
1978
1979nsresult nsLocalFile::CFStringReftoUTF8(CFStringRef aInStrRef, nsACString& aOutStr)
1980{
1981 nsresult rv = NS_ERROR_FAILURE;
1982 CFIndex usedBufLen, inStrLen = ::CFStringGetLength(aInStrRef);
1983 CFIndex charsConverted = ::CFStringGetBytes(aInStrRef, CFRangeMake(0, inStrLen),
1984 kCFStringEncodingUTF8, 0, PR_FALSE, nsnull, 0, &usedBufLen);
1985 if (charsConverted == inStrLen) {
1986 nsAutoBuffer<UInt8, FILENAME_BUFFER_SIZE> buffer;
1987 if (buffer.EnsureElemCapacity(usedBufLen + 1)) {
1988 ::CFStringGetBytes(aInStrRef, CFRangeMake(0, inStrLen),
1989 kCFStringEncodingUTF8, 0, false, buffer.get(), usedBufLen, &usedBufLen);
1990 buffer.get()[usedBufLen] = '\0';
1991 aOutStr.Assign(nsDependentCString((char*)buffer.get()));
1992 rv = NS_OK;
1993 }
1994 }
1995 return rv;
1996}
1997
1998//*****************************************************************************
1999// Global Functions
2000//*****************************************************************************
2001#pragma mark -
2002#pragma mark [Global Functions]
2003
2004void nsLocalFile::GlobalInit()
2005{
2006}
2007
2008void nsLocalFile::GlobalShutdown()
2009{
2010}
2011
2012nsresult NS_NewLocalFile(const nsAString& path, PRBool followLinks, nsILocalFile* *result)
2013{
2014 nsLocalFile* file = new nsLocalFile;
2015 if (file == nsnull)
2016 return NS_ERROR_OUT_OF_MEMORY;
2017 NS_ADDREF(file);
2018
2019 file->SetFollowLinks(followLinks);
2020
2021 if (!path.IsEmpty()) {
2022 nsresult rv = file->InitWithPath(path);
2023 if (NS_FAILED(rv)) {
2024 NS_RELEASE(file);
2025 return rv;
2026 }
2027 }
2028 *result = file;
2029 return NS_OK;
2030}
2031
2032nsresult NS_NewNativeLocalFile(const nsACString& path, PRBool followLinks, nsILocalFile **result)
2033{
2034 return NS_NewLocalFile(NS_ConvertUTF8toUCS2(path), followLinks, result);
2035}
2036
2037nsresult NS_NewLocalFileWithFSSpec(const FSSpec* inSpec, PRBool followLinks, nsILocalFileMac **result)
2038{
2039 nsLocalFile* file = new nsLocalFile();
2040 if (file == nsnull)
2041 return NS_ERROR_OUT_OF_MEMORY;
2042 NS_ADDREF(file);
2043
2044 file->SetFollowLinks(followLinks);
2045
2046 nsresult rv = file->InitWithFSSpec(inSpec);
2047 if (NS_FAILED(rv)) {
2048 NS_RELEASE(file);
2049 return rv;
2050 }
2051 *result = file;
2052 return NS_OK;
2053}
2054
2055//*****************************************************************************
2056// Static Functions
2057//*****************************************************************************
2058
2059static nsresult MacErrorMapper(OSErr inErr)
2060{
2061 nsresult outErr;
2062
2063 switch (inErr)
2064 {
2065 case noErr:
2066 outErr = NS_OK;
2067 break;
2068
2069 case fnfErr:
2070 outErr = NS_ERROR_FILE_NOT_FOUND;
2071 break;
2072
2073 case dupFNErr:
2074 outErr = NS_ERROR_FILE_ALREADY_EXISTS;
2075 break;
2076
2077 case dskFulErr:
2078 outErr = NS_ERROR_FILE_DISK_FULL;
2079 break;
2080
2081 case fLckdErr:
2082 outErr = NS_ERROR_FILE_IS_LOCKED;
2083 break;
2084
2085 // Can't find good map for some
2086 case bdNamErr:
2087 outErr = NS_ERROR_FAILURE;
2088 break;
2089
2090 default:
2091 outErr = NS_ERROR_FAILURE;
2092 break;
2093 }
2094 return outErr;
2095}
2096
2097static OSErr FindRunningAppBySignature(OSType aAppSig, ProcessSerialNumber& outPsn)
2098{
2099 ProcessInfoRec info;
2100 OSErr err = noErr;
2101
2102 outPsn.highLongOfPSN = 0;
2103 outPsn.lowLongOfPSN = kNoProcess;
2104
2105 while (PR_TRUE)
2106 {
2107 err = ::GetNextProcess(&outPsn);
2108 if (err == procNotFound)
2109 break;
2110 if (err != noErr)
2111 return err;
2112 info.processInfoLength = sizeof(ProcessInfoRec);
2113 info.processName = nil;
2114 info.processAppSpec = nil;
2115 err = ::GetProcessInformation(&outPsn, &info);
2116 if (err != noErr)
2117 return err;
2118
2119 if (info.processSignature == aAppSig)
2120 return noErr;
2121 }
2122 return procNotFound;
2123}
2124
2125// Convert a UTF-8 string to a UTF-16 string while normalizing to
2126// Normalization Form C (composed Unicode). We need this because
2127// Mac OS X file system uses NFD (Normalization Form D : decomposed Unicode)
2128// while most other OS', server-side programs usually expect NFC.
2129
2130typedef void (*UnicodeNormalizer) (CFMutableStringRef, CFStringNormalizationForm);
2131static void CopyUTF8toUTF16NFC(const nsACString& aSrc, nsAString& aResult)
2132{
2133 static PRBool sChecked = PR_FALSE;
2134 static UnicodeNormalizer sUnicodeNormalizer = NULL;
2135
2136 // CFStringNormalize was not introduced until Mac OS 10.2
2137 if (!sChecked) {
2138 CFBundleRef carbonBundle =
2139 CFBundleGetBundleWithIdentifier(CFSTR("com.apple.Carbon"));
2140 if (carbonBundle)
2141 sUnicodeNormalizer = (UnicodeNormalizer)
2142 ::CFBundleGetFunctionPointerForName(carbonBundle,
2143 CFSTR("CFStringNormalize"));
2144 sChecked = PR_TRUE;
2145 }
2146
2147 if (!sUnicodeNormalizer) { // OS X 10.2 or earlier
2148 CopyUTF8toUTF16(aSrc, aResult);
2149 return;
2150 }
2151
2152 const nsAFlatCString &inFlatSrc = PromiseFlatCString(aSrc);
2153
2154 // The number of 16bit code units in a UTF-16 string will never be
2155 // larger than the number of bytes in the corresponding UTF-8 string.
2156 CFMutableStringRef inStr =
2157 ::CFStringCreateMutable(NULL, inFlatSrc.Length());
2158
2159 if (!inStr) {
2160 CopyUTF8toUTF16(aSrc, aResult);
2161 return;
2162 }
2163
2164 ::CFStringAppendCString(inStr, inFlatSrc.get(), kCFStringEncodingUTF8);
2165
2166 sUnicodeNormalizer(inStr, kCFStringNormalizationFormC);
2167
2168 CFIndex length = CFStringGetLength(inStr);
2169 const UniChar* chars = CFStringGetCharactersPtr(inStr);
2170
2171 if (chars)
2172 aResult.Assign(chars, length);
2173 else {
2174 nsAutoBuffer<UniChar, FILENAME_BUFFER_SIZE> buffer;
2175 if (!buffer.EnsureElemCapacity(length))
2176 CopyUTF8toUTF16(aSrc, aResult);
2177 else {
2178 CFStringGetCharacters(inStr, CFRangeMake(0, length), buffer.get());
2179 aResult.Assign(buffer.get(), length);
2180 }
2181 }
2182 CFRelease(inStr);
2183}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette