From e8b317b9f341a614859311e14fcb482084a62f40 Mon Sep 17 00:00:00 2001 From: "joshmoz%gmail.com" Date: Tue, 14 Nov 2006 22:06:00 +0000 Subject: [PATCH] Since some platforms do string operations within local file ::Load, we shouldn't declare that objects being created/destroyed from static ctor/dtor is not legal throughout the entire ::Load function. That only needs to be true around the actual PR_LoadLibrary calls. Fixing this stops the ridiculous amount of warning output that we get from every debug mac build. Also removing unused old mac local file impls. b=326837 r=bsmedberg --- xpcom/components/nsNativeComponentLoader.cpp | 7 - xpcom/io/nsLocalFileMac.cpp | 3573 ------------------ xpcom/io/nsLocalFileMac.h | 137 - xpcom/io/nsLocalFileOS2.cpp | 11 +- xpcom/io/nsLocalFileOSX.cpp | 9 + xpcom/io/nsLocalFileUnix.cpp | 9 + xpcom/io/nsLocalFileWin.cpp | 12 + 7 files changed, 40 insertions(+), 3718 deletions(-) delete mode 100644 xpcom/io/nsLocalFileMac.cpp delete mode 100644 xpcom/io/nsLocalFileMac.h diff --git a/xpcom/components/nsNativeComponentLoader.cpp b/xpcom/components/nsNativeComponentLoader.cpp index cc57cc4f384a..cfd46a000150 100644 --- a/xpcom/components/nsNativeComponentLoader.cpp +++ b/xpcom/components/nsNativeComponentLoader.cpp @@ -134,16 +134,9 @@ nsNativeModuleLoader::LoadModule(nsILocalFile* aFile, nsIModule* *aResult) } // We haven't loaded this module before -#ifdef NS_BUILD_REFCNT_LOGGING - nsTraceRefcntImpl::SetActivityIsLegal(PR_FALSE); -#endif rv = aFile->Load(&data.library); -#ifdef NS_BUILD_REFCNT_LOGGING - nsTraceRefcntImpl::SetActivityIsLegal(PR_TRUE); -#endif - if (NS_FAILED(rv)) { char errorMsg[1024] = ""; diff --git a/xpcom/io/nsLocalFileMac.cpp b/xpcom/io/nsLocalFileMac.cpp deleted file mode 100644 index 24cdf388781b..000000000000 --- a/xpcom/io/nsLocalFileMac.cpp +++ /dev/null @@ -1,3573 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla Communicator client code, released - * March 31, 1998. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998-1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Steve Dagley - * John R. McMullen - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - - -#include "nsCOMPtr.h" -#include "nsMemory.h" -#include "nsXPIDLString.h" - -#include "nsLocalFile.h" -#include "nsNativeCharsetUtils.h" -#include "nsISimpleEnumerator.h" -#include "nsIComponentManager.h" -#include "nsIInternetConfigService.h" -#include "nsIMIMEInfo.h" -#include "prtypes.h" -#include "prerror.h" - -#include "nsReadableUtils.h" -#include "nsITimelineService.h" - -#ifdef XP_MACOSX -#include "nsXPIDLString.h" - -#include "private/pprio.h" -#else -#include "pprio.h" // Include this rather than prio.h so we get def of PR_ImportFile -#endif -#include "prmem.h" -#include "plbase64.h" - -#include "FullPath.h" -#include "FileCopy.h" -#include "MoreFilesExtras.h" -#include "DirectoryCopy.h" -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include "macDirectoryCopy.h" - -#include - -// Stupid @#$% header looks like its got extern mojo but it doesn't really -extern "C" -{ -#ifndef XP_MACOSX -// BADPINK - this MSL header doesn't exist under macosx :-( -#include -#endif -} - -#if TARGET_CARBON -#include // Needed for definition of kUnresolvedCFragSymbolAddress -#include -#endif - -#pragma mark [Constants] - -const OSType kDefaultCreator = 'MOSS'; - -#pragma mark - -#pragma mark [nsPathParser] - -class nsPathParser -{ -public: - nsPathParser(const nsACString &path); - - ~nsPathParser() - { - if (mAllocatedBuffer) - nsMemory::Free(mAllocatedBuffer); - } - - const char* First() - { - return nsCRT::strtok(mBuffer, ":", &mNewString); - } - const char* Next() - { - return nsCRT::strtok(mNewString, ":", &mNewString); - } - const char* Remainder() - { - return mNewString; - } - -private: - char mAutoBuffer[512]; - char *mAllocatedBuffer; - char *mBuffer, *mNewString; -}; - -nsPathParser::nsPathParser(const nsACString &inPath) : - mAllocatedBuffer(nsnull), mNewString(nsnull) -{ - PRUint32 inPathLen = inPath.Length(); - if (inPathLen >= sizeof(mAutoBuffer)) { - mAllocatedBuffer = (char *)nsMemory::Alloc(inPathLen + 1); - mBuffer = mAllocatedBuffer; - } - else - mBuffer = mAutoBuffer; - - // copy inPath into mBuffer - nsACString::const_iterator start, end; - inPath.BeginReading(start); - inPath.EndReading(end); - - PRUint32 size, offset = 0; - for ( ; start != end; start.advance(size)) { - const char* buf = start.get(); - size = start.size_forward(); - memcpy(mBuffer + offset, buf, size); - offset += size; - } - mBuffer[offset] = '\0'; -} - -#pragma mark - -#pragma mark [static util funcs] - -static inline void ClearFSSpec(FSSpec& aSpec) -{ - aSpec.vRefNum = 0; - aSpec.parID = 0; - aSpec.name[0] = 0; -} - - -// Simple func to map Mac OS errors into nsresults -static nsresult MacErrorMapper(OSErr inErr) -{ - nsresult outErr; - - switch (inErr) - { - case noErr: - outErr = NS_OK; - break; - - case fnfErr: - outErr = NS_ERROR_FILE_NOT_FOUND; - break; - - case dupFNErr: - outErr = NS_ERROR_FILE_ALREADY_EXISTS; - break; - - case dskFulErr: - outErr = NS_ERROR_FILE_DISK_FULL; - break; - - case fLckdErr: - outErr = NS_ERROR_FILE_IS_LOCKED; - break; - - // Can't find good map for some - case bdNamErr: - outErr = NS_ERROR_FAILURE; - break; - - default: - outErr = NS_ERROR_FAILURE; - break; - } - return outErr; -} - - - -/*---------------------------------------------------------------------------- - IsEqualFSSpec - - Compare two canonical FSSpec records. - - Entry: file1 = pointer to first FSSpec record. - file2 = pointer to second FSSpec record. - - Exit: function result = true if the FSSpec records are equal. -----------------------------------------------------------------------------*/ - -static PRBool IsEqualFSSpec(const FSSpec& file1, const FSSpec& file2) -{ - return - file1.vRefNum == file2.vRefNum && - file1.parID == file2.parID && - EqualString(file1.name, file2.name, false, true); -} - - -/*---------------------------------------------------------------------------- - GetParentFolderSpec - - Given an FSSpec to a (possibly non-existent) file, get an FSSpec for its - parent directory. - -----------------------------------------------------------------------------*/ - -static OSErr GetParentFolderSpec(const FSSpec& fileSpec, FSSpec& parentDirSpec) -{ - CInfoPBRec pBlock = {0}; - OSErr err = noErr; - - parentDirSpec.name[0] = 0; - - pBlock.dirInfo.ioVRefNum = fileSpec.vRefNum; - pBlock.dirInfo.ioDrDirID = fileSpec.parID; - pBlock.dirInfo.ioNamePtr = (StringPtr)parentDirSpec.name; - pBlock.dirInfo.ioFDirIndex = -1; //get info on parID - err = PBGetCatInfoSync(&pBlock); - if (err != noErr) return err; - - parentDirSpec.vRefNum = fileSpec.vRefNum; - parentDirSpec.parID = pBlock.dirInfo.ioDrParID; - - return err; -} - - -/*---------------------------------------------------------------------------- - VolHasDesktopDB - - Check to see if a volume supports the new desktop database. - - Entry: vRefNum = vol ref num of volumn - - Exit: function result = error code. - *hasDesktop = true if volume has the new desktop database. -----------------------------------------------------------------------------*/ - -static OSErr VolHasDesktopDB (short vRefNum, Boolean *hasDesktop) -{ - HParamBlockRec pb; - GetVolParmsInfoBuffer info; - OSErr err = noErr; - - pb.ioParam.ioCompletion = nil; - pb.ioParam.ioNamePtr = nil; - pb.ioParam.ioVRefNum = vRefNum; - pb.ioParam.ioBuffer = (Ptr)&info; - pb.ioParam.ioReqCount = sizeof(info); - err = PBHGetVolParmsSync(&pb); - *hasDesktop = err == noErr && (info.vMAttrib & (1L << bHasDesktopMgr)) != 0; - return err; -} - - -/*---------------------------------------------------------------------------- - GetLastModDateTime - - Get the last mod date and time of a file. - - Entry: fSpec = pointer to file spec. - - Exit: function result = error code. - *lastModDateTime = last mod date and time. -----------------------------------------------------------------------------*/ - -static OSErr GetLastModDateTime(const FSSpec *fSpec, unsigned long *lastModDateTime) -{ - CInfoPBRec pBlock; - OSErr err = noErr; - - pBlock.hFileInfo.ioNamePtr = (StringPtr)fSpec->name; - pBlock.hFileInfo.ioVRefNum = fSpec->vRefNum; - pBlock.hFileInfo.ioFDirIndex = 0; - pBlock.hFileInfo.ioDirID = fSpec->parID; - err = PBGetCatInfoSync(&pBlock); - if (err != noErr) return err; - *lastModDateTime = pBlock.hFileInfo.ioFlMdDat; - return noErr; -} - - -/*---------------------------------------------------------------------------- - FindAppOnVolume - - Find an application on a volume. - - Entry: sig = application signature. - vRefNum = vol ref num - - Exit: function result = error code - = afpItemNotFound if app not found on vol. - *file = file spec for application on volume. -----------------------------------------------------------------------------*/ - -static OSErr FindAppOnVolume (OSType sig, short vRefNum, FSSpec *file) -{ - DTPBRec pb; - OSErr err = noErr; - short ioDTRefNum, i; - FInfo fInfo; - FSSpec candidate; - unsigned long lastModDateTime, maxLastModDateTime; - - memset(&pb, 0, sizeof(DTPBRec)); - pb.ioCompletion = nil; - pb.ioVRefNum = vRefNum; - pb.ioNamePtr = nil; - err = PBDTGetPath(&pb); - if (err != noErr) return err; - ioDTRefNum = pb.ioDTRefNum; - - memset(&pb, 0, sizeof(DTPBRec)); - pb.ioCompletion = nil; - pb.ioIndex = 0; - pb.ioFileCreator = sig; - pb.ioNamePtr = file->name; - pb.ioDTRefNum = ioDTRefNum; - err = PBDTGetAPPLSync(&pb); - - if (err == fnfErr || err == paramErr) return afpItemNotFound; - if (err != noErr) return err; - - file->vRefNum = vRefNum; - file->parID = pb.ioAPPLParID; - - err = FSpGetFInfo(file, &fInfo); - if (err == noErr) return noErr; - - i = 1; - maxLastModDateTime = 0; - while (true) - { - memset(&pb, 0, sizeof(DTPBRec)); - pb.ioCompletion = nil; - pb.ioIndex = i; - pb.ioFileCreator = sig; - pb.ioNamePtr = candidate.name; - pb.ioDTRefNum = ioDTRefNum; - err = PBDTGetAPPLSync(&pb); - if (err != noErr) break; - candidate.vRefNum = vRefNum; - candidate.parID = pb.ioAPPLParID; - err = GetLastModDateTime(file, &lastModDateTime); - if (err == noErr) { - if (lastModDateTime > maxLastModDateTime) { - maxLastModDateTime = lastModDateTime; - *file = candidate; - } - } - i++; - } - - return maxLastModDateTime > 0 ? noErr : afpItemNotFound; -} - - -/*---------------------------------------------------------------------------- - GetIndVolume - - Get a volume reference number by volume index. - - Entry: index = volume index - - Exit: function result = error code. - *vRefNum = vol ref num of indexed volume. -----------------------------------------------------------------------------*/ - -static OSErr GetIndVolume(short index, short *vRefNum) -{ - HParamBlockRec pb; - Str63 volumeName; - OSErr err = noErr; - - pb.volumeParam.ioCompletion = nil; - pb.volumeParam.ioNamePtr = volumeName; - pb.volumeParam.ioVolIndex = index; - - err = PBHGetVInfoSync(&pb); - - *vRefNum = pb.volumeParam.ioVRefNum; - return err; -} - - -// Private NSPR functions -static unsigned long gJanuaryFirst1970Seconds = 0; -/* - * The geographic location and time zone information of a Mac - * are stored in extended parameter RAM. The ReadLocation - * produdure uses the geographic location record, MachineLocation, - * to read the geographic location and time zone information in - * extended parameter RAM. - * - * Because serial port and SLIP conflict with ReadXPram calls, - * we cache the call here. - * - * Caveat: this caching will give the wrong result if a session - * extend across the DST changeover time. - */ - -static void MyReadLocation(MachineLocation *loc) -{ - static MachineLocation storedLoc; - static Boolean didReadLocation = false; - - if (!didReadLocation) { - ReadLocation(&storedLoc); - didReadLocation = true; - } - *loc = storedLoc; -} - -static long GMTDelta(void) -{ - MachineLocation loc; - long gmtDelta; - - MyReadLocation(&loc); - gmtDelta = loc.u.gmtDelta & 0x00ffffff; - if (gmtDelta & 0x00800000) { /* test sign extend bit */ - gmtDelta |= 0xff000000; - } - return gmtDelta; -} - -static void MacintoshInitializeTime(void) -{ - /* - * The NSPR epoch is midnight, Jan. 1, 1970 GMT. - * - * At midnight Jan. 1, 1970 GMT, the local time was - * midnight Jan. 1, 1970 + GMTDelta(). - * - * Midnight Jan. 1, 1970 is 86400 * (365 * (1970 - 1904) + 17) - * = 2082844800 seconds since the Mac epoch. - * (There were 17 leap years from 1904 to 1970.) - * - * So the NSPR epoch is 2082844800 + GMTDelta() seconds since - * the Mac epoch. Whew! :-) - */ - gJanuaryFirst1970Seconds = 2082844800 + GMTDelta(); -} - -static nsresult ConvertMacTimeToMilliseconds( PRInt64* aLastModifiedTime, PRUint32 timestamp ) -{ - if ( gJanuaryFirst1970Seconds == 0) - MacintoshInitializeTime(); - timestamp -= gJanuaryFirst1970Seconds; - PRTime usecPerSec, dateInMicroSeconds; - LL_I2L(dateInMicroSeconds, timestamp); - LL_I2L(usecPerSec, PR_MSEC_PER_SEC); - LL_MUL(*aLastModifiedTime, usecPerSec, dateInMicroSeconds); - return NS_OK; -} - -static nsresult ConvertMillisecondsToMacTime(PRInt64 aTime, PRUint32 *aOutMacTime) -{ - NS_ENSURE_ARG( aOutMacTime ); - - PRTime usecPerSec, dateInSeconds; - dateInSeconds = LL_ZERO; - - LL_I2L(usecPerSec, PR_MSEC_PER_SEC); - LL_DIV(dateInSeconds, aTime, usecPerSec); // dateInSeconds = aTime/1,000 - LL_L2UI(*aOutMacTime, dateInSeconds); - *aOutMacTime += 2082844800; // date + Mac epoch - - return NS_OK; -} - -static void myPLstrcpy(Str255 dst, const char* src) -{ - int srcLength = strlen(src); - NS_ASSERTION(srcLength <= 255, "Oops, Str255 can't hold >255 chars"); - if (srcLength > 255) - srcLength = 255; - dst[0] = srcLength; - memcpy(&dst[1], src, srcLength); -} - -static void myPLstrncpy(Str255 dst, const char* src, int inMax) -{ - int srcLength = strlen(src); - if (srcLength > inMax) - srcLength = inMax; - dst[0] = srcLength; - memcpy(&dst[1], src, srcLength); -} - -/* - NS_TruncNodeName - - Utility routine to do a mid-trunc on a potential file name so that it is - no longer than 31 characters. Until we move to the HFS+ APIs we need this - to come up with legal Mac file names. - - Entry: aNode = initial file name - outBuf = scratch buffer for the truncated name (MUST be >= 32 characters) - - Exit: function result = pointer to truncated name. Will be either aNode or outBuf. - -*/ -const char* NS_TruncNodeName(const char *aNode, char *outBuf) -{ - PRUint32 nodeLen; - if ((nodeLen = strlen(aNode)) > 31) - { - static PRBool sInitialized = PR_FALSE; - static CharByteTable sTable; - // Init to "..." in case we fail to get the ellipsis token - static char sEllipsisTokenStr[4] = { '.', '.', '.', 0 }; - static PRUint8 sEllipsisTokenLen = 3; - - if (!sInitialized) - { - // Entries in the table are: - // 0 == 1 byte char - // 1 == 2 byte char - FillParseTable(sTable, smSystemScript); - - Handle itl4ResHandle = nsnull; - long offset, len; - ::GetIntlResourceTable(smSystemScript, smUnTokenTable, &itl4ResHandle, &offset, &len); - if (itl4ResHandle) - { - UntokenTable *untokenTableRec = (UntokenTable *)(*itl4ResHandle + offset); - if (untokenTableRec->lastToken >= tokenEllipsis) - { - offset += untokenTableRec->index[tokenEllipsis]; - char *tokenStr = (*itl4ResHandle + offset); - sEllipsisTokenLen = tokenStr[0]; - memcpy(sEllipsisTokenStr, &tokenStr[1], sEllipsisTokenLen); - } - ::ReleaseResource(itl4ResHandle); - } - sInitialized = PR_TRUE; - } - - PRInt32 halfLen = (31 - sEllipsisTokenLen) / 2; - PRInt32 charSize = 0, srcPos, destPos; - for (srcPos = 0; srcPos + charSize <= halfLen; srcPos += charSize) - charSize = sTable[aNode[srcPos]] ? 2 : 1; - - memcpy(outBuf, aNode, srcPos); - memcpy(outBuf + srcPos, sEllipsisTokenStr, sEllipsisTokenLen); - destPos = srcPos + sEllipsisTokenLen; - - for (; srcPos < nodeLen - halfLen; srcPos += charSize) - charSize = sTable[aNode[srcPos]] ? 2 : 1; - - memcpy(outBuf + destPos, aNode + srcPos, nodeLen - srcPos); - destPos += (nodeLen - srcPos); - outBuf[destPos] = '\0'; - return outBuf; - } - return aNode; -} - -/** - * HFSPlusGetRawPath returns the path for an FSSpec as a unicode string. - * - * The reason for this routine instead of just calling FSRefMakePath is - * (1) inSpec does not have to exist - * (2) FSRefMakePath uses '/' as the separator under OSX and ':' under OS9 - */ -static OSErr HFSPlusGetRawPath(const FSSpec& inSpec, nsAString& outStr) -{ - OSErr err; - nsAutoString ucPathString; - - outStr.Truncate(0); - - FSRef nodeRef; - FSCatalogInfo catalogInfo; - catalogInfo.parentDirID = 0; - err = ::FSpMakeFSRef(&inSpec, &nodeRef); - - if (err == fnfErr) { - FSSpec parentDirSpec; - err = GetParentFolderSpec(inSpec, parentDirSpec); - if (err == noErr) { - const char *startPtr = (const char*)&inSpec.name[1]; - NS_CopyNativeToUnicode(Substring(startPtr, startPtr + PRUint32(inSpec.name[0])), outStr); - err = ::FSpMakeFSRef(&parentDirSpec, &nodeRef); - } - } - - while (err == noErr && catalogInfo.parentDirID != fsRtParID) { - HFSUniStr255 nodeName; - FSRef parentRef; - err = ::FSGetCatalogInfo(&nodeRef, - kFSCatInfoNodeFlags + kFSCatInfoParentDirID, - &catalogInfo, - &nodeName, - nsnull, - &parentRef); - if (err == noErr) - { - if (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) - nodeName.unicode[nodeName.length++] = PRUnichar(':'); - const PRUnichar* nodeNameUni = (const PRUnichar*) nodeName.unicode; - outStr.Insert(Substring(nodeNameUni, nodeNameUni + nodeName.length), 0); - nodeRef = parentRef; - } - } - return err; -} - - -// The R**co FSSpec resolver - -// it slices, it dices, it juliannes fries and it even creates FSSpecs out of whatever you feed it -// This function will take a path and a starting FSSpec and generate a FSSpec to represent -// the target of the two. If the intial FSSpec is null the path alone will be resolved -static OSErr ResolvePathAndSpec(const char * filePath, FSSpec *inSpec, PRBool createDirs, FSSpec *outSpec) -{ - OSErr err = noErr; - size_t inLength = strlen(filePath); - Boolean isRelative = (filePath && inSpec); - FSSpec tempSpec; - Str255 ppath; - Boolean isDirectory; - - if (isRelative && inSpec) - { - outSpec->vRefNum = inSpec->vRefNum; - outSpec->parID = inSpec->parID; - - if (inSpec->name[0] != 0) - { - long theDirID; - - err = FSpGetDirectoryID(inSpec, &theDirID, &isDirectory); - - if (err == noErr && isDirectory) - outSpec->parID = theDirID; - else if (err == fnfErr && createDirs) - { - err = FSpDirCreate(inSpec, smCurrentScript, &theDirID); - if (err == noErr) - outSpec->parID = theDirID; - else if (err == fnfErr) - err = dirNFErr; - } - } - } - else - { - outSpec->vRefNum = 0; - outSpec->parID = 0; - } - - if (err) - return err; - - // Try making an FSSpec from the path - if (inLength < 255) - { - // Use tempSpec as dest because if FSMakeFSSpec returns dirNFErr, it - // will reset the dest spec and we'll lose what we determined above. - - myPLstrcpy(ppath, filePath); - err = ::FSMakeFSSpec(outSpec->vRefNum, outSpec->parID, ppath, &tempSpec); - if (err == noErr || err == fnfErr) - *outSpec = tempSpec; - } - else if (!isRelative) - { - err = ::FSpLocationFromFullPath(inLength, filePath, outSpec); - } - else - { // If the path is relative and >255 characters we need to manually walk the - // path appending each node to the initial FSSpec so to reach that code we - // set the err to bdNamErr and fall into the code below - err = bdNamErr; - } - - // If we successfully created a spec then leave - if (err == noErr) - return err; - - // We get here when the directory hierarchy needs to be created or we're resolving - // a relative path >255 characters long - if (err == dirNFErr || err == bdNamErr) - { - const char* path = filePath; - - if (!isRelative) // If path is relative, we still need vRefNum & parID. - { - outSpec->vRefNum = 0; - outSpec->parID = 0; - } - - do - { - // Locate the colon that terminates the node. - // But if we've a partial path (starting with a colon), find the second one. - const char* nextColon = strchr(path + (*path == ':'), ':'); - // Well, if there are no more colons, point to the end of the string. - if (!nextColon) - nextColon = path + strlen(path); - - // Make a pascal string out of this node. Include initial - // and final colon, if any! - myPLstrncpy(ppath, path, nextColon - path + 1); - - // Use this string as a relative path using the directory created - // on the previous round (or directory 0,0 on the first round). - err = ::FSMakeFSSpec(outSpec->vRefNum, outSpec->parID, ppath, outSpec); - - // If this was the leaf node, then we are done. - if (!*nextColon) - break; - - // Since there's more to go, we have to get the directory ID, which becomes - // the parID for the next round. - if (err == noErr) - { - // The directory (or perhaps a file) exists. Find its dirID. - long dirID; - err = ::FSpGetDirectoryID(outSpec, &dirID, &isDirectory); - if (!isDirectory) - err = dupFNErr; // oops! a file exists with that name. - if (err != noErr) - break; // bail if we've got an error - outSpec->parID = dirID; - } - else if ((err == fnfErr) && createDirs) - { - // If we got "file not found" and we're allowed to create directories - // then we need to create one - err = ::FSpDirCreate(outSpec, smCurrentScript, &outSpec->parID); - // For some reason, this usually returns fnfErr, even though it works. - if (err == fnfErr) - err = noErr; - } - if (err != noErr) - break; - path = nextColon; // next round - } while (true); - } - - return err; -} - - -#pragma mark - -#pragma mark [StFollowLinksState] -class StFollowLinksState -{ - public: - StFollowLinksState(nsILocalFile *aFile) : - mFile(aFile) - { - NS_ASSERTION(mFile, "StFollowLinksState passed a NULL file."); - if (mFile) - mFile->GetFollowLinks(&mSavedState); - } - - StFollowLinksState(nsILocalFile *aFile, PRBool followLinksState) : - mFile(aFile) - { - NS_ASSERTION(mFile, "StFollowLinksState passed a NULL file."); - if (mFile) { - mFile->GetFollowLinks(&mSavedState); - mFile->SetFollowLinks(followLinksState); - } - } - - ~StFollowLinksState() - { - if (mFile) - mFile->SetFollowLinks(mSavedState); - } - - private: - nsCOMPtr mFile; - PRBool mSavedState; -}; - -#pragma mark - -#pragma mark [nsDirEnumerator] -class nsDirEnumerator : public nsISimpleEnumerator -{ - public: - - NS_DECL_ISUPPORTS - - nsDirEnumerator() - { - } - - nsresult Init(nsILocalFileMac* parent) - { - NS_ENSURE_ARG(parent); - nsresult rv; - FSSpec fileSpec; - - rv = parent->GetFSSpec(&fileSpec); - if (NS_FAILED(rv)) - return rv; - - OSErr err; - Boolean isDirectory; - - err = ::FSpGetDirectoryID(&fileSpec, &mDirID, &isDirectory); - if (err || !isDirectory) - return NS_ERROR_FILE_NOT_DIRECTORY; - - mCatInfo.hFileInfo.ioNamePtr = mItemName; - mCatInfo.hFileInfo.ioVRefNum = fileSpec.vRefNum; - mItemIndex = 1; - - return NS_OK; - } - - NS_IMETHOD HasMoreElements(PRBool *result) - { - nsresult rv = NS_OK; - if (mNext == nsnull) - { - mItemName[0] = 0; - mCatInfo.dirInfo.ioFDirIndex = mItemIndex; - mCatInfo.dirInfo.ioDrDirID = mDirID; - - OSErr err = ::PBGetCatInfoSync(&mCatInfo); - if (err == fnfErr) - { - // end of dir entries - *result = PR_FALSE; - return NS_OK; - } - - // Make a new nsILocalFile for the new element - FSSpec tempSpec; - tempSpec.vRefNum = mCatInfo.hFileInfo.ioVRefNum; - tempSpec.parID = mDirID; - ::BlockMoveData(mItemName, tempSpec.name, mItemName[0] + 1); - - rv = NS_NewLocalFileWithFSSpec(&tempSpec, PR_TRUE, getter_AddRefs(mNext)); - if (NS_FAILED(rv)) - return rv; - } - *result = mNext != nsnull; - return NS_OK; - } - - NS_IMETHOD GetNext(nsISupports **result) - { - NS_ENSURE_ARG_POINTER(result); - *result = nsnull; - - nsresult rv; - PRBool hasMore; - rv = HasMoreElements(&hasMore); - if (NS_FAILED(rv)) return rv; - - *result = mNext; // might return nsnull - NS_IF_ADDREF(*result); - - mNext = nsnull; - ++mItemIndex; - return NS_OK; - } - - private: - ~nsDirEnumerator() {} - - protected: - nsCOMPtr mNext; - - CInfoPBRec mCatInfo; - short mItemIndex; - long mDirID; - Str63 mItemName; -}; - -NS_IMPL_ISUPPORTS1(nsDirEnumerator, nsISimpleEnumerator) - -#pragma mark - - -OSType nsLocalFile::sCurrentProcessSignature = 0; -PRBool nsLocalFile::sHasHFSPlusAPIs = PR_FALSE; -PRBool nsLocalFile::sRunningOSX = PR_FALSE; - -#pragma mark [CTOR/DTOR] -nsLocalFile::nsLocalFile() : - mFollowLinks(PR_TRUE), - mFollowLinksDirty(PR_TRUE), - mSpecDirty(PR_TRUE), - mCatInfoDirty(PR_TRUE), - mType('TEXT'), - mCreator(kDefaultCreator) -{ - ClearFSSpec(mSpec); - ClearFSSpec(mTargetSpec); - - InitClassStatics(); - if (sCurrentProcessSignature != 0) - mCreator = sCurrentProcessSignature; -} - -nsLocalFile::nsLocalFile(const nsLocalFile& srcFile) -{ - *this = srcFile; -} - -nsLocalFile::nsLocalFile(const FSSpec& aSpec, const nsACString& aAppendedPath) : - mFollowLinks(PR_TRUE), - mFollowLinksDirty(PR_TRUE), - mSpecDirty(PR_TRUE), - mSpec(aSpec), - mAppendedPath(aAppendedPath), - mCatInfoDirty(PR_TRUE), - mType('TEXT'), - mCreator(kDefaultCreator) -{ - ClearFSSpec(mTargetSpec); - - InitClassStatics(); - if (sCurrentProcessSignature != 0) - mCreator = sCurrentProcessSignature; -} - -nsLocalFile& nsLocalFile::operator=(const nsLocalFile& rhs) -{ - mFollowLinks = rhs.mFollowLinks; - mFollowLinksDirty = rhs.mFollowLinksDirty; - mSpecDirty = rhs.mSpecDirty; - mSpec = rhs.mSpec; - mAppendedPath = rhs.mAppendedPath; - mTargetSpec = rhs.mTargetSpec; - mCatInfoDirty = rhs.mCatInfoDirty; - mType = rhs.mType; - mCreator = rhs.mCreator; - - if (!rhs.mCatInfoDirty) - mCachedCatInfo = rhs.mCachedCatInfo; - - return *this; -} - -#pragma mark - -#pragma mark [nsISupports interface implementation] - -NS_IMPL_THREADSAFE_ISUPPORTS3(nsLocalFile, - nsILocalFileMac, - nsILocalFile, - nsIFile) - -NS_METHOD -nsLocalFile::nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) -{ - NS_ENSURE_ARG_POINTER(aInstancePtr); - NS_ENSURE_NO_AGGREGATION(outer); - - nsLocalFile* inst = new nsLocalFile(); - if (inst == NULL) - return NS_ERROR_OUT_OF_MEMORY; - - nsresult rv = inst->QueryInterface(aIID, aInstancePtr); - if (NS_FAILED(rv)) - { - delete inst; - return rv; - } - return NS_OK; -} - -// This function resets any cached information about the file. -void -nsLocalFile::MakeDirty() -{ - mSpecDirty = PR_TRUE; - mFollowLinksDirty = PR_TRUE; - mCatInfoDirty = PR_TRUE; - - ClearFSSpec(mTargetSpec); -} - - -/* attribute PRBool followLinks; */ -NS_IMETHODIMP -nsLocalFile::GetFollowLinks(PRBool *aFollowLinks) -{ - NS_ENSURE_ARG_POINTER(aFollowLinks); - *aFollowLinks = mFollowLinks; - return NS_OK; -} - -NS_IMETHODIMP -nsLocalFile::SetFollowLinks(PRBool aFollowLinks) -{ - if (aFollowLinks != mFollowLinks) - { - mFollowLinks = aFollowLinks; - mFollowLinksDirty = PR_TRUE; - } - return NS_OK; -} - -NS_IMETHODIMP -nsLocalFile::ResolveAndStat() -{ - OSErr err = noErr; - FSSpec resolvedSpec; - - // fnfErr means target spec is valid but doesn't exist. - // If the end result is fnfErr, we're cleanly resolved. - - if (mSpecDirty) - { - if (mAppendedPath.Length()) - { - err = ResolvePathAndSpec(mAppendedPath.get(), &mSpec, PR_FALSE, &resolvedSpec); - if (err == noErr) - mAppendedPath.Truncate(0); - } - else - err = ::FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, mSpec.name, &resolvedSpec); - if (err == noErr) - { - mSpec = resolvedSpec; - mSpecDirty = PR_FALSE; - } - mFollowLinksDirty = PR_TRUE; - } - if (mFollowLinksDirty && (err == noErr)) - { - if (mFollowLinks) - { - // Resolve the alias to the original file. - resolvedSpec = mSpec; - Boolean resolvedWasFolder, resolvedWasAlias; - err = ::ResolveAliasFile(&resolvedSpec, TRUE, &resolvedWasFolder, &resolvedWasAlias); - if (err == noErr || err == fnfErr) { - err = noErr; - mTargetSpec = resolvedSpec; - mFollowLinksDirty = PR_FALSE; - } - } - else - { - mTargetSpec = mSpec; - mFollowLinksDirty = PR_FALSE; - } - mCatInfoDirty = PR_TRUE; - } - - return (MacErrorMapper(err)); -} - - -NS_IMETHODIMP -nsLocalFile::Clone(nsIFile **file) -{ - // Just copy-construct ourselves - *file = new nsLocalFile(*this); - if (!*file) - return NS_ERROR_OUT_OF_MEMORY; - - NS_ADDREF(*file); - - return NS_OK; -} - -NS_IMETHODIMP -nsLocalFile::InitWithNativePath(const nsACString &filePath) -{ - // The incoming path must be a FULL path - - if (filePath.IsEmpty()) - return NS_ERROR_INVALID_ARG; - - MakeDirty(); - - // If it starts with a colon, it's invalid - if (filePath.First() == ':') - return NS_ERROR_FILE_UNRECOGNIZED_PATH; - - nsPathParser parser(filePath); - OSErr err; - Str255 pascalNode; - FSSpec nodeSpec; - - const char *root = parser.First(); - if (root == nsnull) - return NS_ERROR_FILE_UNRECOGNIZED_PATH; - - // The first component must be an existing volume - myPLstrcpy(pascalNode, root); - pascalNode[++pascalNode[0]] = ':'; - err = ::FSMakeFSSpec(0, 0, pascalNode, &nodeSpec); - if (err) - return NS_ERROR_FILE_UNRECOGNIZED_PATH; - - // Build as much of a spec as possible from the rest of the path - // What doesn't exist will be left over in mAppendedPath - const char *nextNode; - while ((nextNode = parser.Next()) != nsnull) { - long dirID; - Boolean isDir; - err = ::FSpGetDirectoryID(&nodeSpec, &dirID, &isDir); - if (err || !isDir) - break; - myPLstrcpy(pascalNode, nextNode); - err = ::FSMakeFSSpec(nodeSpec.vRefNum, dirID, pascalNode, &nodeSpec); - if (err == fnfErr) - break; - } - mSpec = nodeSpec; - mAppendedPath = parser.Remainder(); - - return NS_OK; -} - -NS_IMETHODIMP -nsLocalFile::InitWithPath(const nsAString &filePath) -{ - nsresult rv; - nsCAutoString fsStr; - - if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(filePath, fsStr))) - rv = InitWithNativePath(fsStr); - - return rv; -} - -NS_IMETHODIMP -nsLocalFile::InitWithFile(nsILocalFile *aFile) -{ - NS_ENSURE_ARG(aFile); - nsLocalFile *asLocalFile = dynamic_cast(aFile); - if (!asLocalFile) - return NS_ERROR_NO_INTERFACE; // Well, sort of. - *this = *asLocalFile; - return NS_OK; -} - -NS_IMETHODIMP -nsLocalFile::OpenNSPRFileDesc(PRInt32 flags, PRInt32 mode, PRFileDesc **_retval) -{ -// Macintosh doesn't really have mode bits, just drop them -#pragma unused (mode) - - NS_ENSURE_ARG(_retval); - - nsresult rv = NS_OK; - FSSpec spec; - OSErr err = noErr; - - rv = ResolveAndStat(); - if (rv == NS_ERROR_FILE_NOT_FOUND && (flags & PR_CREATE_FILE)) - rv = NS_OK; - - if (flags & PR_CREATE_FILE) { - rv = Create(nsIFile::NORMAL_FILE_TYPE, 0); - /* If opening with the PR_EXCL flag the existence of the file prior to opening is an error */ - if ((flags & PR_EXCL) && (rv == NS_ERROR_FILE_ALREADY_EXISTS)) - return rv; - } - - rv = GetFSSpec(&spec); - if (NS_FAILED(rv)) - return rv; - - SInt8 perm; - if (flags & PR_RDWR) - perm = fsRdWrPerm; - else if (flags & PR_WRONLY) - perm = fsWrPerm; - else - perm = fsRdPerm; - - short refnum; - err = ::FSpOpenDF(&spec, perm, &refnum); - - if (err == noErr && (flags & PR_TRUNCATE)) - err = ::SetEOF(refnum, 0); - if (err == noErr && (flags & PR_APPEND)) - err = ::SetFPos(refnum, fsFromLEOF, 0); - if (err != noErr) - return MacErrorMapper(err); - - if ((*_retval = PR_ImportFile(refnum)) == 0) - return NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES,(PR_GetError() & 0xFFFF)); - - return NS_OK; -} - -NS_IMETHODIMP -nsLocalFile::OpenANSIFileDesc(const char *mode, FILE * *_retval) -{ - NS_ENSURE_ARG(mode); - NS_ENSURE_ARG_POINTER(_retval); - - nsresult rv; - FSSpec spec; - - rv = ResolveAndStat(); - if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) - return rv; - - if (mode[0] == 'w' || mode[0] == 'a') // Create if it doesn't exist - { - if (rv == NS_ERROR_FILE_NOT_FOUND) { - mType = (mode[1] == 'b') ? 'BiNA' : 'TEXT'; - rv = Create(nsIFile::NORMAL_FILE_TYPE, 0); - if (NS_FAILED(rv)) - return rv; - } - } - - rv = GetFSSpec(&spec); - if (NS_FAILED(rv)) - return rv; - -#ifdef MACOSX - // FSp_fopen() doesn't exist under macosx :-( - nsXPIDLCString ourPath; - rv = GetPath(getter_Copies(ourPath)); - if (NS_FAILED(rv)) - return rv; - *_retval = fopen(ourPath, mode); -#else - *_retval = FSp_fopen(&spec, mode); -#endif - - if (*_retval) - return NS_OK; - - return NS_ERROR_FAILURE; -} - - -NS_IMETHODIMP -nsLocalFile::Create(PRUint32 type, PRUint32 attributes) -{ - OSErr err; - - if (type != NORMAL_FILE_TYPE && type != DIRECTORY_TYPE) - return NS_ERROR_FILE_UNKNOWN_TYPE; - - FSSpec newSpec; - - if (mAppendedPath.Length()) - { // We've got an FSSpec and an appended path so pass 'em both to ResolvePathAndSpec - err = ResolvePathAndSpec(mAppendedPath.get(), &mSpec, PR_TRUE, &newSpec); - } - else - { - err = ::FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, mSpec.name, &newSpec); - } - - if (err != noErr && err != fnfErr) - return (MacErrorMapper(err)); - - switch (type) - { - case NORMAL_FILE_TYPE: - SetOSTypeAndCreatorFromExtension(); - err = ::FSpCreate(&newSpec, mCreator, mType, smCurrentScript); - break; - - case DIRECTORY_TYPE: - { - long newDirID; - err = ::FSpDirCreate(&newSpec, smCurrentScript, &newDirID); - // For some reason, this usually returns fnfErr, even though it works. - if (err == fnfErr) - err = noErr; - } - break; - - default: - return NS_ERROR_FILE_UNKNOWN_TYPE; - break; - } - - if (err == noErr) - { - mSpec = mTargetSpec = newSpec; - mAppendedPath.Truncate(0); - } - - return (MacErrorMapper(err)); -} - -NS_IMETHODIMP -nsLocalFile::AppendNative(const nsACString &aNode) -{ - if (aNode.IsEmpty()) - return NS_OK; - - nsACString::const_iterator start, end; - aNode.BeginReading(start); - aNode.EndReading(end); - if (FindCharInReadable(':', start, end)) - return NS_ERROR_FILE_UNRECOGNIZED_PATH; - - MakeDirty(); - - char truncBuffer[32]; - const char *node = NS_TruncNodeName(PromiseFlatCString(aNode).get(), truncBuffer); - - if (!mAppendedPath.Length()) - { - OSErr err; - Boolean resolvedWasFolder, resolvedWasAlias; - err = ::ResolveAliasFile(&mSpec, TRUE, &resolvedWasFolder, &resolvedWasAlias); - if (err == noErr) - { - long dirID; - Boolean isDir; - - if (!resolvedWasFolder) - return NS_ERROR_FILE_NOT_DIRECTORY; - if ((err = ::FSpGetDirectoryID(&mSpec, &dirID, &isDir)) != noErr) - return MacErrorMapper(err); - - FSSpec childSpec; - Str255 pascalNode; - myPLstrcpy(pascalNode, node); - err = ::FSMakeFSSpec(mSpec.vRefNum, dirID, pascalNode, &childSpec); - if (err && err != fnfErr) - return MacErrorMapper(err); - mSpec = childSpec; - } - else if (err == fnfErr) - mAppendedPath.Assign(node); - else - return MacErrorMapper(err); - } - else - { - if (mAppendedPath.First() != ':') - mAppendedPath.Insert(':', 0); - mAppendedPath.Append(":"); - mAppendedPath.Append(node); - } - - return NS_OK; -} - -NS_IMETHODIMP -nsLocalFile::Append(const nsAString &node) -{ - nsresult rv; - nsCAutoString fsStr; - - if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(node, fsStr))) - rv = AppendNative(fsStr); - - return rv; -} - -NS_IMETHODIMP -nsLocalFile::AppendRelativeNativePath(const nsACString &relPath) -{ - if (relPath.IsEmpty()) - return NS_ERROR_INVALID_ARG; - - nsresult rv; - nsPathParser parser(relPath); - const char* node = parser.First(); - - while (node) - { - if (NS_FAILED(rv = AppendNative(nsDependentCString(node)))) - return rv; - node = parser.Next(); - } - - return NS_OK; -} - -NS_IMETHODIMP -nsLocalFile::AppendRelativePath(const nsAString &relPath) -{ - nsresult rv; - nsCAutoString fsStr; - - if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(relPath, fsStr))) - rv = AppendRelativeNativePath(fsStr); - - return rv; -} - -NS_IMETHODIMP -nsLocalFile::GetNativeLeafName(nsACString &aLeafName) -{ - aLeafName.Truncate(); - - // See if we've had a path appended - if (mAppendedPath.Length()) - { - const char* temp = mAppendedPath.get(); - if (temp == nsnull) - return NS_ERROR_FILE_UNRECOGNIZED_PATH; - - const char* leaf = strrchr(temp, ':'); - - // if the working path is just a node without any directory delimiters. - if (leaf == nsnull) - leaf = temp; - else - leaf++; - - aLeafName = leaf; - } - else - { - // We don't have an appended path so grab the leaf name from the FSSpec - // Convert the Pascal string to a C string - PRInt32 len = mSpec.name[0]; - char* leafName = (char *)malloc(len + 1); - if (!leafName) return NS_ERROR_OUT_OF_MEMORY; - ::BlockMoveData(&mSpec.name[1], leafName, len); - leafName[len] = '\0'; - aLeafName = leafName; - free(leafName); - } - - return NS_OK; -} - -NS_IMETHODIMP -nsLocalFile::GetLeafName(nsAString &aLeafName) -{ - nsresult rv; - nsCAutoString fsStr; - - if (NS_SUCCEEDED(rv = GetNativeLeafName(fsStr))) - rv = NS_CopyNativeToUnicode(fsStr, aLeafName); - return rv; -} - -NS_IMETHODIMP -nsLocalFile::SetNativeLeafName(const nsACString &aLeafName) -{ - if (aLeafName.IsEmpty()) - return NS_ERROR_INVALID_ARG; - - MakeDirty(); - - char truncBuffer[32]; - const char *leafName = NS_TruncNodeName(PromiseFlatCString(aLeafName).get(), truncBuffer); - - if (mAppendedPath.Length()) - { // Lop off the end of the appended path and replace it with the new leaf name - PRInt32 offset = mAppendedPath.RFindChar(':'); - if (offset || ((!offset) && (1 < mAppendedPath.Length()))) - { - mAppendedPath.Truncate(offset + 1); - } - mAppendedPath.Append(leafName); - } - else - { - // We don't have an appended path so directly modify the FSSpec - myPLstrcpy(mSpec.name, leafName); - } - - return NS_OK; -} - -NS_IMETHODIMP -nsLocalFile::SetLeafName(const nsAString &aLeafName) -{ - nsresult rv; - nsCAutoString fsStr; - - if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(aLeafName, fsStr))) - rv = SetNativeLeafName(fsStr); - - return rv; -} - -NS_IMETHODIMP -nsLocalFile::GetNativePath(nsACString &_retval) -{ - _retval.Truncate(); - - nsCAutoString fsCharSetPathStr; - -#if TARGET_CARBON - if (sHasHFSPlusAPIs) // should always be true under Carbon, but in case... - { - OSErr err; - nsresult rv; - nsAutoString ucPathString; - - if ((err = HFSPlusGetRawPath(mSpec, ucPathString)) != noErr) - return MacErrorMapper(err); - rv = NS_CopyUnicodeToNative(ucPathString, fsCharSetPathStr); - if (NS_FAILED(rv)) - return rv; - } - else -#endif - { - // Now would be a good time to call the code that makes an FSSpec into a path - short fullPathLen; - Handle fullPathHandle; - (void)::FSpGetFullPath(&mSpec, &fullPathLen, &fullPathHandle); - if (!fullPathHandle) - return NS_ERROR_OUT_OF_MEMORY; - - ::HLock(fullPathHandle); - fsCharSetPathStr.Assign(*fullPathHandle, fullPathLen); - ::DisposeHandle(fullPathHandle); - } - - // We need to make sure that even if we have a path to a - // directory we don't return the trailing colon. It breaks - // the component manager. (Bugzilla bug #26102) - if (fsCharSetPathStr.Last() == ':') - fsCharSetPathStr.Truncate(fsCharSetPathStr.Length() - 1); - - // Now, tack on mAppendedPath. It never ends in a colon. - if (mAppendedPath.Length()) - { - if (mAppendedPath.First() != ':') - fsCharSetPathStr.Append(":"); - fsCharSetPathStr.Append(mAppendedPath); - } - - _retval = fsCharSetPathStr; - return NS_OK; -} - -NS_IMETHODIMP -nsLocalFile::GetPath(nsAString &_retval) -{ - nsresult rv = NS_OK; - -#if TARGET_CARBON - if (sHasHFSPlusAPIs) // should always be true under Carbon, but in case... - { - OSErr err; - nsAutoString ucPathString; - - if ((err = HFSPlusGetRawPath(mSpec, ucPathString)) != noErr) - return MacErrorMapper(err); - - // We need to make sure that even if we have a path to a - // directory we don't return the trailing colon. It breaks - // the component manager. (Bugzilla bug #26102) - if (ucPathString.Last() == PRUnichar(':')) - ucPathString.Truncate(ucPathString.Length() - 1); - - // Now, tack on mAppendedPath. It never ends in a colon. - if (mAppendedPath.Length()) - { - nsAutoString ucAppendage; - if (mAppendedPath.First() != ':') - ucPathString.Append(PRUnichar(':')); - rv = NS_CopyNativeToUnicode(mAppendedPath, ucAppendage); - if (NS_FAILED(rv)) - return rv; - ucPathString.Append(ucAppendage); - } - - _retval = ucPathString; - } - else -#endif - { - nsCAutoString fsStr; - - if (NS_SUCCEEDED(rv = GetNativePath(fsStr))) { - rv = NS_CopyNativeToUnicode(fsStr, _retval); - } - } - return rv; -} - -nsresult nsLocalFile::MoveCopy( nsIFile* newParentDir, const nsACString &newName, PRBool isCopy, PRBool followLinks ) -{ - OSErr macErr; - FSSpec srcSpec; - Str255 newPascalName; - nsresult rv; - - StFollowLinksState srcFollowState(this, followLinks); - rv = GetFSSpec(&srcSpec); - if ( NS_FAILED( rv ) ) - return rv; - - // If newParentDir == nsnull, it's a simple rename - if ( !newParentDir ) - { - myPLstrncpy( newPascalName, PromiseFlatCString(newName).get(), 255 ); - macErr = ::FSpRename( &srcSpec, newPascalName ); - return MacErrorMapper( macErr ); - } - - nsCOMPtr destDir(do_QueryInterface( newParentDir )); - StFollowLinksState destFollowState(destDir, followLinks); - FSSpec destSpec; - rv = destDir->GetFSSpec(&destSpec); - if ( NS_FAILED( rv ) ) - return rv; - - long dirID; - Boolean isDirectory; - macErr = ::FSpGetDirectoryID(&destSpec, &dirID, &isDirectory); - if ( macErr || !isDirectory ) - return NS_ERROR_FILE_DESTINATION_NOT_DIR; - - if ( !newName.IsEmpty() ) - myPLstrncpy( newPascalName, PromiseFlatCString(newName).get(), 255); - else - memcpy(newPascalName, srcSpec.name, srcSpec.name[0] + 1); - if ( isCopy ) - { - macErr = ::FSpGetDirectoryID(&srcSpec, &dirID, &isDirectory); - if (macErr == noErr) - { - const PRInt32 kCopyBufferSize = (1024 * 512); // allocate our own buffer to speed file copies. Bug #103202 - OSErr tempErr; - Handle copyBufferHand = ::TempNewHandle(kCopyBufferSize, &tempErr); - void* copyBuffer = nsnull; - PRInt32 copyBufferSize = 0; - - // it's OK if the allocated failed; FSpFileCopy will just fall back on its own internal 16k buffer - if (copyBufferHand) - { - ::HLock(copyBufferHand); - copyBuffer = *copyBufferHand; - copyBufferSize = kCopyBufferSize; - } - - if ( isDirectory ) - macErr = MacFSpDirectoryCopyRename( &srcSpec, &destSpec, newPascalName, copyBuffer, copyBufferSize, true, NULL ); - else - macErr = ::FSpFileCopy( &srcSpec, &destSpec, newPascalName, copyBuffer, copyBufferSize, true ); - - if (copyBufferHand) - ::DisposeHandle(copyBufferHand); - } - } - else - { - macErr= ::FSpMoveRenameCompat(&srcSpec, &destSpec, newPascalName); - if ( macErr == diffVolErr) - { - // On a different Volume so go for Copy and then delete - rv = CopyToNative( newParentDir, newName ); - if ( NS_FAILED ( rv ) ) - return rv; - return Remove( PR_TRUE ); - } - } - return MacErrorMapper( macErr ); -} - -NS_IMETHODIMP -nsLocalFile::CopyToNative(nsIFile *newParentDir, const nsACString &newName) -{ - return MoveCopy( newParentDir, newName, PR_TRUE, PR_FALSE ); -} - -NS_IMETHODIMP -nsLocalFile::CopyTo(nsIFile *newParentDir, const nsAString &newName) -{ - if (newName.IsEmpty()) - return CopyToNative(newParentDir, EmptyCString()); - - nsresult rv; - nsCAutoString fsStr; - if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(newName, fsStr))) - rv = CopyToNative(newParentDir, fsStr); - return rv; -} - -NS_IMETHODIMP -nsLocalFile::CopyToFollowingLinksNative(nsIFile *newParentDir, const nsACString &newName) -{ - return MoveCopy( newParentDir, newName, PR_TRUE, PR_TRUE ); -} - -NS_IMETHODIMP -nsLocalFile::CopyToFollowingLinks(nsIFile *newParentDir, const nsAString &newName) -{ - if (newName.IsEmpty()) - return CopyToFollowingLinksNative(newParentDir, EmptyCString()); - - nsresult rv; - nsCAutoString fsStr; - if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(newName, fsStr))) - rv = CopyToFollowingLinksNative(newParentDir, fsStr); - return rv; -} - -NS_IMETHODIMP -nsLocalFile::MoveToNative(nsIFile *newParentDir, const nsACString &newName) -{ - return MoveCopy( newParentDir, newName, PR_FALSE, PR_FALSE ); -} - -NS_IMETHODIMP -nsLocalFile::MoveTo(nsIFile *newParentDir, const nsAString &newName) -{ - if (newName.IsEmpty()) - return MoveToNative(newParentDir, EmptyCString()); - - nsresult rv; - nsCAutoString fsStr; - if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(newName, fsStr))) - rv = MoveToNative(newParentDir, fsStr); - return rv; -} - -NS_IMETHODIMP -nsLocalFile::Load(PRLibrary * *_retval) -{ - PRBool isFile; - nsresult rv = IsFile(&isFile); - - if (NS_FAILED(rv)) - return rv; - - if (! isFile) - return NS_ERROR_FILE_IS_DIRECTORY; - - NS_TIMELINE_START_TIMER("PR_LoadLibrary"); - -#if !TARGET_CARBON - // This call to SystemTask is here to give the OS time to grow its - // FCB (file control block) list, which it seems to be unable to - // do unless we yield some time to the OS. See bugs 64978 & 70543 - // for the whole story. - ::SystemTask(); -#endif - - // Use the new PR_LoadLibraryWithFlags which allows us to use a FSSpec - PRLibSpec libSpec; - libSpec.type = PR_LibSpec_MacIndexedFragment; - libSpec.value.mac_indexed_fragment.fsspec = &mTargetSpec; - libSpec.value.mac_indexed_fragment.index = 0; - *_retval = PR_LoadLibraryWithFlags(libSpec, 0); - - NS_TIMELINE_STOP_TIMER("PR_LoadLibrary"); - NS_TIMELINE_MARK_TIMER("PR_LoadLibrary"); - - if (*_retval) - return NS_OK; - - return NS_ERROR_NULL_POINTER; -} - -NS_IMETHODIMP -nsLocalFile::Remove(PRBool recursive) -{ - OSErr err; - nsresult rv; - FSSpec specToDelete; - PRBool isDir; - - StFollowLinksState(this, PR_FALSE); - - rv = IsDirectory(&isDir); // Calls ResolveAndStat() - if (NS_FAILED(rv)) - return rv; - rv = GetFSSpec(&specToDelete); - if (NS_FAILED(rv)) - return rv; - - if (isDir && recursive) - err = ::DeleteDirectory( specToDelete.vRefNum, specToDelete.parID, specToDelete.name ); - else - err = ::HDelete( specToDelete.vRefNum, specToDelete.parID, specToDelete.name ); - - return MacErrorMapper( err ); -} - -NS_IMETHODIMP -nsLocalFile::GetLastModifiedTime(PRInt64 *aLastModifiedTime) -{ - NS_ENSURE_ARG(aLastModifiedTime); - *aLastModifiedTime = 0; - - nsresult rv = ResolveAndStat(); - if ( NS_FAILED( rv ) ) - return rv; - rv = UpdateCachedCatInfo(PR_TRUE); - if ( NS_FAILED( rv ) ) - return rv; - - // The mod date is in the same spot for files and dirs. - return ConvertMacTimeToMilliseconds( aLastModifiedTime, mCachedCatInfo.hFileInfo.ioFlMdDat ); -} - -NS_IMETHODIMP -nsLocalFile::SetLastModifiedTime(PRInt64 aLastModifiedTime) -{ - nsresult rv = ResolveAndStat(); - if ( NS_FAILED(rv) ) - return rv; - - PRUint32 macTime = 0; - OSErr err = noErr; - - ConvertMillisecondsToMacTime(aLastModifiedTime, &macTime); - - if (NS_SUCCEEDED(rv = UpdateCachedCatInfo(PR_TRUE))) - { - if (mCachedCatInfo.hFileInfo.ioFlAttrib & ioDirMask) - { - mCachedCatInfo.dirInfo.ioDrMdDat = macTime; - mCachedCatInfo.dirInfo.ioDrParID = mFollowLinks ? mTargetSpec.parID : mSpec.parID; - } - else - { - mCachedCatInfo.hFileInfo.ioFlMdDat = macTime; - mCachedCatInfo.hFileInfo.ioDirID = mFollowLinks ? mTargetSpec.parID : mSpec.parID; - } - - err = ::PBSetCatInfoSync(&mCachedCatInfo); - if (err != noErr) - return MacErrorMapper(err); - } - - return rv; -} - -NS_IMETHODIMP -nsLocalFile::GetLastModifiedTimeOfLink(PRInt64 *aLastModifiedTime) -{ - NS_ENSURE_ARG(aLastModifiedTime); - - nsresult rv; - PRBool isLink; - - rv = IsSymlink(&isLink); - if (NS_FAILED(rv)) - return rv; - if (!isLink) - return NS_ERROR_FAILURE; - - StFollowLinksState followState(this, PR_FALSE); - return GetLastModifiedTime(aLastModifiedTime); -} - -NS_IMETHODIMP -nsLocalFile::SetLastModifiedTimeOfLink(PRInt64 aLastModifiedTime) -{ - nsresult rv; - PRBool isLink; - - rv = IsSymlink(&isLink); - if (NS_FAILED(rv)) - return rv; - if (!isLink) - return NS_ERROR_FAILURE; - - StFollowLinksState followState(this, PR_FALSE); - return SetLastModifiedTime(aLastModifiedTime); -} - - -NS_IMETHODIMP -nsLocalFile::GetFileSize(PRInt64 *aFileSize) -{ - NS_ENSURE_ARG(aFileSize); - nsresult rv; - - *aFileSize = LL_Zero(); - - if (NS_SUCCEEDED(rv = ResolveAndStat()) && NS_SUCCEEDED(rv = UpdateCachedCatInfo(PR_TRUE))) - { - if (!(mCachedCatInfo.hFileInfo.ioFlAttrib & ioDirMask)) - { - long dataSize = mCachedCatInfo.hFileInfo.ioFlLgLen; - long resSize = mCachedCatInfo.hFileInfo.ioFlRLgLen; - - // For now we've only got 32 bits of file size info - PRInt64 dataInt64 = LL_Zero(); - PRInt64 resInt64 = LL_Zero(); - - // WARNING!!!!!! - // - // For now we do NOT add the data and resource fork sizes as there are several - // assumptions in the code (notably in form submit) that only the data fork is - // used. - // LL_I2L(resInt64, resSize); - - LL_I2L(dataInt64, dataSize); - - LL_ADD((*aFileSize), dataInt64, resInt64); - } - // leave size at zero for dirs - } - - return rv; -} - - -NS_IMETHODIMP -nsLocalFile::SetFileSize(PRInt64 aFileSize) -{ - nsresult rv = ResolveAndStat(); - if (NS_FAILED(rv)) - return rv; - - short refNum; - OSErr err; - PRInt32 aNewLength; - - LL_L2I(aNewLength, aFileSize); - - // Need to open the file to set the size - if (::FSpOpenDF(&mTargetSpec, fsWrPerm, &refNum) != noErr) - return NS_ERROR_FILE_ACCESS_DENIED; - - err = ::SetEOF(refNum, aNewLength); - - // Close the file unless we got an error that it was already closed - if (err != fnOpnErr) - (void)::FSClose(refNum); - - if (err != noErr) - return MacErrorMapper(err); - - return MacErrorMapper(err); -} - -NS_IMETHODIMP -nsLocalFile::GetFileSizeOfLink(PRInt64 *aFileSize) -{ - NS_ENSURE_ARG(aFileSize); - - StFollowLinksState followState(this, PR_FALSE); - return GetFileSize(aFileSize); -} - -NS_IMETHODIMP -nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable) -{ - NS_ENSURE_ARG(aDiskSpaceAvailable); - - PRInt64 space64Bits; - - LL_I2L(space64Bits , LONG_MAX); - - nsresult rv = ResolveAndStat(); - if (NS_FAILED(rv)) - return rv; - - XVolumeParam pb; - pb.ioCompletion = nsnull; - pb.ioVolIndex = 0; - pb.ioNamePtr = nsnull; - pb.ioVRefNum = mFollowLinks ? mTargetSpec.vRefNum : mSpec.vRefNum; - - // we should check if this call is available - OSErr err = ::PBXGetVolInfoSync(&pb); - - if (err == noErr) - { - const UnsignedWide& freeBytes = UInt64ToUnsignedWide(pb.ioVFreeBytes); -#ifdef HAVE_LONG_LONG - space64Bits = UnsignedWideToUInt64(freeBytes); -#else - space64Bits.lo = freeBytes.lo; - space64Bits.hi = freeBytes.hi; -#endif - } - - *aDiskSpaceAvailable = space64Bits; - - return NS_OK; -} - -NS_IMETHODIMP -nsLocalFile::GetParent(nsIFile * *aParent) -{ - NS_ENSURE_ARG_POINTER(aParent); - *aParent = nsnull; - - nsresult rv = NS_OK; - PRInt32 offset; - - nsCOMPtr localFile; - PRInt32 appendedLen = mAppendedPath.Length(); - OSErr err; - - if (!appendedLen || (appendedLen == 1 && mAppendedPath.CharAt(0) == ':')) - { - rv = ResolveAndStat(); - //if the file does not exist, does not mean that the parent does not. - if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) - return rv; - - CInfoPBRec pBlock = {0}; - FSSpec parentFolderSpec; - parentFolderSpec.name[0] = 0; - - pBlock.dirInfo.ioVRefNum = mSpec.vRefNum; - pBlock.dirInfo.ioDrDirID = mSpec.parID; - pBlock.dirInfo.ioNamePtr = (StringPtr)parentFolderSpec.name; - pBlock.dirInfo.ioFDirIndex = -1; //get info on parID - err = PBGetCatInfoSync(&pBlock); - if (err != noErr) - return MacErrorMapper(err); - parentFolderSpec.vRefNum = mSpec.vRefNum; - parentFolderSpec.parID = pBlock.dirInfo.ioDrParID; - - localFile = new nsLocalFile; - if (!localFile) - return NS_ERROR_OUT_OF_MEMORY; - rv = localFile->InitWithFSSpec(&parentFolderSpec); - if (NS_FAILED(rv)) - return rv; - } - else - { - // trim off the last component of the appended path - // construct a new file from our spec + trimmed path - - nsCAutoString parentAppendage(mAppendedPath); - - if (parentAppendage.Last() == ':') - parentAppendage.Truncate(appendedLen - 1); - if ((offset = parentAppendage.RFindChar(':')) != -1) - parentAppendage.Truncate(offset); - else - parentAppendage.Truncate(0); - - localFile = new nsLocalFile(mSpec, parentAppendage); - if (!localFile) - return NS_ERROR_OUT_OF_MEMORY; - } - *aParent = localFile; - NS_ADDREF(*aParent); - - return rv; -} - - -NS_IMETHODIMP -nsLocalFile::Exists(PRBool *_retval) -{ - NS_ENSURE_ARG(_retval); - *_retval = PR_FALSE; - - nsresult rv = ResolveAndStat(); - if (NS_SUCCEEDED(rv)) { - if (NS_SUCCEEDED(UpdateCachedCatInfo(PR_TRUE))) - *_retval = PR_TRUE; - } - - return NS_OK; -} - -NS_IMETHODIMP -nsLocalFile::IsPackage(PRBool *outIsPackage) -{ - NS_ENSURE_ARG(outIsPackage); - *outIsPackage = PR_FALSE; - - // Note: IsDirectory() calls ResolveAndStat() & UpdateCachedCatInfo - PRBool isDir; - nsresult rv = IsDirectory(&isDir); - if (NS_FAILED(rv)) return rv; - - *outIsPackage = ((mCachedCatInfo.dirInfo.ioFlAttrib & kioFlAttribDirMask) && - (mCachedCatInfo.dirInfo.ioDrUsrWds.frFlags & kHasBundle)); - - if ((!*outIsPackage) && isDir) - { - // Believe it or not, folders ending with ".app" are also considered - // to be packages, even if the top-level folder doesn't have bundle set - nsCAutoString name; - if (NS_SUCCEEDED(rv = GetNativeLeafName(name))) - { - const char *extPtr = strrchr(name.get(), '.'); - if (extPtr) - { - if (!nsCRT::strcasecmp(extPtr, ".app")) - { - *outIsPackage = PR_TRUE; - } - } - } - } - - return NS_OK; -} - -NS_IMETHODIMP -nsLocalFile::IsWritable(PRBool *outIsWritable) -{ - NS_ENSURE_ARG(outIsWritable); - *outIsWritable = PR_TRUE; - - nsresult rv = ResolveAndStat(); - if (NS_FAILED(rv)) return rv; - - rv = UpdateCachedCatInfo(PR_TRUE); - if (NS_FAILED(rv)) return rv; - - *outIsWritable = !(mCachedCatInfo.hFileInfo.ioFlAttrib & kioFlAttribLockedMask); - return NS_OK; -} - -NS_IMETHODIMP -nsLocalFile::IsReadable(PRBool *_retval) -{ - NS_ENSURE_ARG(_retval); - - // is it ever not readable on Mac? - *_retval = PR_TRUE; - return NS_OK; -} - - -NS_IMETHODIMP -nsLocalFile::IsExecutable(PRBool *outIsExecutable) -{ - NS_ENSURE_ARG(outIsExecutable); - *outIsExecutable = PR_FALSE; // Assume failure - - nsresult rv = ResolveAndStat(); - if (NS_FAILED(rv)) return rv; - -#if TARGET_CARBON - // If we're running under OS X ask LaunchServices if we're executable - if (sRunningOSX) - { - if ( (UInt32)LSCopyItemInfoForRef != (UInt32)kUnresolvedCFragSymbolAddress ) - { - FSRef theRef; - LSRequestedInfo theInfoRequest = kLSRequestAllInfo; - LSItemInfoRecord theInfo; - - if (::FSpMakeFSRef(&mTargetSpec, &theRef) == noErr) - { - if (::LSCopyItemInfoForRef(&theRef, theInfoRequest, &theInfo) == noErr) - { - if ((theInfo.flags & kLSItemInfoIsApplication) != 0) - *outIsExecutable = PR_TRUE; - } - } - } - } - else -#endif - { - OSType fileType; - rv = GetFileType(&fileType); - if (NS_FAILED(rv)) return rv; - - *outIsExecutable = (fileType == 'APPL' || fileType == 'appe' || fileType == 'FNDR'); - } - - return NS_OK; -} - - -NS_IMETHODIMP -nsLocalFile::IsDirectory(PRBool *outIsDir) -{ - NS_ENSURE_ARG(outIsDir); - *outIsDir = PR_FALSE; - - nsresult rv = ResolveAndStat(); - if (NS_FAILED(rv)) return rv; - - rv = UpdateCachedCatInfo(PR_FALSE); - if (NS_FAILED(rv)) return rv; - - *outIsDir = (mCachedCatInfo.hFileInfo.ioFlAttrib & ioDirMask) != 0; - return NS_OK; -} - -NS_IMETHODIMP -nsLocalFile::IsFile(PRBool *outIsFile) -{ - NS_ENSURE_ARG(outIsFile); - *outIsFile = PR_FALSE; - - nsresult rv = ResolveAndStat(); - if (NS_FAILED(rv)) return rv; - - rv = UpdateCachedCatInfo(PR_FALSE); - if (NS_FAILED(rv)) return rv; - - *outIsFile = (mCachedCatInfo.hFileInfo.ioFlAttrib & ioDirMask) == 0; - return NS_OK; -} - -NS_IMETHODIMP -nsLocalFile::IsHidden(PRBool *_retval) -{ - NS_ENSURE_ARG(_retval); - *_retval = PR_FALSE; - - nsresult rv = ResolveAndStat(); - if (NS_FAILED(rv)) return rv; - - rv = UpdateCachedCatInfo(PR_FALSE); - if (NS_FAILED(rv)) return rv; - - *_retval = (mCachedCatInfo.hFileInfo.ioFlFndrInfo.fdFlags & kIsInvisible) != 0; - - if (sRunningOSX) - { - // on Mac OS X, also follow Unix "convention" where files - // beginning with a period are considered to be hidden - nsCAutoString name; - if (NS_SUCCEEDED(rv = GetNativeLeafName(name))) - { - if (name.First() == '.') - { - *_retval = PR_TRUE; - } - } - } - - return NS_OK; -} - -NS_IMETHODIMP -nsLocalFile::IsSymlink(PRBool *_retval) -{ - NS_ENSURE_ARG(_retval); - *_retval = PR_FALSE; - - nsresult rv = ResolveAndStat(); - if (NS_FAILED(rv)) return rv; - - Boolean isAlias, isFolder; - if (::IsAliasFile(&mSpec, &isAlias, &isFolder) == noErr) - *_retval = isAlias; - return NS_OK; -} - -NS_IMETHODIMP -nsLocalFile::Equals(nsIFile *inFile, PRBool *_retval) -{ - NS_ENSURE_ARG(inFile); - NS_ENSURE_ARG(_retval); - *_retval = PR_FALSE; - - // Building paths is expensive. If we can get the FSSpecs of - // both (they or their parents exist) just compare the specs. - nsCOMPtr inMacFile(do_QueryInterface(inFile)); - FSSpec fileSpec, inFileSpec; - if (NS_SUCCEEDED(GetFSSpec(&fileSpec)) && inMacFile && NS_SUCCEEDED(inMacFile->GetFSSpec(&inFileSpec))) - *_retval = IsEqualFSSpec(fileSpec, inFileSpec); - else - { - nsCAutoString filePath; - GetNativePath(filePath); - - nsXPIDLCString inFilePath; - inFile->GetNativePath(inFilePath); - - if (nsCRT::strcasecmp(inFilePath.get(), filePath.get()) == 0) - *_retval = PR_TRUE; - } - return NS_OK; -} - -NS_IMETHODIMP -nsLocalFile::Contains(nsIFile *inFile, PRBool recur, PRBool *outContains) -{ - /* Note here that we make no attempt to deal with the problem - of folder aliases. Doing a 'Contains' test and dealing with - folder aliases is Hard. Think about it. - */ - *outContains = PR_FALSE; - - PRBool isDir; - nsresult rv = IsDirectory(&isDir); // need to cache this - if (NS_FAILED(rv)) return rv; - if (!isDir) return NS_OK; // must be a dir to contain someone - - nsCOMPtr macFile(do_QueryInterface(inFile)); - if (!macFile) return NS_OK; // trying to compare non-local with local file - - FSSpec mySpec = mSpec; - FSSpec compareSpec; - - // NOTE: we're not resolving inFile if it was an alias - StFollowLinksState followState(macFile, PR_FALSE); - rv = macFile->GetFSSpec(&compareSpec); - if (NS_FAILED(rv)) return rv; - - // if they are on different volumes, bail - if (mSpec.vRefNum != compareSpec.vRefNum) - return NS_OK; - - // if recur == true, test every parent, otherwise just test the first one - // (yes, recur does not get set in this loop) - OSErr err = noErr; - do - { - FSSpec parentFolderSpec; - err = GetParentFolderSpec(compareSpec, parentFolderSpec); - if (err != noErr) break; // we reached the top - - if (IsEqualFSSpec(parentFolderSpec, mySpec)) - { - *outContains = PR_TRUE; - break; - } - - compareSpec = parentFolderSpec; - } while (recur); - - return NS_OK; -} - - - -NS_IMETHODIMP -nsLocalFile::GetNativeTarget(nsACString &_retval) -{ - _retval.Truncate(); - - PRBool symLink; - - nsresult rv = IsSymlink(&symLink); - if (NS_FAILED(rv)) - return rv; - - if (!symLink) - return NS_ERROR_FILE_INVALID_PATH; - - StFollowLinksState followState(this, PR_TRUE); - return GetNativePath(_retval); -} - -NS_IMETHODIMP -nsLocalFile::GetTarget(nsAString &_retval) -{ - nsresult rv; - nsCAutoString fsStr; - - if (NS_SUCCEEDED(rv = GetNativeTarget(fsStr))) { - rv = NS_CopyNativeToUnicode(fsStr, _retval); - } - return rv; -} - -NS_IMETHODIMP -nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator * *entries) -{ - nsresult rv; - - *entries = nsnull; - - PRBool isDir; - rv = IsDirectory(&isDir); - if (NS_FAILED(rv)) - return rv; - if (!isDir) - return NS_ERROR_FILE_NOT_DIRECTORY; - - nsDirEnumerator* dirEnum = new nsDirEnumerator(); - if (dirEnum == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(dirEnum); - rv = dirEnum->Init(this); - if (NS_FAILED(rv)) - { - NS_RELEASE(dirEnum); - return rv; - } - - *entries = dirEnum; - return NS_OK; -} - -NS_IMETHODIMP -nsLocalFile::GetPersistentDescriptor(nsACString &aPersistentDescriptor) -{ - aPersistentDescriptor.Truncate(); - - nsresult rv = ResolveAndStat(); - if ( NS_FAILED( rv ) ) - return rv; - - AliasHandle aliasH; - OSErr err = ::NewAlias(nil, &mTargetSpec, &aliasH); - if (err != noErr) - return MacErrorMapper(err); - - PRUint32 bytes = ::GetHandleSize((Handle) aliasH); - HLock((Handle) aliasH); - char* buf = PL_Base64Encode((const char*)*aliasH, bytes, nsnull); // Passing nsnull for dest makes NULL-term string - ::DisposeHandle((Handle) aliasH); - NS_ENSURE_TRUE(buf, NS_ERROR_OUT_OF_MEMORY); - - aPersistentDescriptor = buf; - PR_Free(buf); - - return NS_OK; -} - -NS_IMETHODIMP -nsLocalFile::SetPersistentDescriptor(const nsACString &aPersistentDescriptor) -{ - if (aPersistentDescriptor.IsEmpty()) - return NS_ERROR_INVALID_ARG; - - nsresult rv = NS_OK; - - PRUint32 dataSize = aPersistentDescriptor.Length(); - char* decodedData = PL_Base64Decode(PromiseFlatCString(aPersistentDescriptor).get(), dataSize, nsnull); - // Cast to an alias record and resolve. - AliasHandle aliasH = nsnull; - if (::PtrToHand(decodedData, &(Handle)aliasH, (dataSize * 3) / 4) != noErr) - rv = NS_ERROR_OUT_OF_MEMORY; - PR_Free(decodedData); - NS_ENSURE_SUCCESS(rv, rv); - - Boolean changed; - FSSpec resolvedSpec; - OSErr err; - err = ::ResolveAlias(nsnull, aliasH, &resolvedSpec, &changed); - if (err == fnfErr) // resolvedSpec is valid in this case - err = noErr; - rv = MacErrorMapper(err); - DisposeHandle((Handle) aliasH); - NS_ENSURE_SUCCESS(rv, rv); - - return InitWithFSSpec(&resolvedSpec); -} - -#pragma mark - - -// a stack-based, exception safe class for an AEDesc - -#pragma mark -class StAEDesc: public AEDesc -{ -public: - StAEDesc() - { - descriptorType = typeNull; - dataHandle = nil; - } - - ~StAEDesc() - { - ::AEDisposeDesc(this); - } - - void Clear() - { - ::AEDisposeDesc(this); - descriptorType = typeNull; - dataHandle = nil; - } - -private: - // disallow copies and assigns - StAEDesc(const StAEDesc& rhs); // copy constructor - StAEDesc& operator= (const StAEDesc&rhs); // throws OSErrs - -}; - -#pragma mark - -#pragma mark [Utility methods] - - -nsresult nsLocalFile::UpdateCachedCatInfo(PRBool forceUpdate) -{ - if (!mCatInfoDirty && !forceUpdate) - return NS_OK; - - FSSpec spectoUse = mFollowLinks ? mTargetSpec : mSpec; - mCachedCatInfo.hFileInfo.ioCompletion = nsnull; - mCachedCatInfo.hFileInfo.ioFDirIndex = 0; // use dirID and name - mCachedCatInfo.hFileInfo.ioVRefNum = spectoUse.vRefNum; - mCachedCatInfo.hFileInfo.ioDirID = spectoUse.parID; - mCachedCatInfo.hFileInfo.ioNamePtr = spectoUse.name; - - OSErr err = ::PBGetCatInfoSync(&mCachedCatInfo); - if (err == noErr) - { - mCatInfoDirty = PR_FALSE; - return NS_OK; - } - return MacErrorMapper(err); -} - - -nsresult nsLocalFile::FindRunningAppBySignature (OSType aAppSig, FSSpec& outSpec, ProcessSerialNumber& outPsn) -{ - ProcessInfoRec info; - FSSpec tempFSSpec; - OSErr err = noErr; - - outPsn.highLongOfPSN = 0; - outPsn.lowLongOfPSN = kNoProcess; - - while (PR_TRUE) - { - err = ::GetNextProcess(&outPsn); - if (err == procNotFound) break; - if (err != noErr) return NS_ERROR_FAILURE; - info.processInfoLength = sizeof(ProcessInfoRec); - info.processName = nil; - info.processAppSpec = &tempFSSpec; - err = ::GetProcessInformation(&outPsn, &info); - if (err != noErr) return NS_ERROR_FAILURE; - - if (info.processSignature == aAppSig) - { - outSpec = tempFSSpec; - return NS_OK; - } - } - - return NS_ERROR_FILE_NOT_FOUND; // really process not found -} - - -nsresult nsLocalFile::FindRunningAppByFSSpec(const FSSpec& appSpec, ProcessSerialNumber& outPsn) -{ - ProcessInfoRec info; - FSSpec tempFSSpec; - OSErr err = noErr; - - outPsn.highLongOfPSN = 0; - outPsn.lowLongOfPSN = kNoProcess; - - while (PR_TRUE) - { - err = ::GetNextProcess(&outPsn); - if (err == procNotFound) break; - if (err != noErr) return NS_ERROR_FAILURE; - info.processInfoLength = sizeof(ProcessInfoRec); - info.processName = nil; - info.processAppSpec = &tempFSSpec; - err = ::GetProcessInformation(&outPsn, &info); - if (err != noErr) return NS_ERROR_FAILURE; - - if (IsEqualFSSpec(appSpec, *info.processAppSpec)) - { - return NS_OK; - } - } - - return NS_ERROR_FILE_NOT_FOUND; // really process not found -} - - -nsresult nsLocalFile::FindAppOnLocalVolumes(OSType sig, FSSpec &outSpec) -{ - OSErr err; - - // get the system volume - long systemFolderDirID; - short sysVRefNum; - err = FindFolder(kOnSystemDisk, kSystemFolderType, false, &sysVRefNum, &systemFolderDirID); - if (err != noErr) return NS_ERROR_FAILURE; - - short vRefNum = sysVRefNum; - short index = 0; - - while (true) - { - if (index == 0 || vRefNum != sysVRefNum) - { - // should we avoid AppleShare volumes? - - Boolean hasDesktopDB; - err = VolHasDesktopDB(vRefNum, &hasDesktopDB); - if (err != noErr) return err; - if (hasDesktopDB) - { - err = FindAppOnVolume(sig, vRefNum, &outSpec); - if (err != afpItemNotFound) return err; - } - } - index++; - err = GetIndVolume(index, &vRefNum); - if (err == nsvErr) return fnfErr; - if (err != noErr) return err; - } - - return NS_OK; -} - -#define aeSelectionKeyword 'fsel' -#define kAEOpenSelection 'sope' -#define kAERevealSelection 'srev' -#define kFinderType 'FNDR' - -NS_IMETHODIMP nsLocalFile::Launch() -{ - AppleEvent aeEvent = {0, nil}; - AppleEvent aeReply = {0, nil}; - StAEDesc aeDirDesc, listElem, myAddressDesc, fileList; - FSSpec dirSpec, appSpec; - AliasHandle DirAlias, FileAlias; - OSErr errorResult = noErr; - ProcessSerialNumber process; - - // for launching a file, we'll use mTargetSpec (which is both a resolved spec and a resolved alias) - ResolveAndStat(); - -#if TARGET_CARBON - if (sRunningOSX) - { // We're running under Mac OS X, LaunchServices here we come - - // First we make sure the LaunchServices routine we want is implemented - if ( (UInt32)LSOpenFSRef != (UInt32)kUnresolvedCFragSymbolAddress ) - { - FSRef theRef; - if (::FSpMakeFSRef(&mTargetSpec, &theRef) == noErr) - { - (void)::LSOpenFSRef(&theRef, NULL); - } - } - } - else -#endif - { // We're running under Mac OS 8.x/9.x, use the Finder Luke - nsresult rv = FindRunningAppBySignature ('MACS', appSpec, process); - if (NS_SUCCEEDED(rv)) - { - errorResult = AECreateDesc(typeProcessSerialNumber, (Ptr)&process, sizeof(process), &myAddressDesc); - if (errorResult == noErr) - { - /* Create the FinderEvent */ - errorResult = AECreateAppleEvent(kFinderType, kAEOpenSelection, &myAddressDesc, kAutoGenerateReturnID, kAnyTransactionID, - &aeEvent); - if (errorResult == noErr) - { - errorResult = FSMakeFSSpec(mTargetSpec.vRefNum, mTargetSpec.parID, nil, &dirSpec); - NewAlias(nil, &dirSpec, &DirAlias); - /* Create alias for file */ - NewAlias(nil, &mTargetSpec, &FileAlias); - - /* Create the file list */ - errorResult = AECreateList(nil, 0, false, &fileList); - /* create the folder descriptor */ - HLock((Handle)DirAlias); - errorResult = AECreateDesc(typeAlias, (Ptr)*DirAlias, GetHandleSize((Handle)DirAlias), &aeDirDesc); - HUnlock((Handle)DirAlias); - if (errorResult == noErr) - { - errorResult = AEPutParamDesc(&aeEvent, keyDirectObject, &aeDirDesc); - if ( errorResult == noErr) - { - /* create the file descriptor and add to aliasList */ - HLock((Handle)FileAlias); - errorResult = AECreateDesc(typeAlias, (Ptr)*FileAlias, GetHandleSize((Handle)FileAlias), &listElem); - HLock((Handle)FileAlias); - if (errorResult == noErr) - { - errorResult = AEPutDesc(&fileList, 0, &listElem); - if (errorResult == noErr) - { - /* Add the file alias list to the event */ - errorResult = AEPutParamDesc(&aeEvent, aeSelectionKeyword, &fileList); - if (errorResult == noErr) - AESend(&aeEvent, &aeReply, kAEWaitReply + kAENeverInteract - + kAECanSwitchLayer, kAEHighPriority, kAEDefaultTimeout, nil, nil); - } - } - } - } - } - } - } - } - - return NS_OK; -} - -NS_IMETHODIMP nsLocalFile::Reveal() -{ - FSSpec specToReveal; - AppleEvent aeEvent = {0, nil}; - AppleEvent aeReply = {0, nil}; - StAEDesc aeDirDesc, listElem, myAddressDesc, fileList; - OSErr errorResult = noErr; - ProcessSerialNumber process; - FSSpec appSpec; - - nsresult rv = ResolveAndStat(); - if (NS_FAILED(rv)) - return rv; - rv = GetFSSpec(&specToReveal); // Pay attention to followLinks - if (NS_FAILED(rv)) - return rv; - - rv = FindRunningAppBySignature ('MACS', appSpec, process); - if (NS_SUCCEEDED(rv)) - { - errorResult = AECreateDesc(typeProcessSerialNumber, (Ptr)&process, sizeof(process), &myAddressDesc); - if (errorResult == noErr) - { - /* Create the FinderEvent */ -#if TARGET_CARBON - // The Finder under OS X uses a different event to reveal - if (sRunningOSX) - errorResult = AECreateAppleEvent(kAEMiscStandards, kAEMakeObjectsVisible, &myAddressDesc, kAutoGenerateReturnID, kAnyTransactionID, - &aeEvent); - else -#endif - errorResult = AECreateAppleEvent(kFinderType, kAERevealSelection, &myAddressDesc, kAutoGenerateReturnID, kAnyTransactionID, - &aeEvent); - if (errorResult == noErr) - { - /* Create the file list */ - errorResult = AECreateList(nil, 0, false, &fileList); - if (errorResult == noErr) - { - errorResult = AEPutPtr(&fileList, 0, typeFSS, &specToReveal, sizeof(FSSpec)); - - if (errorResult == noErr) - { -#if TARGET_CARBON - // When we're sending the event under OS X the FSSpec must be a keyDirectObject - if (sRunningOSX) - errorResult = AEPutParamDesc(&aeEvent, keyDirectObject, &fileList); - else -#endif - errorResult = AEPutParamDesc(&aeEvent,keySelection, &fileList); - - if (errorResult == noErr) - { - errorResult = AESend(&aeEvent, &aeReply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, nil, nil); - if (errorResult == noErr) - SetFrontProcess(&process); - } - } - } - } - } - } - - return NS_OK; -} - -nsresult nsLocalFile::MyLaunchAppWithDoc(const FSSpec& appSpec, const FSSpec* aDocToLoad, PRBool aLaunchInBackground) -{ - ProcessSerialNumber thePSN = {0}; - StAEDesc target; - StAEDesc docDesc; - StAEDesc launchDesc; - StAEDesc docList; - AppleEvent theEvent = {0, nil}; - AppleEvent theReply = {0, nil}; - OSErr err = noErr; - Boolean autoParamValue = false; - Boolean running = false; - nsresult rv = NS_OK; - -#if TARGET_CARBON - if (sRunningOSX) - { // Under Mac OS X we'll use LaunchServices - - // First we make sure the LaunchServices routine we want is implemented - if ( (UInt32)LSOpenFromRefSpec != (UInt32)kUnresolvedCFragSymbolAddress ) - { - FSRef appRef; - FSRef docRef; - LSLaunchFlags theLaunchFlags = kLSLaunchDefaults; - LSLaunchFSRefSpec thelaunchSpec; - - if (::FSpMakeFSRef(&appSpec, &appRef) != noErr) - return NS_ERROR_FAILURE; - - if (aDocToLoad) - if (::FSpMakeFSRef(aDocToLoad, &docRef) != noErr) - return NS_ERROR_FAILURE; - - if (aLaunchInBackground) - theLaunchFlags |= kLSLaunchDontSwitch; - - memset(&thelaunchSpec, 0, sizeof(LSLaunchFSRefSpec)); - - thelaunchSpec.appRef = &appRef; - if (aDocToLoad) - { - thelaunchSpec.numDocs = 1; - thelaunchSpec.itemRefs = &docRef; - } - thelaunchSpec.launchFlags = theLaunchFlags; - - err = ::LSOpenFromRefSpec(&thelaunchSpec, NULL); - NS_ASSERTION((err != noErr), "Error calling LSOpenFromRefSpec"); - if (err != noErr) return NS_ERROR_FAILURE; - } - } - else -#endif - { // The old fashioned way for Mac OS 8.x/9.x - rv = FindRunningAppByFSSpec(appSpec, thePSN); - running = NS_SUCCEEDED(rv); - - err = AECreateDesc(typeProcessSerialNumber, &thePSN, sizeof(thePSN), &target); - if (err != noErr) return NS_ERROR_FAILURE; - - err = AECreateAppleEvent(kCoreEventClass, aDocToLoad ? kAEOpenDocuments : kAEOpenApplication, &target, - kAutoGenerateReturnID, kAnyTransactionID, &theEvent); - if (err != noErr) return NS_ERROR_FAILURE; - - if (aDocToLoad) - { - err = AECreateList(nil, 0, false, &docList); - if (err != noErr) return NS_ERROR_FAILURE; - - err = AECreateDesc(typeFSS, aDocToLoad, sizeof(FSSpec), &docDesc); - if (err != noErr) return NS_ERROR_FAILURE; - - err = AEPutDesc(&docList, 0, &docDesc); - if (err != noErr) return NS_ERROR_FAILURE; - - err = AEPutParamDesc(&theEvent, keyDirectObject, &docList); - if (err != noErr) return NS_ERROR_FAILURE; - } - - if (running) - { - err = AESend(&theEvent, &theReply, kAENoReply, kAENormalPriority, kNoTimeOut, nil, nil); - if (err != noErr) return NS_ERROR_FAILURE; - - if (!aLaunchInBackground) - { - err = ::SetFrontProcess(&thePSN); - if (err != noErr) return NS_ERROR_FAILURE; - } - } - else - { - LaunchParamBlockRec launchThis = {0}; - PRUint16 launchControlFlags = (launchContinue | launchNoFileFlags); - if (aLaunchInBackground) - launchControlFlags |= launchDontSwitch; - - err = AECoerceDesc(&theEvent, typeAppParameters, &launchDesc); - if (err != noErr) return NS_ERROR_FAILURE; - - launchThis.launchAppSpec = (FSSpecPtr)&appSpec; -#if TARGET_CARBON && ACCESSOR_CALLS_ARE_FUNCTIONS - ::AEGetDescData(&launchDesc, &launchThis.launchAppParameters, sizeof(launchThis.launchAppParameters)); -#else - // no need to lock this handle. - launchThis.launchAppParameters = (AppParametersPtr) *(launchDesc.dataHandle); -#endif - launchThis.launchBlockID = extendedBlock; - launchThis.launchEPBLength = extendedBlockLen; - launchThis.launchFileFlags = 0; - launchThis.launchControlFlags = launchControlFlags; - err = ::LaunchApplication(&launchThis); - if (err != noErr) return NS_ERROR_FAILURE; - - // let's be nice and wait until it's running - const PRUint32 kMaxTimeToWait = 60; // wait 1 sec max - PRUint32 endTicks = ::TickCount() + kMaxTimeToWait; - - PRBool foundApp = PR_FALSE; - - do - { - EventRecord theEvent; - (void)WaitNextEvent(nullEvent, &theEvent, 1, NULL); - - ProcessSerialNumber psn; - foundApp = NS_SUCCEEDED(FindRunningAppByFSSpec(appSpec, psn)); - - } while (!foundApp && (::TickCount() <= endTicks)); - - NS_ASSERTION(foundApp, "Failed to find app after launching it"); - } - - if (theEvent.dataHandle != nil) AEDisposeDesc(&theEvent); - if (theReply.dataHandle != nil) AEDisposeDesc(&theReply); - } - - return NS_OK; -} - - -#pragma mark - -#pragma mark [Methods that will not be implemented on Mac] - -NS_IMETHODIMP -nsLocalFile::Normalize() -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -nsLocalFile::GetPermissions(PRUint32 *aPermissions) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -nsLocalFile::GetPermissionsOfLink(PRUint32 *aPermissionsOfLink) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - - -NS_IMETHODIMP -nsLocalFile::SetPermissions(PRUint32 aPermissions) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -nsLocalFile::SetPermissionsOfLink(PRUint32 aPermissions) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP -nsLocalFile::IsSpecial(PRBool *_retval) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -#pragma mark - -#pragma mark [nsILocalFileMac] -// Implementation of Mac specific finctions from nsILocalFileMac - - -NS_IMETHODIMP nsLocalFile::InitWithCFURL(CFURLRef aCFURL) -{ - nsresult rv = NS_ERROR_FAILURE; - -#if TARGET_CARBON - NS_ENSURE_ARG(aCFURL); - - // CFURLGetFSRef can only succeed if the entire path exists. - FSRef fsRef; - if (::CFURLGetFSRef(aCFURL, &fsRef) == PR_TRUE) - rv = InitWithFSRef(&fsRef); - else - { - CFURLRef parentURL = ::CFURLCreateCopyDeletingLastPathComponent(NULL, aCFURL); - if (!parentURL) - return NS_ERROR_FAILURE; - - // Get the FSRef from the parent and the FSSpec from that - FSRef parentFSRef; - FSSpec parentFSSpec; - if ((::CFURLGetFSRef(parentURL, &parentFSRef) == PR_TRUE) && - (::FSGetCatalogInfo(&parentFSRef, kFSCatInfoNone, - nsnull, nsnull, &parentFSSpec, nsnull) == noErr)) - { - // Get the leaf name of the file and turn it into a string HFS can use. - CFStringRef fileNameRef = ::CFURLCopyLastPathComponent(aCFURL); - if (fileNameRef) - { - TextEncoding theEncoding; - if (::UpgradeScriptInfoToTextEncoding(smSystemScript, - kTextLanguageDontCare, - kTextRegionDontCare, - NULL, - &theEncoding) != noErr) - theEncoding = kTextEncodingMacRoman; - - char origName[256]; - char truncBuf[32]; - if (::CFStringGetCString(fileNameRef, origName, sizeof(origName), theEncoding)) - { - MakeDirty(); - mSpec = parentFSSpec; - mAppendedPath = NS_TruncNodeName(origName, truncBuf); - rv = NS_OK; - } - ::CFRelease(fileNameRef); - } - } - ::CFRelease(parentURL); - } -#endif - - return rv; -} - - -NS_IMETHODIMP nsLocalFile::InitWithFSRef(const FSRef * aFSRef) -{ - nsresult rv = NS_ERROR_FAILURE; - -#if TARGET_CARBON - NS_ENSURE_ARG(aFSRef); - - FSSpec fsSpec; - OSErr err = ::FSGetCatalogInfo(aFSRef, kFSCatInfoNone, nsnull, - nsnull, &fsSpec, nsnull); - if (err == noErr) - rv = InitWithFSSpec(&fsSpec); - else - rv = MacErrorMapper(err); -#endif - - return rv; -} - - -NS_IMETHODIMP nsLocalFile::InitWithFSSpec(const FSSpec *fileSpec) -{ - MakeDirty(); - mSpec = *fileSpec; - mTargetSpec = *fileSpec; - mAppendedPath = ""; - return NS_OK; -} - - -NS_IMETHODIMP nsLocalFile::InitToAppWithCreatorCode(OSType aAppCreator) -{ - FSSpec appSpec; - ProcessSerialNumber psn; - -#if TARGET_CARBON - if (sRunningOSX) - { // If we're running under OS X use LaunchServices to determine the app - // corresponding to the creator code - if ( (UInt32)LSFindApplicationForInfo != (UInt32)kUnresolvedCFragSymbolAddress ) - { - FSRef theRef; - if (::LSFindApplicationForInfo(aAppCreator, NULL, NULL, &theRef, NULL) == noErr) - { - FSCatalogInfoBitmap whichInfo = kFSCatInfoNone; - - if (::FSGetCatalogInfo(&theRef, whichInfo, NULL, NULL, &appSpec, NULL) == noErr) - return InitWithFSSpec(&appSpec); - } - - // If we get here we didn't find an app - return NS_ERROR_FILE_NOT_FOUND; - } - } -#endif - - // is the app running? - nsresult rv = FindRunningAppBySignature(aAppCreator, appSpec, psn); - if (rv == NS_ERROR_FILE_NOT_FOUND) - { - // we have to look on disk - rv = FindAppOnLocalVolumes(aAppCreator, appSpec); - if (NS_FAILED(rv)) return rv; - } - else if (NS_FAILED(rv)) - return rv; - - // init with the spec here - return InitWithFSSpec(&appSpec); -} - -NS_IMETHODIMP nsLocalFile::GetCFURL(CFURLRef *_retval) -{ - nsresult rv = NS_ERROR_FAILURE; - -#if TARGET_CARBON - NS_ENSURE_ARG_POINTER(_retval); - *_retval = nsnull; - - PRBool exists; - if (NS_SUCCEEDED(Exists(&exists)) && exists) - { - FSRef fsRef; - FSSpec fsSpec = mFollowLinks ? mTargetSpec : mSpec; - if (::FSpMakeFSRef(&fsSpec, &fsRef) == noErr) - { - *_retval = ::CFURLCreateFromFSRef(NULL, &fsRef); - if (*_retval) - return NS_OK; - } - } - else - { - nsCAutoString tempPath; - if (NS_SUCCEEDED(GetNativePath(tempPath))) - { - CFStringRef pathStrRef = ::CFStringCreateWithCString(NULL, tempPath.get(), kCFStringEncodingMacRoman); - if (!pathStrRef) - return NS_ERROR_FAILURE; - *_retval = ::CFURLCreateWithFileSystemPath(NULL, pathStrRef, kCFURLHFSPathStyle, false); - ::CFRelease(pathStrRef); - if (*_retval) - return NS_OK; - } - } -#endif - - return rv; -} - -NS_IMETHODIMP nsLocalFile::GetFSRef(FSRef *_retval) -{ - nsresult rv = NS_ERROR_FAILURE; - -#if TARGET_CARBON - NS_ENSURE_ARG_POINTER(_retval); - - FSSpec fsSpec; - rv = GetFSSpec(&fsSpec); - if (NS_SUCCEEDED(rv)) - rv = MacErrorMapper(::FSpMakeFSRef(&fsSpec, _retval)); -#endif - - return rv; -} - -NS_IMETHODIMP nsLocalFile::GetFSSpec(FSSpec *fileSpec) -{ - NS_ENSURE_ARG(fileSpec); - nsresult rv = ResolveAndStat(); - if (rv == NS_ERROR_FILE_NOT_FOUND) - rv = NS_OK; - if (NS_SUCCEEDED(rv)) - *fileSpec = mFollowLinks ? mTargetSpec : mSpec; - - return NS_OK; -} - -NS_IMETHODIMP nsLocalFile::GetFileType(OSType *aFileType) -{ - NS_ENSURE_ARG(aFileType); - - FSSpec fileSpec; - (void)GetFSSpec(&fileSpec); - - FInfo info; - OSErr err = ::FSpGetFInfo(&fileSpec, &info); - if (err != noErr) - { - *aFileType = mType; - return NS_ERROR_FILE_NOT_FOUND; - } - - *aFileType = info.fdType; - - return NS_OK; -} - -NS_IMETHODIMP nsLocalFile::SetFileType(OSType aFileType) -{ - mType = aFileType; - - FSSpec fileSpec; - (void)GetFSSpec(&fileSpec); - - FInfo info; - OSErr err = ::FSpGetFInfo(&fileSpec, &info); - if (err != noErr) - return NS_ERROR_FILE_NOT_FOUND; - - info.fdType = aFileType; - err = ::FSpSetFInfo(&fileSpec, &info); - if (err != noErr) - return NS_ERROR_FILE_ACCESS_DENIED; - - return NS_OK; -} - -NS_IMETHODIMP nsLocalFile::GetFileCreator(OSType *aCreator) -{ - NS_ENSURE_ARG(aCreator); - - FSSpec fileSpec; - (void)GetFSSpec(&fileSpec); - - FInfo info; - OSErr err = ::FSpGetFInfo(&fileSpec, &info); - if (err != noErr) - { - *aCreator = mCreator; - return NS_ERROR_FILE_NOT_FOUND; - } - - *aCreator = info.fdCreator; - - return NS_OK; -} - -NS_IMETHODIMP nsLocalFile::SetFileCreator(OSType aCreator) -{ - if (aCreator == CURRENT_PROCESS_CREATOR) - aCreator = sCurrentProcessSignature; - - mCreator = aCreator; - - FSSpec fileSpec; - (void)GetFSSpec(&fileSpec); - - FInfo info; - OSErr err = ::FSpGetFInfo(&fileSpec, &info); - if (err != noErr) - return NS_ERROR_FILE_NOT_FOUND; - - info.fdCreator = aCreator; - err = ::FSpSetFInfo(&fileSpec, &info); - if (err != noErr) - return NS_ERROR_FILE_ACCESS_DENIED; - - return NS_OK; -} - -NS_IMETHODIMP nsLocalFile::SetFileTypeAndCreatorFromExtension(const char *aExtension) -{ - NS_ENSURE_ARG(aExtension); - return SetOSTypeAndCreatorFromExtension(aExtension); -} - -NS_IMETHODIMP nsLocalFile::SetFileTypeAndCreatorFromMIMEType(const char *aMIMEType) -{ - NS_ENSURE_ARG(aMIMEType); - - nsresult rv; - nsCOMPtr icService(do_GetService - (NS_INTERNETCONFIGSERVICE_CONTRACTID, &rv)); - - if (NS_SUCCEEDED(rv)) - { - nsCOMPtr mimeInfo; - PRUint32 fileType = 'TEXT'; - PRUint32 fileCreator = nsILocalFileMac::CURRENT_PROCESS_CREATOR; - - rv = icService->FillInMIMEInfo(aMIMEType, - nsnull, getter_AddRefs(mimeInfo)); - if (NS_SUCCEEDED(rv)) - rv = mimeInfo->GetMacType(&fileType); - if (NS_SUCCEEDED(rv)) - rv = mimeInfo->GetMacCreator(&fileCreator); - if (NS_SUCCEEDED(rv)) - rv = SetFileType(fileType); - if (NS_SUCCEEDED(rv)) - rv = SetFileCreator(fileCreator); - } - - return rv; -} - -NS_IMETHODIMP -nsLocalFile::GetFileSizeWithResFork(PRInt64 *aFileSize) -{ - NS_ENSURE_ARG(aFileSize); - - *aFileSize = LL_Zero(); - - ResolveAndStat(); - - long dataSize = 0; - long resSize = 0; - - OSErr err = FSpGetFileSize(&mTargetSpec, &dataSize, &resSize); - - if (err != noErr) - return MacErrorMapper(err); - - // For now we've only got 32 bits of file size info - PRInt64 dataInt64 = LL_Zero(); - PRInt64 resInt64 = LL_Zero(); - - // Combine the size of the resource and data forks - LL_I2L(resInt64, resSize); - LL_I2L(dataInt64, dataSize); - LL_ADD((*aFileSize), dataInt64, resInt64); - - return NS_OK; -} - - -// this nsLocalFile points to the app. We want to launch it, optionally with the document. -NS_IMETHODIMP -nsLocalFile::LaunchWithDoc(nsILocalFile* aDocToLoad, PRBool aLaunchInBackground) -{ - // are we launchable? - PRBool isExecutable; - nsresult rv = IsExecutable(&isExecutable); - if (NS_FAILED(rv)) return rv; - if (!isExecutable) return NS_ERROR_FILE_EXECUTION_FAILED; - - FSSpec docSpec; - FSSpecPtr docSpecPtr = nsnull; - - nsCOMPtr macDoc = do_QueryInterface(aDocToLoad); - if (macDoc) - { - rv = macDoc->GetFSSpec(&docSpec); // XXX GetTargetFSSpec - if (NS_FAILED(rv)) return rv; - - docSpecPtr = &docSpec; - } - - FSSpec appSpec; - rv = GetFSSpec(&appSpec); // XXX GetResolvedFSSpec - if (NS_FAILED(rv)) return rv; - - rv = MyLaunchAppWithDoc(appSpec, docSpecPtr, aLaunchInBackground); - return rv; -} - - -NS_IMETHODIMP -nsLocalFile::OpenDocWithApp(nsILocalFile* aAppToOpenWith, PRBool aLaunchInBackground) -{ - // if aAppToOpenWith is nil, we have to find the app from the creator code - // of the document - nsresult rv = NS_OK; - - FSSpec appSpec; - - if (aAppToOpenWith) - { - nsCOMPtr appFileMac = do_QueryInterface(aAppToOpenWith, &rv); - if (!appFileMac) return rv; - - rv = appFileMac->GetFSSpec(&appSpec); // XXX GetTargetFSSpec - if (NS_FAILED(rv)) return rv; - - // is it launchable? - PRBool isExecutable; - rv = aAppToOpenWith->IsExecutable(&isExecutable); - if (NS_FAILED(rv)) return rv; - if (!isExecutable) return NS_ERROR_FILE_EXECUTION_FAILED; - } - else - { - // look for one - OSType fileCreator; - rv = GetFileCreator(&fileCreator); - if (NS_FAILED(rv)) return rv; - - // just make one on the stack - nsLocalFile localAppFile; - rv = localAppFile.InitToAppWithCreatorCode(fileCreator); - if (NS_FAILED(rv)) return rv; - - rv = localAppFile.GetFSSpec(&appSpec); // GetTargetFSSpec - if (NS_FAILED(rv)) return rv; - } - - FSSpec docSpec; - rv = GetFSSpec(&docSpec); // XXX GetResolvedFSSpec - if (NS_FAILED(rv)) return rv; - - rv = MyLaunchAppWithDoc(appSpec, &docSpec, aLaunchInBackground); - return rv; -} - -nsresult nsLocalFile::SetOSTypeAndCreatorFromExtension(const char* extension) -{ - nsresult rv; - - nsCAutoString localExtBuf; - const char *extPtr; - - if (!extension) - { - rv = GetNativeLeafName(localExtBuf); - extPtr = strrchr(localExtBuf.get(), '.'); - if (!extPtr) - return NS_ERROR_FAILURE; - ++extPtr; - } - else - { - extPtr = extension; - if (*extPtr == '.') - ++extPtr; - } - - nsCOMPtr icService = - do_GetService(NS_INTERNETCONFIGSERVICE_CONTRACTID, &rv); - if (NS_SUCCEEDED(rv)) - { - nsCOMPtr mimeInfo; - rv = icService->GetMIMEInfoFromExtension(extPtr, getter_AddRefs(mimeInfo)); - if (NS_SUCCEEDED(rv)) - { - PRUint32 osType; - rv = mimeInfo->GetMacType(&osType); - if (NS_SUCCEEDED(rv)) - mType = osType; - PRBool skip; - rv = ExtensionIsOnExceptionList(extPtr, &skip); - if (NS_SUCCEEDED(rv) && !skip) - { - rv = mimeInfo->GetMacCreator(&osType); - if (NS_SUCCEEDED(rv)) - mCreator = osType; - } - } - } - return rv; -} - -nsresult nsLocalFile::ExtensionIsOnExceptionList(const char *extension, PRBool *onList) -{ - // Probably want to make a global list somewhere in the future - // for now, just check for "html" and "htm" - - *onList = PR_FALSE; - - if (!nsCRT::strcasecmp(extension, "html") || - !nsCRT::strcasecmp(extension, "htm")) - *onList = PR_TRUE; - return NS_OK; -} - - -void nsLocalFile::InitClassStatics() -{ - OSErr err; - - - if (sCurrentProcessSignature == 0) - { - ProcessSerialNumber psn; - ProcessInfoRec info; - - psn.highLongOfPSN = 0; - psn.lowLongOfPSN = kCurrentProcess; - - info.processInfoLength = sizeof(ProcessInfoRec); - info.processName = nil; - info.processAppSpec = nil; - err = ::GetProcessInformation(&psn, &info); - if (err == noErr) - sCurrentProcessSignature = info.processSignature; - // Try again next time if error - } - - static PRBool didHFSPlusCheck = PR_FALSE; - if (!didHFSPlusCheck) - { - long response; - err = ::Gestalt(gestaltFSAttr, &response); - sHasHFSPlusAPIs = (err == noErr && (response & (1 << gestaltHasHFSPlusAPIs)) != 0); - didHFSPlusCheck = PR_TRUE; - } - - static PRBool didOSXCheck = PR_FALSE; - if (!didOSXCheck) - { - long version; - sRunningOSX = (::Gestalt(gestaltSystemVersion, &version) == noErr && version >= 0x00001000); - didOSXCheck = PR_TRUE; - } -} - - -#pragma mark - - -// Handy dandy utility create routine for something or the other -nsresult -NS_NewNativeLocalFile(const nsACString &path, PRBool followLinks, nsILocalFile* *result) -{ - nsLocalFile* file = new nsLocalFile(); - if (file == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(file); - - file->SetFollowLinks(followLinks); - - if (!path.IsEmpty()) { - nsresult rv = file->InitWithNativePath(path); - if (NS_FAILED(rv)) { - NS_RELEASE(file); - return rv; - } - } - *result = file; - return NS_OK; -} - -nsresult -NS_NewLocalFile(const nsAString &path, PRBool followLinks, nsILocalFile* *result) -{ - nsCAutoString fsCharSetStr; - nsresult rv = NS_CopyUnicodeToNative(path, fsCharSetStr); - if (NS_FAILED(rv)) - return rv; - return NS_NewNativeLocalFile(fsCharSetStr, followLinks, result); -} - -nsresult -NS_NewLocalFileWithFSSpec(const FSSpec* inSpec, PRBool followLinks, nsILocalFileMac* *result) -{ - nsLocalFile* file = new nsLocalFile(); - if (file == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(file); - - file->SetFollowLinks(followLinks); - - nsresult rv = file->InitWithFSSpec(inSpec); - if (NS_FAILED(rv)) { - NS_RELEASE(file); - return rv; - } - *result = file; - return NS_OK; -} - -nsresult -NS_NewLocalFileWithFSRef(const FSRef* aFSRef, PRBool aFollowLinks, nsILocalFileMac** result) -{ - nsLocalFile* file = new nsLocalFile(); - if (file == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(file); - - file->SetFollowLinks(aFollowLinks); - - nsresult rv = file->InitWithFSRef(aFSRef); - if (NS_FAILED(rv)) { - NS_RELEASE(file); - return rv; - } - *result = file; - return NS_OK; -} - -void -nsLocalFile::GlobalInit() -{ -} - -void -nsLocalFile::GlobalShutdown() -{ -} diff --git a/xpcom/io/nsLocalFileMac.h b/xpcom/io/nsLocalFileMac.h deleted file mode 100644 index 42eb25569496..000000000000 --- a/xpcom/io/nsLocalFileMac.h +++ /dev/null @@ -1,137 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla Communicator client code, released - * March 31, 1998. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998-1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Steve Dagley - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef _nsLocalFileMAC_H_ -#define _nsLocalFileMAC_H_ - -#include "nscore.h" -#include "nsError.h" -#include "nsString.h" -#include "nsCRT.h" -#include "nsIFile.h" -#include "nsILocalFileMac.h" -#include "nsIFactory.h" - -#include - -class NS_COM nsLocalFile : public nsILocalFileMac -{ -public: - NS_DEFINE_STATIC_CID_ACCESSOR(NS_LOCAL_FILE_CID) - - nsLocalFile(); - - static NS_METHOD nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); - - // nsISupports interface - NS_DECL_ISUPPORTS - - // nsIFile interface - NS_DECL_NSIFILE - - // nsILocalFile interface - NS_DECL_NSILOCALFILE - - // nsILocalFileMac interface - NS_DECL_NSILOCALFILEMAC - -public: - - static void GlobalInit(); - static void GlobalShutdown(); - -private: - ~nsLocalFile() {} - -protected: - void MakeDirty(); - nsresult ResolveAndStat(); - nsresult UpdateCachedCatInfo(PRBool forceUpdate); - - nsresult FindAppOnLocalVolumes(OSType sig, FSSpec &outSpec); - - nsresult FindRunningAppBySignature(OSType sig, FSSpec& outSpec, ProcessSerialNumber& outPsn); - nsresult FindRunningAppByFSSpec(const FSSpec& appSpec, ProcessSerialNumber& outPsn); - - nsresult MyLaunchAppWithDoc(const FSSpec& appSpec, const FSSpec* aDocToLoad, PRBool aLaunchInBackground); - - nsresult TestFinderFlag(PRUint16 flagMask, PRBool *outFlagSet, PRBool testTargetSpec = PR_TRUE); - - nsresult MoveCopy( nsIFile* newParentDir, const nsACString &newName, PRBool isCopy, PRBool followLinks ); - - // Passing nsnull for the extension uses leaf name - nsresult SetOSTypeAndCreatorFromExtension(const char* extension = nsnull); - - nsresult ExtensionIsOnExceptionList(const char *extension, PRBool *onList); - -private: - nsLocalFile(const nsLocalFile& srcFile); - nsLocalFile(const FSSpec& aSpec, const nsACString& aAppendedPath); - - // Copies all members except mRefCnt, copies mCachedCatInfo only if it's valid. - nsLocalFile& operator=(const nsLocalFile& rhs); - - PRPackedBool mFollowLinks; - PRPackedBool mFollowLinksDirty; - - // The object we specify is always: mSpec + mAppendedPath. - // mSpec is a valid spec in that its parent is known to exist. - // Appending nodes with Append() will update mSpec immediately - // if the appended node exists. If not, appended nodes are stored - // in mAppendedPath. - - PRPackedBool mSpecDirty; - FSSpec mSpec; - nsCString mAppendedPath; - FSSpec mTargetSpec; // If mSpec is an alias, this is the resolved alias. - - CInfoPBRec mCachedCatInfo; // cached file info, for the GetFSSpec() spec - PRPackedBool mCatInfoDirty; // does this need to be updated? - - OSType mType, mCreator; - - static void InitClassStatics(); - - static OSType sCurrentProcessSignature; - static PRBool sHasHFSPlusAPIs; - static PRBool sRunningOSX; -}; - -#endif - diff --git a/xpcom/io/nsLocalFileOS2.cpp b/xpcom/io/nsLocalFileOS2.cpp index cf8bddbca3fa..a186cb248521 100644 --- a/xpcom/io/nsLocalFileOS2.cpp +++ b/xpcom/io/nsLocalFileOS2.cpp @@ -57,6 +57,7 @@ #include "nsReadableUtils.h" #include "nsISupportsPrimitives.h" #include "nsIMutableArray.h" +#include "nsTraceRefcntImpl.h" //----------------------------------------------------------------------------- // static helper functions @@ -1663,11 +1664,19 @@ nsLocalFile::Load(PRLibrary * *_retval) if (NS_FAILED(rv)) return rv; - if (! isFile) + if (!isFile) return NS_ERROR_FILE_IS_DIRECTORY; +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::SetActivityIsLegal(PR_FALSE); +#endif + *_retval = PR_LoadLibrary(mWorkingPath.get()); +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::SetActivityIsLegal(PR_TRUE); +#endif + if (*_retval) return NS_OK; diff --git a/xpcom/io/nsLocalFileOSX.cpp b/xpcom/io/nsLocalFileOSX.cpp index 4c87fbe67b22..9f7a22af8e73 100644 --- a/xpcom/io/nsLocalFileOSX.cpp +++ b/xpcom/io/nsLocalFileOSX.cpp @@ -57,6 +57,7 @@ #include "MoreFilesX.h" #include "FSCopyObject.h" #include "nsAutoBuffer.h" +#include "nsTraceRefcntImpl.h" // Mac Includes #include @@ -1347,8 +1348,16 @@ NS_IMETHODIMP nsLocalFile::Load(PRLibrary **_retval) if (NS_FAILED(rv)) return rv; +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::SetActivityIsLegal(PR_FALSE); +#endif + *_retval = PR_LoadLibrary(path.get()); +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::SetActivityIsLegal(PR_TRUE); +#endif + NS_TIMELINE_STOP_TIMER("PR_LoadLibrary"); NS_TIMELINE_MARK_TIMER1("PR_LoadLibrary", path.get()); diff --git a/xpcom/io/nsLocalFileUnix.cpp b/xpcom/io/nsLocalFileUnix.cpp index eeb0737912ce..17909cc1ba9f 100644 --- a/xpcom/io/nsLocalFileUnix.cpp +++ b/xpcom/io/nsLocalFileUnix.cpp @@ -83,6 +83,7 @@ #include "nsITimelineService.h" #include "nsNativeCharsetUtils.h" +#include "nsTraceRefcntImpl.h" // On some platforms file/directory name comparisons need to // be case-blind. @@ -1586,8 +1587,16 @@ nsLocalFile::Load(PRLibrary **_retval) NS_TIMELINE_START_TIMER("PR_LoadLibrary"); +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::SetActivityIsLegal(PR_FALSE); +#endif + *_retval = PR_LoadLibrary(mPath.get()); +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::SetActivityIsLegal(PR_TRUE); +#endif + NS_TIMELINE_STOP_TIMER("PR_LoadLibrary"); NS_TIMELINE_MARK_TIMER1("PR_LoadLibrary", mPath.get()); diff --git a/xpcom/io/nsLocalFileWin.cpp b/xpcom/io/nsLocalFileWin.cpp index e39a0ef41e9e..6038b6122028 100644 --- a/xpcom/io/nsLocalFileWin.cpp +++ b/xpcom/io/nsLocalFileWin.cpp @@ -79,6 +79,8 @@ #include "nsAutoLock.h" #include "SpecialSystemDirectory.h" +#include "nsTraceRefcntImpl.h" + // _mbsstr isn't declared in w32api headers but it's there in the libs #ifdef __MINGW32__ extern "C" { @@ -1820,10 +1822,20 @@ nsLocalFile::Load(PRLibrary * *_retval) return NS_ERROR_FILE_IS_DIRECTORY; NS_TIMELINE_START_TIMER("PR_LoadLibraryWithFlags"); + +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::SetActivityIsLegal(PR_FALSE); +#endif + PRLibSpec libSpec; libSpec.value.pathname_u = mResolvedPath.get(); libSpec.type = PR_LibSpec_PathnameU; *_retval = PR_LoadLibraryWithFlags(libSpec, 0); + +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::SetActivityIsLegal(PR_TRUE); +#endif + NS_TIMELINE_STOP_TIMER("PR_LoadLibraryWithFlags"); NS_TIMELINE_MARK_TIMER1("PR_LoadLibraryWithFlags", NS_ConvertUTF16toUTF8(mResolvedPath).get());