Back to index

lightning-sunbird  0.9+nobinonly
macio.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include <string.h>
00039 
00040 #include <Types.h>
00041 #include <Files.h>
00042 #include <Devices.h>
00043 #include <Folders.h>
00044 #include <Errors.h>
00045 #include <Resources.h>
00046 #include <Processes.h>
00047 #include <TextUtils.h>
00048 
00049 #include <fcntl.h>
00050 
00051 #include "FullPath.h"              /* MoreFiles */
00052 
00053 #include "primpl.h"
00054 #include "MacErrorHandling.h"
00055 #include "mdmac.h"
00056 
00057 #include "macio.h"
00058 
00059 /* forward declarations */
00060 extern unsigned long gJanuaryFirst1970Seconds;
00061 
00062 extern void WaitOnThisThread(PRThread *thread, PRIntervalTime timeout);
00063 extern void DoneWaitingOnThisThread(PRThread *thread);
00064 extern void AsyncNotify(PRThread *thread);
00065 
00066 
00067 /* PB for Read and Write */
00068 struct ExtendedParamBlock {
00069        /* PB must be first so that the file system can get the right data. */
00070        ParamBlockRec        pb;
00071        PRThread             *thread;
00072 };
00073 typedef struct ExtendedParamBlock ExtendedParamBlock;
00074 
00075 
00076 /* XXX Not done yet for 68K */
00077 /* I/O completion routne for _MD_READ and _MD_WRITE */
00078 static void AsyncIOCompletion (ExtendedParamBlock *pbAsyncPtr)
00079 {
00080     _PRCPU *cpu = _PR_MD_CURRENT_CPU();
00081     PRThread *thread = pbAsyncPtr->thread;    
00082     PRIntn is;
00083     
00084     if (_PR_MD_GET_INTSOFF()) {
00085         thread->md.missedIONotify = PR_TRUE;
00086         cpu->u.missed[cpu->where] |= _PR_MISSED_IO;
00087     } else {
00088         _PR_INTSOFF(is);
00089 
00090         thread->md.osErrCode = noErr;
00091         DoneWaitingOnThisThread(thread);
00092 
00093         _PR_FAST_INTSON(is);
00094     }
00095 
00096     SignalIdleSemaphore();
00097 }
00098 
00099 void  _MD_SetError(OSErr oserror)
00100 {
00101     PRErrorCode code;
00102 
00103     switch (oserror) {
00104       case memFullErr:
00105         code = PR_OUT_OF_MEMORY_ERROR;
00106         break;
00107       case fnfErr:
00108         code = PR_FILE_NOT_FOUND_ERROR;
00109         break;
00110       case dupFNErr:
00111         code = PR_FILE_EXISTS_ERROR;
00112         break;
00113       case ioErr:
00114         code = PR_IO_ERROR;
00115         break;
00116       case nsvErr:
00117       case wrgVolTypErr:
00118         code = PR_INVALID_DEVICE_STATE_ERROR;
00119         break;
00120       case bdNamErr:
00121       case fsRnErr:
00122         code = PR_NAME_TOO_LONG_ERROR;
00123         break;
00124       case tmfoErr:
00125         code = PR_INSUFFICIENT_RESOURCES_ERROR;
00126         break;
00127       case opWrErr:
00128       case wrPermErr:
00129       case permErr:
00130       case afpAccessDenied:
00131         code = PR_NO_ACCESS_RIGHTS_ERROR;
00132         break;
00133       case afpObjectTypeErr:
00134         code = PR_DIRECTORY_LOOKUP_ERROR;
00135         break;
00136       case wPrErr:
00137       case vLckdErr:
00138         code = PR_DEVICE_IS_LOCKED_ERROR;
00139         break;
00140       case fLckdErr:
00141         code = PR_FILE_IS_LOCKED_ERROR;
00142         break;
00143       case dirNFErr:
00144         code = PR_NOT_DIRECTORY_ERROR;
00145         break;
00146       case dirFulErr:
00147         code = PR_MAX_DIRECTORY_ENTRIES_ERROR;
00148         break;
00149       case dskFulErr:
00150         code = PR_NO_DEVICE_SPACE_ERROR;
00151         break;
00152       case rfNumErr:
00153       case fnOpnErr:
00154         code = PR_BAD_DESCRIPTOR_ERROR;
00155         break;
00156       case eofErr:
00157         code = PR_END_OF_FILE_ERROR;
00158         break;
00159       case posErr:
00160       case gfpErr:
00161         code = PR_FILE_SEEK_ERROR;
00162         break;
00163       case fBsyErr:
00164         code = PR_FILE_IS_BUSY_ERROR;
00165         break;
00166       case extFSErr:
00167         code = PR_REMOTE_FILE_ERROR;
00168         break;
00169       case abortErr:
00170         code = PR_PENDING_INTERRUPT_ERROR;
00171         break;
00172       case paramErr:
00173         code = PR_INVALID_ARGUMENT_ERROR;
00174         break;
00175       case unimpErr:
00176         code = PR_NOT_IMPLEMENTED_ERROR;
00177         break;
00178     }
00179 
00180     PR_SetError(code, oserror);
00181 }
00182 
00183 void _MD_IOInterrupt(void)
00184 {
00185     PRCList *qp;
00186     PRThread *thread, *me = _PR_MD_CURRENT_THREAD();
00187 
00188     PR_ASSERT(_PR_MD_GET_INTSOFF() != 0);
00189 
00190     _PR_SLEEPQ_LOCK(me->cpu);
00191     qp = _PR_PAUSEQ(me->cpu).next;
00192     while (qp != &_PR_PAUSEQ(me->cpu)) {
00193 
00194               thread = _PR_THREAD_PTR(qp);
00195               PR_ASSERT(thread->flags & _PR_ON_PAUSEQ);
00196 
00197               qp = qp->next;
00198               
00199               if (thread->md.missedIONotify) {
00200                      thread->md.missedIONotify = PR_FALSE;
00201                      DoneWaitingOnThisThread(thread);
00202               }
00203 
00204               if (thread->md.missedAsyncNotify) {
00205                      thread->md.missedAsyncNotify = PR_FALSE;
00206                      AsyncNotify(thread);
00207               }
00208     }
00209     qp = _PR_SLEEPQ(me->cpu).next;
00210     while (qp != &_PR_SLEEPQ(me->cpu)) {
00211 
00212               thread = _PR_THREAD_PTR(qp);
00213               PR_ASSERT(thread->flags & _PR_ON_SLEEPQ);
00214 
00215               qp = qp->next;
00216               
00217               if (thread->md.missedIONotify) {
00218                      thread->md.missedIONotify = PR_FALSE;
00219                      DoneWaitingOnThisThread(thread);
00220               }
00221 
00222               if (thread->md.missedAsyncNotify) {
00223                      thread->md.missedAsyncNotify = PR_FALSE;
00224                      AsyncNotify(thread);
00225               }
00226     }
00227        _PR_SLEEPQ_UNLOCK(thread->cpu);
00228 }
00229 
00230 /* 
00231 ** All PR_read and PR_Write calls are synchronous from caller's perspective.
00232 ** They are internally made asynchronous calls.  This gives cpu to other
00233 ** user threads while the async io is in progress.
00234 */
00235 PRInt32 ReadWriteProc(PRFileDesc *fd, void *buf, PRUint32 bytes, IOOperation op)
00236 {
00237        PRInt32 refNum = fd->secret->md.osfd;
00238        OSErr                       err;
00239        ExtendedParamBlock   pbAsync;
00240        PRThread                    *me = _PR_MD_CURRENT_THREAD();
00241        _PRCPU *cpu = _PR_MD_CURRENT_CPU();
00242 
00243        /* quick hack to allow PR_fprintf, etc to work with stderr, stdin, stdout */
00244        /* note, if a user chooses "seek" or the like as an operation in another function */
00245        /* this will not work */
00246        if (refNum >= 0 && refNum < 3)
00247        {
00248               switch (refNum)
00249               {
00250                             case 0:
00251                                    /* stdin - not on a Mac for now */
00252                                    err = paramErr;
00253                                    goto ErrorExit;
00254                                    break;
00255                             case 1: /* stdout */
00256                             case 2: /* stderr */
00257                                    puts(buf);
00258                                    break;
00259               }
00260               
00261               return (bytes);
00262        }
00263        else
00264        {
00265               static IOCompletionUPP      sCompletionUPP = NULL;
00266               
00267               PRBool  doingAsync = PR_FALSE;
00268               
00269               /* allocate the callback Universal Procedure Pointer (UPP). This actually allocates
00270                  a 32 byte Ptr in the heap, so only do this once
00271               */
00272               if (!sCompletionUPP)
00273                      sCompletionUPP = NewIOCompletionUPP((IOCompletionProcPtr)&AsyncIOCompletion);
00274                      
00275               /* grab the thread so we know which one to post to at completion */
00276               pbAsync.thread       = me;
00277 
00278               pbAsync.pb.ioParam.ioCompletion    = sCompletionUPP;
00279               pbAsync.pb.ioParam.ioResult        = noErr;
00280               pbAsync.pb.ioParam.ioRefNum        = refNum;
00281               pbAsync.pb.ioParam.ioBuffer        = buf;
00282               pbAsync.pb.ioParam.ioReqCount      = bytes;
00283               pbAsync.pb.ioParam.ioPosMode       = fsAtMark;
00284               pbAsync.pb.ioParam.ioPosOffset     = 0;
00285 
00286               /* 
00287               ** Issue the async read call and wait for the io semaphore associated
00288               ** with this thread.
00289               ** Async file system calls *never* return error values, so ignore their
00290               ** results (see <http://developer.apple.com/technotes/fl/fl_515.html>);
00291               ** the completion routine is always called.
00292               */
00293               me->io_fd = refNum;
00294               me->md.osErrCode = noErr;
00295               if (op == READ_ASYNC)
00296               {
00297                      /*
00298                      **  Skanky optimization so that reads < 20K are actually done synchronously
00299                      **  to optimize performance on small reads (e.g. registry reads on startup)
00300                      */
00301                      if ( bytes > 20480L )
00302                      {
00303                             doingAsync = PR_TRUE;
00304                             me->io_pending = PR_TRUE;
00305                             
00306                             (void)PBReadAsync(&pbAsync.pb);
00307                      }
00308                      else
00309                      {
00310                             pbAsync.pb.ioParam.ioCompletion = NULL;
00311                             me->io_pending = PR_FALSE;
00312                             
00313                             err = PBReadSync(&pbAsync.pb);
00314                             if (err != noErr && err != eofErr)
00315                                    goto ErrorExit;
00316                      }
00317               }
00318               else
00319               {
00320                      doingAsync = PR_TRUE;
00321                      me->io_pending = PR_TRUE;
00322 
00323                      /* writes are currently always async */
00324                      (void)PBWriteAsync(&pbAsync.pb);
00325               }
00326               
00327               if (doingAsync) {
00328                      WaitOnThisThread(me, PR_INTERVAL_NO_TIMEOUT);
00329               }
00330        }
00331        
00332        err = me->md.osErrCode;
00333        if (err != noErr)
00334               goto ErrorExit;
00335 
00336        err = pbAsync.pb.ioParam.ioResult;
00337        if (err != noErr && err != eofErr)
00338               goto ErrorExit;
00339        
00340        return pbAsync.pb.ioParam.ioActCount;
00341 
00342 ErrorExit:
00343        me->md.osErrCode = err;
00344        _MD_SetError(err);
00345        return -1;
00346 }
00347 
00348 /*
00349 Special WriteSyncProc for logging only.  IO occurs synchronously.  Otherwise,
00350 logging internal to NSPR causes ReadWriteProc above to recurse on PR_WaitSem logging.
00351 */
00352 PRInt32 WriteSyncProc(PRFileDesc *fd, void *buf, PRUint32 bytes)
00353 {
00354        PRInt32                            refNum = fd->secret->md.osfd;
00355        OSErr                       err;
00356        ParamBlockRec               pb;
00357        PRThread                    *me = _PR_MD_CURRENT_THREAD();
00358        
00359        if (refNum >= 0 && refNum < 3)
00360        {
00361               PR_ASSERT(FALSE);    /* writing to these is hazardous to a Mac's health (refNum 2 is the system file) */
00362               err = paramErr;
00363               goto ErrorExit;
00364        }
00365 
00366        pb.ioParam.ioCompletion     = NULL;
00367        pb.ioParam.ioResult         = noErr;
00368        pb.ioParam.ioRefNum         = refNum;
00369        pb.ioParam.ioBuffer         = buf;
00370        pb.ioParam.ioReqCount       = bytes;
00371        pb.ioParam.ioPosMode = fsAtMark;
00372        pb.ioParam.ioPosOffset      = 0;
00373 
00374        err = PBWriteSync(&pb);
00375 
00376        if (err != noErr)
00377               goto ErrorExit;
00378        else
00379               return pb.ioParam.ioActCount;
00380 
00381 ErrorExit:
00382        me->md.osErrCode = err;
00383        _MD_SetError(err);
00384     return -1;
00385 }
00386 
00387 /* File I/O functions called by PR I/O routines */
00388 PRInt32 _MD_Open(const char *path, PRIntn flags, int mode)
00389 {
00390 // Macintosh doesn't really have mode bits, just drop them
00391 #pragma unused (mode)
00392 
00393        OSErr                       err;
00394        HParamBlockRec              hpb;
00395        ParamBlockRec               pb;
00396        char                        *macFileName = NULL;
00397        Str255                      pascalName;
00398        PRInt8                             perm;
00399 
00400     err = ConvertUnixPathToMacPath(path, &macFileName);
00401        
00402        if (err != noErr)
00403               goto ErrorExit;
00404 
00405        hpb.ioParam.ioCompletion    = NULL;
00406        PStrFromCStr(macFileName, pascalName);
00407        PR_DELETE(macFileName);
00408        hpb.ioParam.ioNamePtr       = pascalName;
00409        hpb.ioParam.ioVRefNum       = 0;
00410        hpb.ioParam.ioVersNum       = 0;
00411        hpb.fileParam.ioDirID       = 0;
00412 
00413        if (flags & PR_RDWR)
00414               perm = fsRdWrPerm;
00415        else if (flags & PR_WRONLY)
00416               perm = fsWrPerm;
00417        else
00418               perm = fsRdPerm;     
00419        hpb.ioParam.ioPermssn       = perm;
00420 
00421        
00422     if (flags & PR_CREATE_FILE) {
00423               err = PBHCreateSync(&hpb);
00424                
00425        /* If opening with the PR_EXCL flag the existence of the file prior to opening is an error */
00426        if ((flags & PR_EXCL) &&  (err == dupFNErr)) {
00427            err = PR_FILE_EXISTS_ERROR;
00428            goto ErrorExit;
00429        }
00430        
00431        if ((err != noErr) && (err != dupFNErr))
00432           goto ErrorExit;
00433        }
00434  
00435     err = PBHOpenDFSync(&hpb);
00436 
00437        if (err != noErr)
00438               goto ErrorExit;
00439 
00440        if (flags & PR_TRUNCATE) {
00441               pb.ioParam.ioCompletion = NULL;
00442               pb.ioParam.ioRefNum = hpb.ioParam.ioRefNum;
00443               pb.ioParam.ioMisc = NULL;
00444               err = PBSetEOFSync(&pb);
00445               if (err != noErr)
00446                      goto ErrorExit;
00447        } else if (flags & PR_APPEND) {
00448               pb.ioParam.ioCompletion = NULL;
00449               pb.ioParam.ioRefNum = hpb.ioParam.ioRefNum;
00450               pb.ioParam.ioPosMode = fsFromLEOF;
00451               pb.ioParam.ioPosOffset = 0;
00452               err = PBSetFPosSync(&pb);
00453               if (err != noErr)
00454                      goto ErrorExit;
00455        }
00456        return hpb.ioParam.ioRefNum;
00457               
00458 ErrorExit:
00459        _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
00460        _MD_SetError(err);
00461     return -1;
00462 }
00463 
00464 /* _MD_CLOSE_FILE, _MD_READ, _MD_WRITE, _MD_GET_FILE_ERROR are defined in _macos.h */
00465 
00466 PROffset32 _MD_LSeek(PRFileDesc *fd, PROffset32 offset, PRSeekWhence how)
00467 {
00468        PRInt32 refNum = fd->secret->md.osfd;
00469        OSErr  err = noErr;
00470        long   curPos, endPos;
00471 
00472        /* compute new mark */
00473        switch (how) {
00474               case PR_SEEK_SET:
00475                      endPos = offset;
00476                      break;
00477               
00478               case PR_SEEK_CUR:
00479                      err = GetFPos(refNum, &curPos);
00480                      endPos = curPos + offset;
00481                      break;
00482               
00483               case PR_SEEK_END:
00484                      err = GetEOF(refNum, &curPos);
00485                      endPos = curPos + offset;
00486                      break;
00487 
00488               default:
00489                      err = paramErr;
00490                      break;
00491        }
00492 
00493        /* set the new mark and extend the file if seeking beyond current EOF */
00494        /* making sure to set the mark after any required extend */
00495        if (err == noErr) {
00496               err = SetFPos(refNum, fsFromStart, endPos);
00497               if (err == eofErr) {
00498                      err = SetEOF(refNum, endPos);
00499                      if (err == noErr) {
00500                             err = SetFPos(refNum, fsFromStart, endPos);
00501                      }
00502               }
00503        }
00504 
00505        if (err == noErr) {
00506               return endPos;
00507        } else {
00508               _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
00509            _MD_SetError(err);
00510               return -1;
00511        }
00512 }
00513 
00514 PRInt32 _MD_FSync(PRFileDesc *fd)
00515 {
00516        PRInt32 refNum = fd->secret->md.osfd;
00517        OSErr  err;
00518        ParamBlockRec               pb;
00519 
00520        pb.ioParam.ioCompletion            = NULL;
00521        pb.ioParam.ioRefNum         = refNum;
00522 
00523        err = PBFlushFileSync(&pb);
00524        if (err != noErr)
00525               goto ErrorExit;
00526               
00527        return 0;
00528 
00529 ErrorExit:
00530        _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
00531        _MD_SetError(err);
00532     return -1;       
00533 }
00534 
00535 #include "plstr.h"
00536 
00537 PRStatus _MD_OpenDir(_MDDir *mdDir,const char *name)
00538 {
00539        // Emulate the Unix opendir() routine.
00540 
00541        OSErr                       err;
00542        CInfoPBRec                  pb;
00543        char                        *macDirName = NULL;
00544        char                        *position = NULL;
00545        char                        volumeName[32];
00546        Str255                      pascalName;
00547 
00548        // Get the Macintosh path
00549        err = ConvertUnixPathToMacPath(name, &macDirName);
00550        if (err != noErr)
00551               goto ErrorExit;
00552        
00553        // Get the vRefNum
00554        position = PL_strchr(macDirName, PR_PATH_SEPARATOR);
00555        if ((position == macDirName) || (position == NULL))
00556               mdDir->ioVRefNum = 0;                                                                      // Use application relative searching
00557        else {
00558               memset(volumeName, 0, sizeof(volumeName));
00559               strncpy(volumeName, macDirName, position-macDirName);
00560               mdDir->ioVRefNum = GetVolumeRefNumFromName(volumeName);
00561        }
00562 
00563        // Get info about the object.
00564        PStrFromCStr(macDirName, pascalName);
00565        PR_DELETE(macDirName);
00566        
00567        pb.dirInfo.ioNamePtr = pascalName;
00568        pb.dirInfo.ioVRefNum = mdDir->ioVRefNum;
00569        pb.dirInfo.ioDrDirID = 0;
00570        pb.dirInfo.ioFDirIndex = 0;
00571        err = PBGetCatInfoSync(&pb);
00572        if (err != noErr)
00573               goto ErrorExit;
00574               
00575        // Are we dealing with a directory?
00576        if ((pb.dirInfo.ioFlAttrib & ioDirMask) == 0) {
00577               err = dirNFErr;
00578               goto ErrorExit;
00579        }
00580        
00581        /* This is a directory, store away the pertinent information.
00582        ** We post increment.  I.e. index is always the nth. item we 
00583        ** should get on the next call
00584        */
00585        mdDir->ioDirID = pb.dirInfo.ioDrDirID;
00586        mdDir->currentEntryName = NULL;
00587        mdDir->ioFDirIndex = 1;
00588        return PR_SUCCESS;
00589        
00590 ErrorExit:
00591        _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
00592        _MD_SetError(err);
00593     return PR_FAILURE;
00594 }
00595 
00596 char *_MD_ReadDir(_MDDir *mdDir, PRIntn flags)
00597 {
00598        // Emulate the Unix readdir() routine.
00599 
00600        // Mac doesnÕt have the concept of .(PR_SKIP_DOT) & ..(PR_SKIP_DOT_DOT)
00601 
00602        OSErr                       err;
00603        CInfoPBRec                  pb;
00604        char                        *returnedCStr;
00605        Str255                      pascalName = "\p";
00606        PRBool                      foundEntry;
00607        
00608        PR_ASSERT(mdDir != NULL);
00609 
00610        do {
00611 
00612        // Release the last name read.
00613        PR_DELETE(mdDir->currentEntryName);
00614        mdDir->currentEntryName = NULL;
00615               
00616        // WeÕve got all the info we need, just get info about this guy.
00617        pb.hFileInfo.ioNamePtr = pascalName;
00618        pb.hFileInfo.ioVRefNum = mdDir->ioVRefNum;
00619        pb.hFileInfo.ioFDirIndex = mdDir->ioFDirIndex;
00620        pb.hFileInfo.ioDirID = mdDir->ioDirID;
00621        err = PBGetCatInfoSync(&pb);
00622        if (err != noErr)
00623               goto ErrorExit;
00624        
00625        // Convert the Pascal string to a C string (actual allocation occurs in CStrFromPStr)
00626        CStrFromPStr(pascalName, &returnedCStr);
00627        
00628        mdDir->currentEntryName = returnedCStr;
00629        mdDir->ioFDirIndex++;
00630        
00631        // If it is not a hidden file and the flags did not specify skipping, we are done.
00632        if ((flags & PR_SKIP_HIDDEN) && (pb.hFileInfo.ioFlFndrInfo.fdFlags & fInvisible))
00633               foundEntry = PR_FALSE;
00634        else
00635               foundEntry = PR_TRUE;       
00636        
00637        } while (!foundEntry);
00638        
00639        return (mdDir->currentEntryName);
00640 
00641 ErrorExit:
00642        _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
00643        _MD_SetError(err);
00644     return NULL;
00645 }
00646 
00647 
00648 void _MD_CloseDir(_MDDir *mdDir)
00649 {
00650        // Emulate the Unix closedir() routine
00651 
00652        PR_DELETE(mdDir->currentEntryName);
00653 }
00654 
00655 PRInt32 _MD_MkDir(char *unixPath, PRIntn mode)
00656 {
00657        HFileParam           fpb;
00658        Str255               pascalName = "\p";
00659        char                 *cMacPath = NULL;
00660        OSErr                err;
00661 
00662        #pragma unused (mode)       // Mode is ignored on the Mac
00663 
00664        if (unixPath) {
00665        err = ConvertUnixPathToMacPath(unixPath, &cMacPath);
00666               if (err != noErr)
00667                      goto ErrorExit;
00668 
00669        PStrFromCStr(cMacPath, pascalName);
00670               PR_DELETE(cMacPath);
00671               fpb.ioNamePtr = pascalName;
00672               fpb.ioVRefNum = 0;
00673               fpb.ioDirID = 0L;
00674 
00675               err = PBDirCreateSync((HParmBlkPtr)&fpb);
00676               if (err != noErr)
00677                      goto ErrorExit;
00678        }
00679 
00680        return 0;
00681        
00682 ErrorExit:
00683        _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
00684        _MD_SetError(err);
00685     return -1;
00686 }
00687 
00688 PRInt32 _MD_Delete(char *unixPath)
00689 {
00690        HFileParam           fpb;
00691        Str255               pascalName = "\p";
00692        char                 *cMacPath = NULL;
00693        OSErr                err;
00694 
00695        if (unixPath) {
00696        err = ConvertUnixPathToMacPath(unixPath, &cMacPath);
00697               if (err != noErr)
00698                      goto ErrorExit;
00699 
00700        PStrFromCStr(cMacPath, pascalName);
00701               PR_DELETE(cMacPath);
00702               fpb.ioNamePtr = pascalName;
00703               fpb.ioVRefNum = 0;
00704               fpb.ioDirID = 0L;
00705 
00706               err = PBHDeleteSync((HParmBlkPtr)&fpb);
00707               if (err != noErr)
00708                      goto ErrorExit;
00709        }
00710 
00711        return 0;
00712        
00713 ErrorExit:
00714        _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
00715        _MD_SetError(err);
00716     return -1;
00717 }
00718 
00719 PRInt32 _MD_Rename(char *fromUnixPath, char *toUnixPath)
00720 {
00721        OSErr                err;
00722        FSSpec               fromSpec;
00723        FSSpec               toSpec;
00724        FSSpec               destDirSpec;
00725        FSSpec               beforeRenameSpec;
00726 
00727        if (fromUnixPath && toUnixPath) {
00728        err = ConvertUnixPathToFSSpec(fromUnixPath, &fromSpec);
00729               if (err != noErr)
00730                      goto ErrorExit;
00731 
00732        err = ConvertUnixPathToFSSpec(toUnixPath, &toSpec);
00733               if (err != noErr && err != fnfErr)
00734                      goto ErrorExit;
00735 
00736        /* make an FSSpec for the destination directory */
00737               err = FSMakeFSSpec(toSpec.vRefNum, toSpec.parID, nil, &destDirSpec);
00738               if (err != noErr) /* parent directory must exist */
00739                      goto ErrorExit;
00740 
00741               // move it to the directory specified
00742        err = FSpCatMove(&fromSpec, &destDirSpec);
00743               if (err != noErr)
00744                      goto ErrorExit;
00745            
00746            // make a new FSSpec for the file or directory in its new location       
00747               err = FSMakeFSSpec(toSpec.vRefNum, toSpec.parID, fromSpec.name, &beforeRenameSpec);
00748               if (err != noErr)
00749                      goto ErrorExit;
00750        
00751        // rename the file or directory
00752        err = FSpRename(&beforeRenameSpec, toSpec.name);
00753               if (err != noErr)
00754                      goto ErrorExit;
00755 
00756        } else {
00757               err = paramErr;
00758               goto ErrorExit;
00759        }
00760 
00761        return 0;
00762        
00763 ErrorExit:
00764        _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
00765        _MD_SetError(err);
00766     return -1;
00767 }
00768 
00769 #define kWriteAccessAllowed (0x100)
00770 PRInt32 _MD_Access(char *unixPath, int amode)
00771 {
00772        //
00773        // Emulate the Unix access routine
00774        //
00775        
00776        OSErr                err;
00777        CInfoPBRec           pb;
00778        FCBPBRec             fcbpb;
00779        char                 *cMacPath = NULL;
00780        Str255               pascalMacPath;
00781        struct stat          info;
00782        
00783        // Convert to a Mac style path
00784        err = ConvertUnixPathToMacPath(unixPath, &cMacPath);
00785        if (err != noErr)
00786               goto ErrorExit;
00787        
00788        err = stat(cMacPath, &info);
00789        if (err != noErr)
00790               goto ErrorExit;
00791        
00792        
00793        // If all weÕre doing is checking for the existence of the file, weÕre out of here.
00794        // On the Mac, if a file exists, you can read from it.
00795        // This doesnÕt handle remote AppleShare volumes.  Does it need to?
00796        if ((amode == PR_ACCESS_EXISTS) || (amode == PR_ACCESS_READ_OK)) {
00797               goto success;
00798        }
00799        
00800        PStrFromCStr(cMacPath, pascalMacPath);
00801        
00802        pb.hFileInfo.ioNamePtr = pascalMacPath;
00803        pb.hFileInfo.ioVRefNum = info.st_dev;
00804        pb.hFileInfo.ioDirID = 0;
00805        pb.hFileInfo.ioFDirIndex = 0;
00806        
00807        err = PBGetCatInfoSync(&pb);
00808        if (err != noErr)
00809               goto ErrorExit;
00810        // Check out all the access permissions.
00811        
00812        if (amode == PR_ACCESS_WRITE_OK) {
00813               fcbpb.ioNamePtr = NULL;
00814               fcbpb.ioVRefNum = pb.hFileInfo.ioVRefNum;
00815               fcbpb.ioRefNum = pb.hFileInfo.ioFRefNum;
00816               fcbpb.ioFCBIndx = 0;
00817        
00818               err = PBGetFCBInfoSync(&fcbpb);
00819               if (err != noErr)
00820                      goto ErrorExit;
00821        
00822               /* Look at Inside Mac IV-180 */
00823               if ((fcbpb.ioFCBFlags & kWriteAccessAllowed) == 0) {
00824                      err = permErr;
00825                      goto ErrorExit;
00826               }
00827        }
00828        
00829 success:
00830        PR_DELETE(cMacPath);
00831        return 0;
00832        
00833 ErrorExit:
00834        if (cMacPath != NULL)
00835               PR_DELETE(cMacPath);
00836        _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
00837        _MD_SetError(err);
00838     return -1;
00839 }
00840 
00841 PRInt32 _MD_GetFileInfo(char *unixPath, PRFileInfo *info)
00842 {
00843        CInfoPBRec           pb;
00844        OSErr                err;
00845        char                 *cMacPath = NULL;
00846        Str255               pascalMacPath;
00847        PRTime               oneMillion, dateInMicroSeconds;
00848        
00849        // Convert to a Mac style path
00850        err = ConvertUnixPathToMacPath(unixPath, &cMacPath);
00851        if (err != noErr)
00852               goto ErrorExit;
00853        
00854        PStrFromCStr(cMacPath, pascalMacPath);
00855        PR_DELETE(cMacPath);
00856        
00857        pb.hFileInfo.ioNamePtr = pascalMacPath;
00858        pb.hFileInfo.ioVRefNum = 0;
00859        pb.hFileInfo.ioDirID = 0;
00860        pb.hFileInfo.ioFDirIndex = 0;
00861        
00862        err = PBGetCatInfoSync(&pb);
00863        if (err != noErr)
00864               goto ErrorExit;
00865        
00866        if (pb.hFileInfo.ioFlAttrib & ioDirMask) {
00867               info->type = PR_FILE_DIRECTORY;
00868               info->size = 0;
00869        } else {
00870               info->type = PR_FILE_FILE;
00871               info->size = pb.hFileInfo.ioFlLgLen + pb.hFileInfo.ioFlRLgLen;
00872        }
00873 
00874        pb.hFileInfo.ioFlCrDat -= gJanuaryFirst1970Seconds;
00875        LL_I2L(dateInMicroSeconds, pb.hFileInfo.ioFlCrDat);
00876        LL_I2L(oneMillion, PR_USEC_PER_SEC);
00877        LL_MUL(info->creationTime, oneMillion, dateInMicroSeconds);
00878 
00879        pb.hFileInfo.ioFlMdDat -= gJanuaryFirst1970Seconds;
00880        LL_I2L(dateInMicroSeconds, pb.hFileInfo.ioFlMdDat);
00881        LL_MUL(info->modifyTime, oneMillion, dateInMicroSeconds);
00882 
00883        return 0;
00884        
00885 ErrorExit:
00886        _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
00887        _MD_SetError(err);
00888     return -1;
00889 }
00890 
00891 PRInt32 _MD_GetOpenFileInfo(const PRFileDesc *fd, PRFileInfo *info)
00892 {
00893        OSErr                err;
00894        FCBPBRec             fcbpb;
00895        CInfoPBRec           pb;
00896        Str255               pascalMacPath;
00897        PRTime               oneMillion, dateInMicroSeconds;
00898        
00899        fcbpb.ioNamePtr = pascalMacPath;
00900        fcbpb.ioVRefNum = 0;
00901        fcbpb.ioRefNum = fd->secret->md.osfd;
00902        fcbpb.ioFCBIndx = 0;
00903        
00904        err = PBGetFCBInfoSync(&fcbpb);
00905        if (err != noErr)
00906               goto ErrorExit;
00907        
00908        info->type = PR_FILE_FILE;
00909        info->size = fcbpb.ioFCBEOF;
00910 
00911        pb.hFileInfo.ioNamePtr = pascalMacPath;
00912        pb.hFileInfo.ioVRefNum = fcbpb.ioFCBVRefNum;
00913        pb.hFileInfo.ioDirID = fcbpb.ioFCBParID;
00914        pb.hFileInfo.ioFDirIndex = 0;
00915        
00916        err = PBGetCatInfoSync(&pb);
00917        if (err != noErr)
00918               goto ErrorExit;
00919        
00920        pb.hFileInfo.ioFlCrDat -= gJanuaryFirst1970Seconds;
00921        LL_I2L(dateInMicroSeconds, pb.hFileInfo.ioFlCrDat);
00922        LL_I2L(oneMillion, PR_USEC_PER_SEC);
00923        LL_MUL(info->creationTime, oneMillion, dateInMicroSeconds);
00924 
00925        pb.hFileInfo.ioFlMdDat -= gJanuaryFirst1970Seconds;
00926        LL_I2L(dateInMicroSeconds, pb.hFileInfo.ioFlMdDat);
00927        LL_MUL(info->modifyTime, oneMillion, dateInMicroSeconds);
00928 
00929        return 0;
00930        
00931 ErrorExit:
00932        _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
00933        _MD_SetError(err);
00934     return -1;
00935 }
00936 
00937 PRInt32 _MD_Stat(const char *path, struct stat *buf)
00938 {
00939        OSErr  err;
00940        char   *macFileName = NULL;
00941        
00942     err = ConvertUnixPathToMacPath(path, &macFileName);
00943        if (err != noErr)
00944               goto ErrorExit;
00945        
00946        err = stat(macFileName, buf);
00947        if (err != noErr)
00948               goto ErrorExit;
00949               
00950        PR_DELETE(macFileName);
00951        
00952        return 0;
00953 
00954 ErrorExit:
00955        _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
00956        _MD_SetError(err);
00957     return -1;
00958 }
00959 
00960 PRStatus _MD_LockFile(PRInt32 fd)
00961 {
00962        OSErr                err;
00963        FCBPBRec             fcbpb;
00964        HFileParam           fpb;
00965        Str255               pascalName;
00966        
00967        fcbpb.ioNamePtr = pascalName;
00968        fcbpb.ioVRefNum = 0;
00969        fcbpb.ioRefNum = fd;
00970        fcbpb.ioFCBIndx = 0;
00971        
00972        err = PBGetFCBInfoSync(&fcbpb);
00973        if (err != noErr)
00974               goto ErrorExit;
00975        
00976        fpb.ioCompletion = NULL;
00977        fpb.ioNamePtr = pascalName;
00978        fpb.ioVRefNum = fcbpb.ioFCBVRefNum;
00979        fpb.ioDirID = fcbpb.ioFCBParID;
00980 
00981        err = PBHSetFLockSync((HParmBlkPtr)&fpb);
00982        if (err != noErr)
00983               goto ErrorExit;
00984        
00985        return PR_SUCCESS;
00986        
00987 ErrorExit:
00988        _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
00989        _MD_SetError(err);
00990     return PR_FAILURE;
00991 }
00992 
00993 PRStatus _MD_TLockFile(PRInt32 fd)
00994 {
00995        return (_MD_LockFile(fd));
00996 }
00997 
00998 PRStatus _MD_UnlockFile(PRInt32 fd)
00999 {
01000        OSErr                err;
01001        FCBPBRec             fcbpb;
01002        HFileParam           fpb;
01003        Str255               pascalName;
01004        
01005        fcbpb.ioNamePtr = pascalName;
01006        fcbpb.ioVRefNum = 0;
01007        fcbpb.ioRefNum = fd;
01008        fcbpb.ioFCBIndx = 0;
01009        
01010        err = PBGetFCBInfoSync(&fcbpb);
01011        if (err != noErr)
01012               goto ErrorExit;
01013        
01014        fpb.ioCompletion = NULL;
01015        fpb.ioNamePtr = pascalName;
01016        fpb.ioVRefNum = fcbpb.ioFCBVRefNum;
01017        fpb.ioDirID = fcbpb.ioFCBParID;
01018 
01019        err = PBHRstFLockSync((HParmBlkPtr)&fpb);
01020        if (err != noErr)
01021               goto ErrorExit;
01022        
01023        return PR_SUCCESS;
01024        
01025 ErrorExit:
01026        _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
01027        _MD_SetError(err);
01028     return PR_FAILURE;
01029 }
01030 
01031 void SetLogFileTypeCreator(const char *logFile)
01032 {
01033        HParamBlockRec pb;
01034        OSErr err;
01035        Str31 pName;
01036 
01037        PStrFromCStr(logFile, pName);
01038        pb.fileParam.ioCompletion = nil;
01039        pb.fileParam.ioNamePtr = pName;
01040        pb.fileParam.ioVRefNum = 0;
01041        pb.fileParam.ioFDirIndex = 0;
01042        pb.fileParam.ioDirID = 0;
01043        err = PBHGetFInfoSync(&pb);
01044        PR_ASSERT(err == noErr);
01045 
01046        pb.fileParam.ioDirID = 0;
01047        pb.fileParam.ioFlFndrInfo.fdType = 'TEXT';
01048        pb.fileParam.ioFlFndrInfo.fdCreator = 'ttxt';
01049        err = PBHSetFInfoSync(&pb);
01050        PR_ASSERT(err == noErr);
01051 }
01052 
01053 #if DEVELOPER_DEBUG
01054 PR_IMPLEMENT (void)
01055 SetupMacPrintfLog(char *logFile)
01056 {
01057        /*
01058         * We do _PR_InitLog() twice.  The first to force the implicit initialization which
01059         * will set logging to highest levels in _MD_EARLY_INIT.  Then, change the env variable
01060         * to disable kernel logging and call _PR_InitLog() again to make it effective.  Since
01061         * we are using logging to log test program output, we disable kernel logging to avoid
01062         * all Kernel logging output.
01063         */
01064 #ifdef PR_INTERNAL_LOGGING
01065        _PR_InitLog();
01066        _MD_PutEnv("NSPR_LOG_MODULES=clock:0,cmon:0,io:0,mon:0,linker:0,cvar:0,sched:0,thread:0");
01067        _PR_InitLog();
01068 #endif
01069        PR_ASSERT(PR_SetLogFile(logFile) == PR_TRUE);
01070        
01071        SetLogFileTypeCreator(logFile);
01072 }
01073 #endif
01074 
01075 
01076 /*
01077 ********************** Old name related stuff that is unchanged. **********************
01078 */
01079 
01080 #if !defined(MAC_NSPR_STANDALONE)
01081 
01082 short GetVolumeRefNumFromName(const char *cTgtVolName)
01083 {
01084        OSErr                       err;
01085        Str32                       pVolName;
01086        char                        *cVolName = NULL;
01087        HParamBlockRec              hPB;
01088        short                       refNum = 0;
01089        
01090        hPB.volumeParam.ioVolIndex = 0;
01091        hPB.volumeParam.ioNamePtr = pVolName;
01092        do {
01093               hPB.volumeParam.ioVolIndex++;
01094               err = PBHGetVInfoSync(&hPB);
01095               CStrFromPStr(pVolName, &cVolName);
01096               if (strcmp(cTgtVolName, cVolName) == 0) {
01097                      refNum =  hPB.volumeParam.ioVRefNum;
01098                      PR_DELETE(cVolName);
01099                      break;
01100               }
01101               PR_DELETE(cVolName);
01102        } while (err == noErr);
01103        
01104        return refNum;
01105 }
01106 
01107 static OSErr CreateMacPathFromUnixPath(const char *unixPath, char **macPath)
01108 {
01109        // Given a Unix style path with '/' directory separators, this allocates 
01110        // a path with Mac style directory separators in the path.
01111        //
01112        // It does not do any special directory translation; use ConvertUnixPathToMacPath
01113        // for that.
01114        
01115        const char    *src;
01116        char          *tgt;
01117        OSErr         err = noErr;
01118 
01119        PR_ASSERT(unixPath != nil);
01120        if (nil == unixPath) {
01121               err = paramErr;
01122               goto exit;
01123        }
01124 
01125        // If unixPath is a zero-length string, we copy ":" into
01126        // macPath, so we need a minimum of two bytes to handle
01127        // the case of ":". 
01128        *macPath = malloc(strlen(unixPath) + 2);  // Will be enough extra space.
01129        require_action (*macPath != NULL, exit, err = memFullErr;);
01130 
01131        src = unixPath;
01132        tgt = *macPath;
01133        
01134        if (PL_strchr(src, PR_DIRECTORY_SEPARATOR) == src)                           // If weÕre dealing with an absolute
01135               src++;                                                                                     // path, skip the separator
01136        else
01137               *(tgt++) = PR_PATH_SEPARATOR;      
01138               
01139        if (PL_strstr(src, UNIX_THIS_DIRECTORY_STR) == src)                   // If it starts with /
01140               src += 2;                                                                                  // skip it.
01141               
01142        while (*src) 
01143        {                           // deal with the rest of the path
01144               if (PL_strstr(src, UNIX_PARENT_DIRECTORY_STR) == src) { // Going up?
01145                      *(tgt++) = PR_PATH_SEPARATOR;                                         // simply add an extra colon.
01146                      src +=3;
01147               }
01148               else if (*src == PR_DIRECTORY_SEPARATOR) {                                   // Change the separator
01149                      *(tgt++) = PR_PATH_SEPARATOR;
01150                      src++;
01151               }
01152               else
01153                      *(tgt++) = *(src++);
01154        }
01155        
01156        *tgt = NULL;                                            // make sure itÕs null terminated.
01157 
01158 exit:
01159        return err;
01160 }
01161 
01162 
01163 static ProcessInfoRec gNavigatorProcInfo;
01164 static FSSpec gGutsFolder;
01165 static FSSpec gNetscapeFolder;
01166 
01167 static OSErr SetupRequiredFSSpecs(void)
01168 {
01169        OSErr err;
01170        CInfoPBRec pb;
01171        ProcessSerialNumber curPSN = {0, kCurrentProcess};      
01172        
01173        gNavigatorProcInfo.processInfoLength = sizeof(ProcessInfoRec);
01174        gNavigatorProcInfo.processName = NULL;
01175        gNavigatorProcInfo.processAppSpec = &gNetscapeFolder;
01176 
01177        err = GetProcessInformation (&curPSN, &gNavigatorProcInfo);
01178        if (err != noErr)
01179               goto ErrorExit;
01180 
01181        /* guts folder resides at the same place as the app file itself */
01182        gGutsFolder = gNetscapeFolder;
01183        /* How else do we do this hack??? 
01184         * Should NSPR have a string resource for this ?
01185         */
01186        GetIndString( gGutsFolder.name, 300, 34);
01187 
01188        /* 
01189         * vRefNum and parentDirID are now set up correctly for the app file itself. 
01190         * parentDirID is the Netscape Folder's ID.  Then Find it's parent ID to
01191         * set up the FSSpec and its own name.
01192         */
01193 
01194        pb.dirInfo.ioCompletion = NULL;
01195        pb.dirInfo.ioNamePtr = gNetscapeFolder.name;
01196        pb.dirInfo.ioVRefNum = gNetscapeFolder.vRefNum;
01197        pb.dirInfo.ioFDirIndex = -1;
01198        pb.dirInfo.ioDrDirID = gNetscapeFolder.parID;
01199        
01200        err = PBGetCatInfoSync(&pb);
01201        if (err != noErr)
01202               goto ErrorExit;
01203        
01204        gNetscapeFolder.parID = pb.dirInfo.ioDrParID;
01205        
01206        return noErr; 
01207 
01208 ErrorExit:
01209        return err;
01210 }
01211 
01212 static OSErr FindGutsFolder(FSSpec *foundSpec)
01213 {
01214        OSErr err;
01215        
01216        if (gNavigatorProcInfo.processInfoLength == 0) { /* Uninitialized? */
01217               err = SetupRequiredFSSpecs();
01218               if (err != noErr)
01219                      goto ErrorExit;
01220        } 
01221        
01222        *foundSpec = gGutsFolder;
01223        
01224        return noErr; 
01225 
01226 ErrorExit:
01227        _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
01228     return err;      
01229 }
01230 
01231 static OSErr FindNetscapeFolder(FSSpec *foundSpec)
01232 {
01233        OSErr err;
01234        
01235        if (gNavigatorProcInfo.processInfoLength == 0) { /* Uninitialized? */
01236               err = SetupRequiredFSSpecs();
01237               if (err != noErr)
01238                      goto ErrorExit;
01239        } 
01240        
01241        *foundSpec = gNetscapeFolder;
01242        
01243        return noErr; 
01244 
01245 ErrorExit:
01246        _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
01247     return err;      
01248 }
01249 
01250 
01251 PR_IMPLEMENT (OSErr)
01252 ConvertUnixPathToMacPath(const char *unixPath, char **macPath)
01253 {      
01254               OSErr         err = noErr;
01255               
01256        //     ******** HACK ALERT ********
01257        //
01258        //     Java really wants long file names (>31 chars).  We truncate file names 
01259        //     greater than 31 characters long.  Truncation is from the middle.
01260        //
01261        //     Convert UNIX style path names (with . and / separators) into a Macintosh
01262        //     style path (with :).
01263        //
01264        // There are also a couple of special paths that need to be dealt with
01265        // by translating them to the appropriate Mac special folders.  These include:
01266        //
01267        //                   /usr/tmp/file  =>  {TempFolder}file
01268        //
01269        // The file conversions we need to do are as follows:
01270        //
01271        //                   file                 =>            file
01272        //                   dir/file             =>            :dir:file
01273        //                   ./file               =>            file
01274        //                   ../file                     =>            ::file
01275        //                   ../dir/file          =>            ::dir:file
01276        //                   /file                =>            ::BootDrive:file
01277        //                   /dir/file            =>            ::BootDrive:dir:file
01278        
01279        
01280        if (!strcmp(unixPath, "."))
01281        {
01282               *macPath = malloc(sizeof(":"));
01283               if (*macPath == NULL)
01284                      err = memFullErr;
01285               (*macPath)[0] = ':';
01286               (*macPath)[1] = '\0';
01287        }
01288        else
01289        
01290        if (*unixPath != PR_DIRECTORY_SEPARATOR) {                            // Not root relative, just convert it.
01291               err = CreateMacPathFromUnixPath(unixPath, macPath);
01292        }
01293        
01294        else {
01295               // WeÕre root-relative.  This is either a special Unix directory, or a 
01296               // full path (which weÕll support on the Mac since they might be generated).
01297               // This is not condoning the use of full-paths on the Macintosh for file 
01298               // specification.
01299               
01300               FSSpec        foundSpec;
01301               short         pathBufferSize;
01302 #if DEBUG     
01303               char          *temp;
01304 #endif
01305               int           tempLen;
01306 
01307               // Are we dealing with the temp folder?
01308               if ((strncmp(unixPath, "/usr/tmp", strlen("/usr/tmp")) == 0) || 
01309                      ((strncmp(unixPath, "/tmp", strlen("/tmp")) == 0))) {
01310                   CInfoPBRec pb;
01311 
01312                      unixPath = PL_strchr(unixPath, PR_DIRECTORY_SEPARATOR);
01313                      if (strncmp(unixPath, "/tmp", strlen("/tmp")) == 0) // skip past temp spec
01314                             unixPath += 5;       
01315                      else
01316                             unixPath += 9;       
01317                                                  
01318                      err = FindFolder(kOnSystemDisk, kTemporaryFolderType, kCreateFolder,  // Create if needed
01319                                                         &foundSpec.vRefNum, &foundSpec.parID);
01320                      if (err == noErr) {
01321                             pb.dirInfo.ioCompletion = NULL;
01322                             pb.dirInfo.ioNamePtr = foundSpec.name;
01323                             pb.dirInfo.ioVRefNum = foundSpec.vRefNum;
01324                             pb.dirInfo.ioFDirIndex = -1;
01325                             pb.dirInfo.ioDrDirID = foundSpec.parID;
01326                             
01327                             err = PBGetCatInfoSync(&pb);
01328                             foundSpec.parID = pb.dirInfo.ioDrParID;
01329                      }
01330               }
01331               
01332               else if (!strncmp(unixPath, "/usr/local/netscape/", (tempLen = strlen("/usr/local/netscape/")))) {
01333                      
01334                      unixPath += tempLen;
01335                      
01336                      if (!strncmp(unixPath, "RequiredGuts/", (tempLen = strlen("RequiredGuts/"))))
01337                      {
01338                             unixPath += tempLen;
01339                             err = FindGutsFolder(&foundSpec);
01340                      }
01341                      else if (!strncmp(unixPath, "bin/", (tempLen = strlen("bin/"))))
01342                      {
01343                             unixPath += tempLen;
01344                             err = FindNetscapeFolder(&foundSpec);
01345                      }                    
01346                      else if (*unixPath == '\0')
01347                      {
01348                             // it's /usr/local/netscape
01349                             err = FindGutsFolder(&foundSpec);
01350                      }
01351 
01352               }
01353               
01354               else {
01355                      // This is a root relative directory, weÕll just convert the whole thing.
01356                      err = CreateMacPathFromUnixPath(unixPath, macPath);
01357                      goto Exit_ConvertUnixPathToMacPath;
01358               }
01359        
01360 
01361               
01362               // WeÕre dealing with a special folder
01363               if (err == noErr)
01364               {
01365                      Handle hPathStr;
01366                      // Get the path to the root-relative directory
01367                      err = FSpGetFullPath(&foundSpec, &pathBufferSize, &hPathStr);         // NewHandle's hPathStr
01368                       
01369                      if (noErr == err)
01370                      {
01371                             // convert handle to c-string
01372                             // add one for NULL termination
01373                             // pathBufferSize is now one greater than the length of the string
01374                             pathBufferSize++;    
01375                             
01376                             *macPath = (char*) malloc(sizeof(char) * pathBufferSize);
01377                             (*macPath)[pathBufferSize - 1] = '\0';
01378                             BlockMoveData(*hPathStr, *macPath, pathBufferSize - 1);
01379                      
01380                             DisposeHandle(hPathStr);
01381                      }
01382               }
01383               
01384               if (err == noErr)
01385               {
01386                      UInt32 unixPathLeft;
01387                      UInt32 macPathLen;
01388 
01389                      unixPathLeft =  strlen(unixPath);
01390                      macPathLen = strlen(*macPath);
01391                      
01392 
01393                      // copy over the remaining file name, converting
01394                      if (pathBufferSize - 1 < macPathLen + unixPathLeft) 
01395                      {
01396                             // need to grow string
01397                             *macPath = realloc(*macPath, macPathLen + unixPathLeft + 1);
01398                             err = (*macPath == NULL ? memFullErr : noErr);
01399                      }
01400                      
01401                      if (err == noErr)
01402                      {
01403                             // carefully remove the '/''s out of the unix path.  If we see an "escaped" /
01404                             // we will leave it in there, otherwise we take it out and replace it with a :
01405                             // we have to do this before we convert to a mac-path, so we can tell what is
01406                             // really a path separator and what is in the name of a file or directory
01407                             // Make sure that all of the /Õs are :Õs in the final pathname
01408                             // effectively we do a
01409                             // strcat(*macPath, unixPath); while replace all occurrences of / with : in unixPath
01410                             char*         dp;
01411                             const char*   sp;
01412                             
01413                             sp = unixPath;
01414                             dp = *macPath + macPathLen;
01415                             
01416                             for (;*sp != '\0'; sp++, dp++) 
01417                             {
01418                                    if (*sp == PR_DIRECTORY_SEPARATOR)
01419                                    {
01420                                           // if we can look at the previous character
01421                                           if (sp > unixPath)                               
01422                                           {
01423                                                  // check to see if previous character is an escape
01424                                                  if (sp[-1] == '\\')
01425                                                  {
01426                                                         // leave it in, and cycle
01427                                                         continue;
01428                                                  }
01429                                                  else
01430                                                  {
01431                                                         *dp = PR_PATH_SEPARATOR;
01432                                                  }
01433                                           }
01434                                           else                        
01435                                                  *dp = PR_PATH_SEPARATOR;
01436                                    }
01437                                    else
01438                                    {
01439                                           // just copy;
01440                                           *dp = *sp;
01441                                    }
01442                             }
01443                             
01444                             *dp = '\0';   // NULL terminate *macPath
01445                      }
01446 #if DEBUG     
01447                      // we used to check here, now we check above, we leave this in
01448                      // the debug build to make sure we didn't screw up
01449                      // Make sure that all of the /Õs are :Õs in the final pathname
01450                      for (temp = *macPath + strlen(*macPath) - strlen(unixPath); *temp != '\0'; temp++) {
01451 
01452                             if (*temp == PR_DIRECTORY_SEPARATOR)
01453                             {
01454                                    DebugStr("\pFound a slash");       
01455                                    *temp = PR_PATH_SEPARATOR;
01456                             }
01457                      }
01458 #endif
01459               }
01460        }
01461        
01462        
01463 Exit_ConvertUnixPathToMacPath:
01464 
01465        return err;
01466 }
01467 
01468 // Hey! Before you delete this "hack" you should look at how it's being
01469 // used by sun-java/netscape/applet/appletStubs.c.
01470 PR_IMPLEMENT (OSErr)
01471 ConvertMacPathToUnixPath(const char *macPath, char **unixPath) 
01472 {
01473        // *** HACK ***
01474        // Get minimal version working
01475        
01476        char          *unixPathPtr;
01477        
01478        *unixPath = malloc(strlen(macPath) + 2);  // Add one for the front slash, one for null
01479        if (*unixPath == NULL)
01480               return (memFullErr);
01481               
01482        unixPathPtr = *unixPath;
01483        
01484        *unixPathPtr++ = PR_DIRECTORY_SEPARATOR;
01485        
01486        do {
01487               // Translate all colons to slashes
01488               if (*macPath == PR_PATH_SEPARATOR)
01489                      *unixPathPtr = PR_DIRECTORY_SEPARATOR;
01490               else
01491                      *unixPathPtr = *macPath;
01492 
01493               unixPathPtr++;
01494               macPath++;
01495        } while (*macPath != NULL);
01496        
01497        // Terminate the string
01498        *unixPathPtr = '\0';
01499        
01500        return (noErr);
01501 }
01502 
01503 OSErr
01504 ConvertUnixPathToFSSpec(const char *unixPath, FSSpec *fileSpec)
01505 {
01506     char*                   macPath;
01507     OSErr                   convertError;
01508     int                             len;
01509     
01510     convertError = ConvertUnixPathToMacPath(unixPath, &macPath);
01511     if (convertError != noErr)
01512        return convertError;
01513 
01514     len = strlen(macPath);
01515 
01516     if (*macPath == PR_PATH_SEPARATOR)
01517     {
01518         if (len < sizeof(Str255))
01519         {
01520             short   vRefNum;
01521             long    dirID;
01522             Str255  pascalMacPath;
01523             
01524             convertError = HGetVol(NULL, &vRefNum, &dirID);
01525             if (convertError == noErr)
01526             {
01527                 PStrFromCStr(macPath, pascalMacPath);
01528                 convertError = FSMakeFSSpec(vRefNum, dirID, pascalMacPath, fileSpec);
01529             }
01530         }
01531         else
01532             convertError = paramErr;
01533     }
01534     else
01535     {
01536        convertError = FSpLocationFromFullPath(len, macPath, fileSpec);
01537            if (convertError == fnfErr)
01538            {
01539                      CInfoPBRec           pb;
01540                      Str255 pascalMacPath;
01541                      OSErr err;
01542                      
01543                      PStrFromCStr(macPath, pascalMacPath);
01544                      /* 
01545                      FSpLocationFromFullPath does not work for directories unless there is
01546                      a ":" at the end.  We will make sure of an existence of a directory.
01547                      If so, the returned fileSpec is valid from FSpLocationFromFullPath eventhough
01548                      it returned an error.
01549                      */
01550                      pb.hFileInfo.ioNamePtr = pascalMacPath;
01551                      pb.hFileInfo.ioVRefNum = 0;
01552                      pb.hFileInfo.ioDirID = 0;
01553                      pb.hFileInfo.ioFDirIndex = 0;
01554                      
01555                      err = PBGetCatInfoSync(&pb);
01556                      if (err == noErr)
01557                             convertError = noErr;
01558               }
01559     }
01560     
01561     free(macPath);
01562     
01563     return (convertError);
01564 }
01565  
01566 
01567 FILE *_OS_FOPEN(const char *filename, const char *mode) 
01568 {
01569        OSErr  err = noErr;
01570        char   *macFileName = NULL;
01571        FILE   *result;
01572        
01573     err = ConvertUnixPathToMacPath(filename, &macFileName);
01574        if (err != noErr)
01575               goto ErrorExit;
01576        
01577        result = fopen(macFileName, mode);
01578               
01579        PR_DELETE(macFileName);
01580        
01581        return result;
01582 
01583 ErrorExit:
01584        _PR_MD_CURRENT_THREAD()->md.osErrCode = err;
01585        _MD_SetError(err);
01586     return NULL;
01587 }
01588 
01589 #else
01590 
01591 short GetVolumeRefNumFromName(const char *cTgtVolName)
01592 {
01593        OSErr                       err;
01594        Str32                       pVolName;
01595        char                        *cVolName = NULL;
01596        HParamBlockRec              hPB;
01597        short                       refNum = 0;
01598        
01599        hPB.volumeParam.ioVolIndex = 0;
01600        hPB.volumeParam.ioNamePtr = pVolName;
01601        do {
01602               hPB.volumeParam.ioVolIndex++;
01603               err = PBHGetVInfoSync(&hPB);
01604               CStrFromPStr(pVolName, &cVolName);
01605               if (strcmp(cTgtVolName, cVolName) == 0) {
01606                      refNum =  hPB.volumeParam.ioVRefNum;
01607                      PR_DELETE(cVolName);
01608                      break;
01609               }
01610               PR_DELETE(cVolName);
01611        } while (err == noErr);
01612        
01613        return refNum;
01614 }
01615 
01616 
01617 
01618 static OSErr GetFullPath(short vRefNum, long dirID, char **fullPath, int *strSize)
01619 {
01620        Str255               pascalDirName;
01621        char                 cDirName[256];
01622        char                 *tmpPath = NULL;                                        // needed since sprintf isnÕt safe
01623        CInfoPBRec           myPB;
01624        OSErr                err = noErr;
01625        
01626        
01627        // get the full path of the temp folder.
01628        *strSize = 256;
01629        *fullPath = NULL;
01630        *fullPath = malloc(*strSize);      // How big should this thing be?
01631        require_action (*fullPath != NULL, errorExit, err = memFullErr;);
01632               
01633        tmpPath = malloc(*strSize);
01634        require_action (tmpPath != NULL, errorExit, err = memFullErr;);
01635 
01636        strcpy(*fullPath, "");                           // Clear C result
01637        strcpy(tmpPath, "");
01638        pascalDirName[0] = 0;                            // Clear Pascal intermediate string
01639        
01640        myPB.dirInfo.ioNamePtr = &pascalDirName[0];
01641        myPB.dirInfo.ioVRefNum = vRefNum;
01642        myPB.dirInfo.ioDrParID = dirID;
01643        myPB.dirInfo.ioFDirIndex = -1;                          // Getting info about
01644        
01645        do {
01646               myPB.dirInfo.ioDrDirID = myPB.dirInfo.ioDrParID;
01647 
01648               err = PBGetCatInfoSync(&myPB);
01649               require(err == noErr, errorExit);
01650                      
01651               // Move the name into C domain
01652               memcpy(&cDirName, &pascalDirName, 256);
01653               p2cstr((unsigned char *)&cDirName);                                                 // Changes in place!
01654               
01655               if ((strlen(cDirName) + strlen(*fullPath)) > *strSize) {
01656                      // We need to grow the string, do it in 256 byte chunks
01657                      (*strSize) += 256;                                                                  
01658                      *fullPath = PR_REALLOC(*fullPath, *strSize);
01659                      require_action (*fullPath != NULL, errorExit, err = memFullErr;);
01660 
01661                      tmpPath = PR_REALLOC(tmpPath, *strSize);
01662                      require_action (tmpPath != NULL, errorExit, err = memFullErr;);
01663               }
01664               sprintf(tmpPath, "%s:%s", cDirName, *fullPath);
01665               strcpy(*fullPath, tmpPath);
01666        } while (myPB.dirInfo.ioDrDirID != fsRtDirID);
01667        
01668        PR_DELETE(tmpPath);
01669        
01670        return noErr;
01671        
01672        
01673 errorExit:
01674        PR_DELETE(*fullPath);
01675        PR_DELETE(tmpPath);
01676        
01677        return err;
01678 
01679 }
01680 
01681 static OSErr CreateMacPathFromUnixPath(const char *unixPath, char **macPath)
01682 {
01683        // Given a Unix style path with '/' directory separators, this allocates 
01684        // a path with Mac style directory separators in the path.
01685        //
01686        // It does not do any special directory translation; use ConvertUnixPathToMacPath
01687        // for that.
01688        
01689        const char    *src;
01690        char          *tgt;
01691        OSErr         err = noErr;
01692 
01693        PR_ASSERT(unixPath != nil);
01694        if (nil == unixPath) {
01695               err = paramErr;
01696               goto exit;
01697        }
01698 
01699        // If unixPath is a zero-length string, we copy ":" into
01700        // macPath, so we need a minimum of two bytes to handle
01701        // the case of ":". 
01702        *macPath = malloc(strlen(unixPath) + 2);  // Will be enough extra space.
01703        require_action (*macPath != NULL, exit, err = memFullErr;);
01704 
01705        src = unixPath;
01706        tgt = *macPath;
01707        
01708        if (PL_strchr(src, PR_DIRECTORY_SEPARATOR) == src)                           // If weÕre dealing with an absolute
01709               src++;                                                                                     // path, skip the separator
01710        else
01711               *(tgt++) = PR_PATH_SEPARATOR;      
01712               
01713        if (PL_strstr(src, UNIX_THIS_DIRECTORY_STR) == src)                   // If it starts with ./
01714               src += 2;                                                                                  // skip it.
01715               
01716        while (*src) 
01717        {                           // deal with the rest of the path
01718               if (PL_strstr(src, UNIX_PARENT_DIRECTORY_STR) == src) { // Going up?
01719                      *(tgt++) = PR_PATH_SEPARATOR;                                         // simply add an extra colon.
01720                      src +=3;
01721               }
01722               else if (*src == PR_DIRECTORY_SEPARATOR) {                                   // Change the separator
01723                      *(tgt++) = PR_PATH_SEPARATOR;
01724                      src++;
01725               }
01726               else
01727                      *(tgt++) = *(src++);
01728        }
01729        
01730        *tgt = NULL;                                            // make sure itÕs null terminated.
01731 
01732 exit:
01733        return err;
01734 }
01735 
01736 static OSErr ConvertUnixPathToMacPath(const char *unixPath, char **macPath)
01737 {      
01738               OSErr         err = noErr;
01739               
01740 
01741        //
01742        //     Convert UNIX style path names (with . and / separators) into a Macintosh
01743        //     style path (with :).
01744        //
01745        // There are also a couple of special paths that need to be dealt with
01746        // by translating them to the appropriate Mac special folders.  These include:
01747        //
01748        //                   /usr/tmp/file  =>  {TempFolder}file
01749        //
01750        // The file conversions we need to do are as follows:
01751        //
01752        //                   file                 =>            file
01753        //                   dir/file             =>            :dir:file
01754        //                   ./file               =>            file
01755        //                   ../file                     =>            ::file
01756        //                   ../dir/file          =>            ::dir:file
01757        //                   /file                =>            ::BootDrive:file
01758        //                   /dir/file            =>            ::BootDrive:dir:file
01759        
01760        
01761        if (*unixPath != PR_DIRECTORY_SEPARATOR) {                            // Not root relative, just convert it.
01762               err = CreateMacPathFromUnixPath(unixPath, macPath);
01763        }
01764        
01765        else {
01766               // WeÕre root-relative.  This is either a special Unix directory, or a 
01767               // full path (which weÕll support on the Mac since they might be generated).
01768               // This is not condoning the use of full-paths on the Macintosh for file 
01769               // specification.
01770               
01771               short         foundVRefNum;
01772               long          foundDirID;
01773               int                  pathBufferSize;
01774               char          *temp;
01775               char          isNetscapeDir = false;
01776 
01777               // Are we dealing with the temp folder?
01778               if (strncmp(unixPath, "/usr/tmp", strlen("/usr/tmp")) == 0){
01779                      unixPath += 8;
01780                      if (*unixPath == PR_DIRECTORY_SEPARATOR)
01781                             unixPath++;                                                                                              // Skip the slash
01782                      err = FindFolder(kOnSystemDisk, kTemporaryFolderType, kCreateFolder,  // Create if needed
01783                                                         &foundVRefNum, &foundDirID);
01784               }
01785               
01786               if (strncmp(unixPath, "/tmp", strlen("/tmp")) == 0) {
01787                      unixPath += 4;                                                                                                         // Skip the slash
01788                      if (*unixPath == PR_DIRECTORY_SEPARATOR)
01789                             unixPath++;                                                                                              // Skip the slash
01790                      err = FindFolder(kOnSystemDisk, kTemporaryFolderType, kCreateFolder,  // Create if needed
01791                                                         &foundVRefNum, &foundDirID);
01792               }
01793               
01794               else if (strncmp(unixPath, "/usr", strlen("/usr")) == 0) {
01795               
01796                      int           usrNetscapePathLen;
01797                      
01798                      usrNetscapePathLen = strlen("/usr/local/netscape/");
01799               
01800                      if (strncmp(unixPath, "/usr/local/netscape/", usrNetscapePathLen) == 0) {
01801                             unixPath += usrNetscapePathLen;                         
01802 //                          err = FindPreferencesFolder(&foundVRefNum, &foundDirID);
01803                             err = paramErr;
01804                             isNetscapeDir = true;
01805                      }
01806                      
01807                      else {
01808                             dprintf("Unable to translate Unix file path %s to Mac path\n", unixPath);
01809                             err = -1;
01810                             goto Exit_ConvertUnixPathToMacPath;
01811                      }
01812 
01813               }
01814               
01815               else {
01816                      // This is a root relative directory, weÕll just convert the whole thing.
01817                      err = CreateMacPathFromUnixPath(unixPath, macPath);
01818                      goto Exit_ConvertUnixPathToMacPath;
01819               }
01820        
01821               // WeÕre dealing with a special folder
01822               if (err == noErr)
01823                      // Get the path to the root-relative directory
01824                      err = GetFullPath(foundVRefNum, foundDirID, macPath, &pathBufferSize);              // mallocs macPath
01825               
01826               if (err == noErr){
01827                      
01828                      // copy over the remaining file name, converting
01829                      if (pathBufferSize < (strlen(*macPath) + strlen(unixPath))) {
01830                             // need to grow string
01831                             *macPath = PR_REALLOC(*macPath, (strlen(*macPath) + strlen(unixPath) + 
01832                                    (isNetscapeDir ? strlen("Netscape Ä:") : 0)));
01833                             err = (*macPath == NULL ? memFullErr : noErr);
01834                      }
01835                      
01836                      if (isNetscapeDir)
01837                             strcat(*macPath, "Netscape Ä:");
01838               
01839                      if (err == noErr)
01840                             strcat(*macPath, unixPath);
01841                      
01842                      //     Make sure that all of the /Õs are :Õs in the final pathname
01843                             
01844                      for (temp = *macPath + strlen(*macPath) - strlen(unixPath); *temp != '\0'; temp++) {
01845                             if (*temp == PR_DIRECTORY_SEPARATOR)
01846                                    *temp = PR_PATH_SEPARATOR;
01847                      }
01848 
01849               }
01850        }
01851        
01852        
01853 Exit_ConvertUnixPathToMacPath:
01854 
01855        return err;
01856 }
01857 
01858 OSErr
01859 ConvertUnixPathToFSSpec(const char *unixPath, FSSpec *fileSpec)
01860 {
01861     char*                   macPath;
01862     OSErr                   convertError;
01863     int                             len;
01864     
01865     convertError = ConvertUnixPathToMacPath(unixPath, &macPath);
01866     if (convertError != noErr)
01867        return convertError;
01868 
01869     len = strlen(macPath);
01870 
01871     if (*macPath == PR_PATH_SEPARATOR)
01872     {
01873         if (len < sizeof(Str255))
01874         {
01875             short   vRefNum;
01876             long    dirID;
01877             Str255  pascalMacPath;
01878             
01879             convertError = HGetVol(NULL, &vRefNum, &dirID);
01880             if (convertError == noErr)
01881             {
01882                 PStrFromCStr(macPath, pascalMacPath);
01883                 convertError = FSMakeFSSpec(vRefNum, dirID, pascalMacPath, fileSpec);
01884             }
01885         }
01886         else
01887             convertError = paramErr;
01888     }
01889     else
01890     {
01891        convertError = FSpLocationFromFullPath(len, macPath, fileSpec);
01892     }
01893     
01894     free(macPath);
01895     
01896     return (convertError);
01897 }
01898  
01899 
01900 #endif
01901 
01902 /*
01903  **********************************************************************
01904  *
01905  * Memory-mapped files are not implementable on the Mac.
01906  *
01907  **********************************************************************
01908  */
01909 
01910 PRStatus _MD_CreateFileMap(PRFileMap *fmap, PRInt64 size)
01911 {
01912 #pragma unused (fmap, size)
01913 
01914     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
01915     return PR_FAILURE;
01916 }
01917 
01918 PRInt32 _MD_GetMemMapAlignment(void)
01919 {
01920     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
01921     return -1;
01922 }
01923 
01924 void * _MD_MemMap(
01925     PRFileMap *fmap,
01926     PROffset64 offset,
01927     PRUint32 len)
01928 {
01929 #pragma unused (fmap, offset, len)
01930 
01931     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
01932     return NULL;
01933 }
01934 
01935 PRStatus _MD_MemUnmap(void *addr, PRUint32 len)
01936 {
01937 #pragma unused (addr, len)
01938 
01939     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
01940     return PR_FAILURE;
01941 }
01942 
01943 PRStatus _MD_CloseFileMap(PRFileMap *fmap)
01944 {
01945 #pragma unused (fmap)
01946 
01947     PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
01948     return PR_FAILURE;
01949 }