/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/* OS2 IO module
*
* Assumes synchronous I/O.
*
*/
#include "primpl.h"
#include <direct.h>
struct _MDLock _pr_ioq_lock;
PRStatus
_PR_MD_WAIT(PRThread *thread, PRIntervalTime ticks)
{
PRInt32 rv;
ULONG count;
PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ?
SEM_INDEFINITE_WAIT : PR_IntervalToMilliseconds(ticks);
rv = DosWaitEventSem(thread->md.blocked_sema.sem, msecs);
DosResetEventSem(thread->md.blocked_sema.sem, &count);
switch(rv)
{
case NO_ERROR:
return PR_SUCCESS;
break;
case ERROR_TIMEOUT:
_PR_THREAD_LOCK(thread);
if (thread->state == _PR_IO_WAIT) {
;
} else {
if (thread->wait.cvar != NULL) {
thread->wait.cvar = NULL;
_PR_THREAD_UNLOCK(thread);
} else {
/* The CVAR was notified just as the timeout
* occurred. This led to us being notified twice.
* call SemRequest() to clear the semaphore.
*/
_PR_THREAD_UNLOCK(thread);
rv = DosWaitEventSem(thread->md.blocked_sema.sem, 0);
DosResetEventSem(thread->md.blocked_sema.sem, &count);
PR_ASSERT(rv == NO_ERROR);
}
}
return PR_SUCCESS;
break;
default:
break;
}
return PR_FAILURE;
}
PRStatus
_PR_MD_WAKEUP_WAITER(PRThread *thread)
{
if ( _PR_IS_NATIVE_THREAD(thread) )
{
if (DosPostEventSem(thread->md.blocked_sema.sem) != NO_ERROR)
return PR_FAILURE;
else
return PR_SUCCESS;
}
}
/* --- FILE IO ----------------------------------------------------------- */
/*
* _PR_MD_OPEN() -- Open a file
*
* returns: a fileHandle
*
* The NSPR open flags (osflags) are translated into flags for OS/2
*
* Mode seems to be passed in as a unix style file permissions argument
* as in 0666, in the case of opening the logFile.
*
*/
PRInt32
_PR_MD_OPEN(const char *name, PRIntn osflags, int mode)
{
HFILE file;
PRInt32 access = OPEN_SHARE_DENYNONE;
PRInt32 flags = OPEN_ACTION_OPEN_IF_EXISTS;
PRInt32 rc;
PRUword actionTaken;
ULONG CurMaxFH = 0;
LONG ReqCount = 1;
if (osflags & PR_RDONLY)
access |= OPEN_ACCESS_READONLY;
else if (osflags & PR_WRONLY)
access |= OPEN_ACCESS_WRITEONLY;
else if(osflags & PR_RDWR)
access |= OPEN_ACCESS_READWRITE;
if (osflags & PR_CREATE_FILE)
flags |= OPEN_ACTION_CREATE_IF_NEW;
else if (osflags & PR_TRUNCATE){
flags &= ~OPEN_ACTION_OPEN_IF_EXISTS;
flags |= OPEN_ACTION_REPLACE_IF_EXISTS;
}
/* OS/2 sets the Max file handles per process to 20 by default */
DosSetRelMaxFH(&ReqCount, &CurMaxFH);
rc = DosOpen((char*)name,
&file, /* file handle if successful */
&actionTaken, /* reason for failure */
0, /* initial size of new file */
FILE_NORMAL, /* file system attributes */
flags, /* Open flags */
access, /* Open mode and rights */
0); /* OS/2 Extended Attributes */
if (rc != NO_ERROR) {
_PR_MD_MAP_OPEN_ERROR(rc);
return -1;
}
return (PRInt32)file;
}
PRInt32
_PR_MD_READ(PRFileDesc *fd, void *buf, PRInt32 len)
{
PRUword bytes;
int rv;
rv = DosRead((HFILE)fd->secret->md.osfd,
(PVOID)buf,
len,
&bytes);
if (rv != NO_ERROR)
{
/* ERROR_HANDLE_EOF can only be returned by async io */
PR_ASSERT(rv != ERROR_HANDLE_EOF);
if (rv == ERROR_BROKEN_PIPE)
return 0;
else {
_PR_MD_MAP_READ_ERROR(rv);
return -1;
}
}
return bytes;
}
PRInt32
_PR_MD_WRITE(PRFileDesc *fd, const void *buf, PRInt32 len)
{
PRUword bytes;
int rv;
/* No longer using DosWrite since it doesn't convert \n to \n\r like C runtime does */
#if 0
rv = DosWrite((HFILE)fd->secret->md.osfd,
(PVOID)buf,
len,
&bytes);
if (rv != NO_ERROR)
{
_PR_MD_MAP_WRITE_ERROR(rv);
return -1;
}
#else
bytes = write(fd->secret->md.osfd, buf, len);
if (rv == -1)
_PR_MD_MAP_WRITE_ERROR(errno);
#endif
return bytes;
} /* --- end _PR_MD_WRITE() --- */
PRInt32
_PR_MD_LSEEK(PRFileDesc *fd, PRInt32 offset, int whence)
{
PRInt32 rv;
PRUword newLocation;
rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, offset, whence, &newLocation);
if (rv != NO_ERROR) {
_PR_MD_MAP_LSEEK_ERROR(rv);
return -1;
} else
return newLocation;
}
PRInt64
_PR_MD_LSEEK64(PRFileDesc *fd, PRInt64 offset, int whence)
{
PRInt64 result;
PRInt32 rv, low = offset.lo, hi = offset.hi;
PRUword newLocation;
rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, low, whence, &newLocation);
rv = DosSetFilePtr((HFILE)fd->secret->md.osfd, hi, FILE_CURRENT, &newLocation);
if (rv != NO_ERROR) {
_PR_MD_MAP_LSEEK_ERROR(rv);
hi = newLocation = -1;
}
result.lo = hi;
result.hi = newLocation;
return result;
}
PRInt32
_PR_MD_FSYNC(PRFileDesc *fd)
{
PRInt32 rc = DosResetBuffer((HFILE)fd->secret->md.osfd);
if (rc != NO_ERROR) {
if (rc != ERROR_ACCESS_DENIED) {
_PR_MD_MAP_FSYNC_ERROR(rc);
return -1;
}
}
return 0;
}
PRInt32
_MD_CloseFile(PRInt32 osfd)
{
PRInt32 rv;
rv = DosClose((HFILE)osfd);
if (rv != NO_ERROR)
_PR_MD_MAP_CLOSE_ERROR(rv);
return rv;
}
/* --- DIR IO ------------------------------------------------------------ */
#define GetFileFromDIR(d) (d)->d_entry.achName
void FlipSlashes(char *cp, int len)
{
while (--len >= 0) {
if (cp[0] == '/') {
cp[0] = PR_DIRECTORY_SEPARATOR;
}
cp++;
}
}
/*
**
** Local implementations of standard Unix RTL functions which are not provided
** by the VAC RTL.
**
*/
PRInt32
_PR_MD_CLOSE_DIR(_MDDir *d)
{
PRInt32 rc;
if ( d ) {
rc = DosFindClose(d->d_hdl);
if(rc == NO_ERROR){
d->magic = (PRUint32)-1;
return PR_SUCCESS;
} else {
_PR_MD_MAP_CLOSEDIR_ERROR(rc);
return PR_FAILURE;
}
}
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
return PR_FAILURE;
}
PRStatus
_PR_MD_OPEN_DIR(_MDDir *d, const char *name)
{
char filename[ CCHMAXPATH ];
PRUword numEntries, rc;
PR_snprintf(filename, CCHMAXPATH, "%s%s%s",
name, PR_DIRECTORY_SEPARATOR_STR, "*.*");
FlipSlashes( filename, strlen(filename) );
d->d_hdl = HDIR_CREATE;
rc = DosFindFirst( filename, &d->d_hdl, FILE_DIRECTORY, &(d->d_entry), sizeof(d->d_entry), &numEntries, FIL_STANDARD);
if ( rc != NO_ERROR ) {
_PR_MD_MAP_OPENDIR_ERROR(rc);
return PR_FAILURE;
}
d->firstEntry = PR_TRUE;
d->magic = _MD_MAGIC_DIR;
return PR_SUCCESS;
}
char *
_PR_MD_READ_DIR(_MDDir *d, PRIntn flags)
{
PRUword numFiles = 1;
BOOL rv;
char *fileName;
if ( d ) {
while (1) {
if (d->firstEntry) {
d->firstEntry = PR_FALSE;
rv = NO_ERROR;
} else {
rv = DosFindNext(d->d_hdl, &(d->d_entry), sizeof(d->d_entry), &numFiles);
}
if (rv != NO_ERROR) {
break;
}
fileName = GetFileFromDIR(d);
if ( (flags & PR_SKIP_DOT) &&
(fileName[0] == '.') && (fileName[1] == '\0'))
continue;
if ( (flags & PR_SKIP_DOT_DOT) &&
(fileName[0] == '.') && (fileName[1] == '.') &&
(fileName[2] == '\0'))
continue;
/*
* XXX
* Is this the correct definition of a hidden file on OS/2?
*/
if ( (flags & PR_SKIP_HIDDEN) && (fileName[0] == '.'))
continue;
return fileName;
}
PR_ASSERT(NO_ERROR != rv);
_PR_MD_MAP_READDIR_ERROR(rv);
return NULL;
}
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
return NULL;
}
PRInt32
_PR_MD_DELETE(const char *name)
{
PRInt32 rc = DosDelete((char*)name);
if(rc == NO_ERROR) {
return 0;
} else {
_PR_MD_MAP_DELETE_ERROR(rc);
return -1;
}
}
PRInt32
_PR_MD_STAT(const char *fn, struct stat *info)
{
PRInt32 rv;
rv = _stat((char*)fn, info);
if (-1 == rv) {
/*
* Check for MSVC runtime library _stat() bug.
* (It's really a bug in FindFirstFile().)
* If a pathname ends in a backslash or slash,
* e.g., c:\temp\ or c:/temp/, _stat() will fail.
* Note: a pathname ending in a slash (e.g., c:/temp/)
* can be handled by _stat() on NT but not on Win95.
*
* We remove the backslash or slash at the end and
* try again.
*
* Not sure if this happens on OS/2 or not,
* but it doesn't hurt to be careful.
*/
int len = strlen(fn);
if (len > 0 && len <= _MAX_PATH
&& (fn[len - 1] == '\\' || fn[len - 1] == '/')) {
char newfn[_MAX_PATH + 1];
strcpy(newfn, fn);
newfn[len - 1] = '\0';
rv = _stat(newfn, info);
}
}
if (-1 == rv) {
_PR_MD_MAP_STAT_ERROR(errno);
}
return rv;
}
PRInt32
_PR_MD_GETFILEINFO(const char *fn, PRFileInfo *info)
{
struct stat sb;
PRInt32 rv;
if ( (rv = _PR_MD_STAT(fn, &sb)) == 0 ) {
if (info) {
if (S_IFREG & sb.st_mode)
info->type = PR_FILE_FILE ;
else if (S_IFDIR & sb.st_mode)
info->type = PR_FILE_DIRECTORY;
else
info->type = PR_FILE_OTHER;
info->size = sb.st_size;
info->modifyTime.lo = sb.st_mtime;
info->creationTime.lo = sb.st_ctime;
}
}
return rv;
}
PRInt32
_PR_MD_GETFILEINFO64(const char *fn, PRFileInfo64 *info)
{
PRFileInfo info32;
PRInt32 rv = _PR_MD_GETFILEINFO(fn, &info32);
if (0 == rv)
{
info->type = info32.type;
info->size.lo = info32.size;
info->modifyTime = info32.modifyTime;
info->creationTime = info32.creationTime;
}
return rv;
}
PRInt32
_PR_MD_GETOPENFILEINFO(const PRFileDesc *fd, PRFileInfo *info)
{
/* For once, the VAC compiler/library did a nice thing.
* The file handle used by the C runtime is the same one
* returned by the OS when you call DosOpen(). This means
* that you can take an OS HFILE and use it with C file
* functions. The only caveat is that you have to call
* _setmode() first to initialize some junk. This is
* immensely useful because I did not have a clue how to
* implement this function otherwise. The windows folks
* took the source from the Microsoft C library source, but
* IBM wasn't kind enough to ship the source with VAC.
* On second thought, the needed function could probably
* be gotten from the OS/2 GNU library source, but the
* point is now moot.
*/
struct stat hinfo;
_setmode(fd->secret->md.osfd, O_BINARY);
if(fstat((int)fd->secret->md.osfd, &hinfo) != NO_ERROR) {
_PR_MD_MAP_FSTAT_ERROR(errno);
return -1;
}
if (hinfo.st_mode & S_IFDIR)
info->type = PR_FILE_DIRECTORY;
else
info->type = PR_FILE_FILE;
info->size = hinfo.st_size;
info->modifyTime.lo = hinfo.st_mtime;
info->creationTime.lo = hinfo.st_ctime;
return 0;
}
PRInt32
_PR_MD_GETOPENFILEINFO64(const PRFileDesc *fd, PRFileInfo64 *info)
{
PRFileInfo info32;
PRInt32 rv = _PR_MD_GETOPENFILEINFO(fd, &info32);
if (0 == rv)
{
info->type = info32.type;
info->size.lo = info32.size;
info->modifyTime = info32.modifyTime;
info->creationTime = info32.creationTime;
}
return rv;
}
PRInt32
_PR_MD_RENAME(const char *from, const char *to)
{
PRInt32 rc;
/* Does this work with dot-relative pathnames? */
if ( (rc = DosMove((char *)from, (char *)to)) == NO_ERROR) {
return 0;
} else {
_PR_MD_MAP_RENAME_ERROR(rc);
return -1;
}
}
PRInt32
_PR_MD_ACCESS(const char *name, PRIntn how)
{
PRInt32 rv;
switch (how) {
case PR_ACCESS_WRITE_OK:
rv = access(name, 02);
break;
case PR_ACCESS_READ_OK:
rv = access(name, 04);
break;
case PR_ACCESS_EXISTS:
return access(name, 00);
break;
default:
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
return -1;
}
if (rv < 0)
_PR_MD_MAP_ACCESS_ERROR(errno);
return rv;
}
PRInt32
_PR_MD_MKDIR(const char *name, PRIntn mode)
{
PRInt32 rc;
/* XXXMB - how to translate the "mode"??? */
if ((rc = DosCreateDir((char *)name, NULL)) == NO_ERROR) {
return 0;
} else {
_PR_MD_MAP_MKDIR_ERROR(rc);
return -1;
}
}
PRInt32
_PR_MD_RMDIR(const char *name)
{
PRInt32 rc;
if ( (rc = DosDeleteDir((char *)name)) == NO_ERROR) {
return 0;
} else {
_PR_MD_MAP_RMDIR_ERROR(rc);
return -1;
}
}
PRStatus
_PR_MD_LOCKFILE(PRInt32 f)
{
PRInt32 rv;
FILELOCK lock, unlock;
lock.lOffset = 0;
lock.lRange = 0xffffffff;
unlock.lOffset = 0;
unlock.lRange = 0;
/*
* loop trying to DosSetFileLocks(),
* pause for a few miliseconds when can't get the lock
* and try again
*/
for( rv = FALSE; rv == FALSE; /* do nothing */ )
{
rv = DosSetFileLocks( (HFILE) f,
&unlock, &lock,
0, 0);
if ( rv != NO_ERROR )
{
DosSleep( 50 ); /* Sleep() a few milisecs and try again. */
}
} /* end for() */
return PR_SUCCESS;
} /* end _PR_MD_LOCKFILE() */
PRStatus
_PR_MD_TLOCKFILE(PRInt32 f)
{
return _PR_MD_LOCKFILE(f);
} /* end _PR_MD_TLOCKFILE() */
PRStatus
_PR_MD_UNLOCKFILE(PRInt32 f)
{
PRInt32 rv;
FILELOCK lock, unlock;
lock.lOffset = 0;
lock.lRange = 0;
unlock.lOffset = 0;
unlock.lRange = 0xffffffff;
rv = DosSetFileLocks( (HFILE) f,
&unlock, &lock,
0, 0);
if ( rv != NO_ERROR )
{
return PR_SUCCESS;
}
else
{
return PR_FAILURE;
}
} /* end _PR_MD_UNLOCKFILE() */
syntax highlighted by Code2HTML, v. 0.9.1