gecko-dev/cmd/macfe/utility/xp_file_mac.cp
wtc%netscape.com 96a6a02078 NO_NSPR_PRIVATE_HEADER_BRANCH landing. Removed the inclusions of
private NSPR headers (prosdep.h and primpl.h) from the Mozilla source.
The part of prosdep.h that is actually needed by Mozilla was extracted
and put in the new file mozilla/include/xp_path.h.
1998-09-22 16:59:57 +00:00

1342 lines
36 KiB
C++
Raw Blame History

/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/* xp_file_mac.h
* Mac-only xp_file functions
*/
#include "xp_file_mac.h"
/* macfe */
#include "resgui.h"
#include "ufilemgr.h"
#include "uprefd.h"
/* utilities */
#include "MoreFilesExtras.h"
#include "FSpCompat.h"
#include "FileCopy.h"
#include "PascalString.h"
#include "Files.h"
#include <LString.h>
#include "cstring.h"
// validation flags for overloaded ConvertURLToSpec
enum ConvertURLValidationFlags {
validateValFlag = 0x00000001,
stripValFlag = 0x00000002,
appendValFlag = 0x00000004,
stripAndAppendValFlag = (stripValFlag | appendValFlag) };
// Prototypes
OSErr ConvertURLToSpec
(const char* inName,
FSSpec* outSpec,
ResIDT resid = 0,
Boolean validate = false);
OSErr ConvertURLToSpec(
const char* inName,
FSSpec* outSpec,
const char* suffix = nil,
ConvertURLValidationFlags validate = validateValFlag);
/**************************************************************************************
* See xp_file.h for full documentation. BE SURE TO READ THAT FILE.
**************************************************************************************/
//-----------------------------------
OSErr ConvertURLToSpec(const char* inName, FSSpec* outSpec, ResIDT resid, Boolean validate)
// Returns a file spec given a name (URL form), and resid of an extension to add.
// If ResID is zero, just convert.
// If resid is nonzero and validate is true, check the input name and return an error
// if the name does NOT have the suffix.
// If resid is nonzero and validate is false, append the suffix to the input name
//-----------------------------------
{
if (!inName)
return bdNamErr;
#ifdef DEBUG
if (XP_STRCHR(inName, ':'))
XP_ASSERT(0); // Are they passing us a Mac path?
#endif
OSErr err = CFileMgr::FSSpecFromLocalUnixPath(inName, outSpec);
if (err && err != fnfErr) /* fnfErr is OK */
return err;
if (resid)
{
CStr255 extension;
::GetIndString(extension, 300, resid);
if (validate)
{
SInt32 suffixPosition = (XP_STRLEN(inName) - XP_STRLEN(extension));
if (suffixPosition < 0)
return bdNamErr;
if (XP_STRCASECMP(extension, inName + suffixPosition) != 0)
return bdNamErr;
}
else
*(CStr63*)(outSpec->name) += extension;
}
return noErr;
} // ConvertURLToSpec
//-----------------------------------
OSErr ConvertURLToSpec(const char* inName, FSSpec* outSpec, const char* suffix,
ConvertURLValidationFlags validate)
// Returns a file spec given a name (URL form), and resid of an extension to add.
// If ResID is zero, just convert.
// If resid is nonzero and validate is true, check the input name and return an error
// if the name does NOT have the suffix.
// If resid is nonzero and validate is false, append the suffix to the input name
//-----------------------------------
{
if (!inName)
return bdNamErr;
#ifdef DEBUG
if (XP_STRCHR(inName, ':'))
XP_ASSERT(0); // Are they passing us a Mac path?
#endif
if(validate & stripValFlag) {
char *dot = XP_STRRCHR(inName, '.');
if(dot)
{
*dot = '\0';
}
}
OSErr err = CFileMgr::FSSpecFromLocalUnixPath(inName, outSpec);
if (err && err != fnfErr) /* fnfErr is OK */
return err;
if (validate & validateValFlag)
{
if (suffix)
{
CStr255 extension = suffix;
SInt32 suffixPosition = (XP_STRLEN(inName) - XP_STRLEN(extension));
if (suffixPosition < 0)
return bdNamErr;
if (XP_STRCASECMP(extension, inName + suffixPosition) != 0)
return bdNamErr;
}
}
if(validate & appendValFlag)
{
if (suffix)
{
CStr31 extension = suffix;
CStr63& specName = *(CStr63*)(outSpec->name);
/* If the total length is greater than 31, we want to
* truncate the filename on the right-hand side by the
* appropriate amount.
*/
if(specName.Length() + extension.Length() > 31)
{
specName.Length() = 31 - extension.Length();
}
specName += extension;
} else {
XP_ASSERT(0);
}
}
return noErr;
} // ConvertURLToSpec
const char* CacheFilePrefix = "cache";
extern long _fcreator, _ftype; /* Creator and Type for files created by the open function */
//-----------------------------------
OSErr XP_FileSpec(const char *inName, XP_FileType type, FSSpec* outSpec)
// For the Mac, get the Mac specs first
//-----------------------------------
{
CStr255 tempName(inName);
OSErr err = noErr;
_fcreator = emSignature;
switch (type) {
/* MAIN FOLDER */
case xpUserPrefs: /* Ignored by MacFE */
err = fnfErr;
break;
case xpGlobalHistory: /* Simple */
_ftype = emGlobalHistory;
*outSpec = CPrefs::GetFilePrototype( CPrefs::MainFolder );
GetIndString(outSpec->name, 300, globHistoryName);
break;
#ifdef MOZ_MAIL_NEWS
case xpImapRootDirectory:
_ftype = emMailSubdirectory;
*outSpec = CPrefs::GetFilePrototype( CPrefs::MainFolder );
*(CStr63*)(outSpec->name) = "\pIMAPmail";
break;
case xpImapServerDirectory:
_ftype = emMailSubdirectory;
*outSpec = CPrefs::GetFilePrototype( CPrefs::MainFolder );
*(CStr63*)(outSpec->name) = "\pIMAPmail";
FSSpec tempSpec;
OSErr getInfoErr = FSMakeFSSpec(
outSpec->vRefNum,
outSpec->parID,
outSpec->name,
&tempSpec);
if (getInfoErr == fnfErr)
{
// We have to make the root imap directory ourselves.
long ignored;
err = FSpDirCreate(outSpec, smSystemScript, &ignored);
if (err)
break;
}
CInfoPBRec infoRecord;
XP_MEMSET(&infoRecord, 0, sizeof(infoRecord));
infoRecord.dirInfo.ioDrDirID = outSpec->parID;
infoRecord.dirInfo.ioVRefNum = outSpec->vRefNum;
infoRecord.dirInfo.ioNamePtr = outSpec->name;
getInfoErr = PBGetCatInfoSync(&infoRecord);
if (getInfoErr == noErr)
{
/* any error here is handled by the caller */
/* fnfErr is in fact ok for XP_Stat */
FSMakeFSSpec(
outSpec->vRefNum,
infoRecord.dirInfo.ioDrDirID,
tempName,
outSpec);
}
break;
#endif
case xpBookmarks:
_ftype = emTextType;
err = ConvertURLToSpec(inName, outSpec, (ResIDT)0);
break;
/* MISC */
case xpTemporary:
_ftype = emTextType;
XP_ASSERT(tempName[0] != '/');
*outSpec = CPrefs::GetTempFilePrototype();
*(CStr63*)(outSpec->name) = tempName;
break;
case xpFileToPost:
_ftype = emTextType;
err = ConvertURLToSpec(inName, outSpec, (ResIDT)0);
break;
case xpURL:
case xpExtCache:
// This does not work if file name contains %.
// The problem is that netlib hex-decodes the file names before
// passing them to XP_File, while other libraries do not
// Windows has the same bug. atotic
_ftype = emTextType;
err = CFileMgr::FSSpecFromLocalUnixPath( inName, outSpec);
break;
case xpMimeTypes:
*outSpec = CPrefs::GetFilePrototype( CPrefs::MainFolder );
GetIndString(outSpec->name, 300, mimeTypes);
break;
case xpHTTPCookie:
_ftype = emMagicCookie;
*outSpec = CPrefs::GetFilePrototype( CPrefs::MainFolder );
GetIndString(outSpec->name, 300, magicCookie);
break;
#ifdef CookieManagement
case xpHTTPCookiePermission:
_ftype = emMagicCookie; // is this right?
*outSpec = CPrefs::GetFilePrototype( CPrefs::MainFolder );
GetIndString(outSpec->name, 300, cookiePermissions);
break;
#endif
case xpJSCookieFilters:
_ftype = emTextType;
*outSpec = CPrefs::GetFilePrototype( CPrefs::MainFolder );
*(CStr63*)(outSpec->name) = ":cookies.js";
break;
#ifdef SingleSignon
case xpHTTPSingleSignon:
_ftype = emMagicCookie; // is this right?
*outSpec = CPrefs::GetFilePrototype( CPrefs::MainFolder );
GetIndString(outSpec->name, 300, singleSignons);
break;
#endif
case xpProxyConfig:
_ftype = emTextType;
*outSpec = CPrefs::GetFilePrototype( CPrefs::MainFolder );
GetIndString(outSpec->name, 300, proxyConfig);
break;
case xpJSConfig:
_ftype = emTextType;
*outSpec = CPrefs::GetFilePrototype( CPrefs::MainFolder );
GetIndString(outSpec->name, 300, jsConfig);
break;
case xpSocksConfig:
_ftype = emTextType;
*outSpec = CPrefs::GetFilePrototype( CPrefs::MainFolder );
GetIndString(outSpec->name, 300, socksConfig);
break;
case xpSignature:
_ftype = emTextType;
*outSpec = CPrefs::GetFolderSpec( CPrefs::SignatureFile );
break;
case xpHTMLAddressBook:
_ftype = emTextType; // irrelevant
*outSpec = CPrefs::GetFilePrototype( CPrefs::MainFolder );
GetIndString(outSpec->name, 300, htmlAddressBook);
break;
#ifdef MOZ_MAIL_NEWS
case xpAddrBookNew:
case xpAddrBook:
_ftype = emAddressBookDB;
*outSpec = CPrefs::GetFilePrototype( CPrefs::MainFolder );
*(CStr63*)(outSpec->name) = tempName;
break;
#endif
case xpRegistry:
_ftype = emRegistry;
err = FindFolder( kOnSystemDisk, kPreferencesFolderType, TRUE, &outSpec->vRefNum, &outSpec->parID);
GetIndString(outSpec->name, 300, theRegistry);
break;
/* SECURITY */
case xpKeyChain: /* Should probably be the default name instead */
_ftype = emKeyChain;
*outSpec = CPrefs::GetFilePrototype( CPrefs::SecurityFolder );
*(CStr63*)(outSpec->name) = tempName;
break;
case xpCertDB:
_ftype = emCertificates;
*outSpec = CPrefs::GetFilePrototype( CPrefs::SecurityFolder );
GetIndString(tempName, 300, certDB);
if (inName != NULL)
tempName += inName;
*(CStr63*)(outSpec->name) = tempName;
break;
case xpCertDBNameIDX:
_ftype = emCertIndex;
*outSpec = CPrefs::GetFilePrototype( CPrefs::SecurityFolder );
GetIndString(outSpec->name, 300, certDBNameIDX);
break;
case xpKeyDB:
_ftype = emTextType;
*outSpec = CPrefs::GetFilePrototype( CPrefs::SecurityFolder );
GetIndString(tempName, 300, keyDb);
if (inName != NULL)
tempName += inName;
*(CStr63*)(outSpec->name) = tempName;
break;
case xpSecModuleDB:
_ftype = emTextType;
*outSpec = CPrefs::GetFilePrototype( CPrefs::SecurityFolder );
GetIndString(tempName, 300, secModuleDb);
break;
case xpSignedAppletDB:
_ftype = emTextType;
*outSpec = CPrefs::GetFilePrototype( CPrefs::SecurityFolder );
GetIndString(tempName, 300, signedAppletDb);
if (inName != NULL)
tempName += inName;
*(CStr63*)(outSpec->name) = tempName;
break;
case xpCryptoPolicy:
_ftype = emTextType;
*outSpec = CPrefs::GetFilePrototype( CPrefs::RequiredGutsFolder);
GetIndString(outSpec->name, 300, cryptoPolicy);
break;
/* CACHE */
case xpCache:
_ftype = emTextType;
*outSpec = CPrefs::GetFilePrototype( CPrefs::DiskCacheFolder );
*(CStr63*)(outSpec->name) = tempName;
break;
case xpCacheFAT:
_ftype = emCacheFat;
*outSpec = CPrefs::GetFilePrototype( CPrefs::DiskCacheFolder );
GetIndString(outSpec->name, 300, cacheLog);
break;
case xpExtCacheIndex:
_ftype = emExtCache;
*outSpec = CPrefs::GetFilePrototype( CPrefs::MainFolder );
GetIndString(outSpec->name, 300, extCacheFile);
break;
case xpSARCache:
_ftype = emTextType;
*outSpec = CPrefs::GetFilePrototype( CPrefs::SARCacheFolder );
*(CStr63*)(outSpec->name) = tempName;
break;
case xpSARCacheIndex:
_ftype = emExtCache;
*outSpec = CPrefs::GetFilePrototype( CPrefs::SARCacheFolder );
GetIndString(outSpec->name, 300, sarCacheIndex);
break;
/* NEWS */
case xpNewsRC:
case xpSNewsRC:
#ifdef MOZ_MAIL_NEWS
_ftype = emNewsrcFile;
*outSpec = CPrefs::GetFilePrototype( CPrefs::NewsFolder );
if ( (inName == NULL) || (*inName == 0))
{
GetIndString( tempName, 300, newsrc );
NET_RegisterNewsrcFile( tempName, inName, type == xpSNewsRC, FALSE );
}
else
{
tempName = NET_MapNewsrcHostToFilename( (char*)inName, type == xpSNewsRC, FALSE );
if ( tempName.IsEmpty() )
{
// 3.0 -> 4.02 conversion hack:
// The missing newsrc file from 3.0 probably is "newsrc"
// If we're looking for a file that's not there, try it with "newsrc".
// That's because if "foo" is the default host for 3.0, then these things
// are true:
// (1) When 4.0 is first launched, there is no is no entry in the host
// NewsFAT for foo, and hence no entry in the mapping table for foo.
// (2) The entry that SHOULD be in the table for foo is "newsrc".
// (3) The entry that 4.0 WOULD make, if the user hadn't run 3.0, is
// newsrc-foo.
tempName = "newsrc";
*(CStr63*)(outSpec->name) = tempName;
FInfo fndrInfo;
if (::FSpGetFInfo(outSpec, &fndrInfo) == fnfErr)
{
char * cstr = CStr255(inName); // when we have <host:port>,
char* macptr = XP_STRCHR(cstr, ':'); // ...replace ':' with '.'
if (macptr) *macptr = '.';
CFileMgr::UniqueFileSpec( *outSpec, cstr, *outSpec );
tempName = outSpec->name;
}
NET_RegisterNewsrcFile( tempName, (char*)inName, type == xpSNewsRC, FALSE );
}
}
*(CStr63*)(outSpec->name) = tempName;
break;
case xpNewsgroups:
_ftype = emTextType;
*outSpec = CPrefs::GetFilePrototype( CPrefs::NewsFolder );
tempName = NET_MapNewsrcHostToFilename((char*)inName, FALSE, TRUE );
if ( tempName.IsEmpty() )
{
CStr63 newName( "groups-" );
newName += inName;
tempName = newName;
CFileMgr::UniqueFileSpec( *outSpec, CStr31( tempName ), *outSpec );
tempName = outSpec->name;
NET_RegisterNewsrcFile( tempName, (char*)inName, FALSE, TRUE );
}
*(CStr63*)(outSpec->name) = tempName;
break;
case xpSNewsgroups:
_ftype = emTextType;
*outSpec = CPrefs::GetFilePrototype( CPrefs::NewsFolder );
tempName = NET_MapNewsrcHostToFilename((char*)inName, TRUE, TRUE );
if ( tempName.IsEmpty() )
{
CStr63 newName( "sgroups-" );
newName += inName;
tempName = newName;
CFileMgr::UniqueFileSpec( *outSpec, CStr31( tempName ), *outSpec );
tempName = outSpec->name;
NET_RegisterNewsrcFile( tempName, (char*)inName, TRUE, TRUE );
}
*(CStr63*)(outSpec->name) = tempName;
break;
case xpTemporaryNewsRC:
_ftype = emNewsrcFile;
*outSpec = CPrefs::GetFilePrototype( CPrefs::NewsFolder );
tempName = "temp newsrc";
*(CStr63*)(outSpec->name) = tempName;
break;
case xpNewsrcFileMap:
_ftype = emNewsrcDatabase;
*outSpec = CPrefs::GetFilePrototype( CPrefs::NewsFolder );
GetIndString(outSpec->name, 300, newsFileMap);
break;
case xpXoverCache:
_ftype = emNewsXoverCache;
*outSpec = CPrefs::GetFilePrototype(CPrefs::NewsFolder);
// Boolean isDirectory;
// long dirID;
// // Convert the outSpec of the news folder to a dir ID
// err = FSpGetDirectoryID(outSpec, &dirID, &isDirectory);
if (!err)
{
// Assert_(isDirectory);
// outSpec->parID = dirID;
// Name can contain a slash, so be prepared
err = CFileMgr::FSSpecFromLocalUnixPath(inName, outSpec);
// // name is now a native partial path
// err = FSMakeFSSpec(
// outSpec->vRefNum,
// outSpec->parID,
// tempName,
// outSpec);
if (err == fnfErr) err = noErr;
}
break;
case xpNewsSort:
_ftype = emMailFilterRules;
*outSpec = CPrefs::GetFilePrototype(CPrefs::NewsFolder);
err = CFileMgr::FSSpecFromLocalUnixPath(inName, outSpec);
if (err == fnfErr) err = noErr;
break;
case xpNewsHostDatabase:
_ftype = emNewsHostDatabase;
*outSpec = CPrefs::GetFilePrototype(CPrefs::NewsFolder);
GetIndString(outSpec->name, 300, newsHostDatabase);
break;
case xpJSMailFilters:
_ftype = emTextType;
*outSpec = CPrefs::GetFilePrototype(CPrefs::MailFolder);
if (inName && *inName)
{
// Make sure there are no colons in the server name
char* cp = (char*)&tempName[1];
for (int i = 1; i < tempName[0]; i++,cp++)
if (*cp == ':') *cp = '.';
*(CStr63*)(outSpec->name) += (":" + tempName + ".filters.js"); // in parent of mail folder.
}
else
*(CStr63*)(outSpec->name) = ":filters.js"; // in parent of mail folder.
break;
case xpMailSort: // normal filters
{
_ftype = emMailFilterRules;
*outSpec = CPrefs::GetFilePrototype(CPrefs::MailFolder);
if (inName && *inName)
{
// In 5.0, there are rules for each server.
// Make sure there are no colons in the server name
char* cp = (char*)&tempName[1];
for (int i = 1; i < tempName[0]; i++,cp++)
if (*cp == ':') *cp = '.';
*(CStr63*)(outSpec->name) = (":" + tempName + " Rules"); // in parent of mail folder.
}
else
GetIndString(outSpec->name, 300, mailFilterFile);// in parent of mail folder.
break;
}
case xpMailFilterLog:
_ftype = emMailFilterLog;
*outSpec = CPrefs::GetFilePrototype(CPrefs::MailFolder);
GetIndString(outSpec->name, 300, mailFilterLog);// in parent of mail folder.
break;
case xpMailFolder:
_ftype = emTextType;
err = ConvertURLToSpec(inName, outSpec, (ResIDT)0);
break;
case xpMailFolderSummary:
_ftype = emMailFolderSummary;
err = ConvertURLToSpec(inName, outSpec, mailBoxExt);
break;
case xpMailPopState:
_ftype = emTextType;
*outSpec = CPrefs::GetFilePrototype(CPrefs::MainFolder);
GetIndString(outSpec->name, 300, mailPopState);
break;
case xpMailSubdirectory:
_ftype = emMailSubdirectory;
err = ConvertURLToSpec(inName, outSpec, subdirExt);
break;
case xpVCardFile:
_ftype = emTextType;
// We are required to check for a '.vcf'
err = ConvertURLToSpec(inName, outSpec, vCardExt, true);
break;
case xpLDIFFile:
_ftype = emTextType;
// We are required to check for a '.ldi', '.ldif'
err = ConvertURLToSpec(inName, outSpec, ldifExt1, true);
if (err == bdNamErr)
err = ConvertURLToSpec(inName, outSpec, ldifExt2, true);
if ( err == bdNamErr )
{
ConvertURLToSpec(inName, outSpec, 0, false);
short refNum;
err = ::FSpOpenDF( outSpec, fsRdPerm, &refNum);
FSClose( refNum );
if (err == fnfErr)
err = ConvertURLToSpec(inName, outSpec, ".ldif", stripAndAppendValFlag);
else
err = bdNamErr;
}
break;
case xpPKCS12File:
_ftype = emTextType;
// We are required to check for a '.ldi', '.ldif'
err = ConvertURLToSpec(inName, outSpec, ".p12", stripAndAppendValFlag);
break;
case xpFolderCache:
_ftype = emTextType;
*outSpec = CPrefs::GetFilePrototype(CPrefs::MainFolder);
GetIndString(outSpec->name, 300, mailFolderCache);
break;
case xpLIClientDB:
_ftype = emTextType;
*outSpec = CPrefs::GetFilePrototype( CPrefs::MainFolder );
*(CStr63*)(outSpec->name) = "LIClientdb.dat";
break;
case xpLIPrefs:
_ftype = emTextType;
*outSpec = CPrefs::GetFilePrototype(CPrefs::MainFolder);
*(CStr63*)(outSpec->name) = "liprefs.js";
break;
#endif // ifdef MOZ_MAILNEWS
default:
XP_ASSERT( false ); // Whoever added the enum, it is time to implement it on the Mac
err = bdNamErr;
break;
}
if ( (err == fnfErr) )
err = noErr;
//XP_ASSERT( err == noErr);
// Don't assert, sometimes normal flow of control involves an err here.
return err;
} // XP_FileSpec
//-----------------------------------
char* xp_FileName( const char* name, XP_FileType type, char* buf, char* /* unixConfigBuf */ )
//-----------------------------------
{
FSSpec macSpec;
OSErr err = noErr;
if ( ( type == xpCache ) && name)
{
char * cachePath = CPrefs::GetCachePath();
if (cachePath == NULL)
err = fnfErr;
else
{
XP_STRCPY(buf, cachePath);
XP_STRCAT(buf, name);
}
}
#ifdef _XP_TMP_FILENAME_FOR_LDAP_
/* this is for address book to have a way of getting a temp file
* name for each ldap server, yet preserve the temp file name for
* later use on the same ldap server. we expect name to be unique
* to each ldap server and the return would be a temp file name
* associated with the ldap server - benjie
*/
else if ( ( type == xpAddrBook ) && name)
{
return FE_GetFileName(name, type);
}
#endif
else
{
char* path = NULL;
err = XP_FileSpec( name, type, &macSpec );
if (err != noErr)
return NULL;
path = CFileMgr::PathNameFromFSSpec( macSpec, TRUE );
if ( !path )
return NULL;
if ((strlen(path) > 1000) )
{
XP_ASSERT(FALSE);
XP_FREE( path );
return NULL;
}
XP_STRCPY( buf, path );
XP_FREE( path );
}
if ( err != noErr )
return NULL;
return buf;
} // XP_FileSpec
//-----------------------------------
char* XP_TempDirName(void)
//-----------------------------------
{
FSSpec spec = CPrefs::GetTempFilePrototype();
char* path = CFileMgr::PathNameFromFSSpec(spec, TRUE);
if (strlen(path) > 1000)
{
XP_ASSERT(FALSE);
return NULL;
}
return path;
}
//-----------------------------------
char * xp_FilePlatformName(const char * name, char* path)
//-----------------------------------
{
FSSpec spec;
OSErr err;
char * fullPath;
if (name == NULL)
return NULL;
// Initialize spec, because FSSpecFromLocalUnixPath might use it.
spec.vRefNum = 0;
spec.parID = 0;
err = CFileMgr::FSSpecFromLocalUnixPath(name, &spec);
// <20><><EFBFBD>NOTE: rjc, pchen, and pinkerton changed the behavior of this so that it will no
// longer return NULL when the file does not exist. If this is a problem, come tell us
// because we need to change other code.
if (err != noErr && err != fnfErr && err != dirNFErr )
return NULL;
fullPath = CFileMgr::PathNameFromFSSpec( spec, TRUE );
if (fullPath && (XP_STRLEN(fullPath) < 300))
XP_STRCPY(path, fullPath);
else
return NULL;
if (fullPath)
XP_FREE(fullPath);
return path;
}
//-----------------------------------
char *XP_PlatformFileToURL(const char * inName)
//-----------------------------------
{
char *retVal = NULL;
const char *prefix = "file://";
/* The inName parameter MUST be a native path, ie colons, spaces, etc.
** This assert will help us fix all the various "doubly-encoded path"
** bugs - jrm 97/02/10 */
#ifdef DEBUG
FSSpec tempSpec;
OSErr err = ::FSMakeFSSpec(0, 0, CStr255(inName), &tempSpec);
Boolean nativeMacPath = (err == noErr || err == fnfErr || err == dirNFErr);
Assert_(nativeMacPath);
#endif
char *duplicatedName = XP_STRDUP(inName);
if (duplicatedName)
{ /* YUCK! duplicatedName deleted by CFileMgr::EncodeMacPath */
char *xp_path = CFileMgr::EncodeMacPath(duplicatedName);
retVal = (char *) XP_ALLOC (XP_STRLEN(xp_path) + XP_STRLEN(prefix) + 1);
if (retVal)
{
XP_STRCPY (retVal, prefix);
XP_STRCAT (retVal, xp_path);
}
if (xp_path)
XP_FREE(xp_path);
}
return retVal;
}
char *XP_PlatformPartialPathToXPPartialPath(const char *sourceStringWithSpaces)
{
// convert spaces back to %20 quote char
int numberOfSpaces = 0;
const char *currentSpace = XP_STRSTR(sourceStringWithSpaces, " ");
while (currentSpace)
{
numberOfSpaces++;
currentSpace = XP_STRSTR(currentSpace + 1, " ");
}
char *escapedReturnString = (char *) XP_ALLOC(XP_STRLEN(sourceStringWithSpaces) + (numberOfSpaces*2) + 1);
if (escapedReturnString)
{
XP_STRCPY(escapedReturnString, sourceStringWithSpaces);
if (numberOfSpaces)
{
char *currentSpace = XP_STRSTR(escapedReturnString, " ");
while (currentSpace)
{
XP_MEMMOVE(currentSpace+3,currentSpace+1,XP_STRLEN(currentSpace+1) + 1);
*currentSpace++ = '%';
*currentSpace++ = '2';
*currentSpace++ = '0';
currentSpace = XP_STRSTR(currentSpace, " ");
}
}
}
return escapedReturnString;
}
/* Needs to deal with both CR, CRLF, and LF end-of-line */
extern char * XP_FileReadLine(char * dest, int32 bufferSize, XP_File file)
{
char * retBuf = fgets(dest, bufferSize, file);
if (retBuf == NULL) /* EOF */
return NULL;
char * LFoccurence = (char *)strchr(retBuf, LF);
if (LFoccurence != NULL) /* We have hit LF before CR, */
{
fseek(file, -(strlen(retBuf) - (LFoccurence - retBuf))+1, SEEK_CUR);
LFoccurence[1] = 0;
}
else /* We have CR, check if the next character is LF */
{
int c;
c = fgetc(file);
if (c == EOF)
; /* Do nothing, end of file */
else if (c == LF) /* Swallow CR/LF */
{
int len = strlen(retBuf);
if (len < bufferSize) /* Append LF to our buffer if we can */
{
retBuf[len++] = LF;
retBuf[len] = 0;
}
}
else /* No LF, just clean up the seek */
{
fseek(file, -1, SEEK_CUR);
}
}
return retBuf;
}
static counter = 1; /* temporary name suffix */
/* Returns a temp name given a path
*/
char * xp_TempName(XP_FileType type, const char * prefix, char* buf, char* /* buf2 */, unsigned int * /* count */)
{
FSSpec tempSpec;
CStr255 defaultName(prefix);
OSErr err = noErr;
switch (type) {
case xpTemporaryNewsRC:
defaultName = "temp newsrc";
break;
break;
case xpCache:
defaultName = CacheFilePrefix;
CStr255 dateString;
::NumToString (::TickCount(), dateString);
defaultName += dateString;
break;
case xpBookmarks:
defaultName += ".bak";
break;
case xpJPEGFile:
defaultName += ".jpeg";
break;
case xpMailFolder: /* Ugly. MailFolder callers for temporary names pass in the full path */
case xpMailFolderSummary: /* Ugly. MailFolder callers for temporary names pass in the full path */
{
FSSpec temp;
err = XP_FileSpec(prefix, xpMailFolder, &temp);
if (err == noErr)
defaultName = temp.name;
}
case xpFileToPost: /* Temporary files to post return the full path */
case xpTemporary:
default:
if ( (type == xpURL) && prefix )
{
if ( XP_STRRCHR(prefix, '/') )
{
XP_StatStruct st;
if (XP_Stat (defaultName, &st, xpURL))
XP_MakeDirectoryR (defaultName, xpURL);
defaultName += "su";
}
}
if (defaultName.IsEmpty())
defaultName = "nstemp";
CStr255 counterS;
::NumToString(counter++, counterS);
defaultName += counterS; /* Need counter to guarantee uniqueness if called several times in a row */
break;
}
if (type == xpFileToPost || type == xpMailFolder || type == xpMailFolderSummary || ((type == xpURL) && !prefix))
{
if (defaultName.Length() > 30) // Someone has passed in something weird as a prefix
{
XP_ASSERT(false);
defaultName.Delete(30, 1000);
}
err = XP_FileSpec(defaultName, xpTemporary, &tempSpec);
}
else
err = XP_FileSpec(defaultName, type, &tempSpec);
if (err && err != fnfErr)
return NULL;
FSSpec finalSpec;
err = CFileMgr::UniqueFileSpec(tempSpec, tempSpec.name, finalSpec);
if (err != noErr)
{
XP_ASSERT(FALSE);
return NULL;
}
if ((type == xpFileToPost) ||
(type == xpBookmarks) ||
(type == xpMailFolder) ||
(type == xpURL) ||
(type == xpMailFolderSummary))
/* These files needs full pathname */
{
char* tempPath = CFileMgr::PathNameFromFSSpec( finalSpec, TRUE );
tempPath = CFileMgr::EncodeMacPath(tempPath);
if (tempPath == NULL)
return NULL;
else if (XP_STRLEN(tempPath) > 500) /* Buffer overflow check */
{
XP_FREE(tempPath);
return NULL;
}
XP_STRCPY(buf, tempPath);
XP_FREE(tempPath);
}
else
XP_STRCPY(buf, CStr63(finalSpec.name));
return buf;
} /* xp_TempName */
/* XP_OpenDir is not handling different directories yet. */
XP_Dir XP_OpenDir( const char* name, XP_FileType type )
{
CInfoPBRec pb;
OSErr err;
DirInfo* dipb;
struct dirstruct * dir = XP_NEW(struct dirstruct);
if (dir == NULL)
return NULL;
XP_TRACE(( "opening file: %s", name ));
dir->type = type;
err = XP_FileSpec( name, type, &dir->dirSpecs );
if ( err != noErr )
{
XP_DELETE(dir);
return NULL;
}
dipb = (DirInfo*)&pb;
pb.hFileInfo.ioNamePtr = dir->dirSpecs.name;
pb.hFileInfo.ioVRefNum = dir->dirSpecs.vRefNum;
pb.hFileInfo.ioDirID = dir->dirSpecs.parID;
pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
err = PBGetCatInfoSync( &pb );
/* test that we have gotten a directory back, not a file */
if ( (err != noErr ) || !( dipb->ioFlAttrib & 0x0010 ) )
{
XP_DELETE( dir );
return NULL;
}
dir->dirSpecs.parID = pb.hFileInfo.ioDirID;
dir->index = pb.dirInfo.ioDrNmFls;
return (XP_Dir)dir;
}
void XP_CloseDir( XP_Dir dir )
{
if ( dir )
XP_DELETE(dir);
}
int XP_FileNumberOfFilesInDirectory(const char * dir_name, XP_FileType type)
{
FSSpec spec;
OSErr err = XP_FileSpec(dir_name, type, &spec);
if ((err != noErr) && (err != fnfErr))
goto loser;
CInfoPBRec pb;
pb.hFileInfo.ioNamePtr = spec.name;
pb.hFileInfo.ioVRefNum = spec.vRefNum;
pb.hFileInfo.ioDirID = spec.parID;
pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
err = PBGetCatInfoSync(&pb);
if (err != noErr)
goto loser;
return pb.dirInfo.ioDrNmFls;
loser:
return 10000; /* ???? */
}
XP_DirEntryStruct * XP_ReadDir(XP_Dir dir)
{
tryagain:
if (dir->index <= 0)
return NULL;
CInfoPBRec cipb;
DirInfo *dipb=(DirInfo *)&cipb;
dipb->ioCompletion = NULL;
dipb->ioFDirIndex = dir->index;
dipb->ioVRefNum = dir->dirSpecs.vRefNum; /* Might need to use vRefNum, not sure*/
dipb->ioDrDirID = dir->dirSpecs.parID;
dipb->ioNamePtr = (StringPtr)&dir->dirent.d_name;
OSErr err = PBGetCatInfoSync (&cipb);
/* We are traversing the directory backwards */
if (err != noErr)
{
if (dir->index > 1)
{
dir->index--;
goto tryagain;
}
else
return NULL;
}
p2cstr((StringPtr)&dir->dirent.d_name);
/* Mail folders are treated in a special way */
if ((dir->type == xpMailFolder) ||
(dir->type == xpMailFolderSummary) ||
(dir->type == xpMailSubdirectory) )
{
char * newName = XP_STRDUP(dir->dirent.d_name);
newName = CFileMgr::EncodeMacPath(newName);
if (newName)
{
XP_STRCPY(dir->dirent.d_name, newName);
XP_FREE(newName);
}
}
dir->index--;
return &dir->dirent;
}
int XP_MakeDirectory(const char* name, XP_FileType type)
{
FSSpec spec;
OSErr err = XP_FileSpec(name, type, &spec);
if ((err != noErr) && (err != fnfErr)) /* Should not happen */
return -1;
short refNum;
long dirID;
err = CFileMgr::CreateFolderInFolder(
spec.vRefNum, spec.parID, spec.name, /* Name of the new folder */
&refNum, &dirID);
if (err != noErr)
return -1;
return 0;
}
/* Recursively create all the directories
*/
int XP_MakeDirectoryR(const char* name, XP_FileType type)
{
char separator;
int result = 0;
XP_FILE_NATIVE_PATH finalNameNative = NULL;
XP_FILE_URL_PATH finalName = NULL;
char * dirPath = NULL;
separator = '/';
if ( type == xpURL)
finalNameNative = CFileMgr::MacPathFromUnixPath(name);
else
finalNameNative = WH_FileName(name, type);
if ( finalNameNative == NULL )
{
result = -1;
goto done;
}
finalName = XP_PlatformFileToURL(finalNameNative);
if ( finalName )
{
char * currentEnd;
int err = 0;
XP_StatStruct s;
dirPath = XP_STRDUP( &finalName[7] ); // Skip the file://
if (dirPath == NULL)
{
result = -1;
goto done;
}
currentEnd = XP_STRCHR(dirPath, separator);
if (currentEnd)
currentEnd = XP_STRCHR(&currentEnd[1], separator);
/* Loop through every part of the directory path */
while (currentEnd != 0)
{
char savedChar;
savedChar = currentEnd[1];
currentEnd[1] = 0;
if ( XP_Stat(dirPath, &s, xpURL ) != 0)
err = XP_MakeDirectory(dirPath, xpURL);
if ( err != 0)
{
XP_ASSERT( FALSE ); /* Could not create the directory? */
break;
}
currentEnd[1] = savedChar;
currentEnd = XP_STRCHR( &currentEnd[1], separator);
}
if ( err == 0 )
/* If the path is not terminated with / */
{
if ( dirPath[XP_STRLEN( dirPath) - 1] != separator )
if ( XP_Stat(dirPath, &s, xpURL ) != 0)
err = XP_MakeDirectory(dirPath, xpURL);
}
if ( 0 != err )
result = err;
}
else
result = -1;
done:
XP_FREEIF(finalName);
XP_FREEIF(finalNameNative);
XP_FREEIF(dirPath);
XP_ASSERT( result == 0 ); /* For debugging only */
return result;
}
int XP_RemoveDirectory (const char* name, XP_FileType type)
{
FSSpec spec;
OSErr err = XP_FileSpec(name, type, &spec);
if ((err != noErr) && (err != fnfErr))
return -1;
err = ::FSpDelete(&spec);
if (err != noErr)
return -1;
return 0;
}
// Removes the directory and its contents.
int XP_RemoveDirectoryRecursive(const char *name, XP_FileType type)
{
OSErr err;
FSSpec dirSpec;
err = XP_FileSpec(name, type, &dirSpec);
if ((err != noErr) && (err != fnfErr))
return -1;
err = DeleteDirectory(dirSpec.vRefNum, dirSpec.parID, dirSpec.name);
return (err == noErr) ? 0 : -1;
}
int XP_FileRename( const char* from, XP_FileType fromtype,
const char* to, XP_FileType totype )
{
OSErr err = noErr;
char* fromName = WH_FileName( from, fromtype );
char* toName = WH_FileName( to, totype );
if ( fromName && toName )
{
FSSpec toSpec;
err = CFileMgr::FSSpecFromPathname( toName, &toSpec );
if (err == noErr || err == fnfErr)
{
FSSpec fromSpec;
err = CFileMgr::FSSpecFromPathname( fromName, &fromSpec );
if (err == noErr || err == fnfErr)
{
if (fromSpec.vRefNum == toSpec.vRefNum)
/* Same volume */
{
/* But, er, is it the same file (jrm 97/08/20)? */
if (fromSpec.parID == toSpec.parID
&& *(CStr63*)fromSpec.name == *(CStr63*)toSpec.name)
goto Cleanup; // YOW! Don't delete it!
/* Delete the file */
::FSpDelete( &toSpec ); /* ignore error if not there */
if (fromSpec.parID == toSpec.parID)
{
/* this is a flat node rename use ::FSpRename */
err = ::FSpRename(&fromSpec, toSpec.name);
}
else
{
/* we are moving a file between dirs so use HMoveRenameCompat */
err = ::HMoveRenameCompat(
fromSpec.vRefNum,
fromSpec.parID, (ConstStr255Param)fromSpec.name,
toSpec.parID, nil, (StringPtr)toSpec.name);
}
}
else
/* Different volumes */
{
FSSpec toDir;
err = CFileMgr::FolderSpecFromFolderID(toSpec.vRefNum, toSpec.parID, toDir);
if (err == noErr)
{
::FSpDelete( &toSpec );
err = FSpFileCopy( &fromSpec, &toDir, toSpec.name, NULL, 0, true );
if ( err == noErr)
::FSpDelete( &fromSpec );
}
}
}
}
}
else
err = -1;
Cleanup:
if ( fromName )
XP_FREE( fromName );
if ( toName )
XP_FREE( toName );
if (err != noErr)
return -1;
return 0;
}
int XP_FileRemove( const char* name, XP_FileType type )
{
FSSpec spec;
OSErr err;
err = XP_FileSpec( name, type, &spec);
if ( err == noErr )
{
err = ::FSpDelete( &spec );
#ifdef MOZ_MAIL_NEWS
if ( type == xpNewsRC || type == xpNewsgroups )
NET_UnregisterNewsHost( name, FALSE );
else if ( type == xpSNewsRC || type == xpSNewsgroups)
NET_UnregisterNewsHost( name, TRUE );
#endif
}
if ( err == noErr )
return 0;
return -1;
}
int XP_FileTruncate( const char* name, XP_FileType type, int32 len )
{
FSSpec spec;
OSErr err, err2;
short refNum;
if (len < 0)
return EINVAL;
err = XP_FileSpec( name, type, &spec);
if (err != noErr)
return EINVAL;
err = FSpOpenDF(&spec, fsRdWrPerm, &refNum);
if (err != noErr)
return EACCES;
err = SetEOF(refNum, len);
err2 = FSClose(refNum);
if ((err != noErr) || (err2 != noErr))
return EIO;
return 0;
}
int XP_FileDuplicateResourceFork( const char* oldFilePath, XP_FileType oldType,
const char* newFilePath, XP_FileType newType )
{
OSErr err;
FSSpec oldfs, newfs;
err = XP_FileSpec( oldFilePath, oldType, &oldfs);
if (err != noErr)
return EINVAL;
err = XP_FileSpec( newFilePath, newType, &newfs);
if (err != noErr)
return EINVAL;
short oldFileRefNum = -1, newFileRefNum = -1;
oldFileRefNum = FSpOpenResFileCompat( &oldfs, fsCurPerm );
err = ResError();
if ( err || ( oldFileRefNum == -1 ) )
{
return EACCES;
}
// assume we need to create the new resource fork
// (may not be valid assumption for other uses of this function)
FSpCreateResFileCompat( &newfs, emSignature, emTextType, smSystemScript );
err = ResError();
newFileRefNum = FSpOpenResFileCompat( &newfs, fsRdWrPerm );
err = ResError();
if ( err || ( newFileRefNum == -1 ) )
{
err = FSClose( oldFileRefNum );
XP_ASSERT(0);
return EACCES;
}
long buffsize = 1024;
char buff[ 1024 ];
err = CopyFork( oldFileRefNum, newFileRefNum, buff, buffsize);
FSClose( oldFileRefNum );
FSClose( newFileRefNum );
if ( err )
return EIO;
return 0;
}
//======================================
// I put these stubs here. They can go away when we move to MSL.
//======================================
#include "prenv.h" /* For PR_GetEnv */
extern "C" {
char* getenv(const char *var);
}
char* getenv(const char *var)
{
return PR_GetEnv(var);
}