📄 macio.c
字号:
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* * 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 Netscape are * Copyright (C) 1998-2000 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */#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誸 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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -