diff options
Diffstat (limited to 'src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macio.c')
-rw-r--r-- | src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macio.c | 1949 |
1 files changed, 1949 insertions, 0 deletions
diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macio.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macio.c new file mode 100644 index 00000000..ae3516de --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macio.c @@ -0,0 +1,1949 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include <string.h> + +#include <Types.h> +#include <Files.h> +#include <Devices.h> +#include <Folders.h> +#include <Errors.h> +#include <Resources.h> +#include <Processes.h> +#include <TextUtils.h> + +#include <fcntl.h> + +#include "FullPath.h" /* MoreFiles */ + +#include "primpl.h" +#include "MacErrorHandling.h" +#include "mdmac.h" + +#include "macio.h" + +/* forward declarations */ +extern unsigned long gJanuaryFirst1970Seconds; + +extern void WaitOnThisThread(PRThread *thread, PRIntervalTime timeout); +extern void DoneWaitingOnThisThread(PRThread *thread); +extern void AsyncNotify(PRThread *thread); + + +/* PB for Read and Write */ +struct ExtendedParamBlock { + /* PB must be first so that the file system can get the right data. */ + ParamBlockRec pb; + PRThread *thread; +}; +typedef struct ExtendedParamBlock ExtendedParamBlock; + + +/* XXX Not done yet for 68K */ +/* I/O completion routne for _MD_READ and _MD_WRITE */ +static void AsyncIOCompletion (ExtendedParamBlock *pbAsyncPtr) +{ + _PRCPU *cpu = _PR_MD_CURRENT_CPU(); + PRThread *thread = pbAsyncPtr->thread; + PRIntn is; + + if (_PR_MD_GET_INTSOFF()) { + thread->md.missedIONotify = PR_TRUE; + cpu->u.missed[cpu->where] |= _PR_MISSED_IO; + } else { + _PR_INTSOFF(is); + + thread->md.osErrCode = noErr; + DoneWaitingOnThisThread(thread); + + _PR_FAST_INTSON(is); + } + + SignalIdleSemaphore(); +} + +void _MD_SetError(OSErr oserror) +{ + PRErrorCode code; + + switch (oserror) { + case memFullErr: + code = PR_OUT_OF_MEMORY_ERROR; + break; + case fnfErr: + code = PR_FILE_NOT_FOUND_ERROR; + break; + case dupFNErr: + code = PR_FILE_EXISTS_ERROR; + break; + case ioErr: + code = PR_IO_ERROR; + break; + case nsvErr: + case wrgVolTypErr: + code = PR_INVALID_DEVICE_STATE_ERROR; + break; + case bdNamErr: + case fsRnErr: + code = PR_NAME_TOO_LONG_ERROR; + break; + case tmfoErr: + code = PR_INSUFFICIENT_RESOURCES_ERROR; + break; + case opWrErr: + case wrPermErr: + case permErr: + case afpAccessDenied: + code = PR_NO_ACCESS_RIGHTS_ERROR; + break; + case afpObjectTypeErr: + code = PR_DIRECTORY_LOOKUP_ERROR; + break; + case wPrErr: + case vLckdErr: + code = PR_DEVICE_IS_LOCKED_ERROR; + break; + case fLckdErr: + code = PR_FILE_IS_LOCKED_ERROR; + break; + case dirNFErr: + code = PR_NOT_DIRECTORY_ERROR; + break; + case dirFulErr: + code = PR_MAX_DIRECTORY_ENTRIES_ERROR; + break; + case dskFulErr: + code = PR_NO_DEVICE_SPACE_ERROR; + break; + case rfNumErr: + case fnOpnErr: + code = PR_BAD_DESCRIPTOR_ERROR; + break; + case eofErr: + code = PR_END_OF_FILE_ERROR; + break; + case posErr: + case gfpErr: + code = PR_FILE_SEEK_ERROR; + break; + case fBsyErr: + code = PR_FILE_IS_BUSY_ERROR; + break; + case extFSErr: + code = PR_REMOTE_FILE_ERROR; + break; + case abortErr: + code = PR_PENDING_INTERRUPT_ERROR; + break; + case paramErr: + code = PR_INVALID_ARGUMENT_ERROR; + break; + case unimpErr: + code = PR_NOT_IMPLEMENTED_ERROR; + break; + } + + PR_SetError(code, oserror); +} + +void _MD_IOInterrupt(void) +{ + PRCList *qp; + PRThread *thread, *me = _PR_MD_CURRENT_THREAD(); + + PR_ASSERT(_PR_MD_GET_INTSOFF() != 0); + + _PR_SLEEPQ_LOCK(me->cpu); + qp = _PR_PAUSEQ(me->cpu).next; + while (qp != &_PR_PAUSEQ(me->cpu)) { + + thread = _PR_THREAD_PTR(qp); + PR_ASSERT(thread->flags & _PR_ON_PAUSEQ); + + qp = qp->next; + + if (thread->md.missedIONotify) { + thread->md.missedIONotify = PR_FALSE; + DoneWaitingOnThisThread(thread); + } + + if (thread->md.missedAsyncNotify) { + thread->md.missedAsyncNotify = PR_FALSE; + AsyncNotify(thread); + } + } + qp = _PR_SLEEPQ(me->cpu).next; + while (qp != &_PR_SLEEPQ(me->cpu)) { + + thread = _PR_THREAD_PTR(qp); + PR_ASSERT(thread->flags & _PR_ON_SLEEPQ); + + qp = qp->next; + + if (thread->md.missedIONotify) { + thread->md.missedIONotify = PR_FALSE; + DoneWaitingOnThisThread(thread); + } + + if (thread->md.missedAsyncNotify) { + thread->md.missedAsyncNotify = PR_FALSE; + AsyncNotify(thread); + } + } + _PR_SLEEPQ_UNLOCK(thread->cpu); +} + +/* +** All PR_read and PR_Write calls are synchronous from caller's perspective. +** They are internally made asynchronous calls. This gives cpu to other +** user threads while the async io is in progress. +*/ +PRInt32 ReadWriteProc(PRFileDesc *fd, void *buf, PRUint32 bytes, IOOperation op) +{ + PRInt32 refNum = fd->secret->md.osfd; + OSErr err; + ExtendedParamBlock pbAsync; + PRThread *me = _PR_MD_CURRENT_THREAD(); + _PRCPU *cpu = _PR_MD_CURRENT_CPU(); + + /* quick hack to allow PR_fprintf, etc to work with stderr, stdin, stdout */ + /* note, if a user chooses "seek" or the like as an operation in another function */ + /* this will not work */ + if (refNum >= 0 && refNum < 3) + { + switch (refNum) + { + case 0: + /* stdin - not on a Mac for now */ + err = paramErr; + goto ErrorExit; + break; + case 1: /* stdout */ + case 2: /* stderr */ + puts(buf); + break; + } + + return (bytes); + } + else + { + static IOCompletionUPP sCompletionUPP = NULL; + + PRBool doingAsync = PR_FALSE; + + /* allocate the callback Universal Procedure Pointer (UPP). This actually allocates + a 32 byte Ptr in the heap, so only do this once + */ + if (!sCompletionUPP) + sCompletionUPP = NewIOCompletionUPP((IOCompletionProcPtr)&AsyncIOCompletion); + + /* grab the thread so we know which one to post to at completion */ + pbAsync.thread = me; + + pbAsync.pb.ioParam.ioCompletion = sCompletionUPP; + pbAsync.pb.ioParam.ioResult = noErr; + pbAsync.pb.ioParam.ioRefNum = refNum; + pbAsync.pb.ioParam.ioBuffer = buf; + pbAsync.pb.ioParam.ioReqCount = bytes; + pbAsync.pb.ioParam.ioPosMode = fsAtMark; + pbAsync.pb.ioParam.ioPosOffset = 0; + + /* + ** Issue the async read call and wait for the io semaphore associated + ** with this thread. + ** Async file system calls *never* return error values, so ignore their + ** results (see <http://developer.apple.com/technotes/fl/fl_515.html>); + ** the completion routine is always called. + */ + me->io_fd = refNum; + me->md.osErrCode = noErr; + if (op == READ_ASYNC) + { + /* + ** Skanky optimization so that reads < 20K are actually done synchronously + ** to optimize performance on small reads (e.g. registry reads on startup) + */ + if ( bytes > 20480L ) + { + doingAsync = PR_TRUE; + me->io_pending = PR_TRUE; + + (void)PBReadAsync(&pbAsync.pb); + } + else + { + pbAsync.pb.ioParam.ioCompletion = NULL; + me->io_pending = PR_FALSE; + + err = PBReadSync(&pbAsync.pb); + if (err != noErr && err != eofErr) + goto ErrorExit; + } + } + else + { + doingAsync = PR_TRUE; + me->io_pending = PR_TRUE; + + /* writes are currently always async */ + (void)PBWriteAsync(&pbAsync.pb); + } + + if (doingAsync) { + WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT); + } + } + + err = me->md.osErrCode; + if (err != noErr) + goto ErrorExit; + + err = pbAsync.pb.ioParam.ioResult; + if (err != noErr && err != eofErr) + goto ErrorExit; + + return pbAsync.pb.ioParam.ioActCount; + +ErrorExit: + me->md.osErrCode = err; + _MD_SetError(err); + return -1; +} + +/* +Special WriteSyncProc for logging only. IO occurs synchronously. Otherwise, +logging internal to NSPR causes ReadWriteProc above to recurse on PR_WaitSem logging. +*/ +PRInt32 WriteSyncProc(PRFileDesc *fd, void *buf, PRUint32 bytes) +{ + PRInt32 refNum = fd->secret->md.osfd; + OSErr err; + ParamBlockRec pb; + PRThread *me = _PR_MD_CURRENT_THREAD(); + + if (refNum >= 0 && refNum < 3) + { + PR_ASSERT(FALSE); /* writing to these is hazardous to a Mac's health (refNum 2 is the system file) */ + err = paramErr; + goto ErrorExit; + } + + pb.ioParam.ioCompletion = NULL; + pb.ioParam.ioResult = noErr; + pb.ioParam.ioRefNum = refNum; + pb.ioParam.ioBuffer = buf; + pb.ioParam.ioReqCount = bytes; + pb.ioParam.ioPosMode = fsAtMark; + pb.ioParam.ioPosOffset = 0; + + err = PBWriteSync(&pb); + + if (err != noErr) + goto ErrorExit; + else + return pb.ioParam.ioActCount; + +ErrorExit: + me->md.osErrCode = err; + _MD_SetError(err); + return -1; +} + +/* File I/O functions called by PR I/O routines */ +PRInt32 _MD_Open(const char *path, PRIntn flags, int mode) +{ +// Macintosh doesn't really have mode bits, just drop them +#pragma unused (mode) + + OSErr err; + HParamBlockRec hpb; + ParamBlockRec pb; + char *macFileName = NULL; + Str255 pascalName; + PRInt8 perm; + + err = ConvertUnixPathToMacPath(path, &macFileName); + + if (err != noErr) + goto ErrorExit; + + hpb.ioParam.ioCompletion = NULL; + PStrFromCStr(macFileName, pascalName); + PR_DELETE(macFileName); + hpb.ioParam.ioNamePtr = pascalName; + hpb.ioParam.ioVRefNum = 0; + hpb.ioParam.ioVersNum = 0; + hpb.fileParam.ioDirID = 0; + + if (flags & PR_RDWR) + perm = fsRdWrPerm; + else if (flags & PR_WRONLY) + perm = fsWrPerm; + else + perm = fsRdPerm; + hpb.ioParam.ioPermssn = perm; + + + if (flags & PR_CREATE_FILE) { + err = PBHCreateSync(&hpb); + + /* If opening with the PR_EXCL flag the existence of the file prior to opening is an error */ + if ((flags & PR_EXCL) && (err == dupFNErr)) { + err = PR_FILE_EXISTS_ERROR; + goto ErrorExit; + } + + if ((err != noErr) && (err != dupFNErr)) + goto ErrorExit; + } + + err = PBHOpenDFSync(&hpb); + + if (err != noErr) + goto ErrorExit; + + if (flags & PR_TRUNCATE) { + pb.ioParam.ioCompletion = NULL; + pb.ioParam.ioRefNum = hpb.ioParam.ioRefNum; + pb.ioParam.ioMisc = NULL; + err = PBSetEOFSync(&pb); + if (err != noErr) + goto ErrorExit; + } else if (flags & PR_APPEND) { + pb.ioParam.ioCompletion = NULL; + pb.ioParam.ioRefNum = hpb.ioParam.ioRefNum; + pb.ioParam.ioPosMode = fsFromLEOF; + pb.ioParam.ioPosOffset = 0; + err = PBSetFPosSync(&pb); + if (err != noErr) + goto ErrorExit; + } + return hpb.ioParam.ioRefNum; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return -1; +} + +/* _MD_CLOSE_FILE, _MD_READ, _MD_WRITE, _MD_GET_FILE_ERROR are defined in _macos.h */ + +PROffset32 _MD_LSeek(PRFileDesc *fd, PROffset32 offset, PRSeekWhence how) +{ + PRInt32 refNum = fd->secret->md.osfd; + OSErr err = noErr; + long curPos, endPos; + + /* compute new mark */ + switch (how) { + case PR_SEEK_SET: + endPos = offset; + break; + + case PR_SEEK_CUR: + err = GetFPos(refNum, &curPos); + endPos = curPos + offset; + break; + + case PR_SEEK_END: + err = GetEOF(refNum, &curPos); + endPos = curPos + offset; + break; + + default: + err = paramErr; + break; + } + + /* set the new mark and extend the file if seeking beyond current EOF */ + /* making sure to set the mark after any required extend */ + if (err == noErr) { + err = SetFPos(refNum, fsFromStart, endPos); + if (err == eofErr) { + err = SetEOF(refNum, endPos); + if (err == noErr) { + err = SetFPos(refNum, fsFromStart, endPos); + } + } + } + + if (err == noErr) { + return endPos; + } else { + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return -1; + } +} + +PRInt32 _MD_FSync(PRFileDesc *fd) +{ + PRInt32 refNum = fd->secret->md.osfd; + OSErr err; + ParamBlockRec pb; + + pb.ioParam.ioCompletion = NULL; + pb.ioParam.ioRefNum = refNum; + + err = PBFlushFileSync(&pb); + if (err != noErr) + goto ErrorExit; + + return 0; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return -1; +} + +#include "plstr.h" + +PRStatus _MD_OpenDir(_MDDir *mdDir,const char *name) +{ + // Emulate the Unix opendir() routine. + + OSErr err; + CInfoPBRec pb; + char *macDirName = NULL; + char *position = NULL; + char volumeName[32]; + Str255 pascalName; + + // Get the Macintosh path + err = ConvertUnixPathToMacPath(name, &macDirName); + if (err != noErr) + goto ErrorExit; + + // Get the vRefNum + position = PL_strchr(macDirName, PR_PATH_SEPARATOR); + if ((position == macDirName) || (position == NULL)) + mdDir->ioVRefNum = 0; // Use application relative searching + else { + memset(volumeName, 0, sizeof(volumeName)); + strncpy(volumeName, macDirName, position-macDirName); + mdDir->ioVRefNum = GetVolumeRefNumFromName(volumeName); + } + + // Get info about the object. + PStrFromCStr(macDirName, pascalName); + PR_DELETE(macDirName); + + pb.dirInfo.ioNamePtr = pascalName; + pb.dirInfo.ioVRefNum = mdDir->ioVRefNum; + pb.dirInfo.ioDrDirID = 0; + pb.dirInfo.ioFDirIndex = 0; + err = PBGetCatInfoSync(&pb); + if (err != noErr) + goto ErrorExit; + + // Are we dealing with a directory? + if ((pb.dirInfo.ioFlAttrib & ioDirMask) == 0) { + err = dirNFErr; + goto ErrorExit; + } + + /* 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 + */ + mdDir->ioDirID = pb.dirInfo.ioDrDirID; + mdDir->currentEntryName = NULL; + mdDir->ioFDirIndex = 1; + return PR_SUCCESS; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return PR_FAILURE; +} + +char *_MD_ReadDir(_MDDir *mdDir, PRIntn flags) +{ + // Emulate the Unix readdir() routine. + + // Mac doesnÕt have the concept of .(PR_SKIP_DOT) & ..(PR_SKIP_DOT_DOT) + + OSErr err; + CInfoPBRec pb; + char *returnedCStr; + Str255 pascalName = "\p"; + PRBool foundEntry; + + PR_ASSERT(mdDir != NULL); + + do { + + // Release the last name read. + 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) + CStrFromPStr(pascalName, &returnedCStr); + + 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: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return NULL; +} + + +void _MD_CloseDir(_MDDir *mdDir) +{ + // Emulate the Unix closedir() routine + + PR_DELETE(mdDir->currentEntryName); +} + +PRInt32 _MD_MkDir(char *unixPath, PRIntn mode) +{ + HFileParam fpb; + Str255 pascalName = "\p"; + char *cMacPath = NULL; + OSErr err; + + #pragma unused (mode) // Mode is ignored on the Mac + + if (unixPath) { + err = ConvertUnixPathToMacPath(unixPath, &cMacPath); + if (err != noErr) + goto ErrorExit; + + PStrFromCStr(cMacPath, pascalName); + PR_DELETE(cMacPath); + fpb.ioNamePtr = pascalName; + fpb.ioVRefNum = 0; + fpb.ioDirID = 0L; + + err = PBDirCreateSync((HParmBlkPtr)&fpb); + if (err != noErr) + goto ErrorExit; + } + + return 0; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return -1; +} + +PRInt32 _MD_Delete(char *unixPath) +{ + HFileParam fpb; + Str255 pascalName = "\p"; + char *cMacPath = NULL; + OSErr err; + + if (unixPath) { + err = ConvertUnixPathToMacPath(unixPath, &cMacPath); + if (err != noErr) + goto ErrorExit; + + PStrFromCStr(cMacPath, pascalName); + PR_DELETE(cMacPath); + fpb.ioNamePtr = pascalName; + fpb.ioVRefNum = 0; + fpb.ioDirID = 0L; + + err = PBHDeleteSync((HParmBlkPtr)&fpb); + if (err != noErr) + goto ErrorExit; + } + + return 0; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return -1; +} + +PRInt32 _MD_Rename(char *fromUnixPath, char *toUnixPath) +{ + OSErr err; + FSSpec fromSpec; + FSSpec toSpec; + FSSpec destDirSpec; + FSSpec beforeRenameSpec; + + if (fromUnixPath && toUnixPath) { + err = ConvertUnixPathToFSSpec(fromUnixPath, &fromSpec); + if (err != noErr) + goto ErrorExit; + + err = ConvertUnixPathToFSSpec(toUnixPath, &toSpec); + if (err != noErr && err != fnfErr) + goto ErrorExit; + + /* make an FSSpec for the destination directory */ + err = FSMakeFSSpec(toSpec.vRefNum, toSpec.parID, nil, &destDirSpec); + if (err != noErr) /* parent directory must exist */ + goto ErrorExit; + + // move it to the directory specified + err = FSpCatMove(&fromSpec, &destDirSpec); + if (err != noErr) + goto ErrorExit; + + // make a new FSSpec for the file or directory in its new location + err = FSMakeFSSpec(toSpec.vRefNum, toSpec.parID, fromSpec.name, &beforeRenameSpec); + if (err != noErr) + goto ErrorExit; + + // rename the file or directory + err = FSpRename(&beforeRenameSpec, toSpec.name); + if (err != noErr) + goto ErrorExit; + + } else { + err = paramErr; + goto ErrorExit; + } + + return 0; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return -1; +} + +#define kWriteAccessAllowed (0x100) +PRInt32 _MD_Access(char *unixPath, int amode) +{ + // + // Emulate the Unix access routine + // + + OSErr err; + CInfoPBRec pb; + FCBPBRec fcbpb; + char *cMacPath = NULL; + Str255 pascalMacPath; + struct stat info; + + // Convert to a Mac style path + err = ConvertUnixPathToMacPath(unixPath, &cMacPath); + if (err != noErr) + goto ErrorExit; + + err = stat(cMacPath, &info); + if (err != noErr) + goto ErrorExit; + + + // If all weÕre doing is checking for the existence of the file, weÕre out of here. + // On the Mac, if a file exists, you can read from it. + // This doesnÕt handle remote AppleShare volumes. Does it need to? + if ((amode == PR_ACCESS_EXISTS) || (amode == PR_ACCESS_READ_OK)) { + goto success; + } + + PStrFromCStr(cMacPath, pascalMacPath); + + pb.hFileInfo.ioNamePtr = pascalMacPath; + pb.hFileInfo.ioVRefNum = info.st_dev; + pb.hFileInfo.ioDirID = 0; + pb.hFileInfo.ioFDirIndex = 0; + + err = PBGetCatInfoSync(&pb); + if (err != noErr) + goto ErrorExit; + // Check out all the access permissions. + + if (amode == PR_ACCESS_WRITE_OK) { + fcbpb.ioNamePtr = NULL; + fcbpb.ioVRefNum = pb.hFileInfo.ioVRefNum; + fcbpb.ioRefNum = pb.hFileInfo.ioFRefNum; + fcbpb.ioFCBIndx = 0; + + err = PBGetFCBInfoSync(&fcbpb); + if (err != noErr) + goto ErrorExit; + + /* Look at Inside Mac IV-180 */ + if ((fcbpb.ioFCBFlags & kWriteAccessAllowed) == 0) { + err = permErr; + goto ErrorExit; + } + } + +success: + PR_DELETE(cMacPath); + return 0; + +ErrorExit: + if (cMacPath != NULL) + PR_DELETE(cMacPath); + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return -1; +} + +PRInt32 _MD_GetFileInfo(char *unixPath, PRFileInfo *info) +{ + CInfoPBRec pb; + OSErr err; + char *cMacPath = NULL; + Str255 pascalMacPath; + PRTime oneMillion, dateInMicroSeconds; + + // Convert to a Mac style path + err = ConvertUnixPathToMacPath(unixPath, &cMacPath); + if (err != noErr) + goto ErrorExit; + + PStrFromCStr(cMacPath, pascalMacPath); + PR_DELETE(cMacPath); + + pb.hFileInfo.ioNamePtr = pascalMacPath; + pb.hFileInfo.ioVRefNum = 0; + pb.hFileInfo.ioDirID = 0; + pb.hFileInfo.ioFDirIndex = 0; + + err = PBGetCatInfoSync(&pb); + if (err != noErr) + goto ErrorExit; + + if (pb.hFileInfo.ioFlAttrib & ioDirMask) { + info->type = PR_FILE_DIRECTORY; + info->size = 0; + } else { + info->type = PR_FILE_FILE; + info->size = pb.hFileInfo.ioFlLgLen + pb.hFileInfo.ioFlRLgLen; + } + + pb.hFileInfo.ioFlCrDat -= gJanuaryFirst1970Seconds; + LL_I2L(dateInMicroSeconds, pb.hFileInfo.ioFlCrDat); + LL_I2L(oneMillion, PR_USEC_PER_SEC); + LL_MUL(info->creationTime, oneMillion, dateInMicroSeconds); + + pb.hFileInfo.ioFlMdDat -= gJanuaryFirst1970Seconds; + LL_I2L(dateInMicroSeconds, pb.hFileInfo.ioFlMdDat); + LL_MUL(info->modifyTime, oneMillion, dateInMicroSeconds); + + return 0; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return -1; +} + +PRInt32 _MD_GetOpenFileInfo(const PRFileDesc *fd, PRFileInfo *info) +{ + OSErr err; + FCBPBRec fcbpb; + CInfoPBRec pb; + Str255 pascalMacPath; + PRTime oneMillion, dateInMicroSeconds; + + fcbpb.ioNamePtr = pascalMacPath; + fcbpb.ioVRefNum = 0; + fcbpb.ioRefNum = fd->secret->md.osfd; + fcbpb.ioFCBIndx = 0; + + err = PBGetFCBInfoSync(&fcbpb); + if (err != noErr) + goto ErrorExit; + + info->type = PR_FILE_FILE; + info->size = fcbpb.ioFCBEOF; + + pb.hFileInfo.ioNamePtr = pascalMacPath; + pb.hFileInfo.ioVRefNum = fcbpb.ioFCBVRefNum; + pb.hFileInfo.ioDirID = fcbpb.ioFCBParID; + pb.hFileInfo.ioFDirIndex = 0; + + err = PBGetCatInfoSync(&pb); + if (err != noErr) + goto ErrorExit; + + pb.hFileInfo.ioFlCrDat -= gJanuaryFirst1970Seconds; + LL_I2L(dateInMicroSeconds, pb.hFileInfo.ioFlCrDat); + LL_I2L(oneMillion, PR_USEC_PER_SEC); + LL_MUL(info->creationTime, oneMillion, dateInMicroSeconds); + + pb.hFileInfo.ioFlMdDat -= gJanuaryFirst1970Seconds; + LL_I2L(dateInMicroSeconds, pb.hFileInfo.ioFlMdDat); + LL_MUL(info->modifyTime, oneMillion, dateInMicroSeconds); + + return 0; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return -1; +} + +PRInt32 _MD_Stat(const char *path, struct stat *buf) +{ + OSErr err; + char *macFileName = NULL; + + err = ConvertUnixPathToMacPath(path, &macFileName); + if (err != noErr) + goto ErrorExit; + + err = stat(macFileName, buf); + if (err != noErr) + goto ErrorExit; + + PR_DELETE(macFileName); + + return 0; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return -1; +} + +PRStatus _MD_LockFile(PRInt32 fd) +{ + OSErr err; + FCBPBRec fcbpb; + HFileParam fpb; + Str255 pascalName; + + fcbpb.ioNamePtr = pascalName; + fcbpb.ioVRefNum = 0; + fcbpb.ioRefNum = fd; + fcbpb.ioFCBIndx = 0; + + err = PBGetFCBInfoSync(&fcbpb); + if (err != noErr) + goto ErrorExit; + + fpb.ioCompletion = NULL; + fpb.ioNamePtr = pascalName; + fpb.ioVRefNum = fcbpb.ioFCBVRefNum; + fpb.ioDirID = fcbpb.ioFCBParID; + + err = PBHSetFLockSync((HParmBlkPtr)&fpb); + if (err != noErr) + goto ErrorExit; + + return PR_SUCCESS; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return PR_FAILURE; +} + +PRStatus _MD_TLockFile(PRInt32 fd) +{ + return (_MD_LockFile(fd)); +} + +PRStatus _MD_UnlockFile(PRInt32 fd) +{ + OSErr err; + FCBPBRec fcbpb; + HFileParam fpb; + Str255 pascalName; + + fcbpb.ioNamePtr = pascalName; + fcbpb.ioVRefNum = 0; + fcbpb.ioRefNum = fd; + fcbpb.ioFCBIndx = 0; + + err = PBGetFCBInfoSync(&fcbpb); + if (err != noErr) + goto ErrorExit; + + fpb.ioCompletion = NULL; + fpb.ioNamePtr = pascalName; + fpb.ioVRefNum = fcbpb.ioFCBVRefNum; + fpb.ioDirID = fcbpb.ioFCBParID; + + err = PBHRstFLockSync((HParmBlkPtr)&fpb); + if (err != noErr) + goto ErrorExit; + + return PR_SUCCESS; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return PR_FAILURE; +} + +void SetLogFileTypeCreator(const char *logFile) +{ + HParamBlockRec pb; + OSErr err; + Str31 pName; + + PStrFromCStr(logFile, pName); + pb.fileParam.ioCompletion = nil; + pb.fileParam.ioNamePtr = pName; + pb.fileParam.ioVRefNum = 0; + pb.fileParam.ioFDirIndex = 0; + pb.fileParam.ioDirID = 0; + err = PBHGetFInfoSync(&pb); + PR_ASSERT(err == noErr); + + pb.fileParam.ioDirID = 0; + pb.fileParam.ioFlFndrInfo.fdType = 'TEXT'; + pb.fileParam.ioFlFndrInfo.fdCreator = 'ttxt'; + err = PBHSetFInfoSync(&pb); + PR_ASSERT(err == noErr); +} + +#if DEVELOPER_DEBUG +PR_IMPLEMENT (void) +SetupMacPrintfLog(char *logFile) +{ + /* + * We do _PR_InitLog() twice. The first to force the implicit initialization which + * will set logging to highest levels in _MD_EARLY_INIT. Then, change the env variable + * to disable kernel logging and call _PR_InitLog() again to make it effective. Since + * we are using logging to log test program output, we disable kernel logging to avoid + * all Kernel logging output. + */ +#ifdef PR_INTERNAL_LOGGING + _PR_InitLog(); + _MD_PutEnv("NSPR_LOG_MODULES=clock:0,cmon:0,io:0,mon:0,linker:0,cvar:0,sched:0,thread:0"); + _PR_InitLog(); +#endif + PR_ASSERT(PR_SetLogFile(logFile) == PR_TRUE); + + SetLogFileTypeCreator(logFile); +} +#endif + + +/* +********************** Old name related stuff that is unchanged. ********************** +*/ + +#if !defined(MAC_NSPR_STANDALONE) + +short GetVolumeRefNumFromName(const char *cTgtVolName) +{ + OSErr err; + Str32 pVolName; + char *cVolName = NULL; + HParamBlockRec hPB; + short refNum = 0; + + hPB.volumeParam.ioVolIndex = 0; + hPB.volumeParam.ioNamePtr = pVolName; + do { + hPB.volumeParam.ioVolIndex++; + err = PBHGetVInfoSync(&hPB); + CStrFromPStr(pVolName, &cVolName); + if (strcmp(cTgtVolName, cVolName) == 0) { + refNum = hPB.volumeParam.ioVRefNum; + PR_DELETE(cVolName); + break; + } + PR_DELETE(cVolName); + } while (err == noErr); + + return refNum; +} + +static OSErr CreateMacPathFromUnixPath(const char *unixPath, char **macPath) +{ + // Given a Unix style path with '/' directory separators, this allocates + // a path with Mac style directory separators in the path. + // + // It does not do any special directory translation; use ConvertUnixPathToMacPath + // for that. + + const char *src; + char *tgt; + OSErr err = noErr; + + PR_ASSERT(unixPath != nil); + if (nil == unixPath) { + err = paramErr; + goto exit; + } + + // If unixPath is a zero-length string, we copy ":" into + // macPath, so we need a minimum of two bytes to handle + // the case of ":". + *macPath = malloc(strlen(unixPath) + 2); // Will be enough extra space. + require_action (*macPath != NULL, exit, err = memFullErr;); + + src = unixPath; + tgt = *macPath; + + if (PL_strchr(src, PR_DIRECTORY_SEPARATOR) == src) // If weÕre dealing with an absolute + src++; // path, skip the separator + else + *(tgt++) = PR_PATH_SEPARATOR; + + if (PL_strstr(src, UNIX_THIS_DIRECTORY_STR) == src) // If it starts with / + src += 2; // skip it. + + while (*src) + { // deal with the rest of the path + if (PL_strstr(src, UNIX_PARENT_DIRECTORY_STR) == src) { // Going up? + *(tgt++) = PR_PATH_SEPARATOR; // simply add an extra colon. + src +=3; + } + else if (*src == PR_DIRECTORY_SEPARATOR) { // Change the separator + *(tgt++) = PR_PATH_SEPARATOR; + src++; + } + else + *(tgt++) = *(src++); + } + + *tgt = NULL; // make sure itÕs null terminated. + +exit: + return err; +} + + +static ProcessInfoRec gNavigatorProcInfo; +static FSSpec gGutsFolder; +static FSSpec gNetscapeFolder; + +static OSErr SetupRequiredFSSpecs(void) +{ + OSErr err; + CInfoPBRec pb; + ProcessSerialNumber curPSN = {0, kCurrentProcess}; + + gNavigatorProcInfo.processInfoLength = sizeof(ProcessInfoRec); + gNavigatorProcInfo.processName = NULL; + gNavigatorProcInfo.processAppSpec = &gNetscapeFolder; + + err = GetProcessInformation (&curPSN, &gNavigatorProcInfo); + if (err != noErr) + goto ErrorExit; + + /* guts folder resides at the same place as the app file itself */ + gGutsFolder = gNetscapeFolder; + /* How else do we do this hack??? + * Should NSPR have a string resource for this ? + */ + GetIndString( gGutsFolder.name, 300, 34); + + /* + * vRefNum and parentDirID are now set up correctly for the app file itself. + * parentDirID is the Netscape Folder's ID. Then Find it's parent ID to + * set up the FSSpec and its own name. + */ + + pb.dirInfo.ioCompletion = NULL; + pb.dirInfo.ioNamePtr = gNetscapeFolder.name; + pb.dirInfo.ioVRefNum = gNetscapeFolder.vRefNum; + pb.dirInfo.ioFDirIndex = -1; + pb.dirInfo.ioDrDirID = gNetscapeFolder.parID; + + err = PBGetCatInfoSync(&pb); + if (err != noErr) + goto ErrorExit; + + gNetscapeFolder.parID = pb.dirInfo.ioDrParID; + + return noErr; + +ErrorExit: + return err; +} + +static OSErr FindGutsFolder(FSSpec *foundSpec) +{ + OSErr err; + + if (gNavigatorProcInfo.processInfoLength == 0) { /* Uninitialized? */ + err = SetupRequiredFSSpecs(); + if (err != noErr) + goto ErrorExit; + } + + *foundSpec = gGutsFolder; + + return noErr; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + return err; +} + +static OSErr FindNetscapeFolder(FSSpec *foundSpec) +{ + OSErr err; + + if (gNavigatorProcInfo.processInfoLength == 0) { /* Uninitialized? */ + err = SetupRequiredFSSpecs(); + if (err != noErr) + goto ErrorExit; + } + + *foundSpec = gNetscapeFolder; + + return noErr; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + return err; +} + + +PR_IMPLEMENT (OSErr) +ConvertUnixPathToMacPath(const char *unixPath, char **macPath) +{ + OSErr err = noErr; + + // ******** HACK ALERT ******** + // + // Java really wants long file names (>31 chars). We truncate file names + // greater than 31 characters long. Truncation is from the middle. + // + // Convert UNIX style path names (with . and / separators) into a Macintosh + // style path (with :). + // + // There are also a couple of special paths that need to be dealt with + // by translating them to the appropriate Mac special folders. These include: + // + // /usr/tmp/file => {TempFolder}file + // + // The file conversions we need to do are as follows: + // + // file => file + // dir/file => :dir:file + // ./file => file + // ../file => ::file + // ../dir/file => ::dir:file + // /file => ::BootDrive:file + // /dir/file => ::BootDrive:dir:file + + + if (!strcmp(unixPath, ".")) + { + *macPath = malloc(sizeof(":")); + if (*macPath == NULL) + err = memFullErr; + (*macPath)[0] = ':'; + (*macPath)[1] = '\0'; + } + else + + if (*unixPath != PR_DIRECTORY_SEPARATOR) { // Not root relative, just convert it. + err = CreateMacPathFromUnixPath(unixPath, macPath); + } + + else { + // WeÕre root-relative. This is either a special Unix directory, or a + // full path (which weÕll support on the Mac since they might be generated). + // This is not condoning the use of full-paths on the Macintosh for file + // specification. + + FSSpec foundSpec; + short pathBufferSize; +#if DEBUG + char *temp; +#endif + int tempLen; + + // Are we dealing with the temp folder? + if ((strncmp(unixPath, "/usr/tmp", strlen("/usr/tmp")) == 0) || + ((strncmp(unixPath, "/tmp", strlen("/tmp")) == 0))) { + CInfoPBRec pb; + + unixPath = PL_strchr(unixPath, PR_DIRECTORY_SEPARATOR); + if (strncmp(unixPath, "/tmp", strlen("/tmp")) == 0) // skip past temp spec + unixPath += 5; + else + unixPath += 9; + + err = FindFolder(kOnSystemDisk, kTemporaryFolderType, kCreateFolder, // Create if needed + &foundSpec.vRefNum, &foundSpec.parID); + if (err == noErr) { + pb.dirInfo.ioCompletion = NULL; + pb.dirInfo.ioNamePtr = foundSpec.name; + pb.dirInfo.ioVRefNum = foundSpec.vRefNum; + pb.dirInfo.ioFDirIndex = -1; + pb.dirInfo.ioDrDirID = foundSpec.parID; + + err = PBGetCatInfoSync(&pb); + foundSpec.parID = pb.dirInfo.ioDrParID; + } + } + + else if (!strncmp(unixPath, "/usr/local/netscape/", (tempLen = strlen("/usr/local/netscape/")))) { + + unixPath += tempLen; + + if (!strncmp(unixPath, "RequiredGuts/", (tempLen = strlen("RequiredGuts/")))) + { + unixPath += tempLen; + err = FindGutsFolder(&foundSpec); + } + else if (!strncmp(unixPath, "bin/", (tempLen = strlen("bin/")))) + { + unixPath += tempLen; + err = FindNetscapeFolder(&foundSpec); + } + else if (*unixPath == '\0') + { + // it's /usr/local/netscape + err = FindGutsFolder(&foundSpec); + } + + } + + else { + // This is a root relative directory, weÕll just convert the whole thing. + err = CreateMacPathFromUnixPath(unixPath, macPath); + goto Exit_ConvertUnixPathToMacPath; + } + + + + // WeÕre dealing with a special folder + if (err == noErr) + { + Handle hPathStr; + // Get the path to the root-relative directory + err = FSpGetFullPath(&foundSpec, &pathBufferSize, &hPathStr); // NewHandle's hPathStr + + if (noErr == err) + { + // convert handle to c-string + // add one for NULL termination + // pathBufferSize is now one greater than the length of the string + pathBufferSize++; + + *macPath = (char*) malloc(sizeof(char) * pathBufferSize); + (*macPath)[pathBufferSize - 1] = '\0'; + BlockMoveData(*hPathStr, *macPath, pathBufferSize - 1); + + DisposeHandle(hPathStr); + } + } + + if (err == noErr) + { + UInt32 unixPathLeft; + UInt32 macPathLen; + + unixPathLeft = strlen(unixPath); + macPathLen = strlen(*macPath); + + + // copy over the remaining file name, converting + if (pathBufferSize - 1 < macPathLen + unixPathLeft) + { + // need to grow string + *macPath = realloc(*macPath, macPathLen + unixPathLeft + 1); + err = (*macPath == NULL ? memFullErr : noErr); + } + + if (err == noErr) + { + // carefully remove the '/''s out of the unix path. If we see an "escaped" / + // we will leave it in there, otherwise we take it out and replace it with a : + // we have to do this before we convert to a mac-path, so we can tell what is + // really a path separator and what is in the name of a file or directory + // Make sure that all of the /Õs are :Õs in the final pathname + // effectively we do a + // strcat(*macPath, unixPath); while replace all occurrences of / with : in unixPath + char* dp; + const char* sp; + + sp = unixPath; + dp = *macPath + macPathLen; + + for (;*sp != '\0'; sp++, dp++) + { + if (*sp == PR_DIRECTORY_SEPARATOR) + { + // if we can look at the previous character + if (sp > unixPath) + { + // check to see if previous character is an escape + if (sp[-1] == '\\') + { + // leave it in, and cycle + continue; + } + else + { + *dp = PR_PATH_SEPARATOR; + } + } + else + *dp = PR_PATH_SEPARATOR; + } + else + { + // just copy; + *dp = *sp; + } + } + + *dp = '\0'; // NULL terminate *macPath + } +#if DEBUG + // we used to check here, now we check above, we leave this in + // the debug build to make sure we didn't screw up + // Make sure that all of the /Õs are :Õs in the final pathname + for (temp = *macPath + strlen(*macPath) - strlen(unixPath); *temp != '\0'; temp++) { + + if (*temp == PR_DIRECTORY_SEPARATOR) + { + DebugStr("\pFound a slash"); + *temp = PR_PATH_SEPARATOR; + } + } +#endif + } + } + + +Exit_ConvertUnixPathToMacPath: + + return err; +} + +// Hey! Before you delete this "hack" you should look at how it's being +// used by sun-java/netscape/applet/appletStubs.c. +PR_IMPLEMENT (OSErr) +ConvertMacPathToUnixPath(const char *macPath, char **unixPath) +{ + // *** HACK *** + // Get minimal version working + + char *unixPathPtr; + + *unixPath = malloc(strlen(macPath) + 2); // Add one for the front slash, one for null + if (*unixPath == NULL) + return (memFullErr); + + unixPathPtr = *unixPath; + + *unixPathPtr++ = PR_DIRECTORY_SEPARATOR; + + do { + // Translate all colons to slashes + if (*macPath == PR_PATH_SEPARATOR) + *unixPathPtr = PR_DIRECTORY_SEPARATOR; + else + *unixPathPtr = *macPath; + + unixPathPtr++; + macPath++; + } while (*macPath != NULL); + + // Terminate the string + *unixPathPtr = '\0'; + + return (noErr); +} + +OSErr +ConvertUnixPathToFSSpec(const char *unixPath, FSSpec *fileSpec) +{ + char* macPath; + OSErr convertError; + int len; + + convertError = ConvertUnixPathToMacPath(unixPath, &macPath); + if (convertError != noErr) + return convertError; + + len = strlen(macPath); + + if (*macPath == PR_PATH_SEPARATOR) + { + if (len < sizeof(Str255)) + { + short vRefNum; + long dirID; + Str255 pascalMacPath; + + convertError = HGetVol(NULL, &vRefNum, &dirID); + if (convertError == noErr) + { + PStrFromCStr(macPath, pascalMacPath); + convertError = FSMakeFSSpec(vRefNum, dirID, pascalMacPath, fileSpec); + } + } + else + convertError = paramErr; + } + else + { + convertError = FSpLocationFromFullPath(len, macPath, fileSpec); + if (convertError == fnfErr) + { + CInfoPBRec pb; + Str255 pascalMacPath; + OSErr err; + + PStrFromCStr(macPath, pascalMacPath); + /* + FSpLocationFromFullPath does not work for directories unless there is + a ":" at the end. We will make sure of an existence of a directory. + If so, the returned fileSpec is valid from FSpLocationFromFullPath eventhough + it returned an error. + */ + pb.hFileInfo.ioNamePtr = pascalMacPath; + pb.hFileInfo.ioVRefNum = 0; + pb.hFileInfo.ioDirID = 0; + pb.hFileInfo.ioFDirIndex = 0; + + err = PBGetCatInfoSync(&pb); + if (err == noErr) + convertError = noErr; + } + } + + free(macPath); + + return (convertError); +} + + +FILE *_OS_FOPEN(const char *filename, const char *mode) +{ + OSErr err = noErr; + char *macFileName = NULL; + FILE *result; + + err = ConvertUnixPathToMacPath(filename, &macFileName); + if (err != noErr) + goto ErrorExit; + + result = fopen(macFileName, mode); + + PR_DELETE(macFileName); + + return result; + +ErrorExit: + _PR_MD_CURRENT_THREAD()->md.osErrCode = err; + _MD_SetError(err); + return NULL; +} + +#else + +short GetVolumeRefNumFromName(const char *cTgtVolName) +{ + OSErr err; + Str32 pVolName; + char *cVolName = NULL; + HParamBlockRec hPB; + short refNum = 0; + + hPB.volumeParam.ioVolIndex = 0; + hPB.volumeParam.ioNamePtr = pVolName; + do { + hPB.volumeParam.ioVolIndex++; + err = PBHGetVInfoSync(&hPB); + CStrFromPStr(pVolName, &cVolName); + if (strcmp(cTgtVolName, cVolName) == 0) { + refNum = hPB.volumeParam.ioVRefNum; + PR_DELETE(cVolName); + break; + } + PR_DELETE(cVolName); + } while (err == noErr); + + return refNum; +} + + + +static OSErr GetFullPath(short vRefNum, long dirID, char **fullPath, int *strSize) +{ + Str255 pascalDirName; + char cDirName[256]; + char *tmpPath = NULL; // needed since sprintf isnÕt safe + CInfoPBRec myPB; + OSErr err = noErr; + + + // get the full path of the temp folder. + *strSize = 256; + *fullPath = NULL; + *fullPath = malloc(*strSize); // How big should this thing be? + require_action (*fullPath != NULL, errorExit, err = memFullErr;); + + tmpPath = malloc(*strSize); + require_action (tmpPath != NULL, errorExit, err = memFullErr;); + + strcpy(*fullPath, ""); // Clear C result + strcpy(tmpPath, ""); + pascalDirName[0] = 0; // Clear Pascal intermediate string + + myPB.dirInfo.ioNamePtr = &pascalDirName[0]; + myPB.dirInfo.ioVRefNum = vRefNum; + myPB.dirInfo.ioDrParID = dirID; + myPB.dirInfo.ioFDirIndex = -1; // Getting info about + + do { + myPB.dirInfo.ioDrDirID = myPB.dirInfo.ioDrParID; + + err = PBGetCatInfoSync(&myPB); + require(err == noErr, errorExit); + + // Move the name into C domain + memcpy(&cDirName, &pascalDirName, 256); + p2cstr((unsigned char *)&cDirName); // Changes in place! + + if ((strlen(cDirName) + strlen(*fullPath)) > *strSize) { + // We need to grow the string, do it in 256 byte chunks + (*strSize) += 256; + *fullPath = PR_REALLOC(*fullPath, *strSize); + require_action (*fullPath != NULL, errorExit, err = memFullErr;); + + tmpPath = PR_REALLOC(tmpPath, *strSize); + require_action (tmpPath != NULL, errorExit, err = memFullErr;); + } + sprintf(tmpPath, "%s:%s", cDirName, *fullPath); + strcpy(*fullPath, tmpPath); + } while (myPB.dirInfo.ioDrDirID != fsRtDirID); + + PR_DELETE(tmpPath); + + return noErr; + + +errorExit: + PR_DELETE(*fullPath); + PR_DELETE(tmpPath); + + return err; + +} + +static OSErr CreateMacPathFromUnixPath(const char *unixPath, char **macPath) +{ + // Given a Unix style path with '/' directory separators, this allocates + // a path with Mac style directory separators in the path. + // + // It does not do any special directory translation; use ConvertUnixPathToMacPath + // for that. + + const char *src; + char *tgt; + OSErr err = noErr; + + PR_ASSERT(unixPath != nil); + if (nil == unixPath) { + err = paramErr; + goto exit; + } + + // If unixPath is a zero-length string, we copy ":" into + // macPath, so we need a minimum of two bytes to handle + // the case of ":". + *macPath = malloc(strlen(unixPath) + 2); // Will be enough extra space. + require_action (*macPath != NULL, exit, err = memFullErr;); + + src = unixPath; + tgt = *macPath; + + if (PL_strchr(src, PR_DIRECTORY_SEPARATOR) == src) // If weÕre dealing with an absolute + src++; // path, skip the separator + else + *(tgt++) = PR_PATH_SEPARATOR; + + if (PL_strstr(src, UNIX_THIS_DIRECTORY_STR) == src) // If it starts with ./ + src += 2; // skip it. + + while (*src) + { // deal with the rest of the path + if (PL_strstr(src, UNIX_PARENT_DIRECTORY_STR) == src) { // Going up? + *(tgt++) = PR_PATH_SEPARATOR; // simply add an extra colon. + src +=3; + } + else if (*src == PR_DIRECTORY_SEPARATOR) { // Change the separator + *(tgt++) = PR_PATH_SEPARATOR; + src++; + } + else + *(tgt++) = *(src++); + } + + *tgt = NULL; // make sure itÕs null terminated. + +exit: + return err; +} + +static OSErr ConvertUnixPathToMacPath(const char *unixPath, char **macPath) +{ + OSErr err = noErr; + + + // + // Convert UNIX style path names (with . and / separators) into a Macintosh + // style path (with :). + // + // There are also a couple of special paths that need to be dealt with + // by translating them to the appropriate Mac special folders. These include: + // + // /usr/tmp/file => {TempFolder}file + // + // The file conversions we need to do are as follows: + // + // file => file + // dir/file => :dir:file + // ./file => file + // ../file => ::file + // ../dir/file => ::dir:file + // /file => ::BootDrive:file + // /dir/file => ::BootDrive:dir:file + + + if (*unixPath != PR_DIRECTORY_SEPARATOR) { // Not root relative, just convert it. + err = CreateMacPathFromUnixPath(unixPath, macPath); + } + + else { + // WeÕre root-relative. This is either a special Unix directory, or a + // full path (which weÕll support on the Mac since they might be generated). + // This is not condoning the use of full-paths on the Macintosh for file + // specification. + + short foundVRefNum; + long foundDirID; + int pathBufferSize; + char *temp; + char isNetscapeDir = false; + + // Are we dealing with the temp folder? + if (strncmp(unixPath, "/usr/tmp", strlen("/usr/tmp")) == 0){ + unixPath += 8; + if (*unixPath == PR_DIRECTORY_SEPARATOR) + unixPath++; // Skip the slash + err = FindFolder(kOnSystemDisk, kTemporaryFolderType, kCreateFolder, // Create if needed + &foundVRefNum, &foundDirID); + } + + if (strncmp(unixPath, "/tmp", strlen("/tmp")) == 0) { + unixPath += 4; // Skip the slash + if (*unixPath == PR_DIRECTORY_SEPARATOR) + unixPath++; // Skip the slash + err = FindFolder(kOnSystemDisk, kTemporaryFolderType, kCreateFolder, // Create if needed + &foundVRefNum, &foundDirID); + } + + else if (strncmp(unixPath, "/usr", strlen("/usr")) == 0) { + + int usrNetscapePathLen; + + usrNetscapePathLen = strlen("/usr/local/netscape/"); + + if (strncmp(unixPath, "/usr/local/netscape/", usrNetscapePathLen) == 0) { + unixPath += usrNetscapePathLen; +// err = FindPreferencesFolder(&foundVRefNum, &foundDirID); + err = paramErr; + isNetscapeDir = true; + } + + else { + dprintf("Unable to translate Unix file path %s to Mac path\n", unixPath); + err = -1; + goto Exit_ConvertUnixPathToMacPath; + } + + } + + else { + // This is a root relative directory, weÕll just convert the whole thing. + err = CreateMacPathFromUnixPath(unixPath, macPath); + goto Exit_ConvertUnixPathToMacPath; + } + + // WeÕre dealing with a special folder + if (err == noErr) + // Get the path to the root-relative directory + err = GetFullPath(foundVRefNum, foundDirID, macPath, &pathBufferSize); // mallocs macPath + + if (err == noErr){ + + // copy over the remaining file name, converting + if (pathBufferSize < (strlen(*macPath) + strlen(unixPath))) { + // need to grow string + *macPath = PR_REALLOC(*macPath, (strlen(*macPath) + strlen(unixPath) + + (isNetscapeDir ? strlen("Netscape Ä:") : 0))); + err = (*macPath == NULL ? memFullErr : noErr); + } + + if (isNetscapeDir) + strcat(*macPath, "Netscape Ä:"); + + if (err == noErr) + strcat(*macPath, unixPath); + + // Make sure that all of the /Õs are :Õs in the final pathname + + for (temp = *macPath + strlen(*macPath) - strlen(unixPath); *temp != '\0'; temp++) { + if (*temp == PR_DIRECTORY_SEPARATOR) + *temp = PR_PATH_SEPARATOR; + } + + } + } + + +Exit_ConvertUnixPathToMacPath: + + return err; +} + +OSErr +ConvertUnixPathToFSSpec(const char *unixPath, FSSpec *fileSpec) +{ + char* macPath; + OSErr convertError; + int len; + + convertError = ConvertUnixPathToMacPath(unixPath, &macPath); + if (convertError != noErr) + return convertError; + + len = strlen(macPath); + + if (*macPath == PR_PATH_SEPARATOR) + { + if (len < sizeof(Str255)) + { + short vRefNum; + long dirID; + Str255 pascalMacPath; + + convertError = HGetVol(NULL, &vRefNum, &dirID); + if (convertError == noErr) + { + PStrFromCStr(macPath, pascalMacPath); + convertError = FSMakeFSSpec(vRefNum, dirID, pascalMacPath, fileSpec); + } + } + else + convertError = paramErr; + } + else + { + convertError = FSpLocationFromFullPath(len, macPath, fileSpec); + } + + free(macPath); + + return (convertError); +} + + +#endif + +/* + ********************************************************************** + * + * Memory-mapped files are not implementable on the Mac. + * + ********************************************************************** + */ + +PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size) +{ +#pragma unused (fmap, size) + + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PRInt32 _MD_GetMemMapAlignment(void) +{ + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return -1; +} + +void * _MD_MemMap( + PRFileMap *fmap, + PROffset64 offset, + PRUint32 len) +{ +#pragma unused (fmap, offset, len) + + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return NULL; +} + +PRStatus _MD_MemUnmap(void *addr, PRUint32 len) +{ +#pragma unused (addr, len) + + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} + +PRStatus _MD_CloseFileMap(PRFileMap *fmap) +{ +#pragma unused (fmap) + + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); + return PR_FAILURE; +} |