From 021c9dac7f6ae70fb0dab3a2f14bd356b755f645 Mon Sep 17 00:00:00 2001 From: "ccarlen%netscape.com" Date: Mon, 7 Jan 2002 14:35:04 +0000 Subject: [PATCH] Bug 100828 - nsLocalFileMac reworking. r=rjc@netscape.com/sr=sfraser@netscape.com git-svn-id: svn://10.0.0.236/trunk@111488 18797224-902f-48f8-a5cc-f745e15eee43 --- .../browser/powerplant/source/CBrowserApp.cp | 20 +- .../powerplant/source/CBrowserShell.cpp | 14 +- .../decoders/icon/mac/nsIconChannel.cpp | 2 +- mozilla/netwerk/mime/src/nsMIMEService.cpp | 3 +- .../streamconv/src/nsAppleFileDecoder.cpp | 6 +- .../mac/nsInternetConfigService.cpp | 2 +- .../exthandler/mac/nsOSHelperAppService.cpp | 2 +- .../exthandler/nsExternalHelperAppService.cpp | 6 +- .../components/nsNativeComponentLoader.cpp | 4 +- mozilla/xpcom/io/MANIFEST | 1 - mozilla/xpcom/io/nsLocalFileMac.cpp | 4411 ++++++++--------- mozilla/xpcom/io/nsLocalFileMac.h | 120 +- mozilla/xpcom/macbuild/XPCOMIDL.xml | 30 + mozilla/xpcom/threads/nsProcessMac.cpp | 2 +- .../appshell/src/nsInternetConfigService.cpp | 2 +- .../search/src/nsInternetSearchService.cpp | 13 +- mozilla/xpinstall/src/nsInstall.cpp | 2 +- mozilla/xpinstall/src/nsInstallFileOpItem.cpp | 115 +- .../src/nsLoggingProgressNotifier.cpp | 8 +- 19 files changed, 2246 insertions(+), 2517 deletions(-) diff --git a/mozilla/embedding/browser/powerplant/source/CBrowserApp.cp b/mozilla/embedding/browser/powerplant/source/CBrowserApp.cp index 6260d3cc4e8..f726d8c5cb0 100644 --- a/mozilla/embedding/browser/powerplant/source/CBrowserApp.cp +++ b/mozilla/embedding/browser/powerplant/source/CBrowserApp.cp @@ -76,7 +76,7 @@ #include -#define NATIVE_PROMPTS +#undef NATIVE_PROMPTS #if USE_PROFILES #include "CProfileManager.h" @@ -176,8 +176,7 @@ CBrowserApp::CBrowserApp() RegisterClass_(CWebBrowserCMAttachment); AddAttachment(new LCMAttachment); - // We need to idle threads often - SetSleepTime(0); + SetSleepTime(15); // Get the directory which contains the mozilla parts // In this case it is the app directory but it could @@ -188,7 +187,6 @@ CBrowserApp::CBrowserApp() ProcessInfoRec processInfo; FSSpec appSpec; nsCOMPtr macDir; - nsCOMPtr appDir; // If this ends up being NULL, default is used if (!::GetCurrentProcess(&psn)) { processInfo.processInfoLength = sizeof(processInfo); @@ -196,18 +194,17 @@ CBrowserApp::CBrowserApp() processInfo.processAppSpec = &appSpec; if (!::GetProcessInformation(&psn, &processInfo)) { // Turn the FSSpec of the app into an FSSpec of the app's directory - ::FSMakeFSSpec(appSpec.vRefNum, appSpec.parID, "\p", &appSpec); + OSErr err = ::FSMakeFSSpec(appSpec.vRefNum, appSpec.parID, "\p", &appSpec); // Make an nsILocalFile out of it - rv = NS_NewLocalFileWithFSSpec(&appSpec, PR_TRUE, getter_AddRefs(macDir)); - if (NS_SUCCEEDED(rv)) - appDir = do_QueryInterface(macDir); + if (err == noErr) + (void)NS_NewLocalFileWithFSSpec(&appSpec, PR_TRUE, getter_AddRefs(macDir)); } } CAppFileLocationProvider *fileLocProvider = new CAppFileLocationProvider(kProgramName); ThrowIfNil_(fileLocProvider); - rv = NS_InitEmbedding(appDir, fileLocProvider); + rv = NS_InitEmbedding(macDir, fileLocProvider); OverrideComponents(); InitializeWindowCreator(); @@ -241,7 +238,7 @@ void CBrowserApp::StartUp() { nsresult rv; - + #if USE_PROFILES // Register for profile changes @@ -441,12 +438,11 @@ CBrowserApp::ObeyCommand( rv = NS_NewLocalFileWithFSSpec(&fileSpec, PR_TRUE, getter_AddRefs(macFile)); ThrowIfError_(NS_ERROR_GET_CODE(rv)); - nsCOMPtr localFile(do_QueryInterface(macFile, &rv)); ThrowIfError_(NS_ERROR_GET_CODE(rv)); nsCOMPtr aURL(do_CreateInstance("@mozilla.org/network/standard-url;1", &rv)); ThrowIfError_(NS_ERROR_GET_CODE(rv)); - rv = aURL->SetFile(localFile); + rv = aURL->SetFile(macFile); ThrowIfError_(NS_ERROR_GET_CODE(rv)); nsXPIDLCString urlSpec; diff --git a/mozilla/embedding/browser/powerplant/source/CBrowserShell.cpp b/mozilla/embedding/browser/powerplant/source/CBrowserShell.cpp index 03815bdb9e7..a1cc039ba2e 100644 --- a/mozilla/embedding/browser/powerplant/source/CBrowserShell.cpp +++ b/mozilla/embedding/browser/powerplant/source/CBrowserShell.cpp @@ -617,7 +617,7 @@ NS_METHOD CBrowserShell::Stop() NS_METHOD CBrowserShell::Reload() { - return mWebBrowserAsWebNav->Stop(nsIWebNavigation::LOAD_FLAGS_NONE); + return mWebBrowserAsWebNav->Reload(nsIWebNavigation::LOAD_FLAGS_NONE); } //***************************************************************************** @@ -697,10 +697,8 @@ NS_METHOD CBrowserShell::SaveDocument(const FSSpec& outSpec) if (NS_FAILED(rv)) return rv; FSSpec nonConstOutSpec = outSpec; - nsCOMPtr localMacFile; - rv = NS_NewLocalFileWithFSSpec(&nonConstOutSpec, PR_FALSE, getter_AddRefs(localMacFile)); - if (NS_FAILED(rv)) return rv; - nsCOMPtr localFile(do_QueryInterface(localMacFile, &rv)); + nsCOMPtr localFile; + rv = NS_NewLocalFileWithFSSpec(&nonConstOutSpec, PR_FALSE, getter_AddRefs(localFile)); if (NS_FAILED(rv)) return rv; nsCOMPtr parentDir; rv = localFile->GetParent(getter_AddRefs(parentDir)); @@ -721,10 +719,8 @@ NS_METHOD CBrowserShell::SaveCurrentURI(const FSSpec& outSpec) if (NS_FAILED(rv)) return rv; FSSpec nonConstOutSpec = outSpec; - nsCOMPtr localMacFile; - rv = NS_NewLocalFileWithFSSpec(&nonConstOutSpec, PR_FALSE, getter_AddRefs(localMacFile)); - if (NS_FAILED(rv)) return rv; - nsCOMPtr localFile(do_QueryInterface(localMacFile, &rv)); + nsCOMPtr localFile; + rv = NS_NewLocalFileWithFSSpec(&nonConstOutSpec, PR_FALSE, getter_AddRefs(localFile)); if (NS_FAILED(rv)) return rv; rv = wbPersist->SaveURI(nsnull, nsnull, localFile); diff --git a/mozilla/modules/libpr0n/decoders/icon/mac/nsIconChannel.cpp b/mozilla/modules/libpr0n/decoders/icon/mac/nsIconChannel.cpp index 552d6670bd1..4f75b491320 100644 --- a/mozilla/modules/libpr0n/decoders/icon/mac/nsIconChannel.cpp +++ b/mozilla/modules/libpr0n/decoders/icon/mac/nsIconChannel.cpp @@ -279,7 +279,7 @@ NS_IMETHODIMP nsIconChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports if (NS_FAILED(rv)) return(rv); FSSpec spec; - if (NS_FAILED(localFileMac->GetResolvedFSSpec(&spec))) + if (NS_FAILED(localFileMac->GetFSSpec(&spec))) return(NS_ERROR_FAILURE); SInt16 label; diff --git a/mozilla/netwerk/mime/src/nsMIMEService.cpp b/mozilla/netwerk/mime/src/nsMIMEService.cpp index c8931467bc0..bc11f5c10b1 100644 --- a/mozilla/netwerk/mime/src/nsMIMEService.cpp +++ b/mozilla/netwerk/mime/src/nsMIMEService.cpp @@ -212,7 +212,8 @@ NS_IMETHODIMP nsMIMEService::GetTypeFromFile( nsIFile* aFile, char **aContentTyp if ( NS_SUCCEEDED( rv ) ) { PRUint32 type, creator; - macFile->GetFileTypeAndCreator( (OSType*)&type,(OSType*) &creator ); + macFile->GetFileType( (OSType*)&type ); + macFile->GetFileCreator( (OSType*) &creator ); if( !mXML || NS_FAILED (rv = mXML->GetFromTypeCreator( type, creator, fileExt.get(), getter_AddRefs(info) ) ) ) { if ( mNative ) diff --git a/mozilla/netwerk/streamconv/src/nsAppleFileDecoder.cpp b/mozilla/netwerk/streamconv/src/nsAppleFileDecoder.cpp index 62c552f7949..6e7067628fe 100644 --- a/mozilla/netwerk/streamconv/src/nsAppleFileDecoder.cpp +++ b/mozilla/netwerk/streamconv/src/nsAppleFileDecoder.cpp @@ -77,7 +77,11 @@ NS_IMETHODIMP nsAppleFileDecoder::Initialize(nsIOutputStream *outputStream, nsIF m_output = outputStream; nsCOMPtr macFile = do_QueryInterface(outputFile); - macFile->GetTargetFSSpec(&m_fsFileSpec); + PRBool saveFollowLinks; + macFile->GetFollowLinks(&saveFollowLinks); + macFile->SetFollowLinks(PR_TRUE); + macFile->GetFSSpec(&m_fsFileSpec); + macFile->SetFollowLinks(saveFollowLinks); m_offset = 0; m_dataForkOffset = 0; diff --git a/mozilla/uriloader/exthandler/mac/nsInternetConfigService.cpp b/mozilla/uriloader/exthandler/mac/nsInternetConfigService.cpp index 06daa9f63ed..e085d24e2da 100644 --- a/mozilla/uriloader/exthandler/mac/nsInternetConfigService.cpp +++ b/mozilla/uriloader/exthandler/mac/nsInternetConfigService.cpp @@ -313,7 +313,7 @@ nsresult nsInternetConfigService::FillMIMEInfoForICEntry(ICMapEntry& entry, nsIM nsCOMPtr file (do_CreateInstance(cid)); if (file) { - rv = file->InitFindingAppByCreatorCode(entry.postCreator); + rv = file->InitToAppWithCreatorCode(entry.postCreator); if (rv == NS_OK) { //info->SetAlwaysAskBeforeHandling(PR_FALSE); diff --git a/mozilla/uriloader/exthandler/mac/nsOSHelperAppService.cpp b/mozilla/uriloader/exthandler/mac/nsOSHelperAppService.cpp index fd20a6441e9..0fea2ab7ef6 100644 --- a/mozilla/uriloader/exthandler/mac/nsOSHelperAppService.cpp +++ b/mozilla/uriloader/exthandler/mac/nsOSHelperAppService.cpp @@ -62,7 +62,7 @@ NS_IMETHODIMP nsOSHelperAppService::LaunchAppWithTempFile(nsIMIMEInfo * aMIMEInf nsCOMPtr docToLoad = do_QueryInterface(aTempFile, &rv); if (NS_FAILED(rv)) return rv; - rv = app->LaunchAppWithDoc(docToLoad, PR_FALSE); + rv = app->LaunchWithDoc(docToLoad, PR_FALSE); } } return rv; diff --git a/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp b/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp index 2763f16f5eb..4e256d29477 100644 --- a/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/mozilla/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -857,7 +857,8 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel * aChannel) PRUint32 type, creator; mMimeInfo->GetMacType(&type); mMimeInfo->GetMacCreator(&creator); - macfile->SetFileTypeAndCreator(type, creator); + macfile->SetFileType(type); + macfile->SetFileCreator(creator); } } #else @@ -1573,7 +1574,8 @@ NS_IMETHODIMP nsExternalHelperAppService::GetTypeFromFile( nsIFile* aFile, char if ( NS_SUCCEEDED( rv ) && fileExt.IsEmpty()) { PRUint32 type, creator; - macFile->GetFileTypeAndCreator( (OSType*)&type,(OSType*) &creator ); + macFile->GetFileType( (OSType*)&type ); + macFile->GetFileCreator( (OSType*)&creator ); nsCOMPtr icService (do_GetService(NS_INTERNETCONFIGSERVICE_CONTRACTID)); if (icService) { diff --git a/mozilla/xpcom/components/nsNativeComponentLoader.cpp b/mozilla/xpcom/components/nsNativeComponentLoader.cpp index a29ecf7b58e..97be1d6956e 100644 --- a/mozilla/xpcom/components/nsNativeComponentLoader.cpp +++ b/mozilla/xpcom/components/nsNativeComponentLoader.cpp @@ -761,8 +761,8 @@ nsNativeComponentLoader::AutoRegisterComponent(PRInt32 when, nsCOMPtr localFileMac = do_QueryInterface(component); if (localFileMac) { - OSType type, creator; - rv = localFileMac->GetFileTypeAndCreator(&type, &creator); + OSType type; + rv = localFileMac->GetFileType(&type); if (NS_SUCCEEDED(rv)) { // on Mac, Mozilla shared libraries are of type 'shlb' diff --git a/mozilla/xpcom/io/MANIFEST b/mozilla/xpcom/io/MANIFEST index 6b5166feea1..5ba3afd39e7 100644 --- a/mozilla/xpcom/io/MANIFEST +++ b/mozilla/xpcom/io/MANIFEST @@ -9,7 +9,6 @@ nsSpecialSystemDirectory.h nsStorageStream.h nsLocalFile.h nsLocalFileMac.h -nsILocalFileMac.h nsDirectoryService.h nsDirectoryServiceDefs.h nsStringIO.h diff --git a/mozilla/xpcom/io/nsLocalFileMac.cpp b/mozilla/xpcom/io/nsLocalFileMac.cpp index 328a07683ed..9474b13089c 100644 --- a/mozilla/xpcom/io/nsLocalFileMac.cpp +++ b/mozilla/xpcom/io/nsLocalFileMac.cpp @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file @@ -14,13 +14,13 @@ * released March 31, 1998. * * The Initial Developer of the Original Code is Netscape Communications - * Corporation. Portions created by Netscape are + * Corporation. Portions created by Netscape are * Copyright (C) 1998-1999 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): - * Steve Dagley - * John R. McMullen + * Steve Dagley + * John R. McMullen */ @@ -82,7 +82,7 @@ extern "C" } #if TARGET_CARBON -#include // Needed for definition of kUnresolvedCFragSymbolAddress +#include // Needed for definition of kUnresolvedCFragSymbolAddress #include #endif @@ -94,256 +94,257 @@ const OSType kDefaultCreator = 'MOSS'; static inline void ClearFSSpec(FSSpec& aSpec) { - aSpec.vRefNum = 0; - aSpec.parID = 0; - aSpec.name[0] = 0; + 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; + nsresult outErr; + + switch (inErr) + { + case noErr: + outErr = NS_OK; + break; - case fnfErr: - outErr = NS_ERROR_FILE_NOT_FOUND; - 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; + 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; + 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. + 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); + 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. - + 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; + 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. + 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; + 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. + 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; + 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. + 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; + 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.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; + 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; + 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. + 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; + 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; } @@ -406,300 +407,247 @@ static void MacintoshInitializeTime(void) gJanuaryFirst1970Seconds = 2082844800 + GMTDelta(); } -static nsresult ConvertMacTimeToMilliseconds( PRInt64* aLastModifiedTime, PRUint32 timestamp ) +static nsresult ConvertMacTimeToMilliseconds( PRInt64* aLastModifiedTime, PRUint32 timestamp ) { - if ( gJanuaryFirst1970Seconds == 0) - MacintoshInitializeTime(); - timestamp -= gJanuaryFirst1970Seconds; + 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; + 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 + 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; + return NS_OK; } static void SwapSlashColon(char * s) { - while (*s) - { - if (*s == '/') - *s++ = ':'; - else if (*s == ':') - *s++ = '/'; - else - *s++; - } + while (*s) + { + if (*s == '/') + *s++ = ':'; + else if (*s == ':') + *s++ = '/'; + else + *s++; + } } - -#pragma mark - - 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); + 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); + int srcLength = strlen(src); + if (srcLength > inMax) + srcLength = inMax; + dst[0] = srcLength; + memcpy(&dst[1], src, srcLength); } -// Aaargh!!!! Gotta roll my own equivalents of PR_OpenDir, PR_ReadDir and PR_CloseDir -// I can't use the NSPR versions as they expect a unix path and I can't easily adapt -// the directory iterator function from MoreFIles as it wants to iterate things itself -// and use a callback function to operate on the iterated entries - -typedef struct -{ - short ioVRefNum; - long ioDirID; - short ioFDirIndex; - char *currentEntryName; -} MyPRDir; - -static MyPRDir * My_OpenDir(FSSpec *fileSpec) -{ - MyPRDir *dir = NULL; - OSErr err; - long theDirID; - Boolean isDirectory; - - err = ::FSpGetDirectoryID(fileSpec, &theDirID, &isDirectory); - if (err == noErr) - { - if (isDirectory) - { - /* This is a directory, store away the pertinent information. - ** We post increment. I.e. index is always the nth. item we - ** should get on the next call - */ - dir = PR_NEW(MyPRDir); - if (dir) - { - dir->ioVRefNum = fileSpec->vRefNum; - dir->ioDirID = theDirID; - dir->currentEntryName = NULL; - dir->ioFDirIndex = 1; - } - } - } - - return dir; - -} - -static char * My_ReadDir(MyPRDir *mdDir, PRIntn flags) -{ - OSErr err; - CInfoPBRec pb; - char *returnedCStr; - Str255 pascalName = "\p"; - PRBool foundEntry; - - do - { - // Release the last name read - if (mdDir->currentEntryName) - { - PR_DELETE(mdDir->currentEntryName); - mdDir->currentEntryName = NULL; - } - - // WeÕve got all the info we need, just get info about this guy. - pb.hFileInfo.ioNamePtr = pascalName; - pb.hFileInfo.ioVRefNum = mdDir->ioVRefNum; - pb.hFileInfo.ioFDirIndex = mdDir->ioFDirIndex; - pb.hFileInfo.ioDirID = mdDir->ioDirID; - err = ::PBGetCatInfoSync(&pb); - if (err != noErr) - goto ErrorExit; - - // Convert the Pascal string to a C string (actual allocation occurs in CStrFromPStr) - unsigned long len = pascalName[0]; - returnedCStr = (char *)PR_MALLOC(len + 1); - if (returnedCStr) - { - ::BlockMoveData(&pascalName[1], returnedCStr, len); - returnedCStr[len] = NULL; - } - - mdDir->currentEntryName = returnedCStr; - mdDir->ioFDirIndex++; - - // If it is not a hidden file and the flags did not specify skipping, we are done. - if ((flags & PR_SKIP_HIDDEN) && (pb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible)) - foundEntry = PR_FALSE; - else - foundEntry = PR_TRUE; - - } while (!foundEntry); - - return (mdDir->currentEntryName); - -ErrorExit: - return NULL; -} - -static void My_CloseDir(MyPRDir *mdDir) -{ - if (!mdDir) - return; // Not much we can do with a null mdDir - - // If we'd allocated an entry name then delete it - if (mdDir->currentEntryName) - PR_DELETE(mdDir->currentEntryName); - - // delete the directory info struct as well - PR_DELETE(mdDir); -} +#pragma mark - // The R**co FSSpec resolver - -// it slices, it dices, it juliannes fries and it even creates FSSpecs out of whatever you feed it +// 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 = (inSpec && (strchr(filePath, ':') == 0 || *filePath == ':')); - FSSpec tempSpec; - Str255 ppath; + 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 - { - outSpec->vRefNum = 0; - outSpec->parID = 0; - } - - // 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; - } + + 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); + 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); + // 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; + // 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; + // 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 [nsPathParser] + +class nsPathParser +{ +public: + nsPathParser(const char* 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 char* inPath) : + mAllocatedBuffer(nsnull), mNewString(nsnull) +{ + PRUint32 inPathLen = strlen(inPath); + if (inPathLen >= sizeof(mAutoBuffer)) { + mAllocatedBuffer = (char *)nsMemory::Clone(inPath, inPathLen + 1); + mBuffer = mAllocatedBuffer; + } + else { + strcpy(mAutoBuffer, inPath); + mBuffer = mAutoBuffer; + } } #pragma mark - @@ -828,16 +776,16 @@ void nsFSStringConversionMac::CleanUp() TextEncoding nsFSStringConversionMac::GetSystemEncoding() { - OSStatus err; - TextEncoding theEncoding; - - err = ::UpgradeScriptInfoToTextEncoding(smSystemScript, kTextLanguageDontCare, - kTextRegionDontCare, NULL, &theEncoding); - - if (err != noErr) - theEncoding = kTextEncodingMacRoman; - - return theEncoding; + OSStatus err; + TextEncoding theEncoding; + + err = ::UpgradeScriptInfoToTextEncoding(smSystemScript, kTextLanguageDontCare, + kTextRegionDontCare, NULL, &theEncoding); + + if (err != noErr) + theEncoding = kTextEncodingMacRoman; + + return theEncoding; } nsresult nsFSStringConversionMac::PrepareEncoder() @@ -864,115 +812,137 @@ nsresult nsFSStringConversionMac::PrepareDecoder() return rv; } +#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: + public: - NS_DECL_ISUPPORTS + NS_DECL_ISUPPORTS - nsDirEnumerator() : mDir(nsnull) - { - NS_INIT_REFCNT(); - } + nsDirEnumerator() + { + NS_INIT_REFCNT(); + } - nsresult Init(nsILocalFile* parent) - { - FSSpec fileSpec; - fileSpec.vRefNum = 0; - fileSpec.parID = 0; - - nsCOMPtr localFileMac = do_QueryInterface(parent); - if (localFileMac) { - localFileMac->GetResolvedFSSpec(&fileSpec); - } - - // See if we managed to get a FSSpec - if (!fileSpec.vRefNum && !fileSpec.parID) - { - return NS_ERROR_FAILURE; - } - - mDir = My_OpenDir(&fileSpec); - if (mDir == nsnull) // not a directory? - return NS_ERROR_FAILURE; - - mParent = parent; - return NS_OK; - } + nsresult Init(nsILocalFileMac* parent) + { + NS_ENSURE_ARG(parent); + nsresult rv; + FSSpec fileSpec; - NS_IMETHOD HasMoreElements(PRBool *result) - { - nsresult rv = NS_OK; - if (mNext == nsnull && mDir) - { - char* name = My_ReadDir(mDir, PR_SKIP_BOTH); - if (name == nsnull) - { - // end of dir entries - My_CloseDir(mDir); - mDir = nsnull; - *result = PR_FALSE; - return NS_OK; - } - - // Make a new nsILocalFile for the new element - nsCOMPtr file; - rv = NS_NewLocalFile("dummy:path", PR_TRUE, getter_AddRefs(file)); - if (NS_FAILED(rv)) - return rv; - - // Init with the FSSpec for the current dir - FSSpec tempSpec; - tempSpec.vRefNum = mDir->ioVRefNum; - tempSpec.parID = mDir->ioDirID; - tempSpec.name[0] = 0; - nsCOMPtr localFileMac = do_QueryInterface(file); - if (localFileMac) { - localFileMac->InitWithFSSpec(&tempSpec); - } - - // Now set the leaf name of the new nsILocalFile to the new element - rv = file->SetLeafName(name); - if (NS_FAILED(rv)) - return rv; - - mNext = do_QueryInterface(file); - } - *result = mNext != nsnull; - return NS_OK; - } + rv = parent->GetFSSpec(&fileSpec); + if (NS_FAILED(rv)) + return rv; - NS_IMETHOD GetNext(nsISupports **result) - { - nsresult rv = NS_OK; - PRBool hasMore; - rv = HasMoreElements(&hasMore); - 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; + } - *result = mNext; // might return nsnull - NS_IF_ADDREF(*result); - - mNext = nsnull; - 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; + } - virtual ~nsDirEnumerator() - { - if (mDir) - { - My_CloseDir(mDir); - } - } + NS_IMETHOD GetNext(nsISupports **result) + { + NS_ENSURE_ARG_POINTER(result); + *result = nsnull; - protected: - MyPRDir* mDir; - nsCOMPtr mParent; - nsCOMPtr mNext; + 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; + } + + virtual ~nsDirEnumerator() + { + } + + protected: + nsCOMPtr mNext; + + CInfoPBRec mCatInfo; + short mItemIndex; + long mDirID; + Str63 mItemName; }; NS_IMPL_ISUPPORTS1(nsDirEnumerator, nsISimpleEnumerator) @@ -984,22 +954,58 @@ PRBool nsLocalFile::sHasHFSPlusAPIs = PR_FALSE; PRBool nsLocalFile::sRunningOSX = PR_FALSE; #pragma mark [CTOR/DTOR] -nsLocalFile::nsLocalFile() -: mInitType(eNotInitialized) -, mLastResolveFlag(PR_FALSE) -, mHaveFileInfo(PR_FALSE) -, mFollowSymlinks(PR_FALSE) -, mType('TEXT') -, mCreator(kDefaultCreator) +nsLocalFile::nsLocalFile() : + mFollowLinks(PR_TRUE), + mFollowLinksDirty(PR_TRUE), + mSpecDirty(PR_TRUE), + mCatInfoDirty(PR_TRUE), + mType('TEXT'), + mCreator(kDefaultCreator) { - NS_INIT_REFCNT(); + NS_INIT_REFCNT(); - MakeDirty(); - ClearFSSpec(mSpec); - - InitClassStatics(); - if (sCurrentProcessSignature != 0) - mCreator = sCurrentProcessSignature; + ClearFSSpec(mSpec); + ClearFSSpec(mTargetSpec); + + InitClassStatics(); + if (sCurrentProcessSignature != 0) + mCreator = sCurrentProcessSignature; +} + +nsLocalFile::nsLocalFile(const nsLocalFile& srcFile) : + mFollowLinks(srcFile.mFollowLinks), + mFollowLinksDirty(srcFile.mFollowLinksDirty), + mSpecDirty(srcFile.mSpecDirty), + mSpec(srcFile.mSpec), + mAppendedPath(srcFile.mAppendedPath), + mTargetSpec(srcFile.mTargetSpec), + mCatInfoDirty(srcFile.mCatInfoDirty), + mType(srcFile.mType), + mCreator(srcFile.mCreator) +{ + NS_INIT_REFCNT(); + + if (!mCatInfoDirty) + mCachedCatInfo = srcFile.mCachedCatInfo; +} + +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) +{ + NS_INIT_REFCNT(); + + ClearFSSpec(mTargetSpec); + + InitClassStatics(); + if (sCurrentProcessSignature != 0) + mCreator = sCurrentProcessSignature; } nsLocalFile::~nsLocalFile() @@ -1013,35 +1019,31 @@ NS_IMPL_THREADSAFE_ISUPPORTS3(nsLocalFile, nsILocalFileMac, nsILocalFile, nsIFil NS_METHOD nsLocalFile::nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) { - NS_ENSURE_ARG_POINTER(aInstancePtr); - NS_ENSURE_NO_AGGREGATION(outer); + 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; + 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() { - mStatDirty = PR_TRUE; - - ClearFSSpec(mResolvedSpec); - ClearFSSpec(mTargetSpec); - - mResolvedWasAlias = false; - mResolvedWasFolder = false; - - mHaveFileInfo = PR_FALSE; + mSpecDirty = PR_TRUE; + mFollowLinksDirty = PR_TRUE; + mCatInfoDirty = PR_TRUE; + + ClearFSSpec(mTargetSpec); } @@ -1049,177 +1051,137 @@ nsLocalFile::MakeDirty() NS_IMETHODIMP nsLocalFile::GetFollowLinks(PRBool *aFollowLinks) { - *aFollowLinks = mFollowSymlinks; + NS_ENSURE_ARG_POINTER(aFollowLinks); + *aFollowLinks = mFollowLinks; return NS_OK; } + NS_IMETHODIMP nsLocalFile::SetFollowLinks(PRBool aFollowLinks) { - MakeDirty(); - mFollowSymlinks = aFollowLinks; + if (aFollowLinks != mFollowLinks) + { + mFollowLinks = aFollowLinks; + mFollowLinksDirty = PR_TRUE; + } return NS_OK; } NS_IMETHODIMP -nsLocalFile::ResolveAndStat(PRBool resolveTerminal) +nsLocalFile::ResolveAndStat() { - OSErr err = noErr; - char *filePath; - - if (!mStatDirty && resolveTerminal == mLastResolveFlag) - { - return NS_OK; - } - - mLastResolveFlag = resolveTerminal; - - // See if we have been initialized with a spec - switch (mInitType) - { - case eInitWithPath: - { - filePath = (char *)nsMemory::Clone(mWorkingPath.get(), mWorkingPath.Length()+1); - err = ResolvePathAndSpec(filePath, nsnull, PR_FALSE, &mResolvedSpec); - nsMemory::Free(filePath); - break; - } - - case eInitWithFSSpec: - { - if (!mAppendedPath.IsEmpty()) - { // We've got an FSSpec and an appended path so pass 'em both to ResolvePathAndSpec - filePath = (char *)nsMemory::Clone(mAppendedPath.get(), mAppendedPath.Length()+1); - err = ResolvePathAndSpec(filePath, &mSpec, PR_FALSE, &mResolvedSpec); - nsMemory::Free(filePath); - } - else - { - err = ::FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, mSpec.name, &mResolvedSpec); - } - break; - } - - default: - // !!!!! Danger Will Robinson !!!!! - // we really shouldn't get here - NS_NOTREACHED("Unknown nsLocalFileMac init type"); - break; - } - - if (resolveTerminal && err == noErr) - { - // Resolve the alias to the original file. - FSSpec spec = mResolvedSpec; - err = ::ResolveAliasFile(&spec, TRUE, &mResolvedWasFolder, &mResolvedWasAlias); - if (err == noErr || err == fnfErr) {// fnfErr means target spec is valid but doesn't exist - mTargetSpec = spec; - err = noErr; - } - } - - - if (err == noErr) - { - mStatDirty = PR_FALSE; - } - - return (MacErrorMapper(err)); + 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) + { + 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) { - NS_ENSURE_ARG(file); - *file = nsnull; - - // Create the new nsLocalFile - nsCOMPtr localFile = new nsLocalFile(); - if (localFile == NULL) - return NS_ERROR_OUT_OF_MEMORY; - - // See if it's a nsLocalFileMac (shouldn't be possible for it not to be) - nsCOMPtr localFileMac = do_QueryInterface(localFile); - if (localFileMac == NULL) - return NS_ERROR_NO_INTERFACE; - - nsresult rv = NS_OK; - - // Now we figure out how we were initialized in order to determine how to - // initialize the clone - nsLocalFileMacInitType initializedAs; - localFileMac->GetInitType(&initializedAs); - switch (mInitType) - { - case eInitWithPath: - // The simple case - char *path; - GetPath(&path); - rv = localFile->InitWithPath(path); - nsMemory::Free(path); - break; - - case eInitWithFSSpec: - // Slightly more complex as we need to set the FSSpec and any appended - // path info - // `? Should we just set this to the resolved spec ????? - localFileMac->InitWithFSSpec(&mSpec); - // Now set any appended path info - char *appendedPath; - GetAppendedPath(&appendedPath); - rv = localFileMac->SetAppendedPath(appendedPath); - nsMemory::Free(appendedPath); - break; - - default: - NS_NOTREACHED("we really shouldn't get here"); - break; - } - - if (NS_FAILED(rv)) - return rv; - - *file = localFile; - NS_ADDREF(*file); - - return NS_OK; + NS_ENSURE_ARG(file); + *file = nsnull; + + // Just copy-construct ourselves + nsCOMPtr localFile = new nsLocalFile(*this); + if (localFile == NULL) + return NS_ERROR_OUT_OF_MEMORY; + + *file = localFile; + NS_ADDREF(*file); + + return NS_OK; } NS_IMETHODIMP nsLocalFile::InitWithPath(const char *filePath) { - // The incoming path must be a FULL path + // The incoming path must be a FULL path - MakeDirty(); - NS_ENSURE_ARG(filePath); - - // If it starts with a colon, it's invalid - if (*filePath == ':') - return NS_ERROR_FILE_UNRECOGNIZED_PATH; - - if (strchr(filePath, ':')) - { - // Just save the specified file path since we can't actually do anything - // about turniung it into an FSSpec until the Create() method is called - mWorkingPath.Assign(filePath); - - mInitType = eInitWithPath; - } - else - { - // If there is no colon, it may be a volume (since we strip trailing colons) - Str255 volName; - FSSpec volSpec; + NS_ENSURE_ARG(filePath); + MakeDirty(); + + // If it starts with a colon, it's invalid + if (*filePath == ':') + 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; - myPLstrcpy(volName, filePath); - volName[++volName[0]] = ':'; - if (::FSMakeFSSpec(0, 0, volName, &volSpec) == noErr) - return InitWithFSSpec(&volSpec); - else - return NS_ERROR_FILE_UNRECOGNIZED_PATH; - } - - return NS_OK; + // 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 @@ -1228,66 +1190,49 @@ 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); - - FSSpec spec; - OSErr err = noErr; - - nsresult rv = ResolveAndStat(PR_TRUE); - if ((rv == NS_ERROR_FILE_NOT_FOUND) && (flags & PR_CREATE_FILE)) - spec = mResolvedSpec; - else - spec = mTargetSpec; - - // Resolve the alias to the original file. - Boolean targetIsFolder; - Boolean wasAliased; - err = ::ResolveAliasFile(&spec, TRUE, &targetIsFolder, &wasAliased); - - // If we're going to create a file it's ok if it doesn't exist - if (err == fnfErr && (flags & PR_CREATE_FILE)) - err = noErr; - - if (err != noErr) - return MacErrorMapper(err); - - if (flags & PR_CREATE_FILE) - { - SetOSTypeAndCreatorFromExtension(); - err = ::FSpCreate(&spec, mCreator, mType, 0); + 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; } - - /* If opening with the PR_EXCL flag the existence of the file prior to opening is an error */ - if ((flags & PR_EXCL) && (err == dupFNErr)) - return MacErrorMapper(err); + + 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; - if (err == dupFNErr) - err = noErr; - if (err != noErr) - return MacErrorMapper(err); - - 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); - 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 (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; + if ((*_retval = PR_ImportFile(refnum)) == 0) + return NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES,(PR_GetError() & 0xFFFF)); + + return NS_OK; } NS_IMETHODIMP @@ -1298,1057 +1243,911 @@ nsLocalFile::OpenANSIFileDesc(const char *mode, FILE * *_retval) nsresult rv; FSSpec spec; - - if (mode[0] == 'w' || mode[0] == 'a') // Check if the file exists + + 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 { - PRBool exists; - rv = Exists(&exists); - if (NS_FAILED(rv)) - return rv; - if (!exists) { + 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; - spec = mResolvedSpec; } - else - spec = mTargetSpec; } - else - { - rv = ResolveAndStat(PR_TRUE); - if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) - return rv; - spec = mTargetSpec; - } - -#ifdef XP_MACOSX -// BADPINK - FSp_fopen() doesn't exist under macosx :-( - *_retval = nsnull; + + 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); + *_retval = FSp_fopen(&spec, mode); #endif - if (*_retval) - return NS_OK; + if (*_retval) + return NS_OK; - return NS_ERROR_FAILURE; + return NS_ERROR_FAILURE; } NS_IMETHODIMP nsLocalFile::Create(PRUint32 type, PRUint32 attributes) { - OSErr err; - char *filePath; + OSErr err; - if (type != NORMAL_FILE_TYPE && type != DIRECTORY_TYPE) - return NS_ERROR_FILE_UNKNOWN_TYPE; + if (type != NORMAL_FILE_TYPE && type != DIRECTORY_TYPE) + return NS_ERROR_FILE_UNKNOWN_TYPE; - switch (mInitType) - { - case eInitWithPath: - { - filePath = (char *)nsMemory::Clone(mWorkingPath.get(), mWorkingPath.Length()+1); - err = ResolvePathAndSpec(filePath, nsnull, PR_TRUE, &mResolvedSpec); - nsMemory::Free(filePath); - break; - } - - case eInitWithFSSpec: - { - if (!mAppendedPath.IsEmpty()) - { // We've got an FSSpec and an appended path so pass 'em both to ResolvePathAndSpec - filePath = (char *)nsMemory::Clone(mAppendedPath.get(), mAppendedPath.Length()+1); - err = ResolvePathAndSpec(filePath, &mSpec, PR_TRUE, &mResolvedSpec); - nsMemory::Free(filePath); - } - else - { - err = ::FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, mSpec.name, &mResolvedSpec); - } - break; - } - - default: - // !!!!! Danger Will Robinson !!!!! - // we really shouldn't get here - NS_NOTREACHED("Unknown nsLocalFileMac init type"); - return NS_ERROR_UNEXPECTED; - break; - } - - if (err != noErr && err != fnfErr) - return (MacErrorMapper(err)); + FSSpec newSpec; - switch (type) - { - case NORMAL_FILE_TYPE: - SetOSTypeAndCreatorFromExtension(); - err = ::FSpCreate(&mResolvedSpec, mCreator, mType, smCurrentScript); - break; - - case DIRECTORY_TYPE: - { - long newDirID; - err = ::FSpDirCreate(&mResolvedSpec, 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) - mTargetSpec = mResolvedSpec; + 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); + } - return (MacErrorMapper(err)); + 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::Append(const char *node) { - if (!node || (strchr(node, ':') != nsnull)) - return NS_ERROR_FILE_UNRECOGNIZED_PATH; + NS_ENSURE_ARG(node); + if (strchr(node, ':')) + return NS_ERROR_FILE_UNRECOGNIZED_PATH; + + MakeDirty(); + if (!mAppendedPath.Length()) + { + OSErr err; + Boolean resolvedWasFolder, resolvedWasAlias; + err = ::ResolveAliasFile(&mSpec, TRUE, &resolvedWasFolder, &resolvedWasAlias); + if (err == noErr) + { + long dirID; + Boolean isDir; - return AppendRelativePath(node); + if (!resolvedWasFolder) + return NS_ERROR_FILE_NOT_DIRECTORY; + if ((err = ::FSpGetDirectoryID(&mSpec, &dirID, &isDir)) != noErr) + return MacErrorMapper(err); + + Str255 pascalNode; + myPLstrcpy(pascalNode, node); + err = ::FSMakeFSSpec(mSpec.vRefNum, dirID, pascalNode, &mSpec); + if (err && err != fnfErr) + return MacErrorMapper(err); + } + 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::AppendRelativePath(const char *node) +nsLocalFile::AppendRelativePath(const char *relPath) { - if ( (node == nsnull) ) - return NS_ERROR_FILE_UNRECOGNIZED_PATH; - - MakeDirty(); - - // Yee Hah! We only get a single node at a time so just append it - // to either the mWorkingPath or mAppendedPath, after adding the ':' - // directory delimiter, depending on how we were initialized - switch (mInitType) - { - case eInitWithPath: - if ( (mWorkingPath.Last())!=':' ) - mWorkingPath.Append(":"); - mWorkingPath.Append(node); - break; - - case eInitWithFSSpec: - mAppendedPath.Append(":"); - mAppendedPath.Append(node); - break; - - default: - // !!!!! Danger Will Robinson !!!!! - // we really shouldn't get here - NS_NOTREACHED("Unknown nsLocalFileMac init type"); - break; - } - - return NS_OK; + NS_ENSURE_ARG(relPath); + + nsresult rv; + nsPathParser parser(relPath); + const char* node = parser.First(); + + while (node) + { + if (NS_FAILED(rv = Append(node))) + return rv; + node = parser.Next(); + } + + return NS_OK; } NS_IMETHODIMP nsLocalFile::GetLeafName(char * *aLeafName) { - NS_ENSURE_ARG_POINTER(aLeafName); - - switch (mInitType) - { - case eInitWithPath: + NS_ENSURE_ARG_POINTER(aLeafName); + + // See if we've had a path appended + if (mAppendedPath.Length()) { - const char* temp = mWorkingPath.get(); - if (temp == nsnull) - return NS_ERROR_FILE_UNRECOGNIZED_PATH; + 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++; + const char* leaf = strrchr(temp, ':'); + + // if the working path is just a node without any directory delimeters. + if (leaf == nsnull) + leaf = temp; + else + leaf++; - *aLeafName = (char*) nsMemory::Clone(leaf, strlen(leaf)+1); - break; - } - - case eInitWithFSSpec: + *aLeafName = (char*) nsMemory::Clone(leaf, strlen(leaf)+1); + } + else { - // 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 = (char*) nsMemory::Clone(leaf, strlen(leaf)+1); - } - 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 *)nsMemory::Alloc(len + 1); - if (!leafName) return NS_ERROR_OUT_OF_MEMORY; - ::BlockMoveData(&mSpec.name[1], leafName, len); - leafName[len] = '\0'; - *aLeafName = leafName; - } - break; - } - - default: - // !!!!! Danger Will Robinson !!!!! - // we really shouldn't get here - NS_NOTREACHED("Unknown nsLocalFileMac init type"); - break; - } - - return NS_OK; + // 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 *)nsMemory::Alloc(len + 1); + if (!leafName) return NS_ERROR_OUT_OF_MEMORY; + ::BlockMoveData(&mSpec.name[1], leafName, len); + leafName[len] = '\0'; + *aLeafName = leafName; + } + + return NS_OK; } NS_IMETHODIMP nsLocalFile::SetLeafName(const char * aLeafName) { - NS_ENSURE_ARG_POINTER(aLeafName); + NS_ENSURE_ARG(aLeafName); - MakeDirty(); - - switch (mInitType) - { - case eInitWithPath: - { - PRInt32 offset = mWorkingPath.RFindChar(':'); - if (offset) - { - mWorkingPath.Truncate(offset + 1); - } - mWorkingPath.Append(aLeafName); - break; - } - - case eInitWithFSSpec: + MakeDirty(); + + 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(aLeafName); + } + else { - // See if we've had a path appended - 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(aLeafName); - } - else - { - // We don't have an appended path so directly modify the FSSpec - myPLstrcpy(mSpec.name, aLeafName); - } - break; - } - - default: - // !!!!! Danger Will Robinson !!!!! - // we really shouldn't get here - break; - } - - return NS_OK; + // We don't have an appended path so directly modify the FSSpec + myPLstrcpy(mSpec.name, aLeafName); + } + + return NS_OK; } NS_IMETHODIMP nsLocalFile::GetPath(char **_retval) { - NS_ENSURE_ARG_POINTER(_retval); - - switch (mInitType) - { - case eInitWithPath: - *_retval = (char*) nsMemory::Clone(mWorkingPath.get(), mWorkingPath.Length()+1); - if (!*_retval) - return NS_ERROR_OUT_OF_MEMORY; - break; - - case eInitWithFSSpec: - { - ResolveAndStat(PR_TRUE); - + NS_ENSURE_ARG_POINTER(_retval); + + nsCAutoString fsCharSetPathStr; + #if TARGET_CARBON - if (sHasHFSPlusAPIs) // should always be true under Carbon, but in case... - { - OSErr err; - nsresult rv; - nsAutoString ucPathString; - nsCAutoString fsCharSetPathStr; - - FSRef nodeRef; - FSCatalogInfo catalogInfo; - catalogInfo.parentDirID = 0; - err = ::FSpMakeFSRef(&mResolvedSpec, &nodeRef); - - if (err == fnfErr) { - FSSpec parentDirSpec; - err = GetParentFolderSpec(mResolvedSpec, parentDirSpec); - if (err == noErr) { - const char *startPtr = (const char*)&mResolvedSpec.name[1]; - nsFSStringConversionMac::FSToUCS(Substring(startPtr, startPtr + PRUint32(mResolvedSpec.name[0])), ucPathString); - err = ::FSpMakeFSRef(&parentDirSpec, &nodeRef); - } - } + if (sHasHFSPlusAPIs) // should always be true under Carbon, but in case... + { + OSErr err; + nsresult rv; + nsAutoString ucPathString; + + FSRef nodeRef; + FSCatalogInfo catalogInfo; + catalogInfo.parentDirID = 0; + err = ::FSpMakeFSRef(&mSpec, &nodeRef); + + if (err == fnfErr) { + FSSpec parentDirSpec; + err = GetParentFolderSpec(mSpec, parentDirSpec); + if (err == noErr) { + const char *startPtr = (const char*)&mSpec.name[1]; + nsFSStringConversionMac::FSToUCS(Substring(startPtr, startPtr + PRUint32(mSpec.name[0])), ucPathString); + 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; - ucPathString.Insert(Substring(nodeNameUni, nodeNameUni + nodeName.length), 0); - nodeRef = parentRef; - } - } - rv = MacErrorMapper(err); - if (NS_FAILED(rv)) - return rv; - rv = nsFSStringConversionMac::UCSToFS(ucPathString, fsCharSetPathStr); - if (NS_FAILED(rv)) - return rv; - // When nsIFile params are all nsAString&, we won't have to do this - *_retval = ToNewCString(fsCharSetPathStr); - if (!*_retval) - return NS_ERROR_OUT_OF_MEMORY; - } - else + 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; + ucPathString.Insert(Substring(nodeNameUni, nodeNameUni + nodeName.length), 0); + nodeRef = parentRef; + } + } + + rv = MacErrorMapper(err); + if (NS_FAILED(rv)) + return rv; + rv = nsFSStringConversionMac::UCSToFS(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(&mResolvedSpec, &fullPathLen, &fullPathHandle); - if (!fullPathHandle) - return NS_ERROR_OUT_OF_MEMORY; - - char* fullPath = (char *)nsMemory::Alloc(fullPathLen + 1); - if (!fullPath) - return NS_ERROR_OUT_OF_MEMORY; - - ::HLock(fullPathHandle); - nsCRT::memcpy(fullPath, *fullPathHandle, fullPathLen); - fullPath[fullPathLen] = '\0'; - - *_retval = fullPath; - ::DisposeHandle(fullPathHandle); - } - break; - } - - default: - // !!!!! Danger Will Robinson !!!!! - // we really shouldn't get here - NS_NOTREACHED("Unknown nsLocalFileMac init type"); - break; - } - - // For cross platform reasons we need to make sure that even if we have a path to a - // directory we don't return the trailing colon. This used to break the component - // manager (Bugzilla bug #26102) - PRUint32 lastChar = strlen(*_retval) - 1; - if ((*_retval)[lastChar] == ':') - (*_retval)[lastChar] = '\0'; + { + // 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 = ToNewCString(fsCharSetPathStr); + if (!*_retval) + return NS_ERROR_OUT_OF_MEMORY; + #ifdef XP_MACOSX - // Watch out for a really big hack, coming soon to this space! - char* slashified = (char*) nsMemory::Alloc(sizeof("/Volumes/") + strlen(*_retval)); - if (slashified) { - strcpy(slashified, "/Volumes/"); - strcat(slashified, *_retval); - nsMemory::Free(*_retval); - *_retval = slashified; - char *colon = strchr(slashified, ':'); - while (colon != NULL) { - *colon = '/'; - colon = strchr(colon + 1, ':'); - } - } + // Watch out for a really big hack, coming soon to this space! + char* slashified = (char*) nsMemory::Alloc(sizeof("/Volumes/") + strlen(*_retval)); + if (slashified) { + strcpy(slashified, "/Volumes/"); + strcat(slashified, *_retval); + nsMemory::Free(*_retval); + *_retval = slashified; + char *colon = strchr(slashified, ':'); + while (colon != NULL) { + *colon = '/'; + colon = strchr(colon + 1, ':'); + } + } #endif - return NS_OK; + return NS_OK; } nsresult nsLocalFile::MoveCopy( nsIFile* newParentDir, const char* newName, PRBool isCopy, PRBool followLinks ) { - nsresult rv = ResolveAndStat( PR_TRUE ); - if ( NS_FAILED( rv ) ) - return rv; + 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 ) + { + NS_ENSURE_ARG( newName ); + myPLstrncpy( newPascalName, newName, 255 ); + macErr = ::FSpRename( &srcSpec, newPascalName ); + return MacErrorMapper( macErr ); + } - OSErr macErr; - FSSpec srcSpec; - Str255 newPascalName; - - if (followLinks) - srcSpec = mTargetSpec; - else - srcSpec = mResolvedSpec; - - // If newParentDir == nsnull, it's a simple rename - if ( !newParentDir ) - { - NS_ENSURE_ARG( newName ); - myPLstrncpy( newPascalName, newName, 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; - PRBool isDirectory; - rv = newParentDir->IsDirectory( &isDirectory ); - if ( NS_FAILED( rv ) || !isDirectory ) - return NS_ERROR_FILE_DESTINATION_NOT_DIR; - - nsCOMPtr destDir( do_QueryInterface( newParentDir )); - FSSpec destSpec; - - if (followLinks) - rv = destDir->GetTargetFSSpec( &destSpec ); - else - rv = destDir->GetResolvedFSSpec( &destSpec ); // If resolved spec is an alias file, we'll rightly fail - if ( NS_FAILED( rv ) ) - return rv; - - if ( newName ) - myPLstrncpy( newPascalName, newName, 255); - else - memcpy(newPascalName, srcSpec.name, srcSpec.name[0] + 1); - if ( isCopy ) - { - if ( mResolvedWasFolder ) - macErr = MacFSpDirectoryCopyRename( &srcSpec, &destSpec, newPascalName, NULL, 0, true, NULL ); - else - macErr = ::FSpFileCopy( &srcSpec, &destSpec, newPascalName, NULL, 0, true ); - } - else - { - macErr= ::FSpMoveRenameCompat(&srcSpec, &destSpec, newPascalName); - if ( macErr == diffVolErr) - { - // On a different Volume so go for Copy and then delete - rv = CopyTo( newParentDir, newName ); - if ( NS_FAILED ( rv ) ) - return rv; - return Remove( PR_TRUE ); - } - } - return MacErrorMapper( macErr ); + if ( newName ) + myPLstrncpy( newPascalName, newName, 255); + else + memcpy(newPascalName, srcSpec.name, srcSpec.name[0] + 1); + if ( isCopy ) + { + macErr = ::FSpGetDirectoryID(&srcSpec, &dirID, &isDirectory); + if (macErr == noErr) + { + if ( isDirectory ) + macErr = MacFSpDirectoryCopyRename( &srcSpec, &destSpec, newPascalName, NULL, 0, true, NULL ); + else + macErr = ::FSpFileCopy( &srcSpec, &destSpec, newPascalName, NULL, 0, true ); + } + } + else + { + macErr= ::FSpMoveRenameCompat(&srcSpec, &destSpec, newPascalName); + if ( macErr == diffVolErr) + { + // On a different Volume so go for Copy and then delete + rv = CopyTo( newParentDir, newName ); + if ( NS_FAILED ( rv ) ) + return rv; + return Remove( PR_TRUE ); + } + } + return MacErrorMapper( macErr ); } NS_IMETHODIMP nsLocalFile::CopyTo(nsIFile *newParentDir, const char *newName) { - return MoveCopy( newParentDir, newName, PR_TRUE, PR_FALSE ); + return MoveCopy( newParentDir, newName, PR_TRUE, PR_FALSE ); } NS_IMETHODIMP nsLocalFile::CopyToFollowingLinks(nsIFile *newParentDir, const char *newName) { - return MoveCopy( newParentDir, newName, PR_TRUE, PR_TRUE ); + return MoveCopy( newParentDir, newName, PR_TRUE, PR_TRUE ); } NS_IMETHODIMP nsLocalFile::MoveTo(nsIFile *newParentDir, const char *newName) { - return MoveCopy( newParentDir, newName, PR_FALSE, PR_FALSE ); + return MoveCopy( newParentDir, newName, PR_FALSE, PR_FALSE ); } NS_IMETHODIMP nsLocalFile::Load(PRLibrary * *_retval) { - PRBool isFile; - nsresult rv = IsFile(&isFile); + PRBool isFile; + nsresult rv = IsFile(&isFile); - if (NS_FAILED(rv)) - return rv; - - if (! isFile) - return NS_ERROR_FILE_IS_DIRECTORY; + 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(); + // 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); - + // 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; + if (*_retval) + return NS_OK; - return NS_ERROR_NULL_POINTER; + return NS_ERROR_NULL_POINTER; } NS_IMETHODIMP nsLocalFile::Remove(PRBool recursive) { - MakeDirty(); - - PRBool isDir; - nsresult rv = IsDirectory(&isDir); - if (NS_FAILED(rv)) - return rv; - - const char *filePath = mResolvedPath.get(); - OSErr macerror; - if (isDir && recursive) - macerror = ::DeleteDirectory( mResolvedSpec.vRefNum, mResolvedSpec.parID, mResolvedSpec.name ); - else - macerror = ::HDelete( mResolvedSpec.vRefNum, mResolvedSpec.parID, mResolvedSpec.name ); - - return MacErrorMapper( macerror ); + 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); - nsresult rv = ResolveAndStat( PR_TRUE ); - if ( NS_FAILED( rv ) ) - return rv; - - CInfoPBRec pb; - PRUint32 timestamp; - if (GetTargetSpecCatInfo(pb) == noErr) - timestamp = ((DirInfo*)&pb)->ioDrMdDat; // The mod date is in the same spot for files and dirs. - else - timestamp = 0; - - return ConvertMacTimeToMilliseconds( aLastModifiedTime, timestamp ); + 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) { - MakeDirty(); - nsresult rv = ResolveAndStat( PR_TRUE ); - if ( NS_FAILED(rv) ) - return rv; - - CInfoPBRec pb; - PRUint32 macTime = 0; - OSErr err = noErr; - PRBool bIsDir = PR_FALSE; - - ConvertMillisecondsToMacTime(aLastModifiedTime, &macTime); - rv = IsDirectory(&bIsDir); - if ( NS_FAILED(rv) ) - return rv; - - err = GetTargetSpecCatInfo(pb); - if (err == noErr) - { - if (bIsDir) - { - pb.dirInfo.ioDrMdDat = macTime; - pb.dirInfo.ioDrParID = mTargetSpec.parID; - } - else - { - pb.hFileInfo.ioFlMdDat = macTime; - pb.hFileInfo.ioDirID = mTargetSpec.parID; - } - - err = ::PBSetCatInfoSync(&pb); - if (err != noErr) - return MacErrorMapper(err); - } - - return MacErrorMapper(err); + 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); - - *aLastModifiedTime = LL_Zero(); - - NS_ASSERTION(0, "Not implemented"); - return NS_ERROR_NOT_IMPLEMENTED; + 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) { - MakeDirty(); - - NS_ASSERTION(0, "Not implemented"); - return NS_ERROR_NOT_IMPLEMENTED; + 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); - - *aFileSize = LL_Zero(); - - ResolveAndStat(PR_TRUE); - - long dataSize = 0; - long resSize = 0; - - OSErr err = FSpGetFileSize(&mTargetSpec, &dataSize, &resSize); - - if (err != noErr && !mResolvedWasFolder) - return MacErrorMapper(err); - - // 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); - - return NS_OK; + 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) { - PRBool exists; - - Exists(&exists); - if (exists) - { - 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; + 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); - } - else - { - return NS_ERROR_FILE_NOT_FOUND; - } - - return NS_OK; + 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); - - *aFileSize = LL_Zero(); + NS_ENSURE_ARG(aFileSize); - ResolveAndStat(PR_TRUE); - - long dataSize = 0; - long resSize = 0; - - OSErr err = FSpGetFileSize(&mResolvedSpec, &dataSize, &resSize); - - if (err != noErr && !mResolvedWasFolder) - return MacErrorMapper(err); - - // 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); - - return NS_OK; + StFollowLinksState followState(this, PR_FALSE); + return GetFileSize(aFileSize); } NS_IMETHODIMP nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable) { - NS_ENSURE_ARG(aDiskSpaceAvailable); - - PRInt64 space64Bits; + NS_ENSURE_ARG(aDiskSpaceAvailable); + + PRInt64 space64Bits; - LL_I2L(space64Bits , LONG_MAX); + 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 = mResolvedSpec.vRefNum; - - // we should check if this call is available - OSErr err = ::PBXGetVolInfoSync(&pb); - - if (err == noErr) - { - const UnsignedWide& freeBytes = UInt64ToUnsignedWide(pb.ioVFreeBytes); + 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; + space64Bits.lo = freeBytes.lo; + space64Bits.hi = freeBytes.hi; #endif - } - - *aDiskSpaceAvailable = space64Bits; + } + + *aDiskSpaceAvailable = space64Bits; - return NS_OK; + return NS_OK; } NS_IMETHODIMP nsLocalFile::GetParent(nsIFile * *aParent) { - NS_ENSURE_ARG_POINTER(aParent); - nsresult rv = NS_OK; - - switch (mInitType) - { - case eInitWithPath: - { // The simple case when we have a full path to something - nsCString parentPath = mWorkingPath; + NS_ENSURE_ARG_POINTER(aParent); + *aParent = nsnull; + + nsresult rv = NS_OK; + PRInt32 offset; - PRInt32 offset = parentPath.RFindChar(':'); - if (offset == -1) - return NS_ERROR_FILE_UNRECOGNIZED_PATH; + 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; - parentPath.Truncate(offset); + CInfoPBRec pBlock = {0}; + FSSpec parentFolderSpec; + parentFolderSpec.name[0] = 0; - nsCOMPtr localFile; - rv = NS_NewLocalFile(parentPath.get(), mFollowSymlinks, getter_AddRefs(localFile)); - if (NS_SUCCEEDED(rv) && localFile) - { - rv = localFile->QueryInterface(NS_GET_IID(nsIFile), (void**)aParent); - } - break; - } - - case eInitWithFSSpec: - { - // Now set any appended path info - char* appendedPath; - GetAppendedPath(&appendedPath); - - if (appendedPath == nsnull || appendedPath[0] == '\0'|| (appendedPath[0] == ':' && appendedPath[1] == '\0' )) - { - rv = ResolveAndStat(PR_TRUE); + 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 - //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; + 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); - FSSpec parentFolderSpec; - CInfoPBRec pBlock = {0}; - - parentFolderSpec.name[0] = 0; - - pBlock.dirInfo.ioVRefNum = mResolvedSpec.vRefNum; - pBlock.dirInfo.ioDrDirID = mResolvedSpec.parID; - pBlock.dirInfo.ioNamePtr = (StringPtr)parentFolderSpec.name; - pBlock.dirInfo.ioFDirIndex = -1; //get info on parID - OSErr err = PBGetCatInfoSync(&pBlock); - if (err != noErr) - { - rv = MacErrorMapper(err); - goto bail; - } - parentFolderSpec.vRefNum = mResolvedSpec.vRefNum; - parentFolderSpec.parID = pBlock.dirInfo.ioDrParID; - - nsCOMPtr file; - rv = NS_NewLocalFile("dummy:path", mFollowSymlinks, getter_AddRefs(file)); - if (NS_FAILED(rv)) - goto bail; - - // Init with the FSSpec for the current dir - nsCOMPtr localFileMac = do_QueryInterface(file, &rv); - if (localFileMac) - { - localFileMac->InitWithFSSpec(&parentFolderSpec); - rv = localFileMac->QueryInterface(NS_GET_IID(nsIFile), (void**)aParent); - } - } - else - { - int len = strlen(appendedPath); - if (appendedPath[len] == ':') - appendedPath[len] = '\0'; - - char * doomedChar = strrchr(appendedPath, ':'); - doomedChar[0] = '\0'; - - // Create the new nsLocalFile - nsCOMPtr localFile = new nsLocalFile(); - if (localFile == NULL) - { - rv = NS_ERROR_OUT_OF_MEMORY; - goto bail; - } - - // See if it's a nsLocalFileMac (shouldn't be possible for it not to be) - nsCOMPtr localFileMac = do_QueryInterface(localFile); - if (localFileMac == NULL) - { - rv = NS_ERROR_NO_INTERFACE; - goto bail; - } - localFileMac->InitWithFSSpec(&mSpec); - localFileMac->SetAppendedPath(appendedPath); - localFileMac->QueryInterface(NS_GET_IID(nsIFile), (void**)aParent); - } - bail: - nsMemory::Free(appendedPath); - break; - } - - default: - // !!!!! Danger Will Robinson !!!!! - // we really shouldn't get here - NS_NOTREACHED("Unknown nsLocalFileMac init type"); - rv = NS_ERROR_FAILURE; - break; - } - - return rv; + return rv; } NS_IMETHODIMP nsLocalFile::Exists(PRBool *_retval) { - NS_ENSURE_ARG(_retval); - *_retval = PR_FALSE; // Assume failure - MakeDirty(); - nsresult rv = ResolveAndStat(PR_TRUE); - if ( rv == NS_ERROR_FILE_NOT_FOUND ) - return NS_OK; - - if (NS_SUCCEEDED(rv)) { - // Only use mTargetSpec if mResolvedWasAlias is TRUE - FSSpec spec = mResolvedWasAlias ? mTargetSpec : mResolvedSpec; - FSSpec temp; - if (::FSMakeFSSpec(spec.vRefNum, spec.parID, spec.name, &temp) == noErr) - *_retval = PR_TRUE; + 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; + + return NS_OK; } NS_IMETHODIMP nsLocalFile::IsWritable(PRBool *outIsWritable) { - NS_ENSURE_ARG(outIsWritable); - *outIsWritable = PR_TRUE; + NS_ENSURE_ARG(outIsWritable); + *outIsWritable = PR_TRUE; - nsresult rv = ResolveAndStat(PR_TRUE); - if (NS_FAILED(rv)) return rv; - - CInfoPBRec fileInfo; - OSErr err = GetTargetSpecCatInfo(fileInfo); - if (err != noErr) - return MacErrorMapper(err); - - // bit 0 in ioFlAttrib is the lock bit (apparently) - *outIsWritable = !(fileInfo.hFileInfo.ioFlAttrib & 0x01); - return NS_OK; + 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); + NS_ENSURE_ARG(_retval); - // is it ever not readable on Mac? - *_retval = PR_TRUE; - return NS_OK; + // 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 + NS_ENSURE_ARG(outIsExecutable); + *outIsExecutable = PR_FALSE; // Assume failure - nsresult rv = ResolveAndStat(PR_TRUE); - if (NS_FAILED(rv)) return rv; + 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 + // 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, fileCreator; - rv = GetFileTypeAndCreator(&fileType, &fileCreator); - if (NS_FAILED(rv)) return rv; - - *outIsExecutable = (fileType == 'APPL' || fileType == 'appe' || fileType == 'FNDR'); - } - - return NS_OK; + { + 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; + NS_ENSURE_ARG(outIsDir); + *outIsDir = PR_FALSE; - nsresult rv = ResolveAndStat(PR_TRUE); - if (NS_FAILED(rv)) return rv; - - CInfoPBRec fileInfo; - OSErr err = GetTargetSpecCatInfo(fileInfo); - if (err != noErr) - return MacErrorMapper(err); - - *outIsDir = (fileInfo.hFileInfo.ioFlAttrib & ioDirMask) != 0; - return NS_OK; + 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; + NS_ENSURE_ARG(outIsFile); + *outIsFile = PR_FALSE; - nsresult rv = ResolveAndStat(PR_TRUE); - - if (NS_FAILED(rv)) - return rv; - - CInfoPBRec fileInfo; - OSErr err = GetTargetSpecCatInfo(fileInfo); - if (err != noErr) - return MacErrorMapper(err); + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) return rv; + + rv = UpdateCachedCatInfo(PR_FALSE); + if (NS_FAILED(rv)) return rv; - *outIsFile = (fileInfo.hFileInfo.ioFlAttrib & ioDirMask) == 0; - return NS_OK; + *outIsFile = (mCachedCatInfo.hFileInfo.ioFlAttrib & ioDirMask) == 0; + return NS_OK; } NS_IMETHODIMP nsLocalFile::IsHidden(PRBool *_retval) { - NS_ENSURE_ARG(_retval); - *_retval = PR_FALSE; + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; - nsresult rv = ResolveAndStat(PR_TRUE); - if (NS_FAILED(rv)) return rv; - - return TestFinderFlag(kIsInvisible, _retval); + 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; + return NS_OK; } NS_IMETHODIMP nsLocalFile::IsSymlink(PRBool *_retval) { - NS_ENSURE_ARG(_retval); - *_retval = PR_FALSE; + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; - nsresult rv = ResolveAndStat(PR_TRUE); - if (NS_FAILED(rv)) return rv; - - return TestFinderFlag(kIsAlias, _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; + NS_ENSURE_ARG(inFile); + NS_ENSURE_ARG(_retval); + *_retval = PR_FALSE; - char* inFilePath; - inFile->GetPath(&inFilePath); - - char* filePath; - GetPath(&filePath); - - if (strcmp(inFilePath, filePath) == 0) - *_retval = PR_TRUE; - - nsMemory::Free(inFilePath); - nsMemory::Free(filePath); - - return NS_OK; + // 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 + { + nsXPIDLCString filePath; + GetPath(getter_Copies(filePath)); + + nsXPIDLCString inFilePath; + inFile->GetPath(getter_Copies(inFilePath)); + + if (nsCRT::strcasecmp(inFilePath, filePath) == 0) + *_retval = PR_TRUE; + } + return NS_OK; } NS_IMETHODIMP @@ -2358,98 +2157,98 @@ nsLocalFile::Contains(nsIFile *inFile, PRBool recur, PRBool *outContains) of folder aliases. Doing a 'Contains' test and dealing with folder aliases is Hard. Think about it. */ - *outContains = PR_FALSE; + *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 + 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 + nsCOMPtr macFile(do_QueryInterface(inFile)); + if (!macFile) return NS_OK; // trying to compare non-local with local file - FSSpec mySpec = mResolvedSpec; - FSSpec compareSpec; + FSSpec mySpec = mSpec; + FSSpec compareSpec; - rv = macFile->GetResolvedFSSpec(&compareSpec); - if (NS_FAILED(rv)) return rv; + // 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 (mResolvedSpec.vRefNum != compareSpec.vRefNum) - return NS_OK; + // 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 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; + if (IsEqualFSSpec(parentFolderSpec, mySpec)) + { + *outContains = PR_TRUE; + break; + } + + compareSpec = parentFolderSpec; + } while (recur); + + return NS_OK; } NS_IMETHODIMP nsLocalFile::GetTarget(char **_retval) -{ - NS_ENSURE_ARG(_retval); - *_retval = nsnull; - - PRBool symLink; - - nsresult rv = IsSymlink(&symLink); - if (NS_FAILED(rv)) - return rv; +{ + NS_ENSURE_ARG(_retval); + *_retval = nsnull; + + PRBool symLink; + + nsresult rv = IsSymlink(&symLink); + if (NS_FAILED(rv)) + return rv; - if (!symLink) - { - return NS_ERROR_FILE_INVALID_PATH; - } - - *_retval = (char*) nsMemory::Clone( mResolvedPath.get(), mResolvedPath.Length()+1 ); - return NS_OK; + if (!symLink) + return NS_ERROR_FILE_INVALID_PATH; + + StFollowLinksState followState(this, PR_TRUE); + return GetPath(_retval); } NS_IMETHODIMP nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator * *entries) { - nsresult rv; - - *entries = nsnull; + nsresult rv; + + *entries = nsnull; - PRBool isDir; - rv = IsDirectory(&isDir); - if (NS_FAILED(rv)) - return rv; - if (!isDir) - return NS_ERROR_FILE_NOT_DIRECTORY; + 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; + 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::GetURL(char * *aURL) @@ -2550,7 +2349,7 @@ nsLocalFile::GetPersistentDescriptor(char * *aPersistentDescriptor) NS_ENSURE_ARG_POINTER(aPersistentDescriptor); *aPersistentDescriptor = nsnull; - nsresult rv = ResolveAndStat( PR_TRUE ); + nsresult rv = ResolveAndStat(); if ( NS_FAILED( rv ) ) return rv; @@ -2607,28 +2406,28 @@ nsLocalFile::SetPersistentDescriptor(const char * aPersistentDescriptor) class StAEDesc: public AEDesc { public: - StAEDesc() - { - descriptorType = typeNull; - dataHandle = nil; - } - - ~StAEDesc() - { - ::AEDisposeDesc(this); - } + StAEDesc() + { + descriptorType = typeNull; + dataHandle = nil; + } + + ~StAEDesc() + { + ::AEDisposeDesc(this); + } - void Clear() - { - ::AEDisposeDesc(this); - descriptorType = typeNull; - dataHandle = nil; - } - + 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 + // disallow copies and assigns + StAEDesc(const StAEDesc& rhs); // copy constructor + StAEDesc& operator= (const StAEDesc&rhs); // throws OSErrs }; @@ -2636,303 +2435,275 @@ private: #pragma mark [Utility methods] -OSErr nsLocalFile::GetTargetSpecCatInfo(CInfoPBRec& outInfo) +nsresult nsLocalFile::UpdateCachedCatInfo(PRBool forceUpdate) { - OSErr err = noErr; - - if (!mHaveFileInfo) - { - mTargetFileInfoRec.hFileInfo.ioCompletion = nsnull; - mTargetFileInfoRec.hFileInfo.ioFDirIndex = 0; // use dirID and name - mTargetFileInfoRec.hFileInfo.ioVRefNum = mTargetSpec.vRefNum; - mTargetFileInfoRec.hFileInfo.ioDirID = mTargetSpec.parID; - mTargetFileInfoRec.hFileInfo.ioNamePtr = mTargetSpec.name; + 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; - err = PBGetCatInfoSync(&mTargetFileInfoRec); - mHaveFileInfo = (err == noErr); - } - - outInfo = mTargetFileInfoRec; - return err; -} - - -nsresult nsLocalFile::TestFinderFlag(PRUint16 flagMask, PRBool *outFlagSet, PRBool testTargetSpec /* = PR_TRUE */) -{ - CInfoPBRec fileInfo; - - // we assume here that ResolveAndStat has already been called - - *outFlagSet = PR_FALSE; - OSErr err = noErr; - - if (testTargetSpec) - { - err = GetTargetSpecCatInfo(fileInfo); - } - else - { - // we don't cache this CInfoPBRec, so do it manually - - fileInfo.hFileInfo.ioCompletion = nsnull; - fileInfo.hFileInfo.ioFDirIndex = 0; // use dirID and name - fileInfo.hFileInfo.ioVRefNum = mResolvedSpec.vRefNum; - fileInfo.hFileInfo.ioDirID = mResolvedSpec.parID; - fileInfo.hFileInfo.ioNamePtr = mResolvedSpec.name; - - err = PBGetCatInfoSync(&fileInfo); - } - - if (err != noErr) - return MacErrorMapper(err); - - *outFlagSet = (fileInfo.hFileInfo.ioFlFndrInfo.fdFlags & flagMask) != 0; - return NS_OK; + 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; + 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 + 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; + 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 + 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; + 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; - } + 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; + return NS_OK; } -#define aeSelectionKeyword 'fsel' -#define kAEOpenSelection 'sope' +#define aeSelectionKeyword 'fsel' +#define kAEOpenSelection 'sope' #define kAERevealSelection 'srev' -#define kFinderType 'FNDR' +#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; + 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(PR_TRUE); + ResolveAndStat(); #if TARGET_CARBON - if (sRunningOSX) - { // We're running under Mac OS X, LaunchServices here we come + 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 + // 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 + { // 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); + /* 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); - } - } - } - } - } - } + 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; + } + + return NS_OK; } NS_IMETHODIMP nsLocalFile::Reveal() { - AppleEvent aeEvent = {0, nil}; - AppleEvent aeReply = {0, nil}; - StAEDesc aeDirDesc, listElem, myAddressDesc, fileList; - OSErr errorResult = noErr; - ProcessSerialNumber process; + FSSpec specToReveal; + AppleEvent aeEvent = {0, nil}; + AppleEvent aeReply = {0, nil}; + StAEDesc aeDirDesc, listElem, myAddressDesc, fileList; + OSErr errorResult = noErr; + ProcessSerialNumber process; FSSpec appSpec; - ResolveAndStat(PR_TRUE); + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) + return rv; + rv = GetFSSpec(&specToReveal); // Pay attention to followLinks + if (NS_FAILED(rv)) + return rv; - // for reveal, we'll use mResolvedSpec (which is a resolved spec and possibly an alias) - nsresult rv = FindRunningAppBySignature ('MACS', appSpec, process); + rv = FindRunningAppBySignature ('MACS', appSpec, process); if (NS_SUCCEEDED(rv)) - { + { errorResult = AECreateDesc(typeProcessSerialNumber, (Ptr)&process, sizeof(process), &myAddressDesc); if (errorResult == noErr) { - /* Create the FinderEvent */ + /* 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 + // 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); + 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, &mResolvedSpec, sizeof(FSSpec)); - - 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 + // 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); + errorResult = AEPutParamDesc(&aeEvent,keySelection, &fileList); - if (errorResult == noErr) - { - errorResult = AESend(&aeEvent, &aeReply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, nil, nil); - if (errorResult == noErr) - SetFrontProcess(&process); - } - } - } - } - } + if (errorResult == noErr) + { + errorResult = AESend(&aeEvent, &aeReply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, nil, nil); + if (errorResult == noErr) + SetFrontProcess(&process); + } + } + } + } + } } return NS_OK; @@ -2940,142 +2711,142 @@ NS_IMETHODIMP nsLocalFile::Reveal() 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; - + 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 + 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; + { // 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; + 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); + 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; + 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); + 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)); + 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); - } + 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; + return NS_OK; } @@ -3085,38 +2856,38 @@ nsresult nsLocalFile::MyLaunchAppWithDoc(const FSSpec& appSpec, const FSSpec* aD NS_IMETHODIMP nsLocalFile::Normalize() { - return NS_ERROR_NOT_IMPLEMENTED; + return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsLocalFile::GetPermissions(PRUint32 *aPermissions) { - return NS_ERROR_NOT_IMPLEMENTED; + return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsLocalFile::GetPermissionsOfLink(PRUint32 *aPermissionsOfLink) { - return NS_ERROR_NOT_IMPLEMENTED; + return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsLocalFile::SetPermissions(PRUint32 aPermissions) { - return NS_ERROR_NOT_IMPLEMENTED; + return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsLocalFile::SetPermissionsOfLink(PRUint32 aPermissions) { - return NS_ERROR_NOT_IMPLEMENTED; + return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP nsLocalFile::IsSpecial(PRBool *_retval) { - return NS_ERROR_NOT_IMPLEMENTED; + return NS_ERROR_NOT_IMPLEMENTED; } #pragma mark - @@ -3124,29 +2895,20 @@ nsLocalFile::IsSpecial(PRBool *_retval) // Implementation of Mac specific finctions from nsILocalFileMac -NS_IMETHODIMP nsLocalFile::GetInitType(nsLocalFileMacInitType *type) -{ - NS_ENSURE_ARG(type); - *type = mInitType; - return NS_OK; -} - NS_IMETHODIMP nsLocalFile::InitWithFSSpec(const FSSpec *fileSpec) { - MakeDirty(); - mSpec = *fileSpec; - mResolvedSpec = *fileSpec; - mTargetSpec = *fileSpec; - mAppendedPath = ""; - mInitType = eInitWithFSSpec; - return NS_OK; + MakeDirty(); + mSpec = *fileSpec; + mTargetSpec = *fileSpec; + mAppendedPath = ""; + return NS_OK; } -NS_IMETHODIMP nsLocalFile::InitFindingAppByCreatorCode(OSType aAppCreator) +NS_IMETHODIMP nsLocalFile::InitToAppWithCreatorCode(OSType aAppCreator) { - FSSpec appSpec; - ProcessSerialNumber psn; - + FSSpec appSpec; + ProcessSerialNumber psn; + #if TARGET_CARBON if (sRunningOSX) { // If we're running under OS X use LaunchServices to determine the app @@ -3168,119 +2930,120 @@ NS_IMETHODIMP nsLocalFile::InitFindingAppByCreatorCode(OSType aAppCreator) } #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; + // 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); + // init with the spec here + return InitWithFSSpec(&appSpec); } NS_IMETHODIMP nsLocalFile::GetFSSpec(FSSpec *fileSpec) { - NS_ENSURE_ARG(fileSpec); - *fileSpec = mSpec; - return NS_OK; - + 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::GetResolvedFSSpec(FSSpec *fileSpec) +NS_IMETHODIMP nsLocalFile::GetFileType(OSType *aFileType) { - NS_ENSURE_ARG(fileSpec); - nsresult rv = ResolveAndStat(PR_TRUE); - if (rv == NS_ERROR_FILE_NOT_FOUND) - rv = NS_OK; - if (NS_SUCCEEDED(rv)) - *fileSpec = mResolvedSpec; - return rv; + 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::GetTargetFSSpec(FSSpec *fileSpec) +NS_IMETHODIMP nsLocalFile::SetFileType(OSType aFileType) { - NS_ENSURE_ARG(fileSpec); - nsresult rv = ResolveAndStat(PR_TRUE); - if (rv == NS_ERROR_FILE_NOT_FOUND) - rv = NS_OK; - if (NS_SUCCEEDED(rv)) - *fileSpec = mTargetSpec; - return rv; + 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::SetAppendedPath(const char *aPath) +NS_IMETHODIMP nsLocalFile::GetFileCreator(OSType *aCreator) { - MakeDirty(); - - mAppendedPath.Assign(aPath); - - return NS_OK; + 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::GetAppendedPath(char **_retval) +NS_IMETHODIMP nsLocalFile::SetFileCreator(OSType aCreator) { - NS_ENSURE_ARG_POINTER(_retval); - *_retval = (char*) nsMemory::Clone(mAppendedPath.get(), mAppendedPath.Length()+1); - return NS_OK; + 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::GetFileTypeAndCreator(OSType *type, OSType *creator) +NS_IMETHODIMP nsLocalFile::SetFileTypeAndCreatorFromExtension(const char *aExtension) { - NS_ENSURE_ARG(type); - NS_ENSURE_ARG(creator); - - ResolveAndStat(PR_TRUE); - - FInfo info; - OSErr err = ::FSpGetFInfo(&mTargetSpec, &info); - if (err != noErr) - { - *type = mType; - *creator = mCreator; - return NS_ERROR_FILE_NOT_FOUND; - } - - *type = info.fdType; - *creator = info.fdCreator; - - return NS_OK; -} - -NS_IMETHODIMP nsLocalFile::SetFileTypeAndCreator(OSType type, OSType creator) -{ - mType = type; - mCreator = creator; - - FInfo info; - OSErr err = ::FSpGetFInfo(&mTargetSpec, &info); - if (err != noErr) - return NS_ERROR_FILE_NOT_FOUND; - - if (creator == CURRENT_PROCESS_CREATOR) - creator = (sCurrentProcessSignature != 0) ? sCurrentProcessSignature : kDefaultCreator; - - // See if the user specified a type or creator before changing from what was read - if (type) - info.fdType = type; - if (creator) - info.fdCreator = creator; - - err = ::FSpSetFInfo(&mTargetSpec, &info); - if (err != noErr) - return NS_ERROR_FILE_ACCESS_DENIED; - - return NS_OK; -} - -NS_IMETHODIMP nsLocalFile::SetFileTypeFromSuffix(const char *suffix) -{ - NS_ENSURE_ARG(suffix); - return SetOSTypeAndCreatorFromExtension(suffix); + NS_ENSURE_ARG(aExtension); + return SetOSTypeAndCreatorFromExtension(aExtension); } NS_IMETHODIMP nsLocalFile::SetFileTypeAndCreatorFromMIMEType(const char *aMIMEType) @@ -3304,7 +3067,9 @@ NS_IMETHODIMP nsLocalFile::SetFileTypeAndCreatorFromMIMEType(const char *aMIMETy if (NS_SUCCEEDED(rv)) rv = mimeInfo->GetMacCreator(&fileCreator); if (NS_SUCCEEDED(rv)) - rv = SetFileTypeAndCreator(fileType, fileCreator); + rv = SetFileType(fileType); + if (NS_SUCCEEDED(rv)) + rv = SetFileCreator(fileCreator); } return rv; @@ -3313,109 +3078,109 @@ NS_IMETHODIMP nsLocalFile::SetFileTypeAndCreatorFromMIMEType(const char *aMIMETy NS_IMETHODIMP nsLocalFile::GetFileSizeWithResFork(PRInt64 *aFileSize) { - NS_ENSURE_ARG(aFileSize); - - *aFileSize = LL_Zero(); + NS_ENSURE_ARG(aFileSize); + + *aFileSize = LL_Zero(); - ResolveAndStat(PR_TRUE); - - 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; + 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::LaunchAppWithDoc(nsILocalFile* aDocToLoad, PRBool aLaunchInBackground) +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->GetTargetFSSpec(&docSpec); - if (NS_FAILED(rv)) return rv; - - docSpecPtr = &docSpec; - } - - FSSpec appSpec; - rv = GetResolvedFSSpec(&appSpec); - if (NS_FAILED(rv)) return rv; - - rv = MyLaunchAppWithDoc(appSpec, docSpecPtr, aLaunchInBackground); - return rv; + // 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->GetTargetFSSpec(&appSpec); - if (NS_FAILED(rv)) return rv; + // 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 fileType, fileCreator; - rv = GetFileTypeAndCreator(&fileType, &fileCreator); - if (NS_FAILED(rv)) return rv; - - // just make one on the stack - nsLocalFile localAppFile; - rv = localAppFile.InitFindingAppByCreatorCode(fileCreator); - if (NS_FAILED(rv)) return rv; - - rv = localAppFile.GetTargetFSSpec(&appSpec); - if (NS_FAILED(rv)) return rv; - } - - FSSpec docSpec; - rv = GetResolvedFSSpec(&docSpec); - 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; + rv = MyLaunchAppWithDoc(appSpec, &docSpec, aLaunchInBackground); + return rv; } nsresult nsLocalFile::SetOSTypeAndCreatorFromExtension(const char* extension) @@ -3487,18 +3252,18 @@ void nsLocalFile::InitClassStatics() if (sCurrentProcessSignature == 0) { ProcessSerialNumber psn; - ProcessInfoRec info; - - psn.highLongOfPSN = 0; - psn.lowLongOfPSN = kCurrentProcess; + 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 + 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; @@ -3526,39 +3291,39 @@ void nsLocalFile::InitClassStatics() nsresult NS_NewLocalFile(const char* path, PRBool followLinks, nsILocalFile* *result) { - nsLocalFile* file = new nsLocalFile(); - if (file == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(file); + nsLocalFile* file = new nsLocalFile(); + if (file == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(file); file->SetFollowLinks(followLinks); if (path) { - nsresult rv = file->InitWithPath(path); - if (NS_FAILED(rv)) { - NS_RELEASE(file); - return rv; - } - } - *result = file; - return NS_OK; + nsresult rv = file->InitWithPath(path); + if (NS_FAILED(rv)) { + NS_RELEASE(file); + return rv; + } + } + *result = file; + return NS_OK; } nsresult NS_NewLocalFileWithFSSpec(FSSpec* inSpec, PRBool followLinks, nsILocalFileMac* *result) { - nsLocalFile* file = new nsLocalFile(); - if (file == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(file); + 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 rv = file->InitWithFSSpec(inSpec); + if (NS_FAILED(rv)) { + NS_RELEASE(file); + return rv; + } + *result = file; + return NS_OK; } diff --git a/mozilla/xpcom/io/nsLocalFileMac.h b/mozilla/xpcom/io/nsLocalFileMac.h index 5dc2f81d0c5..1116ac92929 100644 --- a/mozilla/xpcom/io/nsLocalFileMac.h +++ b/mozilla/xpcom/io/nsLocalFileMac.h @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file @@ -35,9 +35,9 @@ #include "nsIFactory.h" #include "nsLocalFile.h" -#include +#include -class NS_COM nsLocalFile : public nsILocalFile, public nsILocalFileMac +class NS_COM nsLocalFile : public nsILocalFileMac { public: NS_DEFINE_STATIC_CID_ACCESSOR(NS_LOCAL_FILE_CID) @@ -49,103 +49,69 @@ public: // nsISupports interface NS_DECL_ISUPPORTS - + // nsIFile interface NS_DECL_NSIFILE - + // nsILocalFile interface NS_DECL_NSILOCALFILE - NS_IMETHOD GetInitType(nsLocalFileMacInitType *type); + // nsILocalFileMac interface + NS_DECL_NSILOCALFILEMAC - NS_IMETHOD InitWithFSSpec(const FSSpec *fileSpec); - NS_IMETHOD InitFindingAppByCreatorCode(OSType aAppCreator); - - NS_IMETHOD GetFSSpec(FSSpec *fileSpec); - NS_IMETHOD GetResolvedFSSpec(FSSpec *fileSpec); - NS_IMETHOD GetTargetFSSpec(FSSpec *fileSpec); - - NS_IMETHOD SetAppendedPath(const char *aPath); - NS_IMETHOD GetAppendedPath(char * *aPath); - - NS_IMETHOD GetFileTypeAndCreator(OSType *type, OSType *creator); - NS_IMETHOD SetFileTypeAndCreator(OSType type, OSType creator); - - NS_IMETHOD SetFileTypeFromSuffix(const char *suffix); - NS_IMETHOD SetFileTypeAndCreatorFromMIMEType(const char *aMIMEType); - - NS_IMETHOD GetFileSizeWithResFork(PRInt64 *aFileSize); - - NS_IMETHOD LaunchAppWithDoc(nsILocalFile* aDocToLoad, PRBool aLaunchInBackground); - NS_IMETHOD OpenDocWithApp(nsILocalFile* aAppToOpenWith, PRBool aLaunchInBackground); static nsresult ParseURL(const char* inURL, char **outHost, char **outDirectory, char **outFileBaseName, char **outFileExtension); - protected: - void MakeDirty(); - nsresult ResolveAndStat(PRBool resolveTerminal); + 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 FindAppOnLocalVolumes(OSType sig, FSSpec &outSpec); - nsresult MyLaunchAppWithDoc(const FSSpec& appSpec, const FSSpec* aDocToLoad, PRBool aLaunchInBackground); - - nsresult TestFinderFlag(PRUint16 flagMask, PRBool *outFlagSet, PRBool testTargetSpec = PR_TRUE); + 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 char* 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); - OSErr GetTargetSpecCatInfo(CInfoPBRec& outInfo); - nsresult MoveCopy( nsIFile* newParentDir, const char* 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); - // It's important we keep track of how we were initialized - nsLocalFileMacInitType mInitType; - - // this is the flag which indicates if I can used cached information about the file - PRPackedBool mStatDirty; - PRPackedBool mLastResolveFlag; - - PRPackedBool mFollowSymlinks; + PRPackedBool mFollowLinks; + PRPackedBool mFollowLinksDirty; - // Is the mResolvedSpec member valid? Only after we resolve the mSpec or mWorkingPath - // PRPackedBool mHaveValidSpec; + // 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. - // If we're inited with a path then we store it here - nsCString mWorkingPath; - - // Any nodes added with AppendPath if we were initialized with an FSSpec are stored here - nsCString mAppendedPath; + PRPackedBool mSpecDirty; + FSSpec mSpec; + nsCString mAppendedPath; + FSSpec mTargetSpec; // If mSpec is an alias, this is the resolved alias. - // this will be the resolved path which will *NEVER* be returned to the user - nsCString mResolvedPath; - - // The Mac data structure for a file system object - FSSpec mSpec; // This is the raw spec from InitWithPath or InitWithFSSpec - FSSpec mResolvedSpec; // This is the spec that we get from the initial spec + path. It might be an alias - FSSpec mTargetSpec; // This is the spec we've called ResolveAlias on - - Boolean mResolvedWasAlias; // mResolvedSpec was for an alias - Boolean mResolvedWasFolder; // mResolvedSpec was for a directory - - - PRPackedBool mHaveFileInfo; // have we got the file info? - CInfoPBRec mTargetFileInfoRec; // cached file info, for the mTargetSpec - - OSType mType, mCreator; + 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; + static PRBool sHasHFSPlusAPIs; + static PRBool sRunningOSX; }; #endif diff --git a/mozilla/xpcom/macbuild/XPCOMIDL.xml b/mozilla/xpcom/macbuild/XPCOMIDL.xml index fb294d37af8..04ad786ac76 100644 --- a/mozilla/xpcom/macbuild/XPCOMIDL.xml +++ b/mozilla/xpcom/macbuild/XPCOMIDL.xml @@ -1018,6 +1018,13 @@ Text + + Name + nsILocalFileMac.idl + MacOS + Text + + Name nsIDirectoryService.idl @@ -1435,6 +1442,11 @@ nsILocalFile.idl MacOS + + Name + nsILocalFileMac.idl + MacOS + Name nsIDirectoryService.idl @@ -2577,6 +2589,13 @@ Text + + Name + nsILocalFileMac.idl + MacOS + Text + + Name nsIDirectoryService.idl @@ -2994,6 +3013,11 @@ nsILocalFile.idl MacOS + + Name + nsILocalFileMac.idl + MacOS + Name nsIDirectoryService.idl @@ -3347,6 +3371,12 @@ nsILocalFile.idl MacOS + + headers + Name + nsILocalFileMac.idl + MacOS + headers Name diff --git a/mozilla/xpcom/threads/nsProcessMac.cpp b/mozilla/xpcom/threads/nsProcessMac.cpp index 35aacfe012a..abc9eb4e1c4 100644 --- a/mozilla/xpcom/threads/nsProcessMac.cpp +++ b/mozilla/xpcom/threads/nsProcessMac.cpp @@ -90,7 +90,7 @@ nsProcess::Run(PRBool blocking, const char **args, PRUint32 count, PRUint32 *pid ProcessInfoRec info; nsCOMPtr macExecutable = do_QueryInterface(mExecutable); - macExecutable->GetResolvedFSSpec(&resolvedSpec); + macExecutable->GetFSSpec(&resolvedSpec); launchPB.launchAppSpec = &resolvedSpec; launchPB.launchAppParameters = NULL; diff --git a/mozilla/xpfe/appshell/src/nsInternetConfigService.cpp b/mozilla/xpfe/appshell/src/nsInternetConfigService.cpp index 06daa9f63ed..e085d24e2da 100644 --- a/mozilla/xpfe/appshell/src/nsInternetConfigService.cpp +++ b/mozilla/xpfe/appshell/src/nsInternetConfigService.cpp @@ -313,7 +313,7 @@ nsresult nsInternetConfigService::FillMIMEInfoForICEntry(ICMapEntry& entry, nsIM nsCOMPtr file (do_CreateInstance(cid)); if (file) { - rv = file->InitFindingAppByCreatorCode(entry.postCreator); + rv = file->InitToAppWithCreatorCode(entry.postCreator); if (rv == NS_OK) { //info->SetAlwaysAskBeforeHandling(PR_FALSE); diff --git a/mozilla/xpfe/components/search/src/nsInternetSearchService.cpp b/mozilla/xpfe/components/search/src/nsInternetSearchService.cpp index d025e380e84..8477f5a9f25 100755 --- a/mozilla/xpfe/components/search/src/nsInternetSearchService.cpp +++ b/mozilla/xpfe/components/search/src/nsInternetSearchService.cpp @@ -2354,8 +2354,10 @@ InternetSearchDataSource::saveContents(nsIChannel* channel, nsIInternetSearchCon #ifdef XP_MAC // set appropriate Mac file type/creator for search engine files nsCOMPtr macFile(do_QueryInterface(outFile)); - if (macFile) - macFile->SetFileTypeAndCreator('issp', 'fndf'); + if (macFile) { + macFile->SetFileType('issp'); + macFile->SetFileCreator('fndf'); + } #endif // check suggested category hint @@ -3946,8 +3948,11 @@ InternetSearchDataSource::GetSearchEngineList(nsIFile *searchDir, PRBool checkMa if (!macFile) continue; OSType type, creator; - rv = macFile->GetFileTypeAndCreator(&type, &creator); - if (NS_FAILED(rv) || type != 'issp' || creator != 'fndf') + rv = macFile->GetFileType(&type); + if (NS_FAILED(rv) || type != 'issp') + continue; + rv = macFile->GetFileCreator(&creator); // Do we really care about creator? + if (NS_FAILED(rv) || creator != 'fndf') continue; } #endif diff --git a/mozilla/xpinstall/src/nsInstall.cpp b/mozilla/xpinstall/src/nsInstall.cpp index 38b3a50e59c..22c3503010d 100644 --- a/mozilla/xpinstall/src/nsInstall.cpp +++ b/mozilla/xpinstall/src/nsInstall.cpp @@ -2694,7 +2694,7 @@ nsInstall::ExtractFileFromJar(const nsString& aJarfile, nsIFile* aSuggestedName, nsCOMPtr tempExtractHereSpec; tempExtractHereSpec = do_QueryInterface(extractHereSpec, &rv); - tempExtractHereSpec->GetResolvedFSSpec(&extractedSpec); + tempExtractHereSpec->GetFSSpec(&extractedSpec); if ( nsAppleSingleDecoder::IsAppleSingleFile(&extractedSpec) ) { diff --git a/mozilla/xpinstall/src/nsInstallFileOpItem.cpp b/mozilla/xpinstall/src/nsInstallFileOpItem.cpp index 50b89c1d633..88490f1066d 100644 --- a/mozilla/xpinstall/src/nsInstallFileOpItem.cpp +++ b/mozilla/xpinstall/src/nsInstallFileOpItem.cpp @@ -1369,49 +1369,26 @@ nsInstallFileOpItem::NativeFileOpMacAliasPrepare() nsCOMPtr targetFile = do_QueryInterface(mTarget); nsCOMPtr sourceFile = do_QueryInterface(mSrc); - FSSpec fsSource, fsAlias, fsAliasParent, fsCheckSource; nsresult rv; - OSErr err; - long aliasDirID; - Boolean isDir; - char *aliasLeaf; + PRBool exists; - rv = sourceFile->GetResolvedFSSpec(&fsSource); - if (NS_FAILED(rv)) return rv; - rv = targetFile->GetFSSpec(&fsAliasParent); - if (NS_FAILED(rv)) return rv; - rv = targetFile->GetAppendedPath(&aliasLeaf); - if (NS_FAILED(rv)) return rv; - // check if source file exists - err = FSMakeFSSpec(fsSource.vRefNum, fsSource.parID, fsSource.name, &fsCheckSource); - if (err != noErr) - return err; - - // construct target alias FSSpec using parent and leaf path - err = FSpGetDirectoryID(&fsAliasParent, &aliasDirID, &isDir); - if (err != noErr) - { - if (aliasLeaf) - nsMemory::Free(aliasLeaf); - return err; - } - c2pstr(aliasLeaf); + rv = sourceFile->Exists(&exists); + if (NS_FAILED(rv) || !exists) + return nsInstall::SOURCE_DOES_NOT_EXIST; + + // check if alias file already exists at target + targetFile->SetFollowLinks(PR_FALSE); + rv = targetFile->Exists(&exists); + if (NS_FAILED(rv)) + return nsInstall::INVALID_PATH_ERR; - // check if file/folder already exists at target - err = FSMakeFSSpec(fsAliasParent.vRefNum, aliasDirID, (unsigned char *) aliasLeaf, &fsAlias); - p2cstr((unsigned char *)aliasLeaf); - if (aliasLeaf) - nsMemory::Free(aliasLeaf); - - // file already exists: delete it before creating an updated alias - if (err == noErr) - { - err = FSpDelete(&fsAlias); - if (err != noErr) - return err; - } - + // if file already exists: delete it before creating an updated alias + if (exists) { + rv = targetFile->Remove(PR_TRUE); + if (NS_FAILED(rv)) + return nsInstall::FILENAME_ALREADY_USED; + } #endif /* XP_MAC */ return nsInstall::SUCCESS; @@ -1427,50 +1404,36 @@ nsInstallFileOpItem::NativeFileOpMacAliasComplete() nsCOMPtr localFileMacTarget = do_QueryInterface(mTarget); nsCOMPtr localFileMacSrc = do_QueryInterface(mSrc); - FSSpec fsSource, fsAliasParent, fsAlias, fsCheckSource; + FSSpec fsSource, fsAlias; + PRBool exists; AliasHandle aliasH; FInfo info; OSErr err = noErr; nsresult rv = NS_OK; - long aliasDirID; - Boolean isDir; - char *aliasLeaf; - - // nsIFile sucks so we have to do special hackery here - rv = localFileMacSrc->GetResolvedFSSpec(&fsSource); - if (NS_FAILED(rv)) return rv; - rv = localFileMacTarget->GetFSSpec(&fsAliasParent); - if (NS_FAILED(rv)) return rv; - rv = localFileMacTarget->GetAppendedPath(&aliasLeaf); - if (NS_FAILED(rv)) return rv; // check if source file exists - err = FSMakeFSSpec(fsSource.vRefNum, fsSource.parID, fsSource.name, &fsCheckSource); - if (err != noErr) - return err; - - // construct target alias FSSpec using parent and leaf path - err = FSpGetDirectoryID(&fsAliasParent, &aliasDirID, &isDir); - if (err != noErr) - { - if (aliasLeaf) - nsMemory::Free(aliasLeaf); - return err; - } - c2pstr(aliasLeaf); - err = FSMakeFSSpec(fsAliasParent.vRefNum, aliasDirID, (unsigned char *) aliasLeaf, &fsAlias); - p2cstr((unsigned char *)aliasLeaf); - if (aliasLeaf) - nsMemory::Free(aliasLeaf); - - // file already exists: delete it before creating an updated alias - if (err == noErr) - { - err = FSpDelete(&fsAlias); - if (err != noErr) - return err; - } + rv = localFileMacSrc->Exists(&exists); + if (NS_FAILED(rv) || !exists) + return nsInstall::SOURCE_DOES_NOT_EXIST; + + // check if file/folder already exists at target + localFileMacTarget->SetFollowLinks(PR_FALSE); + rv = localFileMacTarget->Exists(&exists); + if (NS_FAILED(rv)) + return nsInstall::INVALID_PATH_ERR; + // if file already exists: delete it before creating an updated alias + if (exists) { + rv = localFileMacTarget->Remove(PR_TRUE); + if (NS_FAILED(rv)) + return nsInstall::FILENAME_ALREADY_USED; + } + + rv = localFileMacSrc->GetFSSpec(&fsSource); + if (!NS_SUCCEEDED(rv)) return rv; + rv = localFileMacTarget->GetFSSpec(&fsAlias); + if (!NS_SUCCEEDED(rv)) return rv; + err = NewAliasMinimal( &fsSource, &aliasH ); if (err != noErr) // bubble up Alias Manager error return err; diff --git a/mozilla/xpinstall/src/nsLoggingProgressNotifier.cpp b/mozilla/xpinstall/src/nsLoggingProgressNotifier.cpp index 2ff6095c3a6..424feb4f047 100644 --- a/mozilla/xpinstall/src/nsLoggingProgressNotifier.cpp +++ b/mozilla/xpinstall/src/nsLoggingProgressNotifier.cpp @@ -107,7 +107,8 @@ nsLoggingProgressListener::BeforeJavascriptEvaluation(const PRUnichar *URL) else { nsCOMPtr iMacFile = do_QueryInterface(iFile); - iMacFile->SetFileTypeAndCreator('TEXT', 'R*ch'); + iMacFile->SetFileType('TEXT'); + iMacFile->SetFileCreator('R*ch'); } #endif } @@ -147,7 +148,8 @@ nsLoggingProgressListener::BeforeJavascriptEvaluation(const PRUnichar *URL) #ifdef XP_MAC nsCOMPtr iMacFile = do_QueryInterface(iFile); - iMacFile->SetFileTypeAndCreator('TEXT', 'R*ch'); + iMacFile->SetFileType('TEXT'); + iMacFile->SetFileCreator('R*ch'); #endif } @@ -316,7 +318,7 @@ Convert_nsIFile_To_nsFileSpec(nsIFile *aInIFile, nsFileSpec **aOutFileSpec) iFileMac = do_QueryInterface(aInIFile, &rv); if (NS_SUCCEEDED(rv)) { - iFileMac->GetResolvedFSSpec(&fsSpec); + iFileMac->GetFSSpec(&fsSpec); *aOutFileSpec = new nsFileSpec(fsSpec, PR_FALSE); } #else