Milán Major

netscape-revival

1 branch
Code

nspr-/src/prfileio.c

#include <stdarg.h>
#include <string.h>
#include "prfile.h"

#ifdef SW_THREADS
#include "swkern.h"
#else
#include "hwkern.h"
#endif

#if !defined(XP_STRLEN)
#define XP_STRLEN(str)          strlen(str)
#endif

#define _OS_ERROR_EAGAIN        (-EAGAIN)
#define _OS_ERROR_EINTR         (-EINTR)

#define PR_ERROR_INVALID_FD     (-EBADF)
#define PR_ERROR_WOULD_BLOCK    (-EWOULDBLOCK)

PRIOMethods _pr_file_methods;

extern PRFileHandle _PR_InitFileHandle(PROSFD osfd, PRIOMethods *m);

/*
** Open a file on the native filesystem.
*/
PR_PUBLIC_API(PRFileHandle) PR_OpenFile(const char *fileName, int flags, 
                                       int mode)
{
    PRFileHandle hdl = -1;
    int oserror;
    char *fn;

    _PR_InitIO();

    fn = _OS_PREPARE_NAME(fileName, XP_STRLEN(fileName));
    if (!fn) {
        return 0;
    }

#if defined(XP_UNIX)
    flags |= O_NONBLOCK;

#elif defined(XP_PC)

#elif defined(XP_MAC)
#endif
    oserror = _OS_OPEN(fn, flags, mode);
    if (oserror < 0) {
        /* unable to open the file. */
        PR_SetError(oserror);
        goto done;
    } 

    /* the os-file-handle is valid*/
    hdl = _PR_InitFileHandle((PROSFD) oserror, &_pr_file_methods);
    if( hdl == -1 ) {
        /*
	** Unable to get a slot in the FD table. Ignore error from
	** OS_CLOSE so we don't hide table allocation failure.
	*/
        (void) _OS_CLOSE((PROSFD) oserror);
        hdl = -1;
    }

   done:
    _OS_FREE_NAME(fn);
    return hdl;
}

/*
** Read data from a file object into buffer. This allows for async file
** i/o in case either the underlying system supports it or if (for
** example) files are used to represent devices (e.g. unix).
*/
int32 _PR_ReadFile(PRFileDesc *fd, void *buf, int32 amount)
{
    int32 oserror;

    if (!fd || _OS_INVALID_FD(fd)) {
        PR_SetError(PR_ERROR_INVALID_FD);
        return -1;
    }

    oserror = _OS_READ(fd->osfd, buf, amount);
    while ((oserror < 0) && !_PR_PENDING_EXCEPTION() &&
           (oserror == _OS_ERROR_EAGAIN || oserror == _OS_ERROR_EINTR)) {
        if (oserror == _OS_ERROR_EAGAIN) {
            if (fd->flags & _PR_USER_ASYNC) {
                oserror = PR_ERROR_WOULD_BLOCK;
                PR_SetError(oserror);
                return oserror;
            }
            _PR_WaitForFD(fd, 1);
        }
        oserror = _OS_READ(fd->osfd, buf, amount);
    }
    return oserror;
}

#if 0
/*
** Scatter gather data from a file object into buffer. This allows for
** async file i/o in case either the underlying system supports it or if
** (for example) files are used to represent devices (e.g. unix).
*/
int32 _PR_ReadvFile(PRFileDesc *fd, PRIOVec *iov, int iovcnt)
{
    int32 oserror;

    if (!fd || _OS_INVALID_FD(fd)) {
        PR_SetError(PR_ERROR_INVALID_FD);
        return -1;
    }

    oserror = _OS_READV(fd->osfd, iov, iovcnt);
    while ((oserror < 0) && !_PR_PENDING_EXCEPTION() &&
           ((oserror == _OS_ERROR_EAGAIN) || (oserrno == _OS_ERROR_EINTR))) {
        if (oserror == _OS_ERROR_EAGAIN) {
            if (fd->flags & _PR_USER_ASYNC) {
                oserror = PR_ERROR_WOULD_BLOCK;
                PR_SetError(oserror);
                return oserror;
            }
            _PR_WaitForFD(fd, 1);
        }
        oserror = _OS_READV(fd->osfd, iov, iovcnt);
    }
    return oserror;
}
#endif

