diff --git a/mozilla/xpcom/io/nsLocalFileOSX.cpp b/mozilla/xpcom/io/nsLocalFileOSX.cpp index 882b431facd..3bb1562ba39 100644 --- a/mozilla/xpcom/io/nsLocalFileOSX.cpp +++ b/mozilla/xpcom/io/nsLocalFileOSX.cpp @@ -42,7 +42,6 @@ #include "nsReadableUtils.h" #include "nsISimpleEnumerator.h" #include "nsITimelineService.h" -#include "nsVoidArray.h" #include "plbase64.h" #include "prmem.h" @@ -171,12 +170,9 @@ class nsDirEnumerator : public nsISimpleEnumerator } } if (mArrayIndex < mArrayCnt) { - nsLocalFile *newFile = new nsLocalFile; + nsLocalFile *newFile = new nsLocalFile(mFSRefsArray[mArrayIndex], nsString()); if (!newFile) return NS_ERROR_OUT_OF_MEMORY; - FSRef fsRef = mFSRefsArray[mArrayIndex]; - if (NS_FAILED(newFile->InitWithFSRef(&fsRef))) - return NS_ERROR_FAILURE; mArrayIndex++; mNext = newFile; } @@ -308,47 +304,62 @@ protected: // nsLocalFile //***************************************************************************** -const char nsLocalFile::kPathSepChar = '/'; -const PRUnichar nsLocalFile::kPathSepUnichar = '/'; - // The HFS+ epoch is Jan. 1, 1904 GMT - differs from HFS in which times were local // The NSPR epoch is Jan. 1, 1970 GMT // 2082844800 is the difference in seconds between those dates -const PRInt64 nsLocalFile::kJanuaryFirst1970Seconds = 2082844800LL; +PRInt64 nsLocalFile::kJanuaryFirst1970Seconds = 2082844800LL; +PRUnichar nsLocalFile::kPathSepUnichar; +char nsLocalFile::kPathSepChar; +FSRef nsLocalFile::kInvalidFSRef; // an FSRef filled with zeros is invalid +FSRef nsLocalFile::kRootFSRef; #pragma mark - #pragma mark [CTORs/DTOR] nsLocalFile::nsLocalFile() : - mBaseRef(nsnull), - mTargetRef(nsnull), - mCachedFSRefValid(PR_FALSE), mFollowLinks(PR_TRUE), + mIdentityDirty(PR_TRUE), mFollowLinksDirty(PR_TRUE) { + mFSRef = kInvalidFSRef; + mTargetFSRef = kInvalidFSRef; +} + +nsLocalFile::nsLocalFile(const FSRef& aFSRef, const nsAString& aRelativePath) : + mFSRef(aFSRef), + mFollowLinks(PR_TRUE), + mIdentityDirty(PR_TRUE), + mFollowLinksDirty(PR_TRUE) +{ + mTargetFSRef = kInvalidFSRef; + + if (aRelativePath.Length()) { + nsAString::const_iterator nodeBegin, pathEnd; + aRelativePath.BeginReading(nodeBegin); + aRelativePath.EndReading(pathEnd); + nsAString::const_iterator nodeEnd(nodeBegin); + + while (nodeEnd != pathEnd) { + FindCharInReadable(kPathSepUnichar, nodeEnd, pathEnd); + mNonExtantNodes.push_back(nsString(Substring(nodeBegin, nodeEnd))); + if (nodeEnd != pathEnd) // If there's more left in the string, inc over the '/' nodeEnd is on. + ++nodeEnd; + nodeBegin = nodeEnd; + } + } } nsLocalFile::nsLocalFile(const nsLocalFile& src) : - mBaseRef(src.mBaseRef), - mTargetRef(src.mTargetRef), - mCachedFSRef(src.mCachedFSRef), - mCachedFSRefValid(src.mCachedFSRefValid), + mFSRef(src.mFSRef), mNonExtantNodes(src.mNonExtantNodes), + mTargetFSRef(src.mTargetFSRef), mFollowLinks(src.mFollowLinks), + mIdentityDirty(src.mIdentityDirty), mFollowLinksDirty(src.mFollowLinksDirty) { - // A CFURLRef is immutable so no need to copy, just retain. - if (mBaseRef) - ::CFRetain(mBaseRef); - if (mTargetRef) - ::CFRetain(mTargetRef); } nsLocalFile::~nsLocalFile() { - if (mBaseRef) - ::CFRelease(mBaseRef); - if (mTargetRef) - ::CFRelease(mTargetRef); } @@ -391,32 +402,46 @@ NS_METHOD nsLocalFile::nsLocalFileConstructor(nsISupports* outer, const nsIID& a /* void append (in AString node); */ NS_IMETHODIMP nsLocalFile::Append(const nsAString& aNode) { - return AppendNative(NS_ConvertUCS2toUTF8(aNode)); + nsAString::const_iterator start, end; + aNode.BeginReading(start); + aNode.EndReading(end); + if (FindCharInReadable(kPathSepChar, start, end)) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + mIdentityDirty = mFollowLinksDirty = PR_TRUE; + + if (!mNonExtantNodes.size()) { + // Make sure the leaf is resolved before attempting to append to it. + Boolean isFolder, isAlias; + OSErr err = ::FSResolveAliasFile(&mFSRef, PR_TRUE, &isFolder, &isAlias); + if (err == noErr) { + if (!isFolder) + return NS_ERROR_FILE_NOT_DIRECTORY; + FSRef newLeafRef; + err = ::FSMakeFSRefUnicode(&mFSRef, aNode.Length(), + (UniChar *)PromiseFlatString(aNode).get(), + kTextEncodingUnknown, &newLeafRef); + if (err == noErr) { + mFSRef = newLeafRef; + mIdentityDirty = PR_FALSE; + } + } + if (err == fnfErr) { + mNonExtantNodes.push_back(nsString(aNode)); + err = noErr; + } + return MacErrorMapper(err); + } + else + mNonExtantNodes.push_back(nsString(aNode)); + + return NS_OK; } /* [noscript] void appendNative (in ACString node); */ NS_IMETHODIMP nsLocalFile::AppendNative(const nsACString& aNode) { - nsACString::const_iterator start, end; - aNode.BeginReading(start); - aNode.EndReading(end); - if (FindCharInReadable(kPathSepChar, start, end)) - return NS_ERROR_FILE_UNRECOGNIZED_PATH; - - CFStringRef nodeStrRef = ::CFStringCreateWithCString(kCFAllocatorDefault, - PromiseFlatCString(aNode).get(), - kCFStringEncodingUTF8); - if (nodeStrRef) { - CFURLRef newRef = ::CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, - mBaseRef, nodeStrRef, PR_FALSE); - ::CFRelease(nodeStrRef); - if (newRef) { - SetBaseRef(newRef); - ::CFRelease(newRef); - return NS_OK; - } - } - return NS_ERROR_FAILURE; + return Append(NS_ConvertUTF8toUCS2(aNode)); } /* void normalize (); */ @@ -428,131 +453,110 @@ NS_IMETHODIMP nsLocalFile::Normalize() /* void create (in unsigned long type, in unsigned long permissions); */ NS_IMETHODIMP nsLocalFile::Create(PRUint32 type, PRUint32 permissions) { - if (type != NORMAL_FILE_TYPE && type != DIRECTORY_TYPE) - return NS_ERROR_FILE_UNKNOWN_TYPE; - - nsStringArray nonExtantNodes; - CFURLRef pathURLRef = mBaseRef; - FSRef pathFSRef; - CFStringRef leafStrRef = nsnull; - StBuffer buffer; - Boolean success; - - // Work backwards through the path to find the last node which - // exists. Place the nodes which don't exist in an array and we'll - // create those below. - while ((success = ::CFURLGetFSRef(pathURLRef, &pathFSRef)) == false) { - leafStrRef = ::CFURLCopyLastPathComponent(pathURLRef); - if (!leafStrRef) - break; - CFIndex leafLen = ::CFStringGetLength(leafStrRef); - if (!buffer.EnsureElemCapacity(leafLen + 1)) - break; - ::CFStringGetCharacters(leafStrRef, CFRangeMake(0, leafLen), buffer.get()); - buffer.get()[leafLen] = '\0'; - nonExtantNodes.AppendString(nsString(nsDependentString(buffer.get()))); - ::CFRelease(leafStrRef); - leafStrRef = nsnull; - - // Get the parent of the leaf for the next go round - CFURLRef parent = ::CFURLCreateCopyDeletingLastPathComponent(NULL, pathURLRef); - if (!parent) - break; - if (pathURLRef != mBaseRef) - ::CFRelease(pathURLRef); - pathURLRef = parent; - } - if (pathURLRef != mBaseRef) - ::CFRelease(pathURLRef); - if (leafStrRef != nsnull) - ::CFRelease(leafStrRef); - if (!success) - return NS_ERROR_FAILURE; - PRInt32 nodesToCreate = nonExtantNodes.Count(); - if (nodesToCreate == 0) - return NS_ERROR_FILE_ALREADY_EXISTS; - - OSErr err; - nsAutoString nextNodeName; - for (PRInt32 i = nodesToCreate - 1; i > 0; i--) { - nonExtantNodes.StringAt(i, nextNodeName); - err = ::FSCreateDirectoryUnicode(&pathFSRef, - nextNodeName.Length(), - (const UniChar *)nextNodeName.get(), - kFSCatInfoNone, - nsnull, &pathFSRef, nsnull, nsnull); - if (err != noErr) - return MacErrorMapper(err); - } - nonExtantNodes.StringAt(0, nextNodeName); - if (type == NORMAL_FILE_TYPE) { - err = ::FSCreateFileUnicode(&pathFSRef, - nextNodeName.Length(), - (const UniChar *)nextNodeName.get(), - kFSCatInfoNone, - nsnull, nsnull, nsnull); - } - else { - err = ::FSCreateDirectoryUnicode(&pathFSRef, - nextNodeName.Length(), - (const UniChar *)nextNodeName.get(), + if (type != NORMAL_FILE_TYPE && type != DIRECTORY_TYPE) + return NS_ERROR_FILE_UNKNOWN_TYPE; + + nsresult rv = ResolveNonExtantNodes(PR_TRUE); + if (NS_FAILED(rv)) + return rv; + if (mNonExtantNodes.size() == 0) + return NS_ERROR_FILE_ALREADY_EXISTS; + + OSErr err; + FSRef newRef; + const nsString& leafName = mNonExtantNodes.back(); + + switch (type) + { + case NORMAL_FILE_TYPE: + //SetOSTypeAndCreatorFromExtension(); + err = ::FSCreateFileUnicode(&mFSRef, + leafName.Length(), + (const UniChar *)leafName.get(), kFSCatInfoNone, - nsnull, nsnull, nsnull, nsnull); - } - - return MacErrorMapper(err); + nsnull, &newRef, nsnull); + break; + + case DIRECTORY_TYPE: + err = ::FSCreateDirectoryUnicode(&mFSRef, + leafName.Length(), + (const UniChar *)leafName.get(), + kFSCatInfoNone, + nsnull, &newRef, nsnull, nsnull); + break; + + default: + return NS_ERROR_FILE_UNKNOWN_TYPE; + break; + } + + if (err == noErr) { + mFSRef = newRef; + mNonExtantNodes.clear(); + return NS_OK; + } + + return MacErrorMapper(err); } /* attribute AString leafName; */ NS_IMETHODIMP nsLocalFile::GetLeafName(nsAString& aLeafName) { - nsCAutoString nativeString; - nsresult rv = GetNativeLeafName(nativeString); - if (NS_FAILED(rv)) - return rv; - aLeafName.Assign(NS_ConvertUTF8toUCS2(nativeString)); - return NS_OK; + if (mNonExtantNodes.size()) { + const nsString& leafNode = mNonExtantNodes.back(); + aLeafName.Assign(leafNode); + return NS_OK; + } + HFSUniStr255 leafName; + OSErr err = ::FSGetCatalogInfo(&mFSRef, + kFSCatInfoNone, + nsnull, + &leafName, + nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); + aLeafName.Assign((PRUnichar *)leafName.unicode, leafName.length); + return NS_OK; } NS_IMETHODIMP nsLocalFile::SetLeafName(const nsAString& aLeafName) { - return SetNativeLeafName(NS_ConvertUCS2toUTF8(aLeafName)); + if (aLeafName.IsEmpty()) + return NS_ERROR_INVALID_ARG; + + if (mNonExtantNodes.size()) { + nsString& leafNode = mNonExtantNodes.back(); + leafNode.Assign(aLeafName); + return NS_OK; + } + else { + // Just get the parent ref and assign that to mFSRef + // Stick the new leaf name in mAppendedNodes. + FSRef parentRef; + OSErr err = ::FSGetParentRef(&mFSRef, &parentRef); + if (err != noErr) + return MacErrorMapper(err); + mFSRef = parentRef; + mNonExtantNodes.push_back(nsString(aLeafName)); + mIdentityDirty = PR_TRUE; + } + return NS_OK; } /* [noscript] attribute ACString nativeLeafName; */ NS_IMETHODIMP nsLocalFile::GetNativeLeafName(nsACString& aNativeLeafName) { - nsresult rv = NS_ERROR_FAILURE; - CFStringRef leafStrRef = ::CFURLCopyLastPathComponent(mBaseRef); - if (leafStrRef) { - rv = CFStringReftoUTF8(leafStrRef, aNativeLeafName); - ::CFRelease(leafStrRef); - } - return rv; + nsAutoString temp; + nsresult rv = GetLeafName(temp); + if (NS_FAILED(rv)) + return rv; + aNativeLeafName.Assign(NS_ConvertUCS2toUTF8(temp)); + return NS_OK; } NS_IMETHODIMP nsLocalFile::SetNativeLeafName(const nsACString& aNativeLeafName) { - nsresult rv = NS_ERROR_FAILURE; - CFURLRef parentURLRef = ::CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, mBaseRef); - if (parentURLRef) { - CFStringRef nodeStrRef = ::CFStringCreateWithCString(kCFAllocatorDefault, - PromiseFlatCString(aNativeLeafName).get(), - kCFStringEncodingUTF8); - - if (nodeStrRef) { - CFURLRef newURLRef = ::CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, - parentURLRef, nodeStrRef, PR_FALSE); - if (newURLRef) { - SetBaseRef(newURLRef); - ::CFRelease(newURLRef); - rv = NS_OK; - } - ::CFRelease(nodeStrRef); - } - ::CFRelease(parentURLRef); - } - return rv; + return SetLeafName(NS_ConvertUTF8toUCS2(aNativeLeafName)); } /* void copyTo (in nsIFile newParentDir, in AString newName); */ @@ -605,14 +609,28 @@ NS_IMETHODIMP nsLocalFile::Remove(PRBool recursive) rv = IsDirectory(&isDir); if (NS_FAILED(rv)) return rv; - + + // Since FSRefs can only refer to extant file objects and we're about to become non-extant, + // re-specify ourselves as our parent FSRef + current leaf name + OSErr err; + FSCatalogInfo catalogInfo; + HFSUniStr255 leafName; + FSRef parentRef; + + err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNone, &catalogInfo, &leafName, nsnull, &parentRef); + if (err != noErr) + return MacErrorMapper(err); + + mFSRef = parentRef; + mNonExtantNodes.push_back(nsString(Substring(leafName.unicode, leafName.unicode + leafName.length))); + mIdentityDirty = PR_TRUE; + if (recursive && isDir) err = ::FSDeleteContainer(&fsRef); else err = ::FSDeleteObject(&fsRef); - - mCachedFSRefValid = PR_FALSE; + return MacErrorMapper(err); } @@ -697,6 +715,7 @@ NS_IMETHODIMP nsLocalFile::SetLastModifiedTime(PRInt64 aLastModifiedTime) if (NS_FAILED(rv)) return rv; +#if XP_MACOSX FSRef parentRef; PRBool notifyParent; @@ -708,16 +727,19 @@ NS_IMETHODIMP nsLocalFile::SetLastModifiedTime(PRInt64 aLastModifiedTime) /* Notify the parent if this is a file */ notifyParent = (0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask)); +#endif NSPRtoHFSPlusTime(aLastModifiedTime, catalogInfo.contentModDate); err = ::FSSetCatalogInfo(&fsRef, kFSCatInfoContentMod, &catalogInfo); if (err != noErr) return MacErrorMapper(err); +#if XP_MACOSX /* Send a notification for the parent of the file, or for the directory */ err = FNNotify(notifyParent ? &parentRef : &fsRef, kFNDirectoryModifiedMessage, kNilOptions); if (err != noErr) return MacErrorMapper(err); +#endif return NS_OK; } @@ -801,24 +823,41 @@ NS_IMETHODIMP nsLocalFile::GetNativeTarget(nsACString& aNativeTarget) /* readonly attribute AString path; */ NS_IMETHODIMP nsLocalFile::GetPath(nsAString& aPath) { - nsCAutoString nativeString; - nsresult rv = GetNativePath(nativeString); - if (NS_FAILED(rv)) - return rv; - aPath.Assign(NS_ConvertUTF8toUCS2(nativeString)); + UInt8 pathBuf[PATH_MAX + 1]; + OSErr err = ::FSRefMakePath(&mFSRef, pathBuf, sizeof(pathBuf)); + if (err != noErr) + return MacErrorMapper(err); + aPath.Assign(NS_ConvertUTF8toUCS2((char *)pathBuf)); + + deque::iterator iter(mNonExtantNodes.begin()); + deque::iterator end(mNonExtantNodes.end()); + while (iter != end) { + aPath.Append(kPathSepUnichar); + aPath.Append(*iter); + ++iter; + } + return NS_OK; } /* [noscript] readonly attribute ACString nativePath; */ NS_IMETHODIMP nsLocalFile::GetNativePath(nsACString& aNativePath) { - nsresult rv = NS_ERROR_FAILURE; - CFStringRef pathStrRef = ::CFURLCopyFileSystemPath(mBaseRef, kCFURLPOSIXPathStyle); - if (pathStrRef) { - rv = CFStringReftoUTF8(pathStrRef, aNativePath); - ::CFRelease(pathStrRef); - } - return rv; + UInt8 pathBuf[PATH_MAX + 1]; + OSErr err = ::FSRefMakePath(&mFSRef, pathBuf, sizeof(pathBuf)); + if (err != noErr) + return MacErrorMapper(err); + aNativePath.Assign((char *)pathBuf); + + deque::iterator iter(mNonExtantNodes.begin()); + deque::iterator end(mNonExtantNodes.end()); + while (iter != end) { + aNativePath.Append(kPathSepChar); + aNativePath.Append((NS_ConvertUCS2toUTF8(*iter))); + ++iter; + } + + return NS_OK; } /* boolean exists (); */ @@ -828,10 +867,10 @@ NS_IMETHODIMP nsLocalFile::Exists(PRBool *_retval) *_retval = PR_FALSE; FSRef fsRef; - if (NS_SUCCEEDED(GetFSRefInternal(fsRef, PR_TRUE))) { - *_retval = PR_TRUE; + if (NS_SUCCEEDED(GetFSRefInternal(fsRef))) { + *_retval = (::FSGetCatalogInfo(&mFSRef, kFSCatInfoNone, + nsnull, nsnull, nsnull, nsnull) == noErr); } - return NS_OK; } @@ -902,18 +941,19 @@ NS_IMETHODIMP nsLocalFile::IsHidden(PRBool *_retval) FSCatalogInfo catalogInfo; HFSUniStr255 leafName; - OSErr err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoNodeFlags, &catalogInfo, - &leafName, nsnull, nsnull); + OSErr err = FSGetCatalogInfo(&fsRef, kFSCatInfoFinderInfo, &catalogInfo, + &leafName, nsnull, nsnull); if (err != noErr) return MacErrorMapper(err); - + FileInfo *fInfoPtr = (FileInfo *)(catalogInfo.finderInfo); // Finder flags are in the same place whether we use FileInfo or FolderInfo if ((fInfoPtr->finderFlags & kIsInvisible) != 0) { *_retval = PR_TRUE; } else { // If the leaf name begins with a '.', consider it invisible - if (leafName.length >= 1 && leafName.unicode[0] == UniChar('.')) + nsDependentString leaf(leafName.unicode, leafName.length); + if (leaf.First() == PRUnichar('.')) *_retval = PR_TRUE; } return NS_OK; @@ -926,7 +966,7 @@ NS_IMETHODIMP nsLocalFile::IsDirectory(PRBool *_retval) *_retval = PR_FALSE; FSRef fsRef; - nsresult rv = GetFSRefInternal(fsRef, PR_FALSE); + nsresult rv = GetFSRefInternal(fsRef); if (NS_FAILED(rv)) return rv; @@ -946,7 +986,7 @@ NS_IMETHODIMP nsLocalFile::IsFile(PRBool *_retval) *_retval = PR_FALSE; FSRef fsRef; - nsresult rv = GetFSRefInternal(fsRef, PR_FALSE); + nsresult rv = GetFSRefInternal(fsRef); if (NS_FAILED(rv)) return rv; @@ -965,12 +1005,13 @@ NS_IMETHODIMP nsLocalFile::IsSymlink(PRBool *_retval) NS_ENSURE_ARG(_retval); *_retval = PR_FALSE; - FSRef fsRef; - if (::CFURLGetFSRef(mBaseRef, &fsRef)) { - Boolean isAlias, isFolder; - if (::FSIsAliasFile(&fsRef, &isAlias, &isFolder) == noErr) - *_retval = isAlias; - } + nsresult rv = Resolve(); + if (NS_FAILED(rv)) + return rv; + + Boolean isAlias, isFolder; + if (::FSIsAliasFile(&mFSRef, &isAlias, &isFolder) == noErr) + *_retval = isAlias; return NS_OK; } @@ -1042,6 +1083,27 @@ NS_IMETHODIMP nsLocalFile::Contains(nsIFile *inFile, PRBool recur, PRBool *_retv if (!isDir) return NS_OK; // must be a dir to contain someone + nsCOMPtr inMacFile(do_QueryInterface(inFile)); + if (!inMacFile) + return NS_OK; + + // if we can get FSRefs from both, use them + FSRef thisFSRef, inFSRef; + if (NS_SUCCEEDED(GetFSRef(&thisFSRef)) && NS_SUCCEEDED(inMacFile->GetFSRef(&inFSRef))) { + FSRef parentFSRef; + while ((::FSGetParentRef(&inFSRef, &parentFSRef) == noErr && ::FSRefValid(&parentFSRef))) { + if (::FSCompareFSRefs(&parentFSRef, &thisFSRef) == noErr) { + *_retval = PR_TRUE; + return NS_OK; + } + if (!recur) + return NS_OK; + inFSRef = parentFSRef; + } + return NS_OK; + } + + // If we fall thru to here, we couldn't get the FSRefs so compare paths nsCAutoString thisPath, inPath; if (NS_FAILED(GetNativePath(thisPath)) || NS_FAILED(inFile->GetNativePath(inPath))) return NS_ERROR_FAILURE; @@ -1061,26 +1123,48 @@ NS_IMETHODIMP nsLocalFile::GetParent(nsIFile * *aParent) NS_ENSURE_ARG_POINTER(aParent); *aParent = nsnull; + nsresult rv; + FSRef fsRef; nsLocalFile *newFile = nsnull; // If it can be determined without error that a file does not // have a parent, return nsnull for the parent and NS_OK as the result. // See bug 133617. - nsresult rv = NS_OK; - CFURLRef parentURLRef = ::CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, mBaseRef); - if (parentURLRef) { - rv = NS_ERROR_FAILURE; - newFile = new nsLocalFile; - if (newFile) { - rv = newFile->InitWithCFURL(parentURLRef); - if (NS_SUCCEEDED(rv)) { - NS_ADDREF(*aParent = newFile); - rv = NS_OK; + + rv = GetFSRefInternal(fsRef); + if (NS_SUCCEEDED(rv)) { + FSRef parentRef; + // If an FSRef has no parent, FSGetParentRef returns noErr and + // an FSRef filled with zeros (kInvalidFSRef). + OSErr err = ::FSGetParentRef(&fsRef, &parentRef); + if (err != noErr) + return MacErrorMapper(err); + if (::FSRefValid(&parentRef) == PR_FALSE) + return NS_OK; + newFile = new nsLocalFile(parentRef, nsString()); + } + else { + nsAutoString appendedNodes; + if (mNonExtantNodes.size() > 1) { + deque::iterator iter(mNonExtantNodes.begin()); + deque::iterator end(mNonExtantNodes.end() - 1); + while (iter != end) { + const nsString& currentNode = *iter; + ++iter; + appendedNodes.Append(currentNode); + if (iter < end) + appendedNodes.Append(kPathSepUnichar); } + return NS_ERROR_FAILURE; } - ::CFRelease(parentURLRef); - } - return rv; + newFile = new nsLocalFile(mFSRef, appendedNodes); + } + if (!newFile) + return NS_ERROR_FAILURE; + *aParent = newFile; + NS_ADDREF(*aParent); + + return NS_OK; } /* readonly attribute nsISimpleEnumerator directoryEntries; */ @@ -1140,6 +1224,9 @@ NS_IMETHODIMP nsLocalFile::InitWithNativePath(const nsACString& filePath) fixedPath.Assign(filePath); fixedPath.ReplaceSubstring("//", "/"); + mNonExtantNodes.clear(); + mIdentityDirty = PR_TRUE; + CFStringRef pathAsCFString; CFURLRef pathAsCFURL; @@ -1151,9 +1238,37 @@ NS_IMETHODIMP nsLocalFile::InitWithNativePath(const nsACString& filePath) ::CFRelease(pathAsCFString); return NS_ERROR_FAILURE; } - SetBaseRef(pathAsCFURL); + + CFStringRef leaf = nsnull; + StBuffer buffer; + PRBool success; + while ((success = ::CFURLGetFSRef(pathAsCFURL, &mFSRef)) == PR_FALSE) { + // Extract the last component and push onto the front of mNonExtantNodes + leaf = ::CFURLCopyLastPathComponent(pathAsCFURL); + if (!leaf) + break; + CFIndex leafLen = ::CFStringGetLength(leaf); + if (!buffer.EnsureElemCapacity(leafLen + 1)) + break; + ::CFStringGetCharacters(leaf, CFRangeMake(0, leafLen), buffer.get()); + buffer.get()[leafLen] = '\0'; + mNonExtantNodes.push_front(nsString(nsDependentString(buffer.get()))); + ::CFRelease(leaf); + leaf = nsnull; + + // Get the parent of the leaf for the next go round + CFURLRef parent = ::CFURLCreateCopyDeletingLastPathComponent(NULL, pathAsCFURL); + if (!parent) + break; + ::CFRelease(pathAsCFURL); + pathAsCFURL = parent; + } + ::CFRelease(pathAsCFString); ::CFRelease(pathAsCFURL); - return NS_OK; + if (leaf) + ::CFRelease(leaf); + + return success ? NS_OK : NS_ERROR_FAILURE; } /* void initWithFile (in nsILocalFile aFile); */ @@ -1161,16 +1276,27 @@ NS_IMETHODIMP nsLocalFile::InitWithFile(nsILocalFile *aFile) { NS_ENSURE_ARG(aFile); - nsCOMPtr aFileMac(do_QueryInterface(aFile)); - if (!aFileMac) + // Argh - since no rtti, we have to use a static_cast. + // At least QI to an nsILocalFileMac, making the static_cast less of a leap. + nsCOMPtr asLocalFileMac(do_QueryInterface(aFile)); + if (!asLocalFileMac) return NS_ERROR_UNEXPECTED; - CFURLRef urlRef; - nsresult rv = aFileMac->GetCFURL(&urlRef); - if (NS_FAILED(rv)) - return rv; - rv = InitWithCFURL(urlRef); - ::CFRelease(urlRef); - return rv; + + nsLocalFile *asLocalFile = NS_STATIC_CAST(nsLocalFile*, aFile); + mFSRef = asLocalFile->mFSRef; + + // XXX - deque::operator= generates a signed/unsigned comparison warning which, + // because of templates, is long and ugly. Do it by hand here because, either way, + // the expense here is in copy constructing nsStrings. + mNonExtantNodes.clear(); + deque::iterator iter(asLocalFile->mNonExtantNodes.begin()); + while (iter != asLocalFile->mNonExtantNodes.end()) { + mNonExtantNodes.push_back(*iter); + ++iter; + } + mTargetFSRef = asLocalFile->mTargetFSRef; + mIdentityDirty = PR_TRUE; + return NS_OK; } /* attribute PRBool followLinks; */ @@ -1184,16 +1310,15 @@ NS_IMETHODIMP nsLocalFile::GetFollowLinks(PRBool *aFollowLinks) NS_IMETHODIMP nsLocalFile::SetFollowLinks(PRBool aFollowLinks) { - if (aFollowLinks != mFollowLinks) { - mFollowLinks = aFollowLinks; - UpdateTargetRef(); - } + mFollowLinks = aFollowLinks; + mFollowLinksDirty = PR_TRUE; return NS_OK; } /* [noscript] PRFileDescStar openNSPRFileDesc (in long flags, in long mode); */ NS_IMETHODIMP nsLocalFile::OpenNSPRFileDesc(PRInt32 flags, PRInt32 mode, PRFileDesc **_retval) { + // XXX - needs change for CFM NS_ENSURE_ARG_POINTER(_retval); nsCAutoString path; @@ -1211,6 +1336,7 @@ NS_IMETHODIMP nsLocalFile::OpenNSPRFileDesc(PRInt32 flags, PRInt32 mode, PRFileD /* [noscript] FILE openANSIFileDesc (in string mode); */ NS_IMETHODIMP nsLocalFile::OpenANSIFileDesc(const char *mode, FILE **_retval) { + // XXX - needs change for CFM NS_ENSURE_ARG_POINTER(_retval); nsCAutoString path; @@ -1228,6 +1354,7 @@ NS_IMETHODIMP nsLocalFile::OpenANSIFileDesc(const char *mode, FILE **_retval) /* [noscript] PRLibraryStar load (); */ NS_IMETHODIMP nsLocalFile::Load(PRLibrary **_retval) { + // XXX - needs change for CFM NS_ENSURE_ARG_POINTER(_retval); NS_TIMELINE_START_TIMER("PR_LoadLibrary"); @@ -1253,14 +1380,9 @@ NS_IMETHODIMP nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable) { NS_ENSURE_ARG_POINTER(aDiskSpaceAvailable); - FSRef fsRef; - nsresult rv = GetFSRefInternal(fsRef); - if (NS_FAILED(rv)) - return rv; - OSErr err; FSCatalogInfo catalogInfo; - err = ::FSGetCatalogInfo(&fsRef, kFSCatInfoVolume, &catalogInfo, + err = ::FSGetCatalogInfo(&mFSRef, kFSCatInfoVolume, &catalogInfo, nsnull, nsnull, nsnull); if (err != noErr) return MacErrorMapper(err); @@ -1278,27 +1400,21 @@ NS_IMETHODIMP nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable) /* void appendRelativePath (in AString relativeFilePath); */ NS_IMETHODIMP nsLocalFile::AppendRelativePath(const nsAString& relativeFilePath) { - return AppendRelativeNativePath(NS_ConvertUCS2toUTF8(relativeFilePath)); -} - -/* [noscript] void appendRelativeNativePath (in ACString relativeFilePath); */ -NS_IMETHODIMP nsLocalFile::AppendRelativeNativePath(const nsACString& relativeFilePath) -{ if (relativeFilePath.IsEmpty()) return NS_OK; // No leading '/' if (relativeFilePath.First() == '/') return NS_ERROR_FILE_UNRECOGNIZED_PATH; - + // Parse the nodes and call Append() for each - nsACString::const_iterator nodeBegin, pathEnd; + nsAString::const_iterator nodeBegin, pathEnd; relativeFilePath.BeginReading(nodeBegin); relativeFilePath.EndReading(pathEnd); - nsACString::const_iterator nodeEnd(nodeBegin); + nsAString::const_iterator nodeEnd(nodeBegin); while (nodeEnd != pathEnd) { - FindCharInReadable(kPathSepChar, nodeEnd, pathEnd); - nsresult rv = AppendNative(Substring(nodeBegin, nodeEnd)); + FindCharInReadable(kPathSepUnichar, nodeEnd, pathEnd); + nsresult rv = Append(Substring(nodeBegin, nodeEnd)); if (NS_FAILED(rv)) return rv; if (nodeEnd != pathEnd) // If there's more left in the string, inc over the '/' nodeEnd is on. @@ -1308,6 +1424,12 @@ NS_IMETHODIMP nsLocalFile::AppendRelativeNativePath(const nsACString& relativeFi return NS_OK; } +/* [noscript] void appendRelativeNativePath (in ACString relativeFilePath); */ +NS_IMETHODIMP nsLocalFile::AppendRelativeNativePath(const nsACString& relativeFilePath) +{ + return AppendRelativePath(NS_ConvertUTF8toUCS2(relativeFilePath)); +} + /* attribute ACString persistentDescriptor; */ NS_IMETHODIMP nsLocalFile::GetPersistentDescriptor(nsACString& aPersistentDescriptor) { @@ -1447,25 +1569,26 @@ NS_IMETHODIMP nsLocalFile::Launch() /* void initWithCFURL (in CFURLRef aCFURL); */ NS_IMETHODIMP nsLocalFile::InitWithCFURL(CFURLRef aCFURL) { - NS_ENSURE_ARG(aCFURL); - - SetBaseRef(aCFURL); - return NS_OK; + // XXX - Because we define DARWIN, we can't use CFURLGetFSRef. This blows. + nsresult rv = NS_ERROR_FAILURE; + UInt8 buffer[512]; + if (::CFURLGetFileSystemRepresentation(aCFURL, TRUE, buffer, sizeof(buffer))) + rv = InitWithNativePath(nsDependentCString((char *)buffer)); + + return rv; } /* void initWithFSRef ([const] in FSRefPtr aFSRef); */ NS_IMETHODIMP nsLocalFile::InitWithFSRef(const FSRef *aFSRef) { NS_ENSURE_ARG(aFSRef); - nsresult rv = NS_ERROR_FAILURE; - CFURLRef newURLRef = ::CFURLCreateFromFSRef(kCFAllocatorDefault, aFSRef); - if (newURLRef) { - SetBaseRef(newURLRef); - ::CFRelease(newURLRef); - rv = NS_OK; - } - return rv; + mFSRef = *aFSRef; + mNonExtantNodes.clear(); + mTargetFSRef = kInvalidFSRef; + mIdentityDirty = PR_FALSE; + mFollowLinksDirty = PR_TRUE; + return NS_OK; } /* void initWithFSSpec ([const] in FSSpecPtr aFileSpec); */ @@ -1500,10 +1623,15 @@ NS_IMETHODIMP nsLocalFile::InitWithFSSpec(const FSSpec *aFileSpec) err = ::HFSNameGetUnicodeName(aFileSpec->name, kTextEncodingUnknown, &unicodeName); if (err != noErr) return MacErrorMapper(err); - nsresult rv = InitWithFSRef(&fsRef); - if (NS_FAILED(rv)) - return rv; - return Append(nsDependentString(unicodeName.unicode, unicodeName.length)); + + mFSRef = fsRef; + mNonExtantNodes.clear(); + mNonExtantNodes.push_back(nsString(nsDependentString(unicodeName.unicode, unicodeName.length))); + mTargetFSRef = kInvalidFSRef; + mIdentityDirty = PR_FALSE; + mFollowLinksDirty = PR_TRUE; + + return NS_OK; } return MacErrorMapper(err); } @@ -1522,11 +1650,26 @@ NS_IMETHODIMP nsLocalFile::InitToAppWithCreatorCode(OSType aAppCreator) NS_IMETHODIMP nsLocalFile::GetCFURL(CFURLRef *_retval) { NS_ENSURE_ARG_POINTER(_retval); - CFURLRef whichURLRef = mFollowLinks ? mTargetRef : mBaseRef; - if (whichURLRef) - ::CFRetain(whichURLRef); - *_retval = whichURLRef; - return whichURLRef ? NS_OK : NS_ERROR_FAILURE; + *_retval = nsnull; + + FSRef fsRef; + nsresult rv = GetFSRefInternal(fsRef); + if (NS_SUCCEEDED(rv)) { + *_retval = ::CFURLCreateFromFSRef(NULL, &fsRef); + } + else { + nsCAutoString path; + rv = GetPathInternal(path); + if (NS_FAILED(rv)) + return rv; + CFStringRef pathAsCFString; + pathAsCFString = ::CFStringCreateWithCString(nsnull, path.get(), kCFStringEncodingUTF8); + if (!pathAsCFString) + return NS_ERROR_FAILURE; + *_retval = ::CFURLCreateWithFileSystemPath(nsnull, pathAsCFString, kCFURLPOSIXPathStyle, PR_FALSE); + ::CFRelease(pathAsCFString); + } + return *_retval ? NS_OK : NS_ERROR_FAILURE; } /* FSRef getFSRef (); */ @@ -1550,34 +1693,26 @@ NS_IMETHODIMP nsLocalFile::GetFSSpec(FSSpec *_retval) nsnull, nsnull, _retval, nsnull); return MacErrorMapper(err); } - else if (rv == NS_ERROR_FILE_NOT_FOUND) { + else if (rv == NS_ERROR_FILE_NOT_FOUND && mNonExtantNodes.size() == 1) { // If the parent of the leaf exists, make an FSSpec from that. - CFURLRef parentURLRef = ::CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorDefault, mBaseRef); - if (!parentURLRef) - return NS_ERROR_FAILURE; + FSCatalogInfo catalogInfo; + err = ::FSGetCatalogInfo(&mFSRef, + kFSCatInfoVolume + kFSCatInfoNodeID + kFSCatInfoTextEncoding, + &catalogInfo, nsnull, nsnull, nsnull); + if (err != noErr) + return MacErrorMapper(err); - err = fnfErr; - if (::CFURLGetFSRef(parentURLRef, &fsRef)) { - FSCatalogInfo catalogInfo; - if ((err = ::FSGetCatalogInfo(&fsRef, - kFSCatInfoVolume + kFSCatInfoNodeID + kFSCatInfoTextEncoding, - &catalogInfo, nsnull, nsnull, nsnull)) == noErr) { - nsAutoString leafName; - if (NS_SUCCEEDED(GetLeafName(leafName))) { - Str31 hfsName; - if ((err = ::UnicodeNameGetHFSName(leafName.Length(), - leafName.get(), - catalogInfo.textEncodingHint, - catalogInfo.nodeID == fsRtDirID, - hfsName)) == noErr) - err = ::FSMakeFSSpec(catalogInfo.volume, catalogInfo.nodeID, hfsName, _retval); - } - } - } - ::CFRelease(parentURLRef); - rv = MacErrorMapper(err); + Str31 hfsName; + const nsString& leafName = mNonExtantNodes.back(); + err = ::UnicodeNameGetHFSName(leafName.Length(), + PromiseFlatString(leafName).get(), + catalogInfo.textEncodingHint, + catalogInfo.nodeID == fsRtDirID, + hfsName); + err = ::FSMakeFSSpec(catalogInfo.volume, catalogInfo.nodeID, hfsName, _retval); + return MacErrorMapper(err); } - return rv; + return NS_ERROR_FAILURE; } /* readonly attribute PRInt64 fileSizeWithResFork; */ @@ -1818,80 +1953,105 @@ NS_IMETHODIMP nsLocalFile::IsPackage(PRBool *_retval) #pragma mark - #pragma mark [Protected Methods] -nsresult nsLocalFile::SetBaseRef(CFURLRef aCFURLRef) +nsresult nsLocalFile::Resolve() { - NS_ENSURE_ARG(aCFURLRef); + nsresult rv = NS_OK; - ::CFRetain(aCFURLRef); - if (mBaseRef) - ::CFRelease(mBaseRef); - mBaseRef = aCFURLRef; - - mFollowLinksDirty = PR_TRUE; - UpdateTargetRef(); - mCachedFSRefValid = PR_FALSE; - return NS_OK; -} - -nsresult nsLocalFile::UpdateTargetRef() -{ - if (!mBaseRef) - return NS_ERROR_NOT_INITIALIZED; - - if (mFollowLinksDirty) { - if (mTargetRef) { - ::CFRelease(mTargetRef); - mTargetRef = nsnull; - } + if (mIdentityDirty) { + rv = ResolveNonExtantNodes(PR_FALSE); + if (NS_SUCCEEDED(rv)) + mIdentityDirty = PR_FALSE; + mFollowLinksDirty = PR_TRUE; + } + if (mFollowLinksDirty && NS_SUCCEEDED(rv)) { if (mFollowLinks) { - mTargetRef = mBaseRef; - ::CFRetain(mTargetRef); - - FSRef fsRef; - if (::CFURLGetFSRef(mBaseRef, &fsRef)) { - Boolean targetIsFolder, wasAliased; - if (FSResolveAliasFile(&fsRef, true /*resolveAliasChains*/, - &targetIsFolder, &wasAliased) == noErr && wasAliased) { - ::CFRelease(mTargetRef); - mTargetRef = CFURLCreateFromFSRef(NULL, &fsRef); - if (!mTargetRef) - return NS_ERROR_FAILURE; - } - } + Boolean isFolder, isAlias; + mTargetFSRef = mFSRef; + OSErr err = ::FSResolveAliasFile(&mTargetFSRef, PR_TRUE, &isFolder, &isAlias); + if (err == noErr) + mFollowLinksDirty = PR_FALSE; + else + rv = MacErrorMapper(err); + } + else { + mTargetFSRef = kInvalidFSRef; mFollowLinksDirty = PR_FALSE; } } - return NS_OK; + return rv; } -nsresult nsLocalFile::GetFSRefInternal(FSRef& aFSRef, PRBool bForceUpdateCache) +nsresult nsLocalFile::GetFSRefInternal(FSRef& aFSSpec) { - if (bForceUpdateCache || !mCachedFSRefValid) { - CFURLRef whichURLRef = mFollowLinks ? mTargetRef : mBaseRef; - NS_ENSURE_TRUE(whichURLRef, NS_ERROR_NULL_POINTER); - mCachedFSRefValid = (::CFURLGetFSRef(whichURLRef, &mCachedFSRef) == true) ? - PR_TRUE : PR_FALSE; - } - if (mCachedFSRefValid) { - aFSRef = mCachedFSRef; - return NS_OK; - } - return NS_ERROR_FAILURE; + nsresult rv = Resolve(); + if (NS_FAILED(rv)) + return rv; + aFSSpec = mFollowLinks ? mTargetFSRef : mFSRef; + return NS_OK; } nsresult nsLocalFile::GetPathInternal(nsACString& path) { - nsresult rv = NS_ERROR_FAILURE; - - CFURLRef whichURLRef = mFollowLinks ? mTargetRef : mBaseRef; - NS_ENSURE_TRUE(whichURLRef, NS_ERROR_NULL_POINTER); - - CFStringRef pathStrRef = ::CFURLCopyFileSystemPath(whichURLRef, kCFURLPOSIXPathStyle); - if (pathStrRef) { - rv = CFStringReftoUTF8(pathStrRef, path); - ::CFRelease(pathStrRef); + FSRef fsRef; + UInt8 pathBuf[PATH_MAX + 1]; + + if (NS_SUCCEEDED(Resolve())) + fsRef = mFollowLinks ? mTargetFSRef : mFSRef; + else + fsRef = mFSRef; + + OSErr err = ::FSRefMakePath(&fsRef, pathBuf, sizeof(pathBuf)); + if (err != noErr) + return MacErrorMapper(err); + path.Assign((char *)pathBuf); + + // If Resolve() succeeds, mNonExtantNodes is empty. + deque::iterator iter(mNonExtantNodes.begin()); + deque::iterator end(mNonExtantNodes.end()); + while (iter != end) { + path.Append(kPathSepChar); + path.Append((NS_ConvertUCS2toUTF8(*iter))); + ++iter; } - return rv; + + return NS_OK; +} + +nsresult nsLocalFile::ResolveNonExtantNodes(PRBool aCreateDirs) +{ + deque::iterator iter(mNonExtantNodes.begin()); + while (iter != mNonExtantNodes.end()) { + const nsString& currNode = *iter; + ++iter; + + FSRef newRef; + OSErr err = ::FSMakeFSRefUnicode(&mFSRef, + currNode.Length(), + (const UniChar *)currNode.get(), + kTextEncodingUnknown, + &newRef); + + if (err == fnfErr && aCreateDirs) { + if (iter == mNonExtantNodes.end()) // Don't create the terminal node + return NS_OK; + err = ::FSCreateDirectoryUnicode(&mFSRef, + currNode.Length(), + (const UniChar *)currNode.get(), + kFSCatInfoNone, + nsnull, &newRef, nsnull, nsnull); + } + + // If it exists or we successfully created it, + // pop the node from the front and continue. + if (err == noErr) { + mNonExtantNodes.pop_front(); + iter = mNonExtantNodes.begin(); + mFSRef = newRef; + } + else + return NS_ERROR_FILE_NOT_FOUND; + } + return NS_OK; } nsresult nsLocalFile::MoveCopy(nsIFile* aParentDir, const nsAString& newName, PRBool isCopy, PRBool followLinks) @@ -1900,14 +2060,13 @@ nsresult nsLocalFile::MoveCopy(nsIFile* aParentDir, const nsAString& newName, PR nsresult rv; OSErr err; - FSRef srcFSRef, newFSRef; + FSRef srcRef, newRef; - rv = GetFSRefInternal(srcFSRef); + rv = GetFSRefInternal(srcRef); if (NS_FAILED(rv)) return rv; nsCOMPtr newParentDir = aParentDir; - CFURLRef newBaseURLRef; if (!newParentDir) { if (newName.IsEmpty()) @@ -1928,59 +2087,54 @@ nsresult nsLocalFile::MoveCopy(nsIFile* aParentDir, const nsAString& newName, PR return rv; } - FSRef destFSRef; + FSRef destRef; nsCOMPtr newParentDirMac(do_QueryInterface(newParentDir)); if (!newParentDirMac) return NS_ERROR_NO_INTERFACE; - rv = newParentDirMac->GetFSRef(&destFSRef); + rv = newParentDirMac->GetFSRef(&destRef); if (NS_FAILED(rv)) return rv; if (isCopy) { - err = ::FSCopyObject(&srcFSRef, &destFSRef, + err = ::FSCopyObject(&srcRef, &destRef, newName.Length(), newName.Length() ? PromiseFlatString(newName).get() : nsnull, - 0, kFSCatInfoNone, false, false, nsnull, nsnull, &newFSRef); - // don't update ourselves on a copy + 0, kFSCatInfoNone, false, false, nsnull, nsnull, &newRef); + // don't update mFSRef on a copy } else { // According to the API: "If 'this' is a file, and the destination file already // exists, moveTo will replace the old file." FSCatalogInfo catalogInfo; HFSUniStr255 leafName; - err = ::FSGetCatalogInfo(&srcFSRef, kFSCatInfoNodeFlags, &catalogInfo, + err = ::FSGetCatalogInfo(&srcRef, kFSCatInfoNodeFlags, &catalogInfo, newName.IsEmpty() ? &leafName : nsnull, nsnull, nsnull); if (err == noErr) { if (!(catalogInfo.nodeFlags & kFSNodeIsDirectoryMask)) { FSRef oldFileRef; if (newName.IsEmpty()) - err = ::FSMakeFSRefUnicode(&destFSRef, leafName.length, leafName.unicode, + err = ::FSMakeFSRefUnicode(&destRef, leafName.length, leafName.unicode, kTextEncodingUnknown, &oldFileRef); else - err = ::FSMakeFSRefUnicode(&destFSRef, newName.Length(), PromiseFlatString(newName).get(), + err = ::FSMakeFSRefUnicode(&destRef, newName.Length(), PromiseFlatString(newName).get(), kTextEncodingUnknown, &oldFileRef); if (err == noErr) ::FSDeleteObject(&oldFileRef); } } // First, try the quick way which works only within the same volume - err = ::FSMoveRenameObjectUnicode(&srcFSRef, &destFSRef, + err = ::FSMoveRenameObjectUnicode(&srcRef, &destRef, newName.Length(), newName.Length() ? PromiseFlatString(newName).get() : nsnull, - kTextEncodingUnknown, &newFSRef); + kTextEncodingUnknown, &newRef); if (err == diffVolErr) { // If on different volumes, resort to copy & delete - err = ::FSCopyObject(&srcFSRef, &destFSRef, + err = ::FSCopyObject(&srcRef, &destRef, newName.Length(), newName.Length() ? PromiseFlatString(newName).get() : nsnull, - 0, kFSCatInfoNone, false, false, nsnull, nsnull, &newFSRef); - ::FSDeleteObjects(&srcFSRef); - } - if (err == noErr) { - newBaseURLRef = ::CFURLCreateFromFSRef(kCFAllocatorDefault, &newFSRef); - if (!newBaseURLRef) - return NS_ERROR_FAILURE; - SetBaseRef(newBaseURLRef); - ::CFRelease(newBaseURLRef); + 0, kFSCatInfoNone, false, false, nsnull, nsnull, &newRef); + ::FSDeleteObjects(&srcRef); } + if (err == noErr) + mFSRef = newRef; } return MacErrorMapper(err); } @@ -2011,25 +2165,6 @@ void nsLocalFile::NSPRtoHFSPlusTime(PRInt64 nsprTime, UTCDateTime& utcTime) utcTime.fraction = (UInt16)((fraction * kUTCDateTimeFractionDivisor) / kMilisecsPerSec); } -nsresult nsLocalFile::CFStringReftoUTF8(CFStringRef aInStrRef, nsACString& aOutStr) -{ - nsresult rv = NS_ERROR_FAILURE; - CFIndex usedBufLen, inStrLen = ::CFStringGetLength(aInStrRef); - CFIndex charsConverted = ::CFStringGetBytes(aInStrRef, CFRangeMake(0, inStrLen), - kCFStringEncodingUTF8, 0, PR_FALSE, nsnull, 0, &usedBufLen); - if (charsConverted == inStrLen) { - StBuffer buffer; - if (buffer.EnsureElemCapacity(usedBufLen + 1)) { - ::CFStringGetBytes(aInStrRef, CFRangeMake(0, inStrLen), - kCFStringEncodingUTF8, 0, false, buffer.get(), usedBufLen, &usedBufLen); - buffer.get()[usedBufLen] = '\0'; - aOutStr.Assign(nsDependentCString((char*)buffer.get())); - rv = NS_OK; - } - } - return rv; -} - //***************************************************************************** // Global Functions //***************************************************************************** @@ -2038,6 +2173,19 @@ nsresult nsLocalFile::CFStringReftoUTF8(CFStringRef aInStrRef, nsACString& aOutS void nsLocalFile::GlobalInit() { + long response; + OSErr err = ::Gestalt(gestaltFSAttr, &response); + if (err == noErr && (response & (1 << gestaltFSUsesPOSIXPathsForConversion))) + kPathSepChar = '/'; + else + kPathSepChar = ':'; + kPathSepUnichar = PRUnichar(kPathSepChar); + +#ifdef XP_MACOSX + // Get an FSRef of the root. + err = FSPathMakeRef((UInt8 *)"/", &kRootFSRef, nsnull); + NS_ASSERTION(err == noErr, "Could not make root FSRef"); +#endif } void nsLocalFile::GlobalShutdown() diff --git a/mozilla/xpcom/io/nsLocalFileOSX.h b/mozilla/xpcom/io/nsLocalFileOSX.h index ec9e1567a05..d22c3146574 100644 --- a/mozilla/xpcom/io/nsLocalFileOSX.h +++ b/mozilla/xpcom/io/nsLocalFileOSX.h @@ -43,16 +43,13 @@ #include "nsLocalFile.h" #include "nsString.h" +#include +using namespace std; + class nsDirEnumerator; //***************************************************************************** // nsLocalFile -// -// The native charset of this implementation is UTF-8. The Unicode used by the -// Mac OS file system is decomposed, so "Native" versions of these routines will -// always use decomposed Unicode. Their "non-Native" counterparts are intended -// to be simple wrappers which call the "Native" version and convert between -// UTF-8 and UCS-2. All the work is done on the "Native" side. //***************************************************************************** class NS_COM nsLocalFile : public nsILocalFileMac @@ -78,33 +75,35 @@ public: static void GlobalShutdown(); protected: + nsLocalFile(const FSRef& aFSRef, const nsAString& aRelativePath); nsLocalFile(const nsLocalFile& src); - nsresult SetBaseRef(CFURLRef aCFURLRef); // Does CFRetain on aCFURLRef - nsresult UpdateTargetRef(); - - nsresult GetFSRefInternal(FSRef& aFSSpec, PRBool bForceUpdateCache = PR_TRUE); + nsresult Resolve(); + nsresult GetFSRefInternal(FSRef& aFSSpec); nsresult GetPathInternal(nsACString& path); // Returns path WRT mFollowLinks + nsresult ResolveNonExtantNodes(PRBool aCreateDirs); nsresult MoveCopy(nsIFile* newParentDir, const nsAString &newName, PRBool isCopy, PRBool followLinks); static PRInt64 HFSPlustoNSPRTime(const UTCDateTime& utcTime); static void NSPRtoHFSPlusTime(PRInt64 nsprTime, UTCDateTime& utcTime); - static nsresult CFStringReftoUTF8(CFStringRef aInStrRef, nsACString& aOutStr); - -protected: - CFURLRef mBaseRef; // The FS object we represent - CFURLRef mTargetRef; // If mBaseRef is an alias, its target - - FSRef mCachedFSRef; - PRPackedBool mCachedFSRefValid; +protected: + FSRef mFSRef; + deque mNonExtantNodes; + + FSRef mTargetFSRef; // If mFSRef is an alias file, its target + PRPackedBool mFollowLinks; + + PRPackedBool mIdentityDirty; PRPackedBool mFollowLinksDirty; - static const char kPathSepChar; - static const PRUnichar kPathSepUnichar; - static const PRInt64 kJanuaryFirst1970Seconds; + static PRInt64 kJanuaryFirst1970Seconds; + static PRUnichar kPathSepUnichar; + static char kPathSepChar; + static FSRef kInvalidFSRef; + static FSRef kRootFSRef; }; #endif // nsLocalFileMac_h__ diff --git a/mozilla/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp b/mozilla/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp index 3ef4a398b06..c53dabf6323 100644 --- a/mozilla/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp +++ b/mozilla/xpcom/reflect/xptinfo/src/xptiInterfaceInfoManager.cpp @@ -337,6 +337,7 @@ xptiInterfaceInfoManager::BuildFileList(nsISupportsArray* aSearchPath, nsCOMPtr file = do_QueryInterface(sup); if(!file) return PR_FALSE; + file->SetFollowLinks(PR_FALSE); PRBool isFile; if(NS_FAILED(file->IsFile(&isFile)) || !isFile)