/* -*- 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 #include #include #include #include #include #include #include #include #include #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 ); ** 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; }