/*
** Write data to a file object from a buffer. This allows for async file
** i/o in case either the underlying system supports it or if (for
** example) files are used to represent devices (e.g. unix).
*/
int32 _PR_WriteFile(PRFileDesc *fd, const void *buf, int32 amount)
{
    const char *bp = (const char*) buf;
    int32 oserror, total_written;

    if (!fd || _OS_INVALID_FD(fd)) {
        PR_SetError(PR_ERROR_INVALID_FD);
        return -1;
    }
    total_written = 0;
    while ((total_written < amount) && !_PR_PENDING_EXCEPTION()) {
        oserror = _OS_WRITE(fd->osfd, bp+total_written, amount-total_written);
        while ((oserror < 0) && !_PR_PENDING_EXCEPTION()) {
            if (oserror == _OS_ERROR_EAGAIN) {
                if (fd->flags & _PR_USER_ASYNC) {
                    if (total_written == 0) {
                        oserror = PR_ERROR_WOULD_BLOCK;
                        PR_SetError(oserror);
                        total_written = oserror;
                    }
                    return total_written;
                }
                _PR_WaitForFD(fd, 0);
            } else if (oserror != _OS_ERROR_EINTR) {
                total_written = oserror;
                return total_written;
            }
            oserror = _OS_WRITE(fd->osfd, bp+total_written,
                                amount-total_written);
        }
        total_written += oserror;
    }
    return total_written;
}

#if 0
/*
** Scatter write data to a file object from some buffers. This allows for
** async file i/o in case either the underlying system supports it or if
** (for example) files are used to represent devices (e.g. unix).
*/
int32 _PR_WritevFile(PRFileDesc *fd, PRIOVec *iov, int iovcnt)
{
    int32 total_written = 0;
    int32 nwrote, ndone = 0;
    int32 oserror;

    if (!fd || _OS_INVALID_FD(fd)) {
        PR_SetError(PR_ERROR_INVALID_FD);
        return -1;
    }

    LOCK(pr_asyncOutput);
    _PR_AsyncFD(fd);

    while ((iovcnt > 0) && !pendingException() ) {
        iov->iov_len -= ndone;
        iov->iov_base += ndone;
        nwrote = OS_WRITEV_FILE(fd->osfd, iov, iovcnt, &oserror);
        while (oserror) {
            if (errno == EAGAIN) {
                if (fd->flags & FD_ASYNC) {
                    if (total_written == 0) {
                        total_written = -1;
                    }
                    goto unlock;
                }
                _PR_WaitForFD(fd, 0);
            } else if (errno != EINTR) {
                total_written = -1;
                goto unlock;
            }
            nwrote = OS_WRITEV_FILE(fd->osfd, iov, iovcnt, &oserror);
        }
        total_written += nwrote;
        iov->iov_len += ndone;
        iov->iov_base -= ndone;
        ndone += nwrote;
        for (; (iovcnt > 0) && (ndone >= iov->iov_len) ; iovcnt--, iov++) {
            ndone -= iov->iov_len;
        }
    }

unlock:
    UNLOCK(pr_asyncOutput);
    return total_written;
}
#endif

int32 _PR_CloseFile(PRFileDesc *fd)
{
    int oserror = PR_ERROR_INVALID_FD;

    if (fd) {
        oserror = _OS_CLOSE(fd->osfd);
        fd->osfd = _OS_INVALID_FD_VALUE;
    }
    PR_SetError(oserror);
    return oserror;
}

PRIOMethods _pr_file_methods = {
    0,
    _PR_CloseFile,
    _PR_ReadFile,
    _PR_WriteFile,
};