Back to index

lightning-sunbird  0.9+nobinonly
os2io.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 
00039 /*
00040  * This Original Code has been modified by IBM Corporation.
00041  * Modifications made by IBM described herein are
00042  * Copyright (c) International Business Machines
00043  * Corporation, 2000
00044  *
00045  * Modifications to Mozilla code or documentation
00046  * identified per MPL Section 3.3
00047  *
00048  * Date             Modified by     Description of modification
00049  * 03/23/2000       IBM Corp.       Changed write() to DosWrite(). EMX i/o
00050  *                                  calls cannot be intermixed with DosXXX
00051  *                                  calls since EMX remaps file/socket
00052  *                                  handles.
00053  * 04/27/2000       IBM Corp.       Changed open file to be more like NT and
00054  *                                  better handle PR_TRUNCATE | PR_CREATE_FILE
00055  *                                  and also fixed _PR_MD_SET_FD_INHERITABLE
00056  */
00057 
00058 /* OS2 IO module
00059  *
00060  * Assumes synchronous I/O.
00061  *
00062  */
00063 
00064 #include "primpl.h"
00065 #include "prio.h"
00066 #include <ctype.h>
00067 #include <string.h>
00068 #ifdef XP_OS2_VACPP
00069 #include <direct.h>
00070 #else
00071 #include <limits.h>
00072 #include <dirent.h>
00073 #include <fcntl.h>
00074 #include <io.h>
00075 #endif
00076 
00077 struct _MDLock               _pr_ioq_lock;
00078 
00079 static PRBool isWSEB = PR_FALSE; /* whether we are using an OS/2 kernel that supports large files */
00080 
00081 typedef APIRET (*DosOpenLType)(PSZ pszFileName, PHFILE pHf, PULONG pulAction,
00082                             LONGLONG cbFile, ULONG ulAttribute,
00083                             ULONG fsOpenFlags, ULONG fsOpenMode,
00084                             PEAOP2 peaop2);
00085 
00086 typedef APIRET (*DosSetFileLocksLType)(HFILE hFile, PFILELOCKL pflUnlock,
00087                                     PFILELOCKL pflLock, ULONG timeout,
00088                                     ULONG flags);
00089 
00090 typedef APIRET (*DosSetFilePtrLType)(HFILE hFile, LONGLONG ib, ULONG method,
00091                                   PLONGLONG ibActual);
00092 
00093 DosOpenLType myDosOpenL;
00094 DosSetFileLocksLType myDosSetFileLocksL;
00095 DosSetFilePtrLType myDosSetFilePtrL;
00096 
00097 void
00098 _PR_MD_INIT_IO()
00099 {
00100     APIRET rc;
00101     HMODULE module;
00102 
00103     sock_init();
00104     
00105     rc = DosLoadModule(NULL, 0, "DOSCALL1", &module);
00106     if (rc != NO_ERROR)
00107     {
00108         return;
00109     }
00110     rc = DosQueryProcAddr(module, 981, NULL, (PFN*) &myDosOpenL);
00111     if (rc != NO_ERROR)
00112     {
00113         return;
00114     }
00115     rc = DosQueryProcAddr(module, 986, NULL, (PFN*) &myDosSetFileLocksL);
00116     if (rc != NO_ERROR)
00117     {
00118         return;
00119     }
00120     rc = DosQueryProcAddr(module, 988, NULL, (PFN*) &myDosSetFilePtrL);
00121     if (rc != NO_ERROR)
00122     {
00123         return;
00124     }
00125     isWSEB = PR_TRUE;
00126 }
00127 
00128 PRStatus
00129 _PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks)
00130 {
00131     PRInt32 rv;
00132     ULONG count;
00133 
00134     PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ?
00135         SEM_INDEFINITE_WAIT : PR_IntervalToMilliseconds(ticks);
00136     rv = DosWaitEventSem(thread->md.blocked_sema, msecs);
00137     DosResetEventSem(thread->md.blocked_sema, &count); 
00138     switch(rv) 
00139     {
00140         case NO_ERROR:
00141             return PR_SUCCESS;
00142             break;
00143         case ERROR_TIMEOUT:
00144             _PR_THREAD_LOCK(thread);
00145             if (thread->state == _PR_IO_WAIT) {
00146                        ;
00147             } else {
00148                 if (thread->wait.cvar != NULL) {
00149                     thread->wait.cvar = NULL;
00150                     _PR_THREAD_UNLOCK(thread);
00151                 } else {
00152                     /* The CVAR was notified just as the timeout
00153                      * occurred.  This led to us being notified twice.
00154                      * call SemRequest() to clear the semaphore.
00155                      */
00156                     _PR_THREAD_UNLOCK(thread);
00157                     rv = DosWaitEventSem(thread->md.blocked_sema, 0);
00158                     DosResetEventSem(thread->md.blocked_sema, &count); 
00159                     PR_ASSERT(rv == NO_ERROR);
00160                 }
00161             }
00162             return PR_SUCCESS;
00163             break;
00164         default:
00165             break;
00166     }
00167     return PR_FAILURE;
00168 }
00169 PRStatus
00170 _PR_MD_WAKEUP_WAITER(PRThread *thread)
00171 {
00172     if ( _PR_IS_NATIVE_THREAD(thread) ) 
00173     {
00174         if (DosPostEventSem(thread->md.blocked_sema) != NO_ERROR)
00175             return PR_FAILURE;
00176         else
00177                      return PR_SUCCESS;
00178        }
00179 }
00180 
00181 
00182 /* --- FILE IO ----------------------------------------------------------- */
00183 /*
00184  *  _PR_MD_OPEN() -- Open a file
00185  *
00186  *  returns: a fileHandle
00187  *
00188  *  The NSPR open flags (osflags) are translated into flags for OS/2
00189  *
00190  *  Mode seems to be passed in as a unix style file permissions argument
00191  *  as in 0666, in the case of opening the logFile. 
00192  *
00193  */
00194 PRInt32
00195 _PR_MD_OPEN(const char *name, PRIntn osflags, int mode)
00196 {
00197     HFILE file;
00198     PRInt32 access = OPEN_SHARE_DENYNONE;
00199     PRInt32 flags = 0L;
00200     APIRET rc = 0;
00201     PRUword actionTaken;
00202 
00203     if (osflags & PR_SYNC) access |= OPEN_FLAGS_WRITE_THROUGH;
00204 
00205     if (osflags & PR_RDONLY)
00206         access |= OPEN_ACCESS_READONLY;
00207     else if (osflags & PR_WRONLY)
00208         access |= OPEN_ACCESS_WRITEONLY;
00209     else if(osflags & PR_RDWR)
00210         access |= OPEN_ACCESS_READWRITE;
00211 
00212     if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL )
00213     {
00214         flags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_FAIL_IF_EXISTS;
00215     }
00216     else if (osflags & PR_CREATE_FILE)
00217     {
00218         if (osflags & PR_TRUNCATE)
00219             flags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS;
00220         else
00221             flags = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
00222     } 
00223     else
00224     {
00225         if (osflags & PR_TRUNCATE)
00226             flags = OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS;
00227         else
00228             flags = OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
00229     }
00230 
00231     do {
00232         if (isWSEB)
00233         {
00234                 rc = myDosOpenL((char*)name,
00235                      &file,            /* file handle if successful */
00236                      &actionTaken,     /* reason for failure        */
00237                      0,                /* initial size of new file  */
00238                      FILE_NORMAL,      /* file system attributes    */
00239                      flags,            /* Open flags                */
00240                      access,           /* Open mode and rights      */
00241                      0);               /* OS/2 Extended Attributes  */
00242         }
00243         else
00244         {
00245                 rc = DosOpen((char*)name,
00246                      &file,            /* file handle if successful */
00247                      &actionTaken,     /* reason for failure        */
00248                      0,                /* initial size of new file  */
00249                      FILE_NORMAL,      /* file system attributes    */
00250                      flags,            /* Open flags                */
00251                      access,           /* Open mode and rights      */
00252                      0);               /* OS/2 Extended Attributes  */
00253         };
00254         if (rc == ERROR_TOO_MANY_OPEN_FILES) {
00255             ULONG CurMaxFH = 0;
00256             LONG ReqCount = 20;
00257             APIRET rc2;
00258             rc2 = DosSetRelMaxFH(&ReqCount, &CurMaxFH);
00259             if (rc2 != NO_ERROR) {
00260                 break;
00261             }
00262         }
00263     } while (rc == ERROR_TOO_MANY_OPEN_FILES);
00264 
00265     if (rc != NO_ERROR) {
00266         _PR_MD_MAP_OPEN_ERROR(rc);
00267         return -1; 
00268     }
00269 
00270     return (PRInt32)file;
00271 }
00272 
00273 PRInt32
00274 _PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len)
00275 {
00276     ULONG bytes;
00277     int rv;
00278 
00279     rv = DosRead((HFILE)fd->secret->md.osfd,
00280                  (PVOID)buf,
00281                  len,
00282                  &bytes);
00283     
00284     if (rv != NO_ERROR) 
00285     {
00286         /* ERROR_HANDLE_EOF can only be returned by async io */
00287         PR_ASSERT(rv != ERROR_HANDLE_EOF);
00288         if (rv == ERROR_BROKEN_PIPE)
00289             return 0;
00290               else {
00291                      _PR_MD_MAP_READ_ERROR(rv);
00292         return -1;
00293     }
00294     }
00295     return (PRInt32)bytes;
00296 }
00297 
00298 PRInt32
00299 _PR_MD_WRITE(PRFileDesc *fd, const void *buf, PRInt32 len)
00300 {
00301     PRInt32 bytes;
00302     int rv; 
00303 
00304     rv = DosWrite((HFILE)fd->secret->md.osfd,
00305                   (PVOID)buf,
00306                   len,
00307                   (PULONG)&bytes);
00308 
00309     if (rv != NO_ERROR) 
00310     {
00311         _PR_MD_MAP_WRITE_ERROR(rv);
00312         return -1;
00313     }
00314 
00315     if (len != bytes) {
00316         rv = ERROR_DISK_FULL;
00317         _PR_MD_MAP_WRITE_ERROR(rv);
00318         return -1;
00319     }
00320 
00321     return bytes;
00322 } /* --- end _PR_MD_WRITE() --- */
00323 
00324 PRInt32
00325 _PR_MD_LSEEK(PRFileDesc *fd, PRInt32 offset, PRSeekWhence whence)
00326 {
00327     PRInt32 rv;
00328     PRUword newLocation;
00329 
00330     rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, offset, whence, &newLocation);
00331 
00332        if (rv != NO_ERROR) {
00333               _PR_MD_MAP_LSEEK_ERROR(rv);
00334               return -1;
00335        } else
00336               return newLocation;
00337 }
00338 
00339 PRInt64
00340 _PR_MD_LSEEK64(PRFileDesc *fd, PRInt64 offset, PRSeekWhence whence)
00341 {
00342 #ifdef NO_LONG_LONG
00343     PRInt64 result;
00344     PRInt32 rv, low = offset.lo, hi = offset.hi;
00345     PRUword newLocation;
00346 
00347     rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, low, whence, &newLocation);
00348     rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, hi, FILE_CURRENT, &newLocation);
00349 
00350        if (rv != NO_ERROR) {
00351               _PR_MD_MAP_LSEEK_ERROR(rv);
00352               hi = newLocation = -1;
00353    }
00354 
00355     result.lo = newLocation;
00356     result.hi = hi;
00357        return result;
00358 
00359 #else
00360     PRInt32 where, rc, lo = (PRInt32)offset, hi = (PRInt32)(offset >> 32);
00361     PRUint64 rv;
00362     PRUint32 newLocation, uhi;
00363     PRUint64 newLocationL;
00364 
00365     switch (whence)
00366       {
00367       case PR_SEEK_SET:
00368         where = FILE_BEGIN;
00369         break;
00370       case PR_SEEK_CUR:
00371         where = FILE_CURRENT;
00372         break;
00373       case PR_SEEK_END:
00374         where = FILE_END;
00375         break;
00376       default:
00377         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
00378         return -1;
00379     }
00380     if (isWSEB)
00381     {
00382         rc = myDosSetFilePtrL((HFILE)fd->secret->md.osfd, offset, where, (PLONGLONG)&newLocationL);
00383     }
00384     else
00385     {
00386         rc = DosSetFilePtr((HFILE)fd->secret->md.osfd, lo, where, (PULONG)&newLocation);
00387     }
00388      
00389     if (rc != NO_ERROR) {
00390       _PR_MD_MAP_LSEEK_ERROR(rc);
00391       return -1;
00392     }
00393     
00394     if (isWSEB)
00395     {
00396         return newLocationL;
00397     }
00398 
00399     uhi = (PRUint32)hi;
00400     PR_ASSERT((PRInt32)uhi >= 0);
00401     rv = uhi;
00402     PR_ASSERT((PRInt64)rv >= 0);
00403     rv = (rv << 32);
00404     PR_ASSERT((PRInt64)rv >= 0);
00405     rv += newLocation;
00406     PR_ASSERT((PRInt64)rv >= 0);
00407     return (PRInt64)rv;
00408 #endif
00409 }
00410 
00411 PRInt32
00412 _PR_MD_FSYNC(PRFileDesc *fd)
00413 {
00414     PRInt32 rc = DosResetBuffer((HFILE)fd->secret->md.osfd);
00415 
00416     if (rc != NO_ERROR) {
00417        if (rc != ERROR_ACCESS_DENIED) {   
00418                      _PR_MD_MAP_FSYNC_ERROR(rc);
00419            return -1;
00420        }
00421     }
00422     return 0;
00423 }
00424 
00425 PRInt32
00426 _MD_CloseFile(PRInt32 osfd)
00427 {
00428     PRInt32 rv;
00429     
00430     rv = DosClose((HFILE)osfd);
00431        if (rv != NO_ERROR)
00432               _PR_MD_MAP_CLOSE_ERROR(rv);
00433     return rv;
00434 }
00435 
00436 
00437 /* --- DIR IO ------------------------------------------------------------ */
00438 #define GetFileFromDIR(d)       (isWSEB?(d)->d_entry.large.achName:(d)->d_entry.small.achName)
00439 #define GetFileAttr(d)          (isWSEB?(d)->d_entry.large.attrFile:(d)->d_entry.small.attrFile)
00440 
00441 void FlipSlashes(char *cp, int len)
00442 {
00443     while (--len >= 0) {
00444     if (cp[0] == '/') {
00445         cp[0] = PR_DIRECTORY_SEPARATOR;
00446     }
00447     cp++;
00448     }
00449 }
00450 
00451 /*
00452 **
00453 ** Local implementations of standard Unix RTL functions which are not provided
00454 ** by the VAC RTL.
00455 **
00456 */
00457 
00458 PRInt32
00459 _PR_MD_CLOSE_DIR(_MDDir *d)
00460 {
00461    PRInt32 rc;
00462 
00463     if ( d ) {
00464       rc = DosFindClose(d->d_hdl);
00465       if(rc == NO_ERROR){
00466         d->magic = (PRUint32)-1;
00467         return PR_SUCCESS;
00468               } else {
00469                      _PR_MD_MAP_CLOSEDIR_ERROR(rc);
00470               return PR_FAILURE;
00471               }
00472     }
00473     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
00474     return PR_FAILURE;
00475 }
00476 
00477 
00478 PRStatus
00479 _PR_MD_OPEN_DIR(_MDDir *d, const char *name)
00480 {
00481     char filename[ CCHMAXPATH ];
00482     PRUword numEntries, rc;
00483 
00484     numEntries = 1;
00485 
00486     PR_snprintf(filename, CCHMAXPATH, "%s%s%s",
00487                 name, PR_DIRECTORY_SEPARATOR_STR, "*.*");
00488     FlipSlashes( filename, strlen(filename) );
00489 
00490     d->d_hdl = HDIR_CREATE;
00491 
00492     if (isWSEB)
00493     {
00494         rc = DosFindFirst( filename,
00495                            &d->d_hdl,
00496                            FILE_DIRECTORY | FILE_HIDDEN,
00497                            &(d->d_entry.large),
00498                            sizeof(d->d_entry.large),
00499                            &numEntries,
00500                            FIL_STANDARDL);
00501     }
00502     else
00503     {
00504         rc = DosFindFirst( filename,
00505                            &d->d_hdl,
00506                            FILE_DIRECTORY | FILE_HIDDEN,
00507                            &(d->d_entry.small),
00508                            sizeof(d->d_entry.small),
00509                            &numEntries,
00510                            FIL_STANDARD);
00511     }
00512     if ( rc != NO_ERROR ) {
00513               _PR_MD_MAP_OPENDIR_ERROR(rc);
00514         return PR_FAILURE;
00515     }
00516     d->firstEntry = PR_TRUE;
00517     d->magic = _MD_MAGIC_DIR;
00518     return PR_SUCCESS;
00519 }
00520 
00521 char *
00522 _PR_MD_READ_DIR(_MDDir *d, PRIntn flags)
00523 {
00524     PRUword numFiles = 1;
00525     BOOL rv;
00526     char *fileName;
00527     USHORT fileAttr;
00528 
00529     if ( d ) {
00530        while (1) {
00531            if (d->firstEntry) {
00532                d->firstEntry = PR_FALSE;
00533                rv = NO_ERROR;
00534            } else {
00535                rv = DosFindNext(d->d_hdl,
00536                                 &(d->d_entry),
00537                                 sizeof(d->d_entry),
00538                                 &numFiles);
00539            }
00540            if (rv != NO_ERROR) {
00541                break;
00542            }
00543            fileName = GetFileFromDIR(d);
00544            fileAttr = GetFileAttr(d);
00545            if ( (flags & PR_SKIP_DOT) &&
00546                 (fileName[0] == '.') && (fileName[1] == '\0'))
00547                 continue;
00548            if ( (flags & PR_SKIP_DOT_DOT) &&
00549                 (fileName[0] == '.') && (fileName[1] == '.') &&
00550                 (fileName[2] == '\0'))
00551                 continue;
00552                      /*
00553                       * XXX
00554                       * Is this the correct definition of a hidden file on OS/2?
00555                       */
00556            if ((flags & PR_SKIP_NONE) && (fileAttr & FILE_HIDDEN))
00557                 return fileName;
00558            else if ((flags & PR_SKIP_HIDDEN) && (fileAttr & FILE_HIDDEN))
00559                 continue;
00560            return fileName;
00561         }
00562         PR_ASSERT(NO_ERROR != rv);
00563                      _PR_MD_MAP_READDIR_ERROR(rv);
00564         return NULL;
00565               }
00566     PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
00567     return NULL;
00568 }
00569 
00570 PRInt32
00571 _PR_MD_DELETE(const char *name)
00572 {
00573     PRInt32 rc = DosDelete((char*)name);
00574     if(rc == NO_ERROR) {
00575         return 0;
00576     } else {
00577               _PR_MD_MAP_DELETE_ERROR(rc);
00578         return -1;
00579     }
00580 }
00581 
00582 PRInt32
00583 _PR_MD_STAT(const char *fn, struct stat *info)
00584 {
00585     PRInt32 rv;
00586     char filename[CCHMAXPATH];
00587 
00588     PR_snprintf(filename, CCHMAXPATH, "%s", fn);
00589     FlipSlashes(filename, strlen(filename));
00590 
00591     rv = _stat((char*)filename, info);
00592     if (-1 == rv) {
00593         /*
00594          * Check for MSVC runtime library _stat() bug.
00595          * (It's really a bug in FindFirstFile().)
00596          * If a pathname ends in a backslash or slash,
00597          * e.g., c:\temp\ or c:/temp/, _stat() will fail.
00598          * Note: a pathname ending in a slash (e.g., c:/temp/)
00599          * can be handled by _stat() on NT but not on Win95.
00600          *
00601          * We remove the backslash or slash at the end and
00602          * try again.  
00603          *
00604          * Not sure if this happens on OS/2 or not,
00605          * but it doesn't hurt to be careful.
00606          */
00607 
00608         int len = strlen(fn);
00609         if (len > 0 && len <= _MAX_PATH
00610                 && (fn[len - 1] == '\\' || fn[len - 1] == '/')) {
00611             char newfn[_MAX_PATH + 1];
00612 
00613             strcpy(newfn, fn);
00614             newfn[len - 1] = '\0';
00615             rv = _stat(newfn, info);
00616         }
00617     }
00618 
00619     if (-1 == rv) {
00620         _PR_MD_MAP_STAT_ERROR(errno);
00621     }
00622     return rv;
00623 }
00624 
00625 PRInt32
00626 _PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info)
00627 {
00628     struct stat sb;
00629     PRInt32 rv;
00630     PRInt64 s, s2us;
00631  
00632     if ( (rv = _PR_MD_STAT(fn, &sb)) == 0 ) {
00633         if (info) {
00634             if (S_IFREG & sb.st_mode)
00635                 info->type = PR_FILE_FILE ;
00636             else if (S_IFDIR & sb.st_mode)
00637                 info->type = PR_FILE_DIRECTORY;
00638             else
00639                 info->type = PR_FILE_OTHER;
00640             info->size = sb.st_size;
00641             LL_I2L(s2us, PR_USEC_PER_SEC);
00642             LL_I2L(s, sb.st_mtime);
00643             LL_MUL(s, s, s2us);
00644             info->modifyTime = s;
00645             LL_I2L(s, sb.st_ctime);
00646             LL_MUL(s, s, s2us);
00647             info->creationTime = s;
00648         }
00649     }
00650     return rv;
00651 }
00652 
00653 PRInt32
00654 _PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info)
00655 {
00656     PRFileInfo info32;
00657     PRInt32 rv = _PR_MD_GETFILEINFO(fn, &info32);
00658     if (rv != 0)
00659     {
00660         return rv;
00661     }
00662     info->type = info32.type;
00663     LL_UI2L(info->size,info32.size);
00664     info->modifyTime = info32.modifyTime;
00665     info->creationTime = info32.creationTime;
00666     
00667     if (isWSEB)
00668     {
00669         APIRET rc ;
00670         FILESTATUS3L fstatus;
00671 
00672         rc = DosQueryPathInfo(fn, FIL_STANDARDL, &fstatus, sizeof(fstatus));
00673 
00674         if (NO_ERROR != rc)
00675         {
00676             _PR_MD_MAP_OPEN_ERROR(rc);
00677             return -1;
00678         }
00679 
00680         if (! (fstatus.attrFile & FILE_DIRECTORY))
00681         {
00682             info->size = fstatus.cbFile;
00683         }
00684     }
00685 
00686     return rv;
00687 }
00688 
00689 PRInt32
00690 _PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info)
00691 {
00692    /* For once, the VAC compiler/library did a nice thing.
00693     * The file handle used by the C runtime is the same one
00694     * returned by the OS when you call DosOpen().  This means
00695     * that you can take an OS HFILE and use it with C file
00696     * functions.  The only caveat is that you have to call
00697     * _setmode() first to initialize some junk.  This is
00698     * immensely useful because I did not have a clue how to
00699     * implement this function otherwise.  The windows folks
00700     * took the source from the Microsoft C library source, but
00701     * IBM wasn't kind enough to ship the source with VAC.
00702     * On second thought, the needed function could probably
00703     * be gotten from the OS/2 GNU library source, but the
00704     * point is now moot.
00705     */
00706    struct stat hinfo;
00707     PRInt64 s, s2us;
00708 
00709     _setmode(fd->secret->md.osfd, O_BINARY);
00710     if(fstat((int)fd->secret->md.osfd, &hinfo) != NO_ERROR) {
00711               _PR_MD_MAP_FSTAT_ERROR(errno);
00712         return -1;
00713        }
00714 
00715     if (hinfo.st_mode & S_IFDIR)
00716         info->type = PR_FILE_DIRECTORY;
00717     else
00718         info->type = PR_FILE_FILE;
00719 
00720     info->size = hinfo.st_size;
00721     LL_I2L(s2us, PR_USEC_PER_SEC);
00722     LL_I2L(s, hinfo.st_mtime);
00723     LL_MUL(s, s, s2us);
00724     info->modifyTime = s;
00725     LL_I2L(s, hinfo.st_ctime);
00726     LL_MUL(s, s, s2us);
00727     info->creationTime = s;
00728 
00729     return 0;
00730 }
00731 
00732 PRInt32
00733 _PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info)
00734 {
00735     PRFileInfo info32;
00736     PRInt32 rv = _PR_MD_GETOPENFILEINFO(fd, &info32);
00737     if (0 == rv)
00738     {
00739        info->type = info32.type;
00740        LL_UI2L(info->size,info32.size);
00741     
00742        info->modifyTime = info32.modifyTime;
00743        info->creationTime = info32.creationTime;
00744     }
00745     
00746     if (isWSEB)
00747     {
00748         APIRET rc ;
00749         FILESTATUS3L fstatus;
00750 
00751         rc = DosQueryFileInfo(fd->secret->md.osfd, FIL_STANDARDL, &fstatus, sizeof(fstatus));
00752 
00753         if (NO_ERROR != rc)
00754         {
00755             _PR_MD_MAP_OPEN_ERROR(rc);
00756             return -1;
00757         }
00758 
00759         if (! (fstatus.attrFile & FILE_DIRECTORY))
00760         {
00761             info->size = fstatus.cbFile;
00762         }
00763     }
00764 
00765     return rv;
00766 }
00767 
00768 
00769 PRInt32
00770 _PR_MD_RENAME(const char *from, const char *to)
00771 {
00772    PRInt32 rc;
00773     /* Does this work with dot-relative pathnames? */
00774     if ( (rc = DosMove((char *)from, (char *)to)) == NO_ERROR) {
00775         return 0;
00776     } else {
00777               _PR_MD_MAP_RENAME_ERROR(rc);
00778         return -1;
00779     }
00780 }
00781 
00782 PRInt32
00783 _PR_MD_ACCESS(const char *name, PRAccessHow how)
00784 {
00785   PRInt32 rv;
00786     switch (how) {
00787       case PR_ACCESS_WRITE_OK:
00788         rv = access(name, 02);
00789               break;
00790       case PR_ACCESS_READ_OK:
00791         rv = access(name, 04);
00792               break;
00793       case PR_ACCESS_EXISTS:
00794         return access(name, 00);
00795               break;
00796       default:
00797               PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
00798               return -1;
00799     }
00800        if (rv < 0)
00801               _PR_MD_MAP_ACCESS_ERROR(errno);
00802     return rv;
00803 }
00804 
00805 PRInt32
00806 _PR_MD_MKDIR(const char *name, PRIntn mode)
00807 {
00808    PRInt32 rc;
00809     /* XXXMB - how to translate the "mode"??? */
00810     if ((rc = DosCreateDir((char *)name, NULL))== NO_ERROR) {
00811         return 0;
00812     } else {
00813               _PR_MD_MAP_MKDIR_ERROR(rc);
00814         return -1;
00815     }
00816 }
00817 
00818 PRInt32
00819 _PR_MD_RMDIR(const char *name)
00820 {
00821    PRInt32 rc;
00822     if ( (rc = DosDeleteDir((char *)name)) == NO_ERROR) {
00823         return 0;
00824     } else {
00825               _PR_MD_MAP_RMDIR_ERROR(rc);
00826         return -1;
00827     }
00828 }
00829 
00830 PRStatus
00831 _PR_MD_LOCKFILE(PRInt32 f)
00832 {
00833     PRInt32   rv;
00834     FILELOCK lock, unlock;
00835     FILELOCKL lockL, unlockL;
00836     
00837     lock.lOffset = 0;
00838     lockL.lOffset = 0;
00839     lock.lRange = 0xffffffff;
00840     lockL.lRange =  0xffffffffffffffff;
00841     unlock.lOffset = 0;
00842     unlock.lRange = 0;
00843     unlockL.lOffset = 0;
00844     unlockL.lRange = 0;
00845 
00846     /*
00847      * loop trying to DosSetFileLocks(),
00848      * pause for a few miliseconds when can't get the lock
00849      * and try again
00850      */
00851     for( rv = FALSE; rv == FALSE; /* do nothing */ )
00852     {
00853         if (isWSEB)
00854         {
00855            rv = myDosSetFileLocksL( (HFILE) f,
00856                                          &unlockL, &lockL,
00857                                          0, 0);
00858         }
00859         else
00860         {
00861            rv = DosSetFileLocks( (HFILE) f,
00862                                          &unlock, &lock,
00863                                          0, 0);
00864         }
00865               if ( rv != NO_ERROR )
00866         {
00867             DosSleep( 50 );  /* Sleep() a few milisecs and try again. */
00868         }            
00869     } /* end for() */
00870     return PR_SUCCESS;
00871 } /* end _PR_MD_LOCKFILE() */
00872 
00873 PRStatus
00874 _PR_MD_TLOCKFILE(PRInt32 f)
00875 {
00876     return _PR_MD_LOCKFILE(f);
00877 } /* end _PR_MD_TLOCKFILE() */
00878 
00879 
00880 PRStatus
00881 _PR_MD_UNLOCKFILE(PRInt32 f)
00882 {
00883     PRInt32   rv;
00884     FILELOCK lock, unlock;
00885     FILELOCKL lockL, unlockL;
00886     
00887     lock.lOffset = 0;
00888     lockL.lOffset = 0;
00889     lock.lRange = 0;
00890     lockL.lRange = 0;
00891     unlock.lOffset = 0;
00892     unlockL.lOffset = 0;
00893     unlock.lRange = 0xffffffff;
00894     unlockL.lRange = 0xffffffffffffffff;
00895     
00896     if (isWSEB)
00897     {
00898         rv = myDosSetFileLocksL( (HFILE) f,
00899                                         &unlockL, &lockL,
00900                                         0, 0);
00901     }
00902     else
00903     {
00904         rv = DosSetFileLocks( (HFILE) f,
00905                                     &unlock, &lock,
00906                                     0, 0);
00907     }
00908             
00909     if ( rv != NO_ERROR )
00910     {
00911         return PR_SUCCESS;
00912     }
00913     else
00914     {
00915         return PR_FAILURE;
00916     }
00917 } /* end _PR_MD_UNLOCKFILE() */
00918 
00919 PRStatus
00920 _PR_MD_SET_FD_INHERITABLE(PRFileDesc *fd, PRBool inheritable)
00921 {
00922     APIRET rc = 0;
00923     ULONG flags;
00924     switch (fd->methods->file_type)
00925     {
00926         case PR_DESC_PIPE:
00927         case PR_DESC_FILE:
00928             rc = DosQueryFHState((HFILE)fd->secret->md.osfd, &flags);
00929             if (rc != NO_ERROR) {
00930                 PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO());
00931                 return PR_FAILURE;
00932             }
00933 
00934             if (inheritable)
00935               flags &= ~OPEN_FLAGS_NOINHERIT;
00936             else
00937               flags |= OPEN_FLAGS_NOINHERIT;
00938 
00939             /* Mask off flags DosSetFHState don't want. */
00940             flags &= (OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_CACHE | OPEN_FLAGS_NOINHERIT);
00941             rc = DosSetFHState((HFILE)fd->secret->md.osfd, flags);
00942             if (rc != NO_ERROR) {
00943                 PR_SetError(PR_UNKNOWN_ERROR, _MD_ERRNO());
00944                 return PR_FAILURE;
00945             }
00946             break;
00947 
00948         case PR_DESC_LAYERED:
00949             /* what to do here? */
00950             PR_SetError(PR_UNKNOWN_ERROR, 87 /*ERROR_INVALID_PARAMETER*/);
00951             return PR_FAILURE;
00952 
00953         case PR_DESC_SOCKET_TCP:
00954         case PR_DESC_SOCKET_UDP:
00955             /* These are global on OS/2. */
00956             break;
00957     }
00958 
00959     return PR_SUCCESS;
00960 }
00961 
00962 void
00963 _PR_MD_INIT_FD_INHERITABLE(PRFileDesc *fd, PRBool imported)
00964 {
00965     /* XXX this function needs to be implemented */
00966     fd->secret->inheritable = _PR_TRI_UNKNOWN;
00967 }
00968 
00969 void
00970 _PR_MD_QUERY_FD_INHERITABLE(PRFileDesc *fd)
00971 {
00972     /* XXX this function needs to be reviewed */
00973     ULONG flags;
00974 
00975     PR_ASSERT(_PR_TRI_UNKNOWN == fd->secret->inheritable);
00976     if (DosQueryFHState((HFILE)fd->secret->md.osfd, &flags) == 0) {
00977         if (flags & OPEN_FLAGS_NOINHERIT) {
00978             fd->secret->inheritable = _PR_TRI_FALSE;
00979         } else {
00980             fd->secret->inheritable = _PR_TRI_TRUE;
00981         }
00982     }
00983 }