Back to index

lightning-sunbird  0.9+nobinonly
Classes | Defines | Typedefs | Enumerations | Functions | Variables
ntio.c File Reference
#include "primpl.h"
#include "pprmwait.h"
#include <direct.h>
#include <mbstring.h>

Go to the source code of this file.

Classes

struct  pt_Continuation
struct  pt_TimedQueue
struct  connect_data_s
union  pt_Continuation.arg1
union  pt_Continuation.arg2
union  pt_Continuation.arg3
union  pt_Continuation.arg4
union  pt_Continuation.arg5
union  pt_Continuation.result

Defines

#define RECYCLE_SIZE   512
#define CLOSE_TIMEOUT   PR_SecondsToInterval(5)
#define _NEED_351_FILE_LOCKING_HACK
#define _PR_LOCAL_FILE   1
#define _PR_REMOTE_FILE   2
#define _NT_USE_NB_IO(fd)   ((fd)->secret->nonblocking || (fd)->secret->inheritable == _PR_TRI_TRUE)
#define PT_DEFAULT_SELECT_MSEC   100
#define KEY_IO   0xaaaaaaaa
#define KEY_CVAR   0xbbbbbbbb
#define _NATIVE_IO_WAIT_HANDLES   2
#define _NATIVE_WAKEUP_EVENT_INDEX   0
#define _NATIVE_IO_EVENT_INDEX   1
#define INET_ADDR_PADDED   (sizeof(PRNetAddr) + 16)
#define GetFileFromDIR(d)   (d)->d_entry.cFileName
#define FileIsHidden(d)   ((d)->d_entry.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
#define _PR_IS_SLASH(ch)   ((ch) == '/' || (ch) == '\\')
#define _PR_MAX_DRIVES   26

Typedefs

typedef struct pt_Continuation
typedef PRBool(* ContinuationFn )(pt_Continuation *op, PRInt16 revent)
typedef enum pr_ContuationStatus pr_ContuationStatus

Enumerations

enum  pr_ContuationStatus { pt_continuation_sumbitted, pt_continuation_inprogress, pt_continuation_abort, pt_continuation_done }

Functions

 __declspec (thread)
static PRBool IsPrevCharSlash (const char *str, const char *current)
PRBool IsFileLocalInit ()
PRInt32 IsFileLocal (HANDLE hFile)
static PRInt32 _md_MakeNonblock (HANDLE)
static PRInt32 _nt_nonblock_accept (PRFileDesc *fd, struct sockaddr *addr, int *addrlen, PRIntervalTime)
static PRInt32 _nt_nonblock_connect (PRFileDesc *fd, struct sockaddr *addr, int addrlen, PRIntervalTime)
static PRInt32 _nt_nonblock_recv (PRFileDesc *fd, char *buf, int len, int flags, PRIntervalTime)
static PRInt32 _nt_nonblock_send (PRFileDesc *fd, char *buf, int len, PRIntervalTime)
static PRInt32 _nt_nonblock_writev (PRFileDesc *fd, const PRIOVec *iov, int size, PRIntervalTime)
static PRInt32 _nt_nonblock_sendto (PRFileDesc *, const char *, int, const struct sockaddr *, int, PRIntervalTime)
static PRInt32 _nt_nonblock_recvfrom (PRFileDesc *, char *, int, struct sockaddr *, int *, PRIntervalTime)
static void ContinuationThread (void *arg)
static PRInt32 pt_SendTo (SOCKET osfd, const void *buf, PRInt32 amount, PRInt32 flags, const PRNetAddr *addr, PRIntn addrlen, PRIntervalTime timeout)
static PRInt32 pt_RecvFrom (SOCKET osfd, void *buf, PRInt32 amount, PRInt32 flags, PRNetAddr *addr, PRIntn *addr_len, PRIntervalTime timeout)
PRInt32 _PR_MD_PAUSE_CPU (PRIntervalTime ticks)
static PRStatus _native_thread_md_wait (PRThread *thread, PRIntervalTime ticks)
PRStatus _PR_MD_WAIT (PRThread *thread, PRIntervalTime ticks)
static void _native_thread_io_nowait (PRThread *thread, int rv, int bytes)
static PRStatus _native_thread_io_wait (PRThread *thread, PRIntervalTime ticks)
static PRStatus _NT_IO_WAIT (PRThread *thread, PRIntervalTime timeout)
void _PR_Unblock_IO_Wait (PRThread *thr)
static PRStatus _NT_ResumeIO (PRThread *thread, PRIntervalTime ticks)
PRStatus _PR_MD_WAKEUP_WAITER (PRThread *thread)
void _PR_MD_INIT_IO ()
static SOCKET _md_get_recycled_socket (int af)
static void _md_put_recycled_socket (SOCKET newsock, int af)
PRInt32 _md_Associate (HANDLE file)
static PRInt32 _NT_IO_ABORT (PRInt32 sock)
PRInt32 _PR_MD_SOCKET (int af, int type, int flags)
void _PR_MD_connect_thread (void *cdata)
PRInt32 _PR_MD_CONNECT (PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
PRInt32 _PR_MD_BIND (PRFileDesc *fd, const PRNetAddr *addr, PRUint32 addrlen)
void _PR_MD_UPDATE_ACCEPT_CONTEXT (PRInt32 accept_sock, PRInt32 listen_sock)
PRInt32 _PR_MD_FAST_ACCEPT (PRFileDesc *fd, PRNetAddr *raddr, PRUint32 *rlen, PRIntervalTime timeout, PRBool fast, _PR_AcceptTimeoutCallback callback, void *callbackArg)
PRInt32 _PR_MD_FAST_ACCEPT_READ (PRFileDesc *sd, PRInt32 *newSock, PRNetAddr **raddr, void *buf, PRInt32 amount, PRIntervalTime timeout, PRBool fast, _PR_AcceptTimeoutCallback callback, void *callbackArg)
PRInt32 _PR_MD_SENDFILE (PRFileDesc *sock, PRSendFileData *sfd, PRInt32 flags, PRIntervalTime timeout)
PRInt32 _PR_MD_RECV (PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout)
PRInt32 _PR_MD_SEND (PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, PRIntervalTime timeout)
PRInt32 _PR_MD_SENDTO (PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags, const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
PRInt32 _PR_MD_RECVFROM (PRFileDesc *fd, void *buf, PRInt32 amount, PRIntn flags, PRNetAddr *addr, PRUint32 *addrlen, PRIntervalTime timeout)
PRInt32 _PR_MD_WRITEV (PRFileDesc *fd, const PRIOVec *iov, PRInt32 iov_size, PRIntervalTime timeout)
PRInt32 _PR_MD_LISTEN (PRFileDesc *fd, PRIntn backlog)
PRInt32 _PR_MD_SHUTDOWN (PRFileDesc *fd, PRIntn how)
PRStatus _PR_MD_GETSOCKNAME (PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len)
PRStatus _PR_MD_GETPEERNAME (PRFileDesc *fd, PRNetAddr *addr, PRUint32 *len)
PRStatus _PR_MD_GETSOCKOPT (PRFileDesc *fd, PRInt32 level, PRInt32 optname, char *optval, PRInt32 *optlen)
PRStatus _PR_MD_SETSOCKOPT (PRFileDesc *fd, PRInt32 level, PRInt32 optname, const char *optval, PRInt32 optlen)
PRInt32 _PR_MD_OPEN (const char *name, PRIntn osflags, PRIntn mode)
PRInt32 _PR_MD_OPEN_FILE (const char *name, PRIntn osflags, PRIntn mode)
PRInt32 _PR_MD_READ (PRFileDesc *fd, void *buf, PRInt32 len)
PRInt32 _PR_MD_WRITE (PRFileDesc *fd, const void *buf, PRInt32 len)
PRInt32 _PR_MD_SOCKETAVAILABLE (PRFileDesc *fd)
PRInt32 _PR_MD_PIPEAVAILABLE (PRFileDesc *fd)
PROffset32 _PR_MD_LSEEK (PRFileDesc *fd, PROffset32 offset, PRSeekWhence whence)
PROffset64 _PR_MD_LSEEK64 (PRFileDesc *fd, PROffset64 offset, PRSeekWhence whence)
PRInt32 _PR_MD_FSYNC (PRFileDesc *fd)
PRInt32 _PR_MD_CLOSE (PRInt32 osfd, PRBool socket)
PRStatus _PR_MD_SET_FD_INHERITABLE (PRFileDesc *fd, PRBool inheritable)
void _PR_MD_INIT_FD_INHERITABLE (PRFileDesc *fd, PRBool imported)
void _PR_MD_QUERY_FD_INHERITABLE (PRFileDesc *fd)
void FlipSlashes (char *cp, int len)
PRStatus _PR_MD_CLOSE_DIR (_MDDir *d)
PRStatus _PR_MD_OPEN_DIR (_MDDir *d, const char *name)
char * _PR_MD_READ_DIR (_MDDir *d, PRIntn flags)
PRInt32 _PR_MD_DELETE (const char *name)
void _PR_FileTimeToPRTime (const FILETIME *filetime, PRTime *prtm)
PRInt32 _PR_MD_STAT (const char *fn, struct stat *info)
static PRBool IsRootDirectory (char *fn, size_t buflen)
PRInt32 _PR_MD_GETFILEINFO64 (const char *fn, PRFileInfo64 *info)
PRInt32 _PR_MD_GETFILEINFO (const char *fn, PRFileInfo *info)
PRInt32 _PR_MD_GETOPENFILEINFO64 (const PRFileDesc *fd, PRFileInfo64 *info)
PRInt32 _PR_MD_GETOPENFILEINFO (const PRFileDesc *fd, PRFileInfo *info)
PRInt32 _PR_MD_RENAME (const char *from, const char *to)
PRInt32 _PR_MD_ACCESS (const char *name, PRAccessHow how)
PRInt32 _PR_MD_MKDIR (const char *name, PRIntn mode)
PRInt32 _PR_MD_MAKE_DIR (const char *name, PRIntn mode)
PRInt32 _PR_MD_RMDIR (const char *name)
PRStatus _PR_MD_LOCKFILE (PRInt32 f)
PRStatus _PR_MD_TLOCKFILE (PRInt32 f)
PRStatus _PR_MD_UNLOCKFILE (PRInt32 f)
void _PR_MD_MAKE_NONBLOCK (PRFileDesc *f)
 PR_IMPLEMENT (PRStatus)
static void pt_InsertTimedInternal (pt_Continuation *op)
static pt_Continuationpt_FinishTimedInternal (pt_Continuation *op)
static int pt_Continue (pt_Continuation *op)
static PRBool pt_sendto_cont (pt_Continuation *op, PRInt16 revents)
static PRBool pt_recvfrom_cont (pt_Continuation *op, PRInt16 revents)

Variables

static HANDLE _pr_completion_port
static PRThread_pr_io_completion_thread
static struct _MDLock
static PRInt32 _pr_recycle_INET_array [RECYCLE_SIZE]
static PRInt32 _pr_recycle_INET_tail = 0
static PRInt32 _pr_recycle_INET6_array [RECYCLE_SIZE]
static PRInt32 _pr_recycle_INET6_tail = 0
static DWORD dirAccessTable []
static const PRTime _pr_filetime_offset = 116444736000000000i64
static struct pt_TimedQueue pt_tq
static int missing_completions = 0
static int max_wait_loops = 0
_MDLock cachedVolumeLock
DWORD dwCachedVolumeSerialNumbers [_PR_MAX_DRIVES] = {0}
DWORD dwLastCachedDrive = 0
DWORD dwRemoveableDrivesToCheck = 0

Class Documentation

struct pt_Continuation

Definition at line 174 of file ntio.c.

Collaboration diagram for pt_Continuation:
Class Members
union pt_Continuation arg1
union pt_Continuation arg2
union pt_Continuation arg3
union pt_Continuation arg4
union pt_Continuation arg5
PRCondVar * complete
PRIntn event
ContinuationFn function
pt_Continuation * next
pt_Continuation * prev
union pt_Continuation result
pr_ContuationStatus status
PRIntn syserrno
PRIntervalTime timeout
struct pt_TimedQueue

Definition at line 203 of file ntio.c.

Collaboration diagram for pt_TimedQueue:
Class Members
PRIntervalTime epoch
PRCondVar * finish_op
pt_Continuation * head
PRLock * ml
PRCondVar * new_op
pt_Continuation * op
PRUintn op_count
pt_Continuation * tail
PRThread * thread
struct connect_data_s

Definition at line 1168 of file ntio.c.

Collaboration diagram for connect_data_s:
Class Members
struct sockaddr * addr
PRUint32 addrlen
PRInt32 error
PRInt32 osfd
PRInt32 status
PRIntervalTime timeout
union pt_Continuation.arg1

Definition at line 181 of file ntio.c.

Class Members
SOCKET osfd
union pt_Continuation.arg2

Definition at line 182 of file ntio.c.

Class Members
void * buffer
union pt_Continuation.arg3

Definition at line 183 of file ntio.c.

Class Members
PRIntn amount
union pt_Continuation.arg4

Definition at line 184 of file ntio.c.

Class Members
PRIntn flags
union pt_Continuation.arg5

Definition at line 185 of file ntio.c.

Class Members
PRNetAddr * addr
union pt_Continuation.result

Definition at line 196 of file ntio.c.

Class Members
PRIntn code
void * object

Define Documentation

Definition at line 116 of file ntio.c.

#define _NT_USE_NB_IO (   fd)    ((fd)->secret->nonblocking || (fd)->secret->inheritable == _PR_TRI_TRUE)

Definition at line 146 of file ntio.c.

#define _PR_IS_SLASH (   ch)    ((ch) == '/' || (ch) == '\\')

Definition at line 2940 of file ntio.c.

Definition at line 118 of file ntio.c.

Definition at line 3597 of file ntio.c.

Definition at line 119 of file ntio.c.

#define CLOSE_TIMEOUT   PR_SecondsToInterval(5)
#define FileIsHidden (   d)    ((d)->d_entry.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)

Definition at line 2733 of file ntio.c.

#define GetFileFromDIR (   d)    (d)->d_entry.cFileName

Definition at line 2732 of file ntio.c.

#define INET_ADDR_PADDED   (sizeof(PRNetAddr) + 16)

Definition at line 1285 of file ntio.c.

#define KEY_CVAR   0xbbbbbbbb

Definition at line 239 of file ntio.c.

#define KEY_IO   0xaaaaaaaa

Definition at line 238 of file ntio.c.

Definition at line 161 of file ntio.c.

#define RECYCLE_SIZE   512

Definition at line 65 of file ntio.c.


Typedef Documentation

Definition at line 164 of file ntio.c.

typedef struct pt_Continuation

Definition at line 163 of file ntio.c.


Enumeration Type Documentation

Enumerator:
pt_continuation_sumbitted 
pt_continuation_inprogress 
pt_continuation_abort 
pt_continuation_done 

Definition at line 166 of file ntio.c.


Function Documentation

__declspec ( thread  )

Definition at line 72 of file ntio.c.

                                 {
    FILE_GENERIC_READ,
    FILE_GENERIC_WRITE,
    FILE_GENERIC_EXECUTE
};

Definition at line 1026 of file ntio.c.

{
    HANDLE port;

       if (!_native_threads_only) {
              port = CreateIoCompletionPort((HANDLE)file, 
                                                                      _pr_completion_port, 
                                                                      KEY_IO,
                                                                      0);

              /* XXX should map error codes on failures */
              return (port == _pr_completion_port);
       } else {
              return 1;
       }
}

Here is the caller graph for this function:

static SOCKET _md_get_recycled_socket ( int  af) [static]

Definition at line 968 of file ntio.c.

{
    SOCKET rv;

    _MD_LOCK(&_pr_recycle_lock);
    if (af == AF_INET && _pr_recycle_INET_tail) {
        _pr_recycle_INET_tail--;
        rv = _pr_recycle_INET_array[_pr_recycle_INET_tail];
        _MD_UNLOCK(&_pr_recycle_lock);
        return rv;
    }
    if (af == AF_INET6 && _pr_recycle_INET6_tail) {
        _pr_recycle_INET6_tail--;
        rv = _pr_recycle_INET6_array[_pr_recycle_INET6_tail];
        _MD_UNLOCK(&_pr_recycle_lock);
        return rv;
    }
    _MD_UNLOCK(&_pr_recycle_lock);

    rv = _PR_MD_SOCKET(af, SOCK_STREAM, 0);
    if (rv != INVALID_SOCKET && _md_Associate((HANDLE)rv) == 0) {
        closesocket(rv);
        return INVALID_SOCKET;
    }
    return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRInt32 _md_MakeNonblock ( HANDLE  file) [static]

Definition at line 1049 of file ntio.c.

{
    int rv;
    u_long one = 1;

    rv = ioctlsocket((SOCKET)file, FIONBIO, &one);
    /* XXX should map error codes on failures */
    return (rv == 0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void _md_put_recycled_socket ( SOCKET  newsock,
int  af 
) [static]

Definition at line 999 of file ntio.c.

Here is the call graph for this function:

Here is the caller graph for this function:

static void _native_thread_io_nowait ( PRThread thread,
int  rv,
int  bytes 
) [static]

Definition at line 596 of file ntio.c.

{
    int rc;

    PR_ASSERT(rv != 0);
    _PR_THREAD_LOCK(thread);
    if (thread->state == _PR_IO_WAIT) {
        PR_ASSERT(thread->io_suspended == PR_FALSE);
        PR_ASSERT(thread->io_pending == PR_TRUE);
        thread->state = _PR_RUNNING;
        thread->io_pending = PR_FALSE;
        _PR_THREAD_UNLOCK(thread);
    } else {
        /* The IO completed just at the same time the
         * thread was interrupted. This left the semaphore
         * in the signaled state. Call WaitForSingleObject()
         * to clear the semaphore.
         */
        PR_ASSERT(thread->io_suspended == PR_TRUE);
        PR_ASSERT(thread->io_pending == PR_TRUE);
        thread->io_pending = PR_FALSE;
        _PR_THREAD_UNLOCK(thread);
        rc = WaitForSingleObject(thread->md.blocked_sema, INFINITE);
        PR_ASSERT(rc == WAIT_OBJECT_0);
    }

    thread->md.blocked_io_status = rv;
    thread->md.blocked_io_bytes = bytes;
    rc = ResetEvent(thread->md.thr_event);
    PR_ASSERT(rc != 0);
    return;
}

Here is the caller graph for this function:

static PRStatus _native_thread_io_wait ( PRThread thread,
PRIntervalTime  ticks 
) [static]

Definition at line 633 of file ntio.c.

{
    DWORD rv, bytes;
#define _NATIVE_IO_WAIT_HANDLES           2
#define _NATIVE_WAKEUP_EVENT_INDEX 0
#define _NATIVE_IO_EVENT_INDEX            1

       HANDLE wait_handles[_NATIVE_IO_WAIT_HANDLES];

       PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ?
              INFINITE : PR_IntervalToMilliseconds(ticks);

    PR_ASSERT(thread->flags & _PR_GLOBAL_SCOPE);

       wait_handles[0] = thread->md.blocked_sema;
       wait_handles[1] = thread->md.thr_event;
       rv = WaitForMultipleObjects(_NATIVE_IO_WAIT_HANDLES, wait_handles,
                                                                      FALSE, msecs);

       switch(rv) {
              case WAIT_OBJECT_0 + _NATIVE_IO_EVENT_INDEX:
                     /*
                      * I/O op completed
                      */
                     _PR_THREAD_LOCK(thread);
                     if (thread->state == _PR_IO_WAIT) {

                            PR_ASSERT(thread->io_suspended == PR_FALSE);
                            PR_ASSERT(thread->io_pending == PR_TRUE);
                            thread->state = _PR_RUNNING;
                            thread->io_pending = PR_FALSE;
                            _PR_THREAD_UNLOCK(thread);
                     } else {
                            /* The IO completed just at the same time the
                             * thread was interrupted. This led to us being
                             * notified twice. Call WaitForSingleObject()
                             * to clear the semaphore.
                             */
                            PR_ASSERT(thread->io_suspended == PR_TRUE);
                            PR_ASSERT(thread->io_pending == PR_TRUE);
                            thread->io_pending = PR_FALSE;
                            _PR_THREAD_UNLOCK(thread);
                            rv = WaitForSingleObject(thread->md.blocked_sema,
                                                 INFINITE);
                            PR_ASSERT(rv == WAIT_OBJECT_0);
                     }

                     rv = GetOverlappedResult((HANDLE) thread->io_fd,
                            &thread->md.overlapped.overlapped, &bytes, FALSE);

                     thread->md.blocked_io_status = rv;
                     if (rv != 0) {
                            thread->md.blocked_io_bytes = bytes;
                     } else {
                            thread->md.blocked_io_error = GetLastError();
                            PR_ASSERT(ERROR_IO_PENDING != thread->md.blocked_io_error);
                     }
                     rv = ResetEvent(thread->md.thr_event);
                     PR_ASSERT(rv != 0);
                     break;
              case WAIT_OBJECT_0 + _NATIVE_WAKEUP_EVENT_INDEX:
                     /*
                      * I/O interrupted; 
                      */
#ifdef DEBUG
                     _PR_THREAD_LOCK(thread);
                     PR_ASSERT(thread->io_suspended == PR_TRUE);
                     _PR_THREAD_UNLOCK(thread);
#endif
                     break;
              case WAIT_TIMEOUT:
                     _PR_THREAD_LOCK(thread);
                     if (thread->state == _PR_IO_WAIT) {
                            thread->state = _PR_RUNNING;
                            thread->io_suspended = PR_TRUE;
                            _PR_THREAD_UNLOCK(thread);
                     } else {
                            /*
                             * The thread was interrupted just as the timeout
                             * occurred. This left the semaphore in the signaled
                             * state. Call WaitForSingleObject() to clear the
                             * semaphore.
                             */
                            PR_ASSERT(thread->io_suspended == PR_TRUE);
                            _PR_THREAD_UNLOCK(thread);
                            rv = WaitForSingleObject(thread->md.blocked_sema, INFINITE);
                            PR_ASSERT(rv == WAIT_OBJECT_0);
                     }
                     break;
              default:
                     return PR_FAILURE;
                     break;
       }

    return PR_SUCCESS;
}

Here is the caller graph for this function:

static PRStatus _native_thread_md_wait ( PRThread thread,
PRIntervalTime  ticks 
) [static]

Definition at line 487 of file ntio.c.

{
    DWORD rv;
       PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ?
              INFINITE : PR_IntervalToMilliseconds(ticks);

       /*
        * thread waiting for a cvar or a joining thread
        */
       rv = WaitForSingleObject(thread->md.blocked_sema, msecs);
       switch(rv) {
              case WAIT_OBJECT_0:
                     return PR_SUCCESS;
                     break;
              case WAIT_TIMEOUT:
                     _PR_THREAD_LOCK(thread);
                     PR_ASSERT (thread->state != _PR_IO_WAIT);
                     if (thread->wait.cvar != NULL) {
                            PR_ASSERT(thread->state == _PR_COND_WAIT);
                            thread->wait.cvar = NULL;
                            thread->state = _PR_RUNNING;
                            _PR_THREAD_UNLOCK(thread);
                     } else {
                            /* The CVAR was notified just as the timeout
                             * occurred.  This left the semaphore in the
                             * signaled state.  Call WaitForSingleObject()
                             * to clear the semaphore.
                             */
                            _PR_THREAD_UNLOCK(thread);
                            rv = WaitForSingleObject(thread->md.blocked_sema, INFINITE);
                            PR_ASSERT(rv == WAIT_OBJECT_0);
                     }
                     return PR_SUCCESS;
                     break;
              default:
                     return PR_FAILURE;
                     break;
       }

    return PR_SUCCESS;
}

Here is the caller graph for this function:

static PRInt32 _NT_IO_ABORT ( PRInt32  sock) [static]

Definition at line 1063 of file ntio.c.

{
    PRThread *me = _PR_MD_CURRENT_THREAD();
    PRBool fWait;
    PRInt32 rv;
    int loop_count;

    /* This is a clumsy way to abort the IO, but it is all we can do.
     * It looks a bit racy, but we handle all the cases. 
     * case 1:  IO completes before calling closesocket
     *     case 1a:  fWait is set to PR_FALSE
     *           This should e the most likely case.  We'll properly
     *           not wait call _NT_IO_WAIT, since the closesocket()
     *           won't be forcing a completion.
     *     case 1b: fWait is set to PR_TRUE
     *           This hopefully won't happen much.  When it does, this
     *           thread will timeout in _NT_IO_WAIT for CLOSE_INTERVAL
     *           before cleaning up.
     * case 2:  IO does not complete before calling closesocket
     *     case 2a: IO never completes
     *           This is the likely case.  We'll close it and wait
     *           for the completion forced by the close.  Return should
     *           be immediate.
     *     case 2b: IO completes just after calling closesocket
     *           Since the closesocket is issued, we'll either get a
     *           completion back for the real IO or for the close.  We
     *           don't really care.  It may not even be possible to get
     *           a real completion here.  In any event, we'll awaken
     *           from NT_IO_WAIT immediately.
     */

    _PR_THREAD_LOCK(me);
    fWait = me->io_pending;
    if (fWait) {
        /*
         * If there's still I/O pending, it should have already timed
         * out once before this function is called.
         */
        PR_ASSERT(me->io_suspended == PR_TRUE);

        /* Set up to wait for I/O completion again */
        me->state = _PR_IO_WAIT;
        me->io_suspended = PR_FALSE;
        me->md.interrupt_disabled = PR_TRUE;
    }
    _PR_THREAD_UNLOCK(me);

    /* Close the socket if there is one */
    if (sock != INVALID_SOCKET) {
        rv = closesocket((SOCKET)sock);
    }

    /* If there was I/O pending before the close, wait for it to complete */
    if (fWait) {

        /* Wait and wait for the I/O to complete */
        for (loop_count = 0; fWait; ++loop_count) {

            _NT_IO_WAIT(me, CLOSE_TIMEOUT);

            _PR_THREAD_LOCK(me);
            fWait = me->io_pending;
            if (fWait) {
                PR_ASSERT(me->io_suspended == PR_TRUE);
                me->state = _PR_IO_WAIT;
                me->io_suspended = PR_FALSE;
            }
            _PR_THREAD_UNLOCK(me);

            if (loop_count > max_wait_loops) {
                max_wait_loops = loop_count;
            }
        }

        if (loop_count > 1) {
            ++missing_completions;
        }

        me->md.interrupt_disabled = PR_FALSE;
        me->io_pending = PR_FALSE;
        me->state = _PR_RUNNING;
    }

    PR_ASSERT(me->io_pending == PR_FALSE);
    me->md.thr_bound_cpu = NULL;
    me->io_suspended = PR_FALSE;

    return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRStatus _NT_IO_WAIT ( PRThread thread,
PRIntervalTime  timeout 
) [static]

Definition at line 732 of file ntio.c.

{
    PRBool fWait = PR_TRUE;

       if (_native_threads_only) {
              return(_native_thread_io_wait(thread, timeout));
       }
    if (!_PR_IS_NATIVE_THREAD(thread))  {

        _PR_THREAD_LOCK(thread);

        /* The IO may have already completed; if so, don't add to sleepQ, 
         * since we are already on the runQ!
         */
        if (thread->io_pending == PR_TRUE) {
            _PR_SLEEPQ_LOCK(thread->cpu);
            _PR_ADD_SLEEPQ(thread, timeout);
            _PR_SLEEPQ_UNLOCK(thread->cpu);
        } else
            fWait = PR_FALSE;
        _PR_THREAD_UNLOCK(thread);
    }
    if (fWait)
        return _PR_MD_WAIT(thread, timeout);
    else
        return PR_SUCCESS;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRInt32 _nt_nonblock_accept ( PRFileDesc fd,
struct sockaddr addr,
int addrlen,
PRIntervalTime  timeout 
) [static]

Definition at line 3821 of file ntio.c.

{
    PRInt32 osfd = fd->secret->md.osfd;
    PRInt32 rv, err;
    fd_set rd;
    struct timeval tv, *tvp;

    FD_ZERO(&rd);
    FD_SET((SOCKET)osfd, &rd);
    if (timeout == PR_INTERVAL_NO_TIMEOUT) {
        while ((rv = accept(osfd, addr, addrlen)) == -1) {
            if (((err = WSAGetLastError()) == WSAEWOULDBLOCK)
                    && (!fd->secret->nonblocking)) {
                if ((rv = _PR_NTFiberSafeSelect(osfd + 1, &rd, NULL, NULL,
                        NULL)) == -1) {
                    _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
                    break;
                }
            } else {
                _PR_MD_MAP_ACCEPT_ERROR(err);
                break;
            }
        }
    } else if (timeout == PR_INTERVAL_NO_WAIT) {
        if ((rv = accept(osfd, addr, addrlen)) == -1) {
            if (((err = WSAGetLastError()) == WSAEWOULDBLOCK)
                    && (!fd->secret->nonblocking)) {
                PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
            } else {
                _PR_MD_MAP_ACCEPT_ERROR(err);
            }
        }
    } else {
retry:
        if ((rv = accept(osfd, addr, addrlen)) == -1) {
            if (((err = WSAGetLastError()) == WSAEWOULDBLOCK)
                    && (!fd->secret->nonblocking)) {
                tv.tv_sec = PR_IntervalToSeconds(timeout);
                tv.tv_usec = PR_IntervalToMicroseconds(
                    timeout - PR_SecondsToInterval(tv.tv_sec));
                tvp = &tv;

                rv = _PR_NTFiberSafeSelect(osfd + 1, &rd, NULL, NULL, tvp);
                if (rv > 0) {
                    goto retry;
                } else if (rv == 0) {
                    PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
                    rv = -1;
                } else {
                    _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
                }
            } else {
                _PR_MD_MAP_ACCEPT_ERROR(err);
            }
        }
    }
    return(rv);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRInt32 _nt_nonblock_connect ( PRFileDesc fd,
struct sockaddr addr,
int  addrlen,
PRIntervalTime  timeout 
) [static]

Definition at line 3880 of file ntio.c.

{
    PRInt32 osfd = fd->secret->md.osfd;
    PRInt32 rv;
    int err;
    fd_set wr, ex;
    struct timeval tv, *tvp;
    int len;

    if ((rv = connect(osfd, addr, addrlen)) == -1) {
        if ((err = WSAGetLastError()) == WSAEWOULDBLOCK) {
            if ( timeout == PR_INTERVAL_NO_TIMEOUT ) {
                tvp = NULL;
            } else {
                tv.tv_sec = PR_IntervalToSeconds(timeout);
                tv.tv_usec = PR_IntervalToMicroseconds(
                    timeout - PR_SecondsToInterval(tv.tv_sec));
                tvp = &tv;
            }
            FD_ZERO(&wr);
            FD_ZERO(&ex);
            FD_SET((SOCKET)osfd, &wr);
            FD_SET((SOCKET)osfd, &ex);
            if ((rv = _PR_NTFiberSafeSelect(osfd + 1, NULL, &wr, &ex,
                    tvp)) == -1) {
                _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
                return rv;
            }
            if (rv == 0) {
                PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
                return -1;
            }
            /* Call Sleep(0) to work around a Winsock timeing bug. */
            Sleep(0);
            if (FD_ISSET((SOCKET)osfd, &ex)) {
                len = sizeof(err);
                if (getsockopt(osfd, SOL_SOCKET, SO_ERROR,
                        (char *) &err, &len) == SOCKET_ERROR) {
                    _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
                    return -1;
                }
                _PR_MD_MAP_CONNECT_ERROR(err);
                return -1;
            } 
            PR_ASSERT(FD_ISSET((SOCKET)osfd, &wr));
            rv = 0;
        } else {
            _PR_MD_MAP_CONNECT_ERROR(err);
        }
    }
    return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRInt32 _nt_nonblock_recv ( PRFileDesc fd,
char *  buf,
int  len,
int  flags,
PRIntervalTime  timeout 
) [static]

Definition at line 3933 of file ntio.c.

{
    PRInt32 osfd = fd->secret->md.osfd;
    PRInt32 rv, err;
    struct timeval tv, *tvp;
    fd_set rd;
    int osflags;

    if (0 == flags) {
        osflags = 0;
    } else {
        PR_ASSERT(PR_MSG_PEEK == flags);
        osflags = MSG_PEEK;
    }
    while ((rv = recv(osfd,buf,len,osflags)) == -1) {
        if (((err = WSAGetLastError()) == WSAEWOULDBLOCK)
                && (!fd->secret->nonblocking)) {
            FD_ZERO(&rd);
            FD_SET((SOCKET)osfd, &rd);
            if (timeout == PR_INTERVAL_NO_TIMEOUT) {
                tvp = NULL;
            } else {
                tv.tv_sec = PR_IntervalToSeconds(timeout);
                tv.tv_usec = PR_IntervalToMicroseconds(
                timeout - PR_SecondsToInterval(tv.tv_sec));
                tvp = &tv;
            }
            if ((rv = _PR_NTFiberSafeSelect(osfd + 1, &rd, NULL, NULL,
                    tvp)) == -1) {
                _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
                break;
            } else if (rv == 0) {
                PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
                rv = -1;
                break;
            }
        } else {
            _PR_MD_MAP_RECV_ERROR(err);
            break;
        }
    }
    return(rv);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRInt32 _nt_nonblock_recvfrom ( PRFileDesc fd,
char *  buf,
int  len,
struct sockaddr addr,
int addrlen,
PRIntervalTime  timeout 
) [static]

Definition at line 4138 of file ntio.c.

{
    PRInt32 osfd = fd->secret->md.osfd;
    PRInt32 rv, err;
    struct timeval tv, *tvp;
    fd_set rd;

    while ((rv = recvfrom(osfd,buf,len,0,addr, addrlen)) == -1) {
        if (((err = WSAGetLastError()) == WSAEWOULDBLOCK)
                && (!fd->secret->nonblocking)) {
            if (timeout == PR_INTERVAL_NO_TIMEOUT) {
                tvp = NULL;
            } else {
                tv.tv_sec = PR_IntervalToSeconds(timeout);
                tv.tv_usec = PR_IntervalToMicroseconds(
                timeout - PR_SecondsToInterval(tv.tv_sec));
                tvp = &tv;
            }
            FD_ZERO(&rd);
            FD_SET((SOCKET)osfd, &rd);
            if ((rv = _PR_NTFiberSafeSelect(osfd + 1, &rd, NULL, NULL,
                    tvp)) == -1) {
                _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
                break;
            } else if (rv == 0) {
                PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
                rv = -1;
                break;
            }
        } else {
            _PR_MD_MAP_RECVFROM_ERROR(err);
            break;
        }
    }
    return(rv);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRInt32 _nt_nonblock_send ( PRFileDesc fd,
char *  buf,
int  len,
PRIntervalTime  timeout 
) [static]

Definition at line 3977 of file ntio.c.

{
    PRInt32 osfd = fd->secret->md.osfd;
    PRInt32 rv, err;
    struct timeval tv, *tvp;
    fd_set wd;
    PRInt32 bytesSent = 0;

    while(bytesSent < len) {
        while ((rv = send(osfd,buf,len,0)) == -1) {
            if (((err = WSAGetLastError()) == WSAEWOULDBLOCK)
                    && (!fd->secret->nonblocking)) {
                if ( timeout == PR_INTERVAL_NO_TIMEOUT ) {
                    tvp = NULL;
                } else {
                    tv.tv_sec = PR_IntervalToSeconds(timeout);
                    tv.tv_usec = PR_IntervalToMicroseconds(
                        timeout - PR_SecondsToInterval(tv.tv_sec));
                    tvp = &tv;
                }
                FD_ZERO(&wd);
                FD_SET((SOCKET)osfd, &wd);
                if ((rv = _PR_NTFiberSafeSelect(osfd + 1, NULL, &wd, NULL,
                        tvp)) == -1) {
                    _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
                    return -1;
                }
                if (rv == 0) {
                    PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
                    return -1;
                }
            } else {
                _PR_MD_MAP_SEND_ERROR(err);
                return -1;
            }
        }
        bytesSent += rv;
        if (fd->secret->nonblocking) {
            break;
        }
        if (bytesSent < len) {
            if ( timeout == PR_INTERVAL_NO_TIMEOUT ) {
                tvp = NULL;
            } else {
                tv.tv_sec = PR_IntervalToSeconds(timeout);
                tv.tv_usec = PR_IntervalToMicroseconds(
                    timeout - PR_SecondsToInterval(tv.tv_sec));
                tvp = &tv;
            }
            FD_ZERO(&wd);
            FD_SET((SOCKET)osfd, &wd);
            if ((rv = _PR_NTFiberSafeSelect(osfd + 1, NULL, &wd, NULL,
                    tvp)) == -1) {
                _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
                return -1;
            }
            if (rv == 0) {
                PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
                return -1;
            }
        }
    }
    return bytesSent;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRInt32 _nt_nonblock_sendto ( PRFileDesc fd,
const char *  buf,
int  len,
const struct sockaddr addr,
int  addrlen,
PRIntervalTime  timeout 
) [static]

Definition at line 4071 of file ntio.c.

{
    PRInt32 osfd = fd->secret->md.osfd;
    PRInt32 rv, err;
    struct timeval tv, *tvp;
    fd_set wd;
    PRInt32 bytesSent = 0;

    while(bytesSent < len) {
        while ((rv = sendto(osfd,buf,len,0, addr, addrlen)) == -1) {
            if (((err = WSAGetLastError()) == WSAEWOULDBLOCK)
                    && (!fd->secret->nonblocking)) {
                if ( timeout == PR_INTERVAL_NO_TIMEOUT ) {
                    tvp = NULL;
                } else {
                    tv.tv_sec = PR_IntervalToSeconds(timeout);
                    tv.tv_usec = PR_IntervalToMicroseconds(
                        timeout - PR_SecondsToInterval(tv.tv_sec));
                    tvp = &tv;
                }
                FD_ZERO(&wd);
                FD_SET((SOCKET)osfd, &wd);
                if ((rv = _PR_NTFiberSafeSelect(osfd + 1, NULL, &wd, NULL,
                        tvp)) == -1) {
                    _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
                    return -1;
                }
                if (rv == 0) {
                    PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
                    return -1;
                }
            } else {
                _PR_MD_MAP_SENDTO_ERROR(err);
                return -1;
            }
        }
        bytesSent += rv;
        if (fd->secret->nonblocking) {
            break;
        }
        if (bytesSent < len) {
            if ( timeout == PR_INTERVAL_NO_TIMEOUT ) {
                tvp = NULL;
            } else {
                tv.tv_sec = PR_IntervalToSeconds(timeout);
                tv.tv_usec = PR_IntervalToMicroseconds(
                    timeout - PR_SecondsToInterval(tv.tv_sec));
                tvp = &tv;
            }
            FD_ZERO(&wd);
            FD_SET((SOCKET)osfd, &wd);
            if ((rv = _PR_NTFiberSafeSelect(osfd + 1, NULL, &wd, NULL,
                    tvp)) == -1) {
                _PR_MD_MAP_SELECT_ERROR(WSAGetLastError());
                return -1;
            }
            if (rv == 0) {
                PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
                return -1;
            }
        }
    }
    return bytesSent;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRInt32 _nt_nonblock_writev ( PRFileDesc fd,
const PRIOVec iov,
int  size,
PRIntervalTime  timeout 
) [static]

Definition at line 4042 of file ntio.c.

{
    int index;
    int sent = 0;
    int rv;

    for (index=0; index<size; index++) {
        rv = _nt_nonblock_send(fd, iov[index].iov_base, iov[index].iov_len, timeout);
        if (rv > 0) 
            sent += rv;
        if ( rv != iov[index].iov_len ) {
            if (rv < 0) {
                if (fd->secret->nonblocking
                        && (PR_GetError() == PR_WOULD_BLOCK_ERROR)
                        && (sent > 0)) {
                    return sent;
                } else {
                    return -1;
                }
            }
            /* Only a nonblocking socket can have partial sends */
            PR_ASSERT(fd->secret->nonblocking);
            return sent;
        }
    }

    return sent;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRStatus _NT_ResumeIO ( PRThread thread,
PRIntervalTime  ticks 
) [static]

Definition at line 808 of file ntio.c.

{
    PRBool fWait = PR_TRUE;

    if (!_PR_IS_NATIVE_THREAD(thread)) {
        if (_pr_use_static_tls) {
            _pr_io_restarted_io = thread;
        } else {
            TlsSetValue(_pr_io_restartedIOIndex, thread);
        }
    } else {
        _PR_THREAD_LOCK(thread);
        if (!thread->io_pending)
            fWait = PR_FALSE;
        thread->io_suspended = PR_FALSE;
            
        _PR_THREAD_UNLOCK(thread);
    }
    /* We don't put ourselves back on the sleepQ yet; until we 
     * set the suspended bit to false, we can't do that.  Just save
     * the sleep time here, and then continue.  The restarted_io handler
     * will add us to the sleepQ if needed.
     */
    thread->sleep = ticks;

    if (fWait) {
        if (!_PR_IS_NATIVE_THREAD(thread))
            return _PR_MD_WAIT(thread, ticks);
        else
            return _NT_IO_WAIT(thread, ticks);
    }
    return PR_SUCCESS;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void _PR_FileTimeToPRTime ( const FILETIME *  filetime,
PRTime prtm 
)

Definition at line 2854 of file ntio.c.

{
    PR_ASSERT(sizeof(FILETIME) == sizeof(PRTime));
    CopyMemory(prtm, filetime, sizeof(PRTime));
#ifdef __GNUC__
    *prtm = (*prtm - _pr_filetime_offset) / 10LL;
#else
    *prtm = (*prtm - _pr_filetime_offset) / 10i64;
#endif

#ifdef DEBUG
    /* Doublecheck our calculation. */
    {
        SYSTEMTIME systime;
        PRExplodedTime etm;
        PRTime cmp; /* for comparison */
        BOOL rv;

        rv = FileTimeToSystemTime(filetime, &systime);
        PR_ASSERT(0 != rv);

        /*
         * PR_ImplodeTime ignores wday and yday.
         */
        etm.tm_usec = systime.wMilliseconds * PR_USEC_PER_MSEC;
        etm.tm_sec = systime.wSecond;
        etm.tm_min = systime.wMinute;
        etm.tm_hour = systime.wHour;
        etm.tm_mday = systime.wDay;
        etm.tm_month = systime.wMonth - 1;
        etm.tm_year = systime.wYear;
        /*
         * It is not well-documented what time zone the FILETIME's
         * are in.  WIN32_FIND_DATA is documented to be in UTC (GMT).
         * But BY_HANDLE_FILE_INFORMATION is unclear about this.
         * By our best judgement, we assume that FILETIME is in UTC.
         */
        etm.tm_params.tp_gmt_offset = 0;
        etm.tm_params.tp_dst_offset = 0;
        cmp = PR_ImplodeTime(&etm);

        /*
         * SYSTEMTIME is in milliseconds precision, so we convert PRTime's
         * microseconds to milliseconds before doing the comparison.
         */
        PR_ASSERT((cmp / PR_USEC_PER_MSEC) == (*prtm / PR_USEC_PER_MSEC));
    }
#endif /* DEBUG */
}

Here is the call graph for this function:

PRInt32 _PR_MD_ACCESS ( const char *  name,
PRAccessHow  how 
)

Definition at line 3221 of file ntio.c.

{
    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:
        rv = _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_BIND ( PRFileDesc fd,
const PRNetAddr addr,
PRUint32  addrlen 
)

Definition at line 1235 of file ntio.c.

{
    PRInt32 rv;
#if 0
    int one = 1;
#endif

    rv = bind(fd->secret->md.osfd, (const struct sockaddr *)&(addr->inet), addrlen);

    if (rv == SOCKET_ERROR) {
        _PR_MD_MAP_BIND_ERROR(WSAGetLastError());
        return -1;
    }

#if 0
    /* Disable nagle- so far unknown if this is good or not...
     */
    rv = setsockopt(fd->secret->md.osfd, 
                    SOL_SOCKET,
                    TCP_NODELAY,
                    (const char *)&one,
                    sizeof(one));
    PR_ASSERT(rv == 0);
#endif

    return 0;
}

Here is the call graph for this function:

PRInt32 _PR_MD_CLOSE ( PRInt32  osfd,
PRBool  socket 
)

Definition at line 2631 of file ntio.c.

{
    PRInt32 rv;
    PRThread *me = _PR_MD_CURRENT_THREAD();

    if (socket)  {
        rv = closesocket((SOCKET)osfd);
        if (rv < 0)
            _PR_MD_MAP_CLOSE_ERROR(WSAGetLastError());
    } else {
        rv = CloseHandle((HANDLE)osfd)?0:-1;
        if (rv < 0)
            _PR_MD_MAP_CLOSE_ERROR(GetLastError());
    }

    if (rv == 0 && me->io_suspended) {
        if (me->io_fd == osfd) {
            PRBool fWait;

            _PR_THREAD_LOCK(me);
            me->state = _PR_IO_WAIT;
            /* The IO could have completed on another thread just after
             * calling closesocket while the io_suspended flag was true.  
             * So we now grab the lock to do a safe check on io_pending to
             * see if we need to wait or not.
             */
            fWait = me->io_pending;
            me->io_suspended = PR_FALSE;
            me->md.interrupt_disabled = PR_TRUE;
            _PR_THREAD_UNLOCK(me);

            if (fWait)
                _NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT);
            PR_ASSERT(me->io_suspended ==  PR_FALSE);
            PR_ASSERT(me->io_pending ==  PR_FALSE);
            /*
             * I/O operation is no longer pending; the thread can now
             * run on any cpu
             */
            _PR_THREAD_LOCK(me);
            me->md.interrupt_disabled = PR_FALSE;
            me->md.thr_bound_cpu = NULL;
            me->io_suspended = PR_FALSE;
            me->io_pending = PR_FALSE;
            me->state = _PR_RUNNING;
            _PR_THREAD_UNLOCK(me);
        }
    }
    return rv;
}

Here is the call graph for this function:

Definition at line 2753 of file ntio.c.

{
    if ( d ) {
        if (FindClose( d->d_hdl )) {
            d->magic = (PRUint32)-1;
            return PR_SUCCESS;
        } else {
            _PR_MD_MAP_CLOSEDIR_ERROR(GetLastError());
            return PR_FAILURE;
        }
    }
    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    return PR_FAILURE;
}
PRInt32 _PR_MD_CONNECT ( PRFileDesc fd,
const PRNetAddr addr,
PRUint32  addrlen,
PRIntervalTime  timeout 
)

Definition at line 1192 of file ntio.c.

{
    PRInt32 osfd = fd->secret->md.osfd;
    PRInt32 rv, err;
    u_long nbio;
    PRInt32 rc;

    if (fd->secret->nonblocking) {
        if (!fd->secret->md.io_model_committed) {
            rv = _md_MakeNonblock((HANDLE)osfd);
            PR_ASSERT(0 != rv);
            fd->secret->md.io_model_committed = PR_TRUE;
        }

        if ((rv = connect(osfd, (struct sockaddr *) addr, addrlen)) == -1) {
            err = WSAGetLastError();
            _PR_MD_MAP_CONNECT_ERROR(err);
        }
        return rv;
    }

    /*
     * Temporarily make the socket non-blocking so that we can
     * initiate a non-blocking connect and wait for its completion
     * (with a timeout) in select.
     */
    PR_ASSERT(!fd->secret->md.io_model_committed);
    nbio = 1;
    rv = ioctlsocket((SOCKET)osfd, FIONBIO, &nbio);
    PR_ASSERT(0 == rv);

    rc = _nt_nonblock_connect(fd, (struct sockaddr *) addr, addrlen, timeout);

    /* Set the socket back to blocking. */
    nbio = 0;
    rv = ioctlsocket((SOCKET)osfd, FIONBIO, &nbio);
    PR_ASSERT(0 == rv);

    return rc;
}

Here is the call graph for this function:

Definition at line 1178 of file ntio.c.

{
    struct connect_data_s *cd = (struct connect_data_s *)cdata;

    cd->status = connect(cd->osfd, cd->addr, cd->addrlen);

    if (cd->status == SOCKET_ERROR)
        cd->error = WSAGetLastError();

    return;
}

Here is the call graph for this function:

PRInt32 _PR_MD_DELETE ( const char *  name)

Definition at line 2843 of file ntio.c.

{
    if (DeleteFile(name)) {
              return 0;
       } else {
              _PR_MD_MAP_DELETE_ERROR(GetLastError());
              return -1;
       }
}
PRInt32 _PR_MD_FAST_ACCEPT ( PRFileDesc fd,
PRNetAddr raddr,
PRUint32 rlen,
PRIntervalTime  timeout,
PRBool  fast,
_PR_AcceptTimeoutCallback  callback,
void callbackArg 
)

Definition at line 1287 of file ntio.c.

{
    PRInt32 osfd = fd->secret->md.osfd;
    PRThread *me = _PR_MD_CURRENT_THREAD();
    SOCKET accept_sock;
    int bytes;
    PRNetAddr *Laddr;
    PRNetAddr *Raddr;
    PRUint32 llen, err;
    int rv;

    if (_NT_USE_NB_IO(fd)) {
        if (!fd->secret->md.io_model_committed) {
            rv = _md_MakeNonblock((HANDLE)osfd);
            PR_ASSERT(0 != rv);
            fd->secret->md.io_model_committed = PR_TRUE;
        }
        /*
         * The accepted socket inherits the nonblocking and
         * inheritable (HANDLE_FLAG_INHERIT) attributes of
         * the listening socket.
         */
        accept_sock = _nt_nonblock_accept(fd, (struct sockaddr *)raddr, rlen, timeout);
        if (!fd->secret->nonblocking) {
            u_long zero = 0;

            rv = ioctlsocket(accept_sock, FIONBIO, &zero);
            PR_ASSERT(0 == rv);
        }
        return accept_sock;
    }

    if (me->io_suspended) {
        PR_SetError(PR_INVALID_STATE_ERROR, 0);
        return -1;
    }

    if (!fd->secret->md.io_model_committed) {
        rv = _md_Associate((HANDLE)osfd);
        PR_ASSERT(0 != rv);
        fd->secret->md.io_model_committed = PR_TRUE;
    }

    if (!me->md.acceptex_buf) {
        me->md.acceptex_buf = PR_MALLOC(2*INET_ADDR_PADDED);
        if (!me->md.acceptex_buf) {
            PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
            return -1;
        }
    }

    accept_sock = _md_get_recycled_socket(fd->secret->af);
    if (accept_sock == INVALID_SOCKET)
        return -1;

    memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));
       if (_native_threads_only)
              me->md.overlapped.overlapped.hEvent = me->md.thr_event;

    _PR_THREAD_LOCK(me);
       if (_PR_PENDING_INTERRUPT(me)) {
              me->flags &= ~_PR_INTERRUPT;
              PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
       _PR_THREAD_UNLOCK(me);
              closesocket(accept_sock);
              return -1;
       }
    me->io_pending = PR_TRUE;
    me->state = _PR_IO_WAIT;
    _PR_THREAD_UNLOCK(me);
    me->io_fd = osfd;

    rv = AcceptEx((SOCKET)osfd,
                  accept_sock,
                  me->md.acceptex_buf,
                  0,
                  INET_ADDR_PADDED,
                  INET_ADDR_PADDED,
                  &bytes,
                  &(me->md.overlapped.overlapped));

    if ( (rv == 0) && ((err = WSAGetLastError()) != ERROR_IO_PENDING))  {
        /* Argh! The IO failed */
              closesocket(accept_sock);
              _PR_THREAD_LOCK(me);
              me->io_pending = PR_FALSE;
              me->state = _PR_RUNNING;
              if (_PR_PENDING_INTERRUPT(me)) {
                     me->flags &= ~_PR_INTERRUPT;
                     PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
                     _PR_THREAD_UNLOCK(me);
                     return -1;
              }
              _PR_THREAD_UNLOCK(me);

              _PR_MD_MAP_ACCEPTEX_ERROR(err);
        return -1;
    }

    if (_native_threads_only && rv) {
        _native_thread_io_nowait(me, rv, bytes);
    } else if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) {
        PR_ASSERT(0);
        closesocket(accept_sock);
        return -1;
    }

    PR_ASSERT(me->io_pending == PR_FALSE || me->io_suspended == PR_TRUE);

    if (me->io_suspended) {
        closesocket(accept_sock);
        if (_PR_PENDING_INTERRUPT(me)) {
            me->flags &= ~_PR_INTERRUPT;
            PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
        } else {
            PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
        }
        return -1;
    }

    if (me->md.blocked_io_status == 0) {
              closesocket(accept_sock);
              _PR_MD_MAP_ACCEPTEX_ERROR(me->md.blocked_io_error);
        return -1;
    }

    if (!fast)
        _PR_MD_UPDATE_ACCEPT_CONTEXT((SOCKET)accept_sock, (SOCKET)osfd);

    /* IO is done */
    GetAcceptExSockaddrs(
            me->md.acceptex_buf,
            0,
            INET_ADDR_PADDED,
            INET_ADDR_PADDED,
            (LPSOCKADDR *)&(Laddr),
            &llen,
            (LPSOCKADDR *)&(Raddr),
            (unsigned int *)rlen);

    if (raddr != NULL)
        memcpy((char *)raddr, (char *)&Raddr->inet, *rlen);

    PR_ASSERT(me->io_pending == PR_FALSE);

    return accept_sock;
}

Here is the call graph for this function:

PRInt32 _PR_MD_FAST_ACCEPT_READ ( PRFileDesc sd,
PRInt32 newSock,
PRNetAddr **  raddr,
void buf,
PRInt32  amount,
PRIntervalTime  timeout,
PRBool  fast,
_PR_AcceptTimeoutCallback  callback,
void callbackArg 
)

Definition at line 1438 of file ntio.c.

{
    PRInt32 sock = sd->secret->md.osfd;
    PRThread *me = _PR_MD_CURRENT_THREAD();
    int bytes;
    PRNetAddr *Laddr;
    PRUint32 llen, rlen, err;
    int rv;
    PRBool isConnected;
    PRBool madeCallback = PR_FALSE;

    if (me->io_suspended) {
        PR_SetError(PR_INVALID_STATE_ERROR, 0);
        return -1;
    }

    if (!sd->secret->md.io_model_committed) {
        rv = _md_Associate((HANDLE)sock);
        PR_ASSERT(0 != rv);
        sd->secret->md.io_model_committed = PR_TRUE;
    }

    *newSock = _md_get_recycled_socket(sd->secret->af);
    if (*newSock == INVALID_SOCKET)
        return -1;

    memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));
       if (_native_threads_only)
              me->md.overlapped.overlapped.hEvent = me->md.thr_event;

    _PR_THREAD_LOCK(me);
       if (_PR_PENDING_INTERRUPT(me)) {
              me->flags &= ~_PR_INTERRUPT;
              PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
       _PR_THREAD_UNLOCK(me);
              closesocket(*newSock);
              return -1;
       }
    me->io_pending = PR_TRUE;
    me->state = _PR_IO_WAIT;
    _PR_THREAD_UNLOCK(me);
    me->io_fd = sock;

    rv = AcceptEx((SOCKET)sock,
                  *newSock,
                  buf,
                  amount,
                  INET_ADDR_PADDED,
                  INET_ADDR_PADDED,
                  &bytes,
                  &(me->md.overlapped.overlapped));

    if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING)) {
              closesocket(*newSock);
              _PR_THREAD_LOCK(me);
              me->io_pending = PR_FALSE;
              me->state = _PR_RUNNING;
              if (_PR_PENDING_INTERRUPT(me)) {
                     me->flags &= ~_PR_INTERRUPT;
                     PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
                     _PR_THREAD_UNLOCK(me);
                     return -1;
              }
              _PR_THREAD_UNLOCK(me);

              _PR_MD_MAP_ACCEPTEX_ERROR(err);
        return -1;
    }

    if (_native_threads_only && rv) {
        _native_thread_io_nowait(me, rv, bytes);
    } else if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) {
        PR_ASSERT(0);
        closesocket(*newSock);
        return -1;
    }

retry:
    if (me->io_suspended) {
        PRInt32 err;
        INT seconds;
        INT bytes = sizeof(seconds);

        PR_ASSERT(timeout != PR_INTERVAL_NO_TIMEOUT);

        err = getsockopt(*newSock, 
                         SOL_SOCKET,
                         SO_CONNECT_TIME,
                         (char *)&seconds,
                         (PINT)&bytes);
        if ( err == NO_ERROR ) {
            PRIntervalTime elapsed = PR_SecondsToInterval(seconds);

            if (seconds == 0xffffffff) 
                isConnected = PR_FALSE;
            else 
                isConnected = PR_TRUE;

            if (!isConnected) {
                if (madeCallback == PR_FALSE && callback)
                    callback(callbackArg);
                madeCallback = PR_TRUE;
                me->state = _PR_IO_WAIT;
                if (_NT_ResumeIO(me, timeout) == PR_FAILURE) {
                    closesocket(*newSock);
                    return -1;
                }
                goto retry;
            }

            if (elapsed < timeout) {
                /* Socket is connected but time not elapsed, RESUME IO */
                timeout -= elapsed;
                me->state = _PR_IO_WAIT;
                if (_NT_ResumeIO(me, timeout) == PR_FAILURE) {
                    closesocket(*newSock);
                    return -1;
                }
                goto retry;
            }
        } else {
            /*  What to do here? Assume socket not open?*/
            PR_ASSERT(0);
            isConnected = PR_FALSE;
        }

        rv = _NT_IO_ABORT(*newSock);

        PR_ASSERT(me->io_pending ==  PR_FALSE);
        PR_ASSERT(me->io_suspended ==  PR_FALSE);
        PR_ASSERT(me->md.thr_bound_cpu ==  NULL);
        /* If the IO is still suspended, it means we didn't get any 
         * completion from NT_IO_WAIT.  This is not disasterous, I hope,
         * but it may mean we still have an IO outstanding...  Try to 
         * recover by just allowing ourselves to continue.
         */
        me->io_suspended = PR_FALSE;
        if (_PR_PENDING_INTERRUPT(me)) {
            me->flags &= ~_PR_INTERRUPT;
            PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
        } else {
            PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
        }
        me->state = _PR_RUNNING;
        closesocket(*newSock);
        return -1;
    }

    PR_ASSERT(me->io_pending == PR_FALSE);
    PR_ASSERT(me->io_suspended == PR_FALSE);
    PR_ASSERT(me->md.thr_bound_cpu == NULL);

    if (me->md.blocked_io_status == 0) {
              _PR_MD_MAP_ACCEPTEX_ERROR(me->md.blocked_io_error);
        closesocket(*newSock);
        return -1;
    }

    if (!fast) 
        _PR_MD_UPDATE_ACCEPT_CONTEXT((SOCKET)*newSock, (SOCKET)sock);

    /* IO is done */
    GetAcceptExSockaddrs(
            buf,
            amount,
            INET_ADDR_PADDED,
            INET_ADDR_PADDED,
            (LPSOCKADDR *)&(Laddr),
            &llen,
            (LPSOCKADDR *)(raddr),
            (unsigned int *)&rlen);

    return me->md.blocked_io_bytes;
}

Here is the call graph for this function:

Definition at line 2598 of file ntio.c.

{
    /*
     * From the documentation:
     *
     *    On Windows NT, the function FlushFileBuffers fails if hFile
     *    is a handle to console output. That is because console
     *    output is not buffered. The function returns FALSE, and
     *    GetLastError returns ERROR_INVALID_HANDLE.
     *
     * On the other hand, on Win95, it returns without error.  I cannot
     * assume that 0, 1, and 2 are console, because if someone closes
     * System.out and then opens a file, they might get file descriptor
     * 1.  An error on *that* version of 1 should be reported, whereas
     * an error on System.out (which was the original 1) should be
     * ignored.  So I use isatty() to ensure that such an error was
     * because of this, and if it was, I ignore the error.
     */

    BOOL ok = FlushFileBuffers((HANDLE)fd->secret->md.osfd);

    if (!ok) {
       DWORD err = GetLastError();

       if (err != ERROR_ACCESS_DENIED) {  /* from winerror.h */
                     _PR_MD_MAP_FSYNC_ERROR(err);
           return -1;
       }
    }
    return 0;
}
PRInt32 _PR_MD_GETFILEINFO ( const char *  fn,
PRFileInfo info 
)

Definition at line 3141 of file ntio.c.

{
    PRFileInfo64 info64;
    PRInt32 rv = _PR_MD_GETFILEINFO64(fn, &info64);
    if (0 == rv)
    {
        info->type = info64.type;
        info->size = (PRUint32) info64.size;
        info->modifyTime = info64.modifyTime;
        info->creationTime = info64.creationTime;
    }
    return rv;
}
PRInt32 _PR_MD_GETFILEINFO64 ( const char *  fn,
PRFileInfo64 info 
)

Definition at line 3042 of file ntio.c.

{
    HANDLE hFindFile;
    WIN32_FIND_DATA findFileData;
    char pathbuf[MAX_PATH + 1];
    
    if (NULL == fn || '\0' == *fn) {
        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
        return -1;
    }

    /*
     * FindFirstFile() expands wildcard characters.  So
     * we make sure the pathname contains no wildcard.
     */
    if (NULL != _mbspbrk(fn, "?*")) {
        PR_SetError(PR_FILE_NOT_FOUND_ERROR, 0);
        return -1;
    }

    hFindFile = FindFirstFile(fn, &findFileData);
    if (INVALID_HANDLE_VALUE == hFindFile) {
        DWORD len;
        char *filePart;

        /*
         * FindFirstFile() does not work correctly on root directories.
         * It also doesn't work correctly on a pathname that ends in a
         * slash.  So we first check to see if the pathname specifies a
         * root directory.  If not, and if the pathname ends in a slash,
         * we remove the final slash and try again.
         */

        /*
         * If the pathname does not contain ., \, and /, it cannot be
         * a root directory or a pathname that ends in a slash.
         */
        if (NULL == _mbspbrk(fn, ".\\/")) {
            _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
            return -1;
        } 
        len = GetFullPathName(fn, sizeof(pathbuf), pathbuf,
                &filePart);
        if (0 == len) {
            _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
            return -1;
        }
        if (len > sizeof(pathbuf)) {
            PR_SetError(PR_NAME_TOO_LONG_ERROR, 0);
            return -1;
        }
        if (IsRootDirectory(pathbuf, sizeof(pathbuf))) {
            info->type = PR_FILE_DIRECTORY;
            info->size = 0;
            /*
             * These timestamps don't make sense for root directories.
             */
            info->modifyTime = 0;
            info->creationTime = 0;
            return 0;
        }
        if (!IsPrevCharSlash(pathbuf, pathbuf + len)) {
            _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
            return -1;
        } else {
            pathbuf[len - 1] = '\0';
            hFindFile = FindFirstFile(pathbuf, &findFileData);
            if (INVALID_HANDLE_VALUE == hFindFile) {
                _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
                return -1;
            }
        }
    }

    FindClose(hFindFile);

    if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
        info->type = PR_FILE_DIRECTORY;
    } else {
        info->type = PR_FILE_FILE;
    }

    info->size = findFileData.nFileSizeHigh;
    info->size = (info->size << 32) + findFileData.nFileSizeLow;

    _PR_FileTimeToPRTime(&findFileData.ftLastWriteTime, &info->modifyTime);

    if (0 == findFileData.ftCreationTime.dwLowDateTime &&
            0 == findFileData.ftCreationTime.dwHighDateTime) {
        info->creationTime = info->modifyTime;
    } else {
        _PR_FileTimeToPRTime(&findFileData.ftCreationTime,
                &info->creationTime);
    }

    return 0;
}

Here is the call graph for this function:

Definition at line 3183 of file ntio.c.

{
    int rv;

    BY_HANDLE_FILE_INFORMATION hinfo;

    rv = GetFileInformationByHandle((HANDLE)fd->secret->md.osfd, &hinfo);
    if (rv == FALSE) {
              _PR_MD_MAP_FSTAT_ERROR(GetLastError());
        return -1;
       }

    if (hinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
        info->type = PR_FILE_DIRECTORY;
    else
        info->type = PR_FILE_FILE;

    info->size = hinfo.nFileSizeLow;

    _PR_FileTimeToPRTime(&hinfo.ftLastWriteTime, &(info->modifyTime) );
    _PR_FileTimeToPRTime(&hinfo.ftCreationTime, &(info->creationTime) );

    return 0;
}

Here is the call graph for this function:

Definition at line 3156 of file ntio.c.

{
    int rv;

    BY_HANDLE_FILE_INFORMATION hinfo;

    rv = GetFileInformationByHandle((HANDLE)fd->secret->md.osfd, &hinfo);
    if (rv == FALSE) {
              _PR_MD_MAP_FSTAT_ERROR(GetLastError());
        return -1;
       }

    if (hinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
        info->type = PR_FILE_DIRECTORY;
    else
        info->type = PR_FILE_FILE;

    info->size = hinfo.nFileSizeHigh;
    info->size = (info->size << 32) + hinfo.nFileSizeLow;

    _PR_FileTimeToPRTime(&hinfo.ftLastWriteTime, &(info->modifyTime) );
    _PR_FileTimeToPRTime(&hinfo.ftCreationTime, &(info->creationTime) );

    return 0;
}

Here is the call graph for this function:

PRStatus _PR_MD_GETPEERNAME ( PRFileDesc fd,
PRNetAddr addr,
PRUint32 len 
)

Definition at line 2021 of file ntio.c.

{
    PRInt32 rv;

    /*
     * NT has a bug that, when invoked on a socket accepted by
     * AcceptEx(), getpeername() returns an all-zero peer address.
     * To work around this bug, we store the peer's address (returned
     * by AcceptEx()) with the socket fd and use the cached peer
     * address if the socket is an accepted socket.
     */

    if (fd->secret->md.accepted_socket) {
        INT seconds;
        INT bytes = sizeof(seconds);

        /*
         * Determine if the socket is connected.
         */

        rv = getsockopt(fd->secret->md.osfd, 
                        SOL_SOCKET,
                        SO_CONNECT_TIME,
                        (char *) &seconds,
                        (PINT) &bytes);
        if (rv == NO_ERROR) {
            if (seconds == 0xffffffff) {
                PR_SetError(PR_NOT_CONNECTED_ERROR, 0);
                return PR_FAILURE;
            }
            *len = PR_NETADDR_SIZE(&fd->secret->md.peer_addr);
            memcpy(addr, &fd->secret->md.peer_addr, *len);
            return PR_SUCCESS;
        } else {
            _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError());
            return PR_FAILURE;
        }
    } else { 
        rv = getpeername((SOCKET)fd->secret->md.osfd,
                         (struct sockaddr *) addr, len);
        if (rv == 0) {
            return PR_SUCCESS;
        } else {
            _PR_MD_MAP_GETPEERNAME_ERROR(WSAGetLastError());
            return PR_FAILURE;
        }
    }
}

Here is the call graph for this function:

PRStatus _PR_MD_GETSOCKNAME ( PRFileDesc fd,
PRNetAddr addr,
PRUint32 len 
)

Definition at line 2007 of file ntio.c.

{
    PRInt32 rv;

    rv = getsockname((SOCKET)fd->secret->md.osfd, (struct sockaddr *)addr, len);
    if (rv==0)
              return PR_SUCCESS;
       else {
              _PR_MD_MAP_GETSOCKNAME_ERROR(WSAGetLastError());
              return PR_FAILURE;
       }
}

Here is the call graph for this function:

PRStatus _PR_MD_GETSOCKOPT ( PRFileDesc fd,
PRInt32  level,
PRInt32  optname,
char *  optval,
PRInt32 optlen 
)

Definition at line 2071 of file ntio.c.

Here is the call graph for this function:

Definition at line 2703 of file ntio.c.

Definition at line 883 of file ntio.c.

{
    WORD WSAVersion = 0x0101;
    WSADATA WSAData;
    int err;
    OSVERSIONINFO OSversion;

    err = WSAStartup( WSAVersion, &WSAData );
    PR_ASSERT(0 == err);
                                                      
    _pr_completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 
                                                 NULL, 
                                                 0, 
                                                 0);
 
    _MD_NEW_LOCK(&_pr_recycle_lock);
    _MD_NEW_LOCK(&_pr_ioq_lock);

    OSversion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    if (GetVersionEx(&OSversion)) {
        _nt_version_gets_lockfile_completion = PR_FALSE;
        if (OSversion.dwMajorVersion >= 4) {
            _nt_version_gets_lockfile_completion = PR_TRUE;
        }
    } else 
        PR_ASSERT(0);

    IsFileLocalInit();

    /*
     * UDP support: start up the continuation thread
     */

    pt_tq.op_count = 0;
    pt_tq.head = pt_tq.tail = NULL;
    pt_tq.ml = PR_NewLock();
    PR_ASSERT(NULL != pt_tq.ml);
    pt_tq.new_op = PR_NewCondVar(pt_tq.ml);
    PR_ASSERT(NULL != pt_tq.new_op);
#if defined(DEBUG)
    memset(&pt_debug, 0, sizeof(struct pt_debug_s));
#endif

    pt_tq.thread = PR_CreateThread(
        PR_SYSTEM_THREAD, ContinuationThread, NULL,
        PR_PRIORITY_URGENT, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);

    PR_ASSERT(NULL != pt_tq.thread);

#ifdef DEBUG
    /* Doublecheck _pr_filetime_offset's hard-coded value is correct. */
    {
        SYSTEMTIME systime;
        union {
           PRTime prt;
           FILETIME ft;
        } filetime;
        BOOL rv;

        systime.wYear = 1970;
        systime.wMonth = 1;
        /* wDayOfWeek is ignored */
        systime.wDay = 1;
        systime.wHour = 0;
        systime.wMinute = 0;
        systime.wSecond = 0;
        systime.wMilliseconds = 0;

        rv = SystemTimeToFileTime(&systime, &filetime.ft);
        PR_ASSERT(0 != rv);
        PR_ASSERT(filetime.prt == _pr_filetime_offset);
    }
#endif /* DEBUG */

    _PR_NT_InitSids();
}

Here is the call graph for this function:

PRInt32 _PR_MD_LISTEN ( PRFileDesc fd,
PRIntn  backlog 
)

Definition at line 1985 of file ntio.c.

{
    PRInt32 rv;

    rv = listen(fd->secret->md.osfd, backlog);
       if (rv < 0)
              _PR_MD_MAP_LISTEN_ERROR(WSAGetLastError());
       return(rv);
}

Here is the call graph for this function:

Definition at line 3297 of file ntio.c.

{
    PRInt32 rv, err;
    PRThread *me = _PR_MD_CURRENT_THREAD();

    if (me->io_suspended) {
        PR_SetError(PR_INVALID_STATE_ERROR, 0);
        return PR_FAILURE;
    }

    memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));

    _PR_THREAD_LOCK(me);
       if (_PR_PENDING_INTERRUPT(me)) {
              me->flags &= ~_PR_INTERRUPT;
              PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
       _PR_THREAD_UNLOCK(me);
              return -1;
       }
    me->io_pending = PR_TRUE;
    me->state = _PR_IO_WAIT;
    _PR_THREAD_UNLOCK(me);

    rv = LockFileEx((HANDLE)f, 
                    LOCKFILE_EXCLUSIVE_LOCK,
                    0,
                    0x7fffffff,
                    0,
                    &me->md.overlapped.overlapped);

    if (_native_threads_only) {
              _PR_THREAD_LOCK(me);
              me->io_pending = PR_FALSE;
              me->state = _PR_RUNNING;
              if (_PR_PENDING_INTERRUPT(me)) {
                     me->flags &= ~_PR_INTERRUPT;
                     PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
                     _PR_THREAD_UNLOCK(me);
                     return PR_FAILURE;
              }
              _PR_THREAD_UNLOCK(me);

        if (rv == FALSE) {
            err = GetLastError();
            PR_ASSERT(err != ERROR_IO_PENDING);
            _PR_MD_MAP_LOCKF_ERROR(err);
            return PR_FAILURE;
        }
        return PR_SUCCESS;
    }

    /* HACK AROUND NT BUG
     * NT 3.51 has a bug.  In NT 3.51, if LockFileEx returns true, you
     * don't get any completion on the completion port.  This is a bug.
     *
     * They fixed it on NT4.0 so that you do get a completion.
     *
     * If we pretend we won't get a completion, NSPR gets confused later
     * when the unexpected completion arrives.  If we assume we do get
     * a completion, we hang on 3.51.  Worse, Microsoft informs me that the 
     * behavior varies on 3.51 depending on if you are using a network
     * file system or a local disk!
     *
     * Solution:  For now, _nt_version_gets_lockfile_completion is set
     * depending on whether or not this system is EITHER
     *      - running NT 4.0
     *      - running NT 3.51 with a service pack greater than 5.
     * 
     * In the meantime, this code may not work on network file systems.
     *
     */

    if ( rv == FALSE && ((err = GetLastError()) != ERROR_IO_PENDING)) {
              _PR_THREAD_LOCK(me);
              me->io_pending = PR_FALSE;
              me->state = _PR_RUNNING;
              if (_PR_PENDING_INTERRUPT(me)) {
                     me->flags &= ~_PR_INTERRUPT;
                     PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
                     _PR_THREAD_UNLOCK(me);
                     return PR_FAILURE;
              }
              _PR_THREAD_UNLOCK(me);

              _PR_MD_MAP_LOCKF_ERROR(err);
        return PR_FAILURE;
    }
#ifdef _NEED_351_FILE_LOCKING_HACK
    else if (rv)  {
        /* If this is NT 3.51 and the file is local, then we won't get a 
         * completion back from LockFile when it succeeded.
         */
        if (_nt_version_gets_lockfile_completion == PR_FALSE) {
            if ( IsFileLocal((HANDLE)f) == _PR_LOCAL_FILE) {
                me->io_pending = PR_FALSE;
                me->state = _PR_RUNNING;
                return PR_SUCCESS; 
            }
        }
    }
#endif /* _NEED_351_FILE_LOCKING_HACK */

    if (_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) {
              _PR_THREAD_LOCK(me);
        me->io_pending = PR_FALSE;
        me->state = _PR_RUNNING;
              _PR_THREAD_UNLOCK(me);
        return PR_FAILURE;
    }

    if (me->md.blocked_io_status == 0) {
              _PR_MD_MAP_LOCKF_ERROR(me->md.blocked_io_error);
        return PR_FAILURE;
    }

    return PR_SUCCESS;
}

Here is the call graph for this function:

PROffset32 _PR_MD_LSEEK ( PRFileDesc fd,
PROffset32  offset,
PRSeekWhence  whence 
)

Definition at line 2526 of file ntio.c.

{
    DWORD moveMethod;
    PROffset32 rv;

    switch (whence) {
        case PR_SEEK_SET:
            moveMethod = FILE_BEGIN;
            break;
        case PR_SEEK_CUR:
            moveMethod = FILE_CURRENT;
            break;
        case PR_SEEK_END:
            moveMethod = FILE_END;
            break;
        default:
            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
            return -1;
    }

    rv = SetFilePointer((HANDLE)fd->secret->md.osfd, offset, NULL, moveMethod);

    /*
     * If the lpDistanceToMoveHigh argument (third argument) is
     * NULL, SetFilePointer returns 0xffffffff on failure.
     */
    if (-1 == rv) {
        _PR_MD_MAP_LSEEK_ERROR(GetLastError());
    }
    return rv;
}
PROffset64 _PR_MD_LSEEK64 ( PRFileDesc fd,
PROffset64  offset,
PRSeekWhence  whence 
)

Definition at line 2559 of file ntio.c.

{
    DWORD moveMethod;
    LARGE_INTEGER li;
    DWORD err;

    switch (whence) {
        case PR_SEEK_SET:
            moveMethod = FILE_BEGIN;
            break;
        case PR_SEEK_CUR:
            moveMethod = FILE_CURRENT;
            break;
        case PR_SEEK_END:
            moveMethod = FILE_END;
            break;
        default:
            PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
            return -1;
    }

    li.QuadPart = offset;
    li.LowPart = SetFilePointer((HANDLE)fd->secret->md.osfd,
            li.LowPart, &li.HighPart, moveMethod);

    if (0xffffffff == li.LowPart && (err = GetLastError()) != NO_ERROR) {
        _PR_MD_MAP_LSEEK_ERROR(err);
        li.QuadPart = -1;
    }
    return li.QuadPart;
}
PRInt32 _PR_MD_MAKE_DIR ( const char *  name,
PRIntn  mode 
)

Definition at line 3258 of file ntio.c.

{
    BOOL rv;
    SECURITY_ATTRIBUTES sa;
    LPSECURITY_ATTRIBUTES lpSA = NULL;
    PSECURITY_DESCRIPTOR pSD = NULL;
    PACL pACL = NULL;

    if (_PR_NT_MakeSecurityDescriptorACL(mode, dirAccessTable,
            &pSD, &pACL) == PR_SUCCESS) {
        sa.nLength = sizeof(sa);
        sa.lpSecurityDescriptor = pSD;
        sa.bInheritHandle = FALSE;
        lpSA = &sa;
    }
    rv = CreateDirectory(name, lpSA);
    if (lpSA != NULL) {
        _PR_NT_FreeSecurityDescriptorACL(pSD, pACL);
    }
    if (rv) {
        return 0;
    } else {
        _PR_MD_MAP_MKDIR_ERROR(GetLastError());
        return -1;
    }
}

Here is the call graph for this function:

Definition at line 3557 of file ntio.c.

{
    /*
     * On NT, we either call _md_Associate() or _md_MakeNonblock(),
     * depending on whether the socket is blocking or not.
     *
     * Once we associate a socket with the io completion port,
     * there is no way to disassociate it from the io completion
     * port.  So we have to call _md_Associate/_md_MakeNonblock
     * lazily.
     */
}
PRInt32 _PR_MD_MKDIR ( const char *  name,
PRIntn  mode 
)

Definition at line 3246 of file ntio.c.

{
    /* XXXMB - how to translate the "mode"??? */
    if (CreateDirectory(name, NULL)) {
        return 0;
    } else {
        _PR_MD_MAP_MKDIR_ERROR(GetLastError());
        return -1;
    }
}
PRInt32 _PR_MD_OPEN ( const char *  name,
PRIntn  osflags,
PRIntn  mode 
)

Definition at line 2101 of file ntio.c.

{
    HANDLE file;
    PRInt32 access = 0;
    PRInt32 flags = 0;
    PRInt32 flag6 = 0;
    
    if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH;
 
    if (osflags & PR_RDONLY || osflags & PR_RDWR) access |= GENERIC_READ;
    if (osflags & PR_WRONLY || osflags & PR_RDWR) access |= GENERIC_WRITE;

    if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL )
        flags = CREATE_NEW;
    else if (osflags & PR_CREATE_FILE)
        flags = (0 != (osflags & PR_TRUNCATE)) ? CREATE_ALWAYS : OPEN_ALWAYS;
    else if (osflags & PR_TRUNCATE) flags = TRUNCATE_EXISTING;
    else flags = OPEN_EXISTING;


    flag6 |= FILE_FLAG_OVERLAPPED;

    file = CreateFile(name, 
                      access, 
                      FILE_SHARE_READ|FILE_SHARE_WRITE,
                      NULL,
                      flags, 
                      flag6,
                      NULL);
    if (file == INVALID_HANDLE_VALUE) {
        _PR_MD_MAP_OPEN_ERROR(GetLastError());
        return -1;
    }

    if (osflags & PR_APPEND) {
        if ( SetFilePointer(file, 0, 0, FILE_END) == 0xFFFFFFFF ) {
            _PR_MD_MAP_LSEEK_ERROR(GetLastError());
            CloseHandle(file);
            return -1;
        }
    }

    return (PRInt32)file;
}
PRStatus _PR_MD_OPEN_DIR ( _MDDir d,
const char *  name 
)

Definition at line 2770 of file ntio.c.

{
    char filename[ MAX_PATH ];
    int len;

    len = strlen(name);
    /* Need 5 bytes for \*.* and the trailing null byte. */
    if (len + 5 > MAX_PATH) {
        PR_SetError(PR_NAME_TOO_LONG_ERROR, 0);
        return PR_FAILURE;
    }
    strcpy(filename, name);

    /*
     * If 'name' ends in a slash or backslash, do not append
     * another backslash.
     */
    if (IsPrevCharSlash(filename, filename + len)) {
        len--;
    }
    strcpy(&filename[len], "\\*.*");
    FlipSlashes( filename, strlen(filename) );

    d->d_hdl = FindFirstFile( filename, &(d->d_entry) );
    if ( d->d_hdl == INVALID_HANDLE_VALUE ) {
              _PR_MD_MAP_OPENDIR_ERROR(GetLastError());
        return PR_FAILURE;
    }
    d->firstEntry = PR_TRUE;
    d->magic = _MD_MAGIC_DIR;
    return PR_SUCCESS;
}

Here is the call graph for this function:

PRInt32 _PR_MD_OPEN_FILE ( const char *  name,
PRIntn  osflags,
PRIntn  mode 
)

Definition at line 2147 of file ntio.c.

{
    HANDLE file;
    PRInt32 access = 0;
    PRInt32 flags = 0;
    PRInt32 flag6 = 0;
    SECURITY_ATTRIBUTES sa;
    LPSECURITY_ATTRIBUTES lpSA = NULL;
    PSECURITY_DESCRIPTOR pSD = NULL;
    PACL pACL = NULL;

    if (osflags & PR_SYNC) flag6 = FILE_FLAG_WRITE_THROUGH;
 
    if (osflags & PR_RDONLY || osflags & PR_RDWR) access |= GENERIC_READ;
    if (osflags & PR_WRONLY || osflags & PR_RDWR) access |= GENERIC_WRITE;

    if ( osflags & PR_CREATE_FILE && osflags & PR_EXCL )
        flags = CREATE_NEW;
    else if (osflags & PR_CREATE_FILE)
        flags = (0 != (osflags & PR_TRUNCATE)) ? CREATE_ALWAYS : OPEN_ALWAYS;
    else if (osflags & PR_TRUNCATE) flags = TRUNCATE_EXISTING;
    else flags = OPEN_EXISTING;


    flag6 |= FILE_FLAG_OVERLAPPED;

    if (osflags & PR_CREATE_FILE) {
        if (_PR_NT_MakeSecurityDescriptorACL(mode, fileAccessTable,
                &pSD, &pACL) == PR_SUCCESS) {
            sa.nLength = sizeof(sa);
            sa.lpSecurityDescriptor = pSD;
            sa.bInheritHandle = FALSE;
            lpSA = &sa;
        }
    }
    file = CreateFile(name, 
                      access, 
                      FILE_SHARE_READ|FILE_SHARE_WRITE,
                      lpSA,
                      flags, 
                      flag6,
                      NULL);
    if (lpSA != NULL) {
        _PR_NT_FreeSecurityDescriptorACL(pSD, pACL);
    }
    if (file == INVALID_HANDLE_VALUE) {
        _PR_MD_MAP_OPEN_ERROR(GetLastError());
        return -1;
    }

    if (osflags & PR_APPEND) {
        if ( SetFilePointer(file, 0, 0, FILE_END) == 0xFFFFFFFF ) {
            _PR_MD_MAP_LSEEK_ERROR(GetLastError());
            CloseHandle(file);
            return -1;
        }
    }

    return (PRInt32)file;
}

Here is the call graph for this function:

Definition at line 242 of file ntio.c.

{
    int awoken = 0;
    unsigned long bytes, key;
    int rv;
    LPOVERLAPPED olp;
    _MDOverlapped *mdOlp;
    PRUint32 timeout;

    if (_nt_idleCount > 0) {
        PRThread *deadThread;

        _MD_LOCK(&_nt_idleLock);
        while( !PR_CLIST_IS_EMPTY(&_nt_idleList) ) {
            deadThread = _PR_THREAD_PTR(PR_LIST_HEAD(&_nt_idleList));
            PR_REMOVE_LINK(&deadThread->links);

            PR_ASSERT(deadThread->state == _PR_DEAD_STATE);

            /* XXXMB - cleanup to do here? */
            if ( !_PR_IS_NATIVE_THREAD(deadThread) ){
                /* Spinlock while user thread is still running.
                 * There is no way to use a condition variable here. The thread
                 * is dead, and we have to wait until we switch off the dead 
                 * thread before we can kill the fiber completely.
                 */
                while ( deadThread->no_sched)
                    ;

                DeleteFiber(deadThread->md.fiber_id);
            }
            memset(deadThread, 0xa, sizeof(PRThread)); /* debugging */
            if (!deadThread->threadAllocatedOnStack)
                PR_DELETE(deadThread);
            _nt_idleCount--;
        }
        _MD_UNLOCK(&_nt_idleLock);
    }

    if (ticks == PR_INTERVAL_NO_TIMEOUT)
#if 0
        timeout = INFINITE;
#else
    /*
     * temporary hack to poll the runq every 5 seconds because of bug in
     * native threads creating user threads and not poking the right cpu.
     *
     * A local thread that was interrupted is bound to its current
     * cpu but there is no easy way for the interrupter to poke the
     * right cpu.  This is a hack to poll the runq every 5 seconds.
     */
        timeout = 5000;
#endif
    else 
        timeout = PR_IntervalToMilliseconds(ticks);

    /*
     * The idea of looping here is to complete as many IOs as possible before
     * returning.  This should minimize trips to the idle thread.
     */
    while(1) {
        rv = GetQueuedCompletionStatus(
                _pr_completion_port,
                &bytes,
                &key,
                &olp,
                timeout); 
        if (rv == 0 && olp == NULL) {
            /* Error in GetQueuedCompetionStatus */
            if (GetLastError() != WAIT_TIMEOUT) {
                /* ARGH - what can we do here? Log an error? XXXMB */
                return -1;
            } else {
                /* If awoken == 0, then we just had a timeout */
                return awoken;
            }
        }

        if (olp == NULL) 
            return 0;

        mdOlp = (_MDOverlapped *)olp;

        if (mdOlp->ioModel == _MD_MultiWaitIO) {
            PRRecvWait *desc;
            PRWaitGroup *group;
            PRThread *thred = NULL;
            PRMWStatus mwstatus;

            desc = mdOlp->data.mw.desc;
            PR_ASSERT(desc != NULL);
            mwstatus = rv ? PR_MW_SUCCESS : PR_MW_FAILURE;
            if (InterlockedCompareExchange((PVOID *)&desc->outcome,
                    (PVOID)mwstatus, (PVOID)PR_MW_PENDING)
                    == (PVOID)PR_MW_PENDING) {
                if (mwstatus == PR_MW_SUCCESS) {
                    desc->bytesRecv = bytes;
                } else {
                    mdOlp->data.mw.error = GetLastError();
                }
            }
            group = mdOlp->data.mw.group;
            PR_ASSERT(group != NULL);

            _PR_MD_LOCK(&group->mdlock);
            PR_APPEND_LINK(&mdOlp->data.mw.links, &group->io_ready);
            PR_ASSERT(desc->fd != NULL);
            NT_HashRemoveInternal(group, desc->fd);
            if (!PR_CLIST_IS_EMPTY(&group->wait_list)) {
                thred = _PR_THREAD_CONDQ_PTR(PR_LIST_HEAD(&group->wait_list));
                PR_REMOVE_LINK(&thred->waitQLinks);
            }
            _PR_MD_UNLOCK(&group->mdlock);

            if (thred) {
                if (!_PR_IS_NATIVE_THREAD(thred)) {
                    int pri = thred->priority;
                    _PRCPU *lockedCPU = _PR_MD_CURRENT_CPU();
                    _PR_THREAD_LOCK(thred);
                    if (thred->flags & _PR_ON_PAUSEQ) {
                        _PR_SLEEPQ_LOCK(thred->cpu);
                        _PR_DEL_SLEEPQ(thred, PR_TRUE);
                        _PR_SLEEPQ_UNLOCK(thred->cpu);
                        _PR_THREAD_UNLOCK(thred);
                        thred->cpu = lockedCPU;
                        thred->state = _PR_RUNNABLE;
                        _PR_RUNQ_LOCK(lockedCPU);
                        _PR_ADD_RUNQ(thred, lockedCPU, pri);
                        _PR_RUNQ_UNLOCK(lockedCPU);
                    } else {
                        /*
                         * The thread was just interrupted and moved
                         * from the pause queue to the run queue.
                         */
                        _PR_THREAD_UNLOCK(thred);
                    }
                } else {
                    _PR_THREAD_LOCK(thred);
                    thred->state = _PR_RUNNABLE;
                    _PR_THREAD_UNLOCK(thred);
                    ReleaseSemaphore(thred->md.blocked_sema, 1, NULL);
                }
            }
        } else {
            PRThread *completed_io;

            PR_ASSERT(mdOlp->ioModel == _MD_BlockingIO);
            completed_io = _PR_THREAD_MD_TO_PTR(mdOlp->data.mdThread);
            completed_io->md.blocked_io_status = rv;
            if (rv == 0)
                completed_io->md.blocked_io_error = GetLastError();
            completed_io->md.blocked_io_bytes = bytes;

            if ( !_PR_IS_NATIVE_THREAD(completed_io) ) {
                int pri = completed_io->priority;
                _PRCPU *lockedCPU = _PR_MD_CURRENT_CPU();

                /* The KEY_CVAR notification only occurs when a native thread
                 * is notifying a user thread.  For user-user notifications
                 * the wakeup occurs by having the notifier place the thread 
                 * on the runq directly; for native-native notifications the
                 * wakeup occurs by calling ReleaseSemaphore.
                 */
                if ( key == KEY_CVAR ) {
                    PR_ASSERT(completed_io->io_pending == PR_FALSE);
                    PR_ASSERT(completed_io->io_suspended == PR_FALSE);
                    PR_ASSERT(completed_io->md.thr_bound_cpu == NULL);

                    /* Thread has already been deleted from sleepQ */

                    /* Switch CPU and add to runQ */
                    completed_io->cpu = lockedCPU;
                    completed_io->state = _PR_RUNNABLE;
                    _PR_RUNQ_LOCK(lockedCPU);
                    _PR_ADD_RUNQ(completed_io, lockedCPU, pri);
                    _PR_RUNQ_UNLOCK(lockedCPU);
                } else {
                    PR_ASSERT(key == KEY_IO);
                    PR_ASSERT(completed_io->io_pending == PR_TRUE);

                    _PR_THREAD_LOCK(completed_io);

                    completed_io->io_pending = PR_FALSE;

                    /* If io_suspended is true, then this IO has already resumed.
                     * We don't need to do anything; because the thread is
                     * already running.
                     */
                    if (completed_io->io_suspended == PR_FALSE) {
                        if (completed_io->flags & (_PR_ON_SLEEPQ|_PR_ON_PAUSEQ)) {
                            _PR_SLEEPQ_LOCK(completed_io->cpu);
                            _PR_DEL_SLEEPQ(completed_io, PR_TRUE);
                            _PR_SLEEPQ_UNLOCK(completed_io->cpu);

                            _PR_THREAD_UNLOCK(completed_io);

                                          /*
                                           * If an I/O operation is suspended, the thread
                                           * must be running on the same cpu on which the
                                           * I/O operation was issued.
                                           */
                                          PR_ASSERT(!completed_io->md.thr_bound_cpu ||
                                   (completed_io->cpu == completed_io->md.thr_bound_cpu));

                                                 if (!completed_io->md.thr_bound_cpu)
                                   completed_io->cpu = lockedCPU;
                            completed_io->state = _PR_RUNNABLE;
                            _PR_RUNQ_LOCK(completed_io->cpu);
                            _PR_ADD_RUNQ(completed_io, completed_io->cpu, pri);
                            _PR_RUNQ_UNLOCK(completed_io->cpu);
                        } else {
                            _PR_THREAD_UNLOCK(completed_io);
                        }
                    } else {
                        _PR_THREAD_UNLOCK(completed_io);
                    }
                }
            } else {
                /* For native threads, they are only notified through this loop
                 * when completing IO.  So, don't worry about this being a CVAR
                 * notification, because that is not possible.
                 */
                _PR_THREAD_LOCK(completed_io);
                completed_io->io_pending = PR_FALSE;
                if (completed_io->io_suspended == PR_FALSE) {
                    completed_io->state = _PR_RUNNABLE;
                    _PR_THREAD_UNLOCK(completed_io);
                    rv = ReleaseSemaphore(completed_io->md.blocked_sema,
                            1, NULL);
                    PR_ASSERT(0 != rv);
                } else {
                    _PR_THREAD_UNLOCK(completed_io);
                }
            }
        }

        awoken++;
        timeout = 0;   /* Don't block on subsequent trips through the loop */
    }

    /* never reached */
    return 0;
}

Here is the call graph for this function:

Definition at line 2516 of file ntio.c.

{
    if (NULL == fd)
              PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
       else
              PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
    return -1;
}

Definition at line 2713 of file ntio.c.

PRInt32 _PR_MD_READ ( PRFileDesc fd,
void buf,
PRInt32  len 
)

Definition at line 2209 of file ntio.c.

{
    PRInt32 f = fd->secret->md.osfd;
    PRUint32 bytes;
    int rv, err;
    LONG hiOffset = 0;
    LONG loOffset;

    if (!fd->secret->md.sync_file_io) {
        PRThread *me = _PR_MD_CURRENT_THREAD();

        if (me->io_suspended) {
            PR_SetError(PR_INVALID_STATE_ERROR, 0);
            return -1;
        }

        memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));

        me->md.overlapped.overlapped.Offset = SetFilePointer((HANDLE)f, 0, &me->md.overlapped.overlapped.OffsetHigh, FILE_CURRENT);
        PR_ASSERT((me->md.overlapped.overlapped.Offset != 0xffffffff) || (GetLastError() == NO_ERROR));

        if (fd->secret->inheritable == _PR_TRI_TRUE) {
            rv = ReadFile((HANDLE)f, 
                          (LPVOID)buf, 
                          len, 
                          &bytes, 
                          &me->md.overlapped.overlapped);
            if (rv != 0) {
                loOffset = SetFilePointer((HANDLE)f, bytes, &hiOffset, FILE_CURRENT);
                PR_ASSERT((loOffset != 0xffffffff) || (GetLastError() == NO_ERROR));
                return bytes;
            }
            err = GetLastError();
            if (err == ERROR_IO_PENDING) {
                rv = GetOverlappedResult((HANDLE)f,
                        &me->md.overlapped.overlapped, &bytes, TRUE);
                if (rv != 0) {
                    loOffset = SetFilePointer((HANDLE)f, bytes, &hiOffset, FILE_CURRENT);
                    PR_ASSERT((loOffset != 0xffffffff) || (GetLastError() == NO_ERROR));
                    return bytes;
                }
                err = GetLastError();
            }
            if (err == ERROR_HANDLE_EOF) {
                return 0;
            } else {
                _PR_MD_MAP_READ_ERROR(err);
                return -1;
            }
        } else {
            if (!fd->secret->md.io_model_committed) {
                rv = _md_Associate((HANDLE)f);
                PR_ASSERT(rv != 0);
                fd->secret->md.io_model_committed = PR_TRUE;
            }

                     if (_native_threads_only)
                     me->md.overlapped.overlapped.hEvent = me->md.thr_event;

                     _PR_THREAD_LOCK(me);
                     if (_PR_PENDING_INTERRUPT(me)) {
                            me->flags &= ~_PR_INTERRUPT;
                            PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
                            _PR_THREAD_UNLOCK(me);
                            return -1;
                     }
                     me->io_pending = PR_TRUE;
                     me->state = _PR_IO_WAIT;
                     _PR_THREAD_UNLOCK(me);
                     me->io_fd = f;

            rv = ReadFile((HANDLE)f, 
                          (LPVOID)buf, 
                          len, 
                          &bytes, 
                          &me->md.overlapped.overlapped);
            if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING) ) {
                            _PR_THREAD_LOCK(me);
                            me->io_pending = PR_FALSE;
                            me->state = _PR_RUNNING;
                            if (_PR_PENDING_INTERRUPT(me)) {
                                   me->flags &= ~_PR_INTERRUPT;
                                   PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
                                   _PR_THREAD_UNLOCK(me);
                                   return -1;
                            }
                            _PR_THREAD_UNLOCK(me);

                if (err == ERROR_HANDLE_EOF) {
                    return 0;
                }
                _PR_MD_MAP_READ_ERROR(err);
                return -1;
            }

            if (_native_threads_only && rv) {
                _native_thread_io_nowait(me, rv, bytes);
            } else if (_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) {
                PR_ASSERT(0);
                return -1;
            }

            PR_ASSERT(me->io_pending == PR_FALSE || me->io_suspended == PR_TRUE);

            if (me->io_suspended) {
                if (_PR_PENDING_INTERRUPT(me)) {
                    me->flags &= ~_PR_INTERRUPT;
                    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
                } else {
                    PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
                }
                return -1;
            }

            if (me->md.blocked_io_status == 0) {
                if (me->md.blocked_io_error == ERROR_HANDLE_EOF) {
                    return 0;
                }
                _PR_MD_MAP_READ_ERROR(me->md.blocked_io_error);
                return -1;
            }

            SetFilePointer((HANDLE)f, me->md.blocked_io_bytes, 0, FILE_CURRENT);
    
            PR_ASSERT(me->io_pending == PR_FALSE);

            return me->md.blocked_io_bytes;
        }
    } else {

        rv = ReadFile((HANDLE)f,
                      (LPVOID)buf,
                      len,
                      &bytes,
                      NULL);
        if (rv == 0) {
            err = GetLastError();
            /* ERROR_HANDLE_EOF can only be returned by async io */
            PR_ASSERT(err != ERROR_HANDLE_EOF);
            if (err == ERROR_BROKEN_PIPE) {
                /* The write end of the pipe has been closed. */ 
                return 0;
            }
            _PR_MD_MAP_READ_ERROR(err);
            return -1;
        }
        return bytes;
    }
}

Here is the call graph for this function:

char* _PR_MD_READ_DIR ( _MDDir d,
PRIntn  flags 
)

Definition at line 2804 of file ntio.c.

{
    PRInt32 err;
    BOOL rv;
    char *fileName;

    if ( d ) {
        while (1) {
            if (d->firstEntry) {
                d->firstEntry = PR_FALSE;
                rv = 1;
            } else {
                rv = FindNextFile(d->d_hdl, &(d->d_entry));
            }
            if (rv == 0) {
                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;
            if ( (flags & PR_SKIP_HIDDEN) && FileIsHidden(d))
                 continue;
            return fileName;
        }
       err = GetLastError();
       PR_ASSERT(NO_ERROR != err);
                     _PR_MD_MAP_READDIR_ERROR(err);
       return NULL;
              }
    PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
    return NULL;
}
PRInt32 _PR_MD_RECV ( PRFileDesc fd,
void buf,
PRInt32  amount,
PRIntn  flags,
PRIntervalTime  timeout 
)

Definition at line 1722 of file ntio.c.

{
    PRInt32 osfd = fd->secret->md.osfd;
    PRThread *me = _PR_MD_CURRENT_THREAD();
    int bytes;
    int rv, err;

    if (_NT_USE_NB_IO(fd)) {
        if (!fd->secret->md.io_model_committed) {
            rv = _md_MakeNonblock((HANDLE)osfd);
            PR_ASSERT(0 != rv);
            fd->secret->md.io_model_committed = PR_TRUE;
        }
        return _nt_nonblock_recv(fd, buf, amount, flags, timeout);
    }

    if (me->io_suspended) {
        PR_SetError(PR_INVALID_STATE_ERROR, 0);
        return -1;
    }

    if (!fd->secret->md.io_model_committed) {
        rv = _md_Associate((HANDLE)osfd);
        PR_ASSERT(0 != rv);
        fd->secret->md.io_model_committed = PR_TRUE;
    }

    memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));
       if (_native_threads_only)
              me->md.overlapped.overlapped.hEvent = me->md.thr_event;

    _PR_THREAD_LOCK(me);
       if (_PR_PENDING_INTERRUPT(me)) {
              me->flags &= ~_PR_INTERRUPT;
              PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
       _PR_THREAD_UNLOCK(me);
              return -1;
       }
    me->io_pending = PR_TRUE;
    me->state = _PR_IO_WAIT;
    _PR_THREAD_UNLOCK(me);
    me->io_fd = osfd;

    rv = ReadFile((HANDLE)osfd,
                  buf, 
                  amount,
                  &bytes,
                  &(me->md.overlapped.overlapped));
    if ( (rv == 0) && (GetLastError() != ERROR_IO_PENDING) ) {
       _PR_THREAD_LOCK(me);
        me->io_pending = PR_FALSE;
        me->state = _PR_RUNNING;
              if (_PR_PENDING_INTERRUPT(me)) {
                     me->flags &= ~_PR_INTERRUPT;
                     PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
                     _PR_THREAD_UNLOCK(me);
                     return -1;
              }
              _PR_THREAD_UNLOCK(me);

        if ((err = GetLastError()) == ERROR_HANDLE_EOF)
            return 0;
              _PR_MD_MAP_READ_ERROR(err);
        return -1;
    }

    if (_native_threads_only && rv) {
        _native_thread_io_nowait(me, rv, bytes);
    } else if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) {
        PR_ASSERT(0);
        return -1;
    }

    PR_ASSERT(me->io_pending == PR_FALSE || me->io_suspended == PR_TRUE);

    if (me->io_suspended) {
        if (_PR_PENDING_INTERRUPT(me)) {
            me->flags &= ~_PR_INTERRUPT;
            PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
        } else {
            PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
        }
        return -1;
    }

    if (me->md.blocked_io_status == 0) {
        if (me->md.blocked_io_error == ERROR_HANDLE_EOF)
            return 0;
              _PR_MD_MAP_READ_ERROR(me->md.blocked_io_error);
        return -1;
    }

    PR_ASSERT(me->io_pending == PR_FALSE);

    return me->md.blocked_io_bytes;
}

Here is the call graph for this function:

PRInt32 _PR_MD_RECVFROM ( PRFileDesc fd,
void buf,
PRInt32  amount,
PRIntn  flags,
PRNetAddr addr,
PRUint32 addrlen,
PRIntervalTime  timeout 
)

Definition at line 1934 of file ntio.c.

{
    PRInt32 osfd = fd->secret->md.osfd;
    PRInt32 rv;

    if (!fd->secret->md.io_model_committed) {
        rv = _md_MakeNonblock((HANDLE)osfd);
        PR_ASSERT(0 != rv);
        fd->secret->md.io_model_committed = PR_TRUE;
    }
    if (_NT_USE_NB_IO(fd))
        return _nt_nonblock_recvfrom(fd, buf, amount, (struct sockaddr *)addr, addrlen, timeout);
    else
        return pt_RecvFrom(osfd, buf, amount, flags, addr, addrlen, timeout);
}

Here is the call graph for this function:

PRInt32 _PR_MD_RENAME ( const char *  from,
const char *  to 
)

Definition at line 3209 of file ntio.c.

{
    /* Does this work with dot-relative pathnames? */
    if (MoveFile(from, to)) {
              return 0;
       } else {
              _PR_MD_MAP_RENAME_ERROR(GetLastError());
              return -1;
       }
}
PRInt32 _PR_MD_RMDIR ( const char *  name)

Definition at line 3286 of file ntio.c.

{
    if (RemoveDirectory(name)) {
        return 0;
    } else {
        _PR_MD_MAP_RMDIR_ERROR(GetLastError());
        return -1;
    }
}
PRInt32 _PR_MD_SEND ( PRFileDesc fd,
const void buf,
PRInt32  amount,
PRIntn  flags,
PRIntervalTime  timeout 
)

Definition at line 1821 of file ntio.c.

{
    PRInt32 osfd = fd->secret->md.osfd;
    PRThread *me = _PR_MD_CURRENT_THREAD();
    int bytes;
    int rv, err;

    if (_NT_USE_NB_IO(fd)) {
        if (!fd->secret->md.io_model_committed) {
            rv = _md_MakeNonblock((HANDLE)osfd);
            PR_ASSERT(0 != rv);
            fd->secret->md.io_model_committed = PR_TRUE;
        }
        return _nt_nonblock_send(fd, (char *)buf, amount, timeout);
    }

    if (me->io_suspended) {
        PR_SetError(PR_INVALID_STATE_ERROR, 0);
        return -1;
    }

    if (!fd->secret->md.io_model_committed) {
        rv = _md_Associate((HANDLE)osfd);
        PR_ASSERT(0 != rv);
        fd->secret->md.io_model_committed = PR_TRUE;
    }

    memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));
       if (_native_threads_only)
              me->md.overlapped.overlapped.hEvent = me->md.thr_event;

    _PR_THREAD_LOCK(me);
       if (_PR_PENDING_INTERRUPT(me)) {
              me->flags &= ~_PR_INTERRUPT;
              PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
       _PR_THREAD_UNLOCK(me);
              return -1;
       }
    me->io_pending = PR_TRUE;
    me->state = _PR_IO_WAIT;
    _PR_THREAD_UNLOCK(me);
    me->io_fd = osfd;

    rv = WriteFile((HANDLE)osfd,
                   buf, 
                   amount,
                   &bytes,
                   &(me->md.overlapped.overlapped));
    if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING) ) {
       _PR_THREAD_LOCK(me);
        me->io_pending = PR_FALSE;
        me->state = _PR_RUNNING;
              if (_PR_PENDING_INTERRUPT(me)) {
                     me->flags &= ~_PR_INTERRUPT;
                     PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
                     _PR_THREAD_UNLOCK(me);
                     return -1;
              }
              _PR_THREAD_UNLOCK(me);

              _PR_MD_MAP_WRITE_ERROR(err);
        return -1;
    }

    if (_native_threads_only && rv) {
        _native_thread_io_nowait(me, rv, bytes);
    } else if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) {
        PR_ASSERT(0);
        return -1;
    }

    PR_ASSERT(me->io_pending == PR_FALSE || me->io_suspended == PR_TRUE);

    if (me->io_suspended) {
        if (_PR_PENDING_INTERRUPT(me)) {
            me->flags &= ~_PR_INTERRUPT;
            PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
        } else {
            PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
        }
        return -1;
    }

    if (me->md.blocked_io_status == 0) {
              _PR_MD_MAP_WRITE_ERROR(me->md.blocked_io_error);
        return -1;
    }

    PR_ASSERT(me->io_pending == PR_FALSE);

    return me->md.blocked_io_bytes;
}

Here is the call graph for this function:

PRInt32 _PR_MD_SENDFILE ( PRFileDesc sock,
PRSendFileData sfd,
PRInt32  flags,
PRIntervalTime  timeout 
)

Definition at line 1617 of file ntio.c.

{
    PRThread *me = _PR_MD_CURRENT_THREAD();
    PRInt32 tflags;
    int rv, err;

    if (me->io_suspended) {
        PR_SetError(PR_INVALID_STATE_ERROR, 0);
        return -1;
    }

    if (!sock->secret->md.io_model_committed) {
        rv = _md_Associate((HANDLE)sock->secret->md.osfd);
        PR_ASSERT(0 != rv);
        sock->secret->md.io_model_committed = PR_TRUE;
    }
    if (!me->md.xmit_bufs) {
        me->md.xmit_bufs = PR_NEW(TRANSMIT_FILE_BUFFERS);
        if (!me->md.xmit_bufs) {
            PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
            return -1;
        }
    }
    me->md.xmit_bufs->Head       = (void *)sfd->header;
    me->md.xmit_bufs->HeadLength = sfd->hlen;
    me->md.xmit_bufs->Tail       = (void *)sfd->trailer;
    me->md.xmit_bufs->TailLength = sfd->tlen;

    memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));
    me->md.overlapped.overlapped.Offset = sfd->file_offset;
       if (_native_threads_only)
              me->md.overlapped.overlapped.hEvent = me->md.thr_event;

    tflags = 0;
    if (flags & PR_TRANSMITFILE_CLOSE_SOCKET)
        tflags = TF_DISCONNECT | TF_REUSE_SOCKET;

    _PR_THREAD_LOCK(me);
       if (_PR_PENDING_INTERRUPT(me)) {
              me->flags &= ~_PR_INTERRUPT;
              PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
       _PR_THREAD_UNLOCK(me);
              return -1;
       }
    me->io_pending = PR_TRUE;
    me->state = _PR_IO_WAIT;
    _PR_THREAD_UNLOCK(me);
    me->io_fd = sock->secret->md.osfd;

    rv = TransmitFile((SOCKET)sock->secret->md.osfd,
                      (HANDLE)sfd->fd->secret->md.osfd,
                      (DWORD)sfd->file_nbytes,
                      (DWORD)0,
                      (LPOVERLAPPED)&(me->md.overlapped.overlapped),
                      (TRANSMIT_FILE_BUFFERS *)me->md.xmit_bufs,
                      (DWORD)tflags);
    if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING) ) {
              _PR_THREAD_LOCK(me);
              me->io_pending = PR_FALSE;
              me->state = _PR_RUNNING;
              if (_PR_PENDING_INTERRUPT(me)) {
                     me->flags &= ~_PR_INTERRUPT;
                     PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
                     _PR_THREAD_UNLOCK(me);
                     return -1;
              }
              _PR_THREAD_UNLOCK(me);

              _PR_MD_MAP_TRANSMITFILE_ERROR(err);
        return -1;
    }

    if (_NT_IO_WAIT(me, timeout) == PR_FAILURE) {
        PR_ASSERT(0);
        return -1;
    }

    PR_ASSERT(me->io_pending == PR_FALSE || me->io_suspended == PR_TRUE);

    if (me->io_suspended) {
        if (_PR_PENDING_INTERRUPT(me)) {
            me->flags &= ~_PR_INTERRUPT;
            PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
        } else {
            PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
        }
        return -1;
    }

    if (me->md.blocked_io_status == 0) {
              _PR_MD_MAP_TRANSMITFILE_ERROR(me->md.blocked_io_error);
        return -1;
    }

    if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) {
        _md_put_recycled_socket(sock->secret->md.osfd, sock->secret->af);
    }

    PR_ASSERT(me->io_pending == PR_FALSE);

    return me->md.blocked_io_bytes;
}

Here is the call graph for this function:

PRInt32 _PR_MD_SENDTO ( PRFileDesc fd,
const void buf,
PRInt32  amount,
PRIntn  flags,
const PRNetAddr addr,
PRUint32  addrlen,
PRIntervalTime  timeout 
)

Definition at line 1916 of file ntio.c.

{
    PRInt32 osfd = fd->secret->md.osfd;
    PRInt32 rv;

    if (!fd->secret->md.io_model_committed) {
        rv = _md_MakeNonblock((HANDLE)osfd);
        PR_ASSERT(0 != rv);
        fd->secret->md.io_model_committed = PR_TRUE;
    }
    if (_NT_USE_NB_IO(fd))
        return _nt_nonblock_sendto(fd, buf, amount, (struct sockaddr *)addr, addrlen, timeout);
    else
        return pt_SendTo(osfd, buf, amount, flags, addr, addrlen, timeout);
}

Here is the call graph for this function:

PRStatus _PR_MD_SET_FD_INHERITABLE ( PRFileDesc fd,
PRBool  inheritable 
)

Definition at line 2683 of file ntio.c.

PRStatus _PR_MD_SETSOCKOPT ( PRFileDesc fd,
PRInt32  level,
PRInt32  optname,
const char *  optval,
PRInt32  optlen 
)

Definition at line 2085 of file ntio.c.

Here is the call graph for this function:

PRInt32 _PR_MD_SHUTDOWN ( PRFileDesc fd,
PRIntn  how 
)

Definition at line 1996 of file ntio.c.

{
    PRInt32 rv;

    rv = shutdown(fd->secret->md.osfd, how);
       if (rv < 0)
              _PR_MD_MAP_SHUTDOWN_ERROR(WSAGetLastError());
       return(rv);
}

Here is the call graph for this function:

PRInt32 _PR_MD_SOCKET ( int  af,
int  type,
int  flags 
)

Definition at line 1155 of file ntio.c.

{
    SOCKET sock;

    sock = socket(af, type, flags);

    if (sock == INVALID_SOCKET) {
        _PR_MD_MAP_SOCKET_ERROR(WSAGetLastError());
    }

    return (PRInt32)sock;
}

Here is the call graph for this function:

Definition at line 2504 of file ntio.c.

{
    PRInt32 result;

    if (ioctlsocket(fd->secret->md.osfd, FIONREAD, &result) < 0) {
              PR_SetError(PR_BAD_DESCRIPTOR_ERROR, WSAGetLastError());
        return -1;
    }
    return result;
}

Here is the call graph for this function:

PRInt32 _PR_MD_STAT ( const char *  fn,
struct stat info 
)

Definition at line 2905 of file ntio.c.

{
    PRInt32 rv;

    rv = _stat(fn, (struct _stat *)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.
         */

        int len = strlen(fn);
        if (len > 0 && len <= _MAX_PATH
                && IsPrevCharSlash(fn, fn + len)) {
            char newfn[_MAX_PATH + 1];

            strcpy(newfn, fn);
            newfn[len - 1] = '\0';
            rv = _stat(newfn, (struct _stat *)info);
        }
    }

    if (-1 == rv) {
        _PR_MD_MAP_STAT_ERROR(errno);
    }
    return rv;
}

Here is the call graph for this function:

Definition at line 3416 of file ntio.c.

{
    PRInt32 rv, err;
    PRThread *me = _PR_MD_CURRENT_THREAD();

    if (me->io_suspended) {
        PR_SetError(PR_INVALID_STATE_ERROR, 0);
        return PR_FAILURE;
    }

    memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));

    _PR_THREAD_LOCK(me);
       if (_PR_PENDING_INTERRUPT(me)) {
              me->flags &= ~_PR_INTERRUPT;
              PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
       _PR_THREAD_UNLOCK(me);
              return -1;
       }
    me->io_pending = PR_TRUE;
    me->state = _PR_IO_WAIT;
    _PR_THREAD_UNLOCK(me);

    rv = LockFileEx((HANDLE)f, 
                    LOCKFILE_FAIL_IMMEDIATELY|LOCKFILE_EXCLUSIVE_LOCK,
                    0,
                    0x7fffffff,
                    0,
                    &me->md.overlapped.overlapped);
    if (_native_threads_only) {
              _PR_THREAD_LOCK(me);
              me->io_pending = PR_FALSE;
              me->state = _PR_RUNNING;
              if (_PR_PENDING_INTERRUPT(me)) {
                     me->flags &= ~_PR_INTERRUPT;
                     PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
                     _PR_THREAD_UNLOCK(me);
                     return PR_FAILURE;
              }
              _PR_THREAD_UNLOCK(me);

        if (rv == FALSE) {
            err = GetLastError();
            PR_ASSERT(err != ERROR_IO_PENDING);
            _PR_MD_MAP_LOCKF_ERROR(err);
            return PR_FAILURE;
        }
        return PR_SUCCESS;
    }
    if ( rv == FALSE && ((err = GetLastError()) != ERROR_IO_PENDING)) {
              _PR_THREAD_LOCK(me);
              me->io_pending = PR_FALSE;
              me->state = _PR_RUNNING;
              if (_PR_PENDING_INTERRUPT(me)) {
                     me->flags &= ~_PR_INTERRUPT;
                     PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
                     _PR_THREAD_UNLOCK(me);
                     return PR_FAILURE;
              }
              _PR_THREAD_UNLOCK(me);

        _PR_MD_MAP_LOCKF_ERROR(err);
        return PR_FAILURE;
    }
#ifdef _NEED_351_FILE_LOCKING_HACK
    else if (rv)  {
        /* If this is NT 3.51 and the file is local, then we won't get a 
         * completion back from LockFile when it succeeded.
         */
        if (_nt_version_gets_lockfile_completion == PR_FALSE) {
            if ( IsFileLocal((HANDLE)f) == _PR_LOCAL_FILE) {
                            _PR_THREAD_LOCK(me);
                            me->io_pending = PR_FALSE;
                            me->state = _PR_RUNNING;
                            if (_PR_PENDING_INTERRUPT(me)) {
                                   me->flags &= ~_PR_INTERRUPT;
                                   PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
                                   _PR_THREAD_UNLOCK(me);
                                   return PR_FAILURE;
                            }
                            _PR_THREAD_UNLOCK(me);

                return PR_SUCCESS; 
            }
        }
    }
#endif /* _NEED_351_FILE_LOCKING_HACK */

    if (_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) {
              _PR_THREAD_LOCK(me);
              me->io_pending = PR_FALSE;
              me->state = _PR_RUNNING;
              if (_PR_PENDING_INTERRUPT(me)) {
                     me->flags &= ~_PR_INTERRUPT;
                     PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
                     _PR_THREAD_UNLOCK(me);
                     return PR_FAILURE;
              }
              _PR_THREAD_UNLOCK(me);

        return PR_FAILURE;
    }

    if (me->md.blocked_io_status == 0) {
              _PR_MD_MAP_LOCKF_ERROR(me->md.blocked_io_error);
        return PR_FAILURE;
    }

    return PR_SUCCESS;
}

Here is the call graph for this function:

Definition at line 3529 of file ntio.c.

{
    PRInt32 rv;
    PRThread *me = _PR_MD_CURRENT_THREAD();

    if (me->io_suspended) {
        PR_SetError(PR_INVALID_STATE_ERROR, 0);
        return PR_FAILURE;
    }

    memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));

    rv = UnlockFileEx((HANDLE)f,
                      0,
                      0x7fffffff,
                      0,
                      &me->md.overlapped.overlapped);

    if (rv)
        return PR_SUCCESS;
    else {
        int err = GetLastError();
              _PR_MD_MAP_LOCKF_ERROR(err);
        return PR_FAILURE;
    }
}

Here is the call graph for this function:

void _PR_MD_UPDATE_ACCEPT_CONTEXT ( PRInt32  accept_sock,
PRInt32  listen_sock 
)

Definition at line 1263 of file ntio.c.

{
    /* Sockets accept()'d with AcceptEx need to call this setsockopt before
     * calling anything other than ReadFile(), WriteFile(), send(), recv(), 
     * Transmitfile(), and closesocket().  In order to call any other 
     * winsock functions, we have to make this setsockopt call.
     *
     * XXXMB - For the server, we *NEVER* need this in
     * the "normal" code path.  But now we have to call it.  This is a waste
     * of a system call.  We'd like to only call it before calling the 
     * obscure socket calls, but since we don't know at that point what the
     * original socket was (or even if it is still alive) we can't do it
     * at that point... 
     */
    setsockopt((SOCKET)accept_sock, 
               SOL_SOCKET, 
               SO_UPDATE_ACCEPT_CONTEXT,
               (char *)&listen_sock,
               sizeof(listen_sock));

}

Here is the call graph for this function:

Here is the caller graph for this function:

PRStatus _PR_MD_WAIT ( PRThread thread,
PRIntervalTime  ticks 
)

Definition at line 530 of file ntio.c.

{
    DWORD rv;

       if (_native_threads_only) {
              return(_native_thread_md_wait(thread, ticks));
       }
    if ( thread->flags & _PR_GLOBAL_SCOPE ) {
        PRUint32 msecs = (ticks == PR_INTERVAL_NO_TIMEOUT) ?
            INFINITE : PR_IntervalToMilliseconds(ticks);
        rv = WaitForSingleObject(thread->md.blocked_sema, msecs);
        switch(rv) {
            case WAIT_OBJECT_0:
                return PR_SUCCESS;
                break;
            case WAIT_TIMEOUT:
                _PR_THREAD_LOCK(thread);
                if (thread->state == _PR_IO_WAIT) {
                    if (thread->io_pending == PR_TRUE) {
                        thread->state = _PR_RUNNING;
                        thread->io_suspended = PR_TRUE;
                        _PR_THREAD_UNLOCK(thread);
                    } else {
                        /* The IO completed just at the same time the timeout
                         * occurred.  This left the semaphore in the signaled
                         * state.  Call WaitForSingleObject() to clear the
                         * semaphore.
                         */
                        _PR_THREAD_UNLOCK(thread);
                        rv = WaitForSingleObject(thread->md.blocked_sema, INFINITE);
                        PR_ASSERT(rv == WAIT_OBJECT_0);
                    }
                } else {
                    if (thread->wait.cvar != NULL) {
                        PR_ASSERT(thread->state == _PR_COND_WAIT);
                        thread->wait.cvar = NULL;
                        thread->state = _PR_RUNNING;
                        _PR_THREAD_UNLOCK(thread);
                    } else {
                        /* The CVAR was notified just as the timeout
                         * occurred.  This left the semaphore in the
                         * signaled state.  Call WaitForSingleObject()
                         * to clear the semaphore.
                         */
                        _PR_THREAD_UNLOCK(thread);
                        rv = WaitForSingleObject(thread->md.blocked_sema, INFINITE);
                        PR_ASSERT(rv == WAIT_OBJECT_0);
                    }
                }
                return PR_SUCCESS;
                break;
            default:
                return PR_FAILURE;
                break;
        }
    } else {
        PRInt32 is;

        _PR_INTSOFF(is);
        _PR_MD_SWITCH_CONTEXT(thread);
    }

    return PR_SUCCESS;
}

Here is the call graph for this function:

Definition at line 843 of file ntio.c.

{
    if (thread == NULL) {
        /* If thread is NULL, we aren't waking a thread, we're just poking
         * idle thread 
         */
        if ( PostQueuedCompletionStatus(_pr_completion_port, 0, 
            KEY_CVAR, NULL) == FALSE) 
            return PR_FAILURE;
        return PR_SUCCESS;
    }

    if ( _PR_IS_NATIVE_THREAD(thread) ) {
        if (ReleaseSemaphore(thread->md.blocked_sema, 1, NULL) == FALSE)
            return PR_FAILURE;
        else
            return PR_SUCCESS;
    } else {
        PRThread *me = _PR_MD_CURRENT_THREAD();

        /* When a Native thread has to awaken a user thread, it has to poke
         * the completion port because all user threads might be idle, and
         * thus the CPUs are just waiting for a completion.  
         *
         * XXXMB - can we know when we are truely idle (and not checking 
         *         the runq)?
         */
        if ((_PR_IS_NATIVE_THREAD(me) || (thread->cpu != me->cpu)) &&
                (!thread->md.thr_bound_cpu)) {
            /* The thread should not be in any queue */
            PR_ASSERT(thread->queueCount == 0);
            if ( PostQueuedCompletionStatus(_pr_completion_port, 0, 
                KEY_CVAR, &(thread->md.overlapped.overlapped)) == FALSE) 
                return PR_FAILURE;
        }
        return PR_SUCCESS;
    }
}
PRInt32 _PR_MD_WRITE ( PRFileDesc fd,
const void buf,
PRInt32  len 
)

Definition at line 2360 of file ntio.c.

{
    PRInt32 f = fd->secret->md.osfd;
    PRInt32 bytes;
    int rv, err;
    LONG hiOffset = 0;
    LONG loOffset;
    LARGE_INTEGER offset; /* use for the calculation of the new offset */

    if (!fd->secret->md.sync_file_io) {
        PRThread *me = _PR_MD_CURRENT_THREAD();

        if (me->io_suspended) {
            PR_SetError(PR_INVALID_STATE_ERROR, 0);
            return -1;
        }

        memset(&(me->md.overlapped.overlapped), 0, sizeof(OVERLAPPED));

        me->md.overlapped.overlapped.Offset = SetFilePointer((HANDLE)f, 0, &me->md.overlapped.overlapped.OffsetHigh, FILE_CURRENT);
        PR_ASSERT((me->md.overlapped.overlapped.Offset != 0xffffffff) || (GetLastError() == NO_ERROR));

        if (fd->secret->inheritable == _PR_TRI_TRUE) {
            rv = WriteFile((HANDLE)f, 
                          (LPVOID)buf, 
                          len, 
                          &bytes, 
                          &me->md.overlapped.overlapped);
            if (rv != 0) {
                loOffset = SetFilePointer((HANDLE)f, bytes, &hiOffset, FILE_CURRENT);
                PR_ASSERT((loOffset != 0xffffffff) || (GetLastError() == NO_ERROR));
                return bytes;
            }
            err = GetLastError();
            if (err == ERROR_IO_PENDING) {
                rv = GetOverlappedResult((HANDLE)f,
                        &me->md.overlapped.overlapped, &bytes, TRUE);
                if (rv != 0) {
                    loOffset = SetFilePointer((HANDLE)f, bytes, &hiOffset, FILE_CURRENT);
                    PR_ASSERT((loOffset != 0xffffffff) || (GetLastError() == NO_ERROR));
                    return bytes;
                }
                err = GetLastError();
            }
            _PR_MD_MAP_READ_ERROR(err);
            return -1;
        } else {
            if (!fd->secret->md.io_model_committed) {
                rv = _md_Associate((HANDLE)f);
                PR_ASSERT(rv != 0);
                fd->secret->md.io_model_committed = PR_TRUE;
            }
                     if (_native_threads_only)
                     me->md.overlapped.overlapped.hEvent = me->md.thr_event;

                     _PR_THREAD_LOCK(me);
                     if (_PR_PENDING_INTERRUPT(me)) {
                            me->flags &= ~_PR_INTERRUPT;
                            PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
                            _PR_THREAD_UNLOCK(me);
                            return -1;
                     }
                     me->io_pending = PR_TRUE;
                     me->state = _PR_IO_WAIT;
                     _PR_THREAD_UNLOCK(me);
                     me->io_fd = f;

            rv = WriteFile((HANDLE)f, 
                           buf, 
                           len, 
                           &bytes, 
                           &(me->md.overlapped.overlapped));
            if ( (rv == 0) && ((err = GetLastError()) != ERROR_IO_PENDING) ) {
                            _PR_THREAD_LOCK(me);
                            me->io_pending = PR_FALSE;
                            me->state = _PR_RUNNING;
                            if (_PR_PENDING_INTERRUPT(me)) {
                                   me->flags &= ~_PR_INTERRUPT;
                                   PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
                                   _PR_THREAD_UNLOCK(me);
                                   return -1;
                            }
                            _PR_THREAD_UNLOCK(me);

                _PR_MD_MAP_WRITE_ERROR(err);
                return -1;
            }

            if (_native_threads_only && rv) {
                _native_thread_io_nowait(me, rv, bytes);
            } else if (_NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT) == PR_FAILURE) {
                PR_ASSERT(0);
                return -1;
            }

            PR_ASSERT(me->io_pending == PR_FALSE || me->io_suspended == PR_TRUE);

            if (me->io_suspended) {
                if (_PR_PENDING_INTERRUPT(me)) {
                    me->flags &= ~_PR_INTERRUPT;
                    PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
                } else {
                    PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
                }
                return -1;
            }

            if (me->md.blocked_io_status == 0) {
                _PR_MD_MAP_WRITE_ERROR(me->md.blocked_io_error);
                return -1;
            }

            /*
             * Moving the file pointer by a relative offset (FILE_CURRENT)
             * does not work with a file on a network drive exported by a
             * Win2K system.  We still don't know why.  A workaround is to
             * move the file pointer by an absolute offset (FILE_BEGIN).
             * (Bugzilla bug 70765)
             */
            offset.LowPart = me->md.overlapped.overlapped.Offset;
            offset.HighPart = me->md.overlapped.overlapped.OffsetHigh;
            offset.QuadPart += me->md.blocked_io_bytes;

            SetFilePointer((HANDLE)f, offset.LowPart, &offset.HighPart, FILE_BEGIN);
    
            PR_ASSERT(me->io_pending == PR_FALSE);

            return me->md.blocked_io_bytes;
        }
    } else {
        rv = WriteFile((HANDLE)f,
                       buf,
                       len,
                       &bytes,
                       NULL);
        if (rv == 0) {
            _PR_MD_MAP_WRITE_ERROR(GetLastError());
            return -1;
        }
        return bytes;
    }
}

Here is the call graph for this function:

PRInt32 _PR_MD_WRITEV ( PRFileDesc fd,
const PRIOVec iov,
PRInt32  iov_size,
PRIntervalTime  timeout 
)

Definition at line 1953 of file ntio.c.

{
    PRInt32 osfd = fd->secret->md.osfd;
    int index;
    int sent = 0;
    int rv;

    if (_NT_USE_NB_IO(fd)) {
        if (!fd->secret->md.io_model_committed) {
            rv = _md_MakeNonblock((HANDLE)osfd);
            PR_ASSERT(0 != rv);
            fd->secret->md.io_model_committed = PR_TRUE;
        }
        return _nt_nonblock_writev(fd, iov, iov_size, timeout);
    }

    for (index=0; index<iov_size; index++) {
        rv = _PR_MD_SEND(fd, iov[index].iov_base, iov[index].iov_len, 0,
                                          timeout);
        if (rv > 0) 
            sent += rv;
        if ( rv != iov[index].iov_len ) {
            if (sent <= 0)
                return -1;
            return -1;
        }
    }

    return sent;
}

Here is the call graph for this function:

Definition at line 767 of file ntio.c.

{
    PRStatus rv;
    _PRCPU *cpu = thr->cpu;
 
    PR_ASSERT(thr->state == _PR_IO_WAIT);
       /*
        * A thread for which an I/O timed out or was interrupted cannot be
        * in an IO_WAIT state except as a result of calling PR_Close or
        * PR_NT_CancelIo for the FD. For these two cases, _PR_IO_WAIT state
        * is not interruptible
        */
       if (thr->md.interrupt_disabled == PR_TRUE) {
       _PR_THREAD_UNLOCK(thr);
              return;
       }
    thr->io_suspended = PR_TRUE;
    thr->state = _PR_RUNNABLE;

    if (!_PR_IS_NATIVE_THREAD(thr)) {
        PRThread *me = _PR_MD_CURRENT_THREAD();
        PR_ASSERT(thr->flags & (_PR_ON_SLEEPQ | _PR_ON_PAUSEQ));
        _PR_SLEEPQ_LOCK(cpu);
        _PR_DEL_SLEEPQ(thr, PR_TRUE);
        _PR_SLEEPQ_UNLOCK(cpu);
              /*
               * this thread will continue to run on the same cpu until the
               * I/O is aborted by closing the FD or calling CancelIO
               */
              thr->md.thr_bound_cpu = cpu;

        PR_ASSERT(!(thr->flags & _PR_IDLE_THREAD));
        _PR_AddThreadToRunQ(me, thr);
    }
    _PR_THREAD_UNLOCK(thr);
    rv = _PR_MD_WAKEUP_WAITER(thr);
    PR_ASSERT(PR_SUCCESS == rv);
}

Here is the call graph for this function:

static void ContinuationThread ( void arg) [static]

Definition at line 4342 of file ntio.c.

{
    /* initialization */
    fd_set readSet, writeSet, exceptSet;
    struct timeval tv;
    SOCKET *pollingList = 0;                /* list built for polling */
    PRIntn pollingListUsed;                 /* # entries used in the list */
    PRIntn pollingListNeeded;               /* # entries needed this time */
    PRIntn pollingSlotsAllocated = 0;       /* # entries available in list */
    PRIntervalTime mx_select_ticks = PR_MillisecondsToInterval(PT_DEFAULT_SELECT_MSEC);

    /* do some real work */
    while (1)
    {
        PRIntn rv;
        PRStatus status;
        PRIntn pollIndex;
        pt_Continuation *op;
        PRIntervalTime now = PR_IntervalNow();
        PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT;

        PR_Lock(pt_tq.ml);
        while (NULL == pt_tq.head)
        {
            status = PR_WaitCondVar(pt_tq.new_op, PR_INTERVAL_NO_TIMEOUT);
            if ((PR_FAILURE == status)
                && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) break;
        }
        pollingListNeeded = pt_tq.op_count;
        PR_Unlock(pt_tq.ml);

        /* Okay. We're history */
        if ((PR_FAILURE == status)
            && (PR_PENDING_INTERRUPT_ERROR == PR_GetError())) break;

       /*
        * We are not holding the pt_tq.ml lock now, so more items may
        * get added to pt_tq during this window of time.  We hope
        * that 10 more spaces in the polling list should be enough.
        */

        FD_ZERO(&readSet);
        FD_ZERO(&writeSet);
        FD_ZERO(&exceptSet);
        pollingListNeeded += 10;
        if (pollingListNeeded > pollingSlotsAllocated)
        {
            if (NULL != pollingList) PR_DELETE(pollingList);
            pollingList = PR_MALLOC(pollingListNeeded * sizeof(PRPollDesc));
            PR_ASSERT(NULL != pollingList);
            pollingSlotsAllocated = pollingListNeeded;
        }

#if defined(DEBUG)
        if (pollingListNeeded > pt_debug.pollingListMax)
            pt_debug.pollingListMax = pollingListUsed;
#endif

        /*
         * Build up a polling list.
         * This list is sorted on time. Operations that have been
         * interrupted are completed and not included in the list.
         * There is an assertion that the operation is in progress.
         */
        pollingListUsed = 0;
        PR_Lock(pt_tq.ml);

        for (op = pt_tq.head; NULL != op;)
        {
            if (pt_continuation_abort == op->status)
            {
                op->result.code = -1;
                op->syserrno = WSAEINTR;
                op = pt_FinishTimedInternal(op);
            }
            else
            {
                PR_ASSERT(pt_continuation_done != op->status);
                op->status = pt_continuation_inprogress;
                if (op->event & PR_POLL_READ) {
                    FD_SET(op->arg1.osfd, &readSet);
                }
                if (op->event & PR_POLL_WRITE) {
                    FD_SET(op->arg1.osfd, &writeSet);
                }
                if (op->event & PR_POLL_EXCEPT) {
                    FD_SET(op->arg1.osfd, &exceptSet);
                }
                pollingList[pollingListUsed] = op->arg1.osfd;
                pollingListUsed += 1;
                if (pollingListUsed == pollingSlotsAllocated) break;
                op = op->next;
            }
        }

        PR_Unlock(pt_tq.ml);

        /*
         * If 'op' isn't NULL at this point, then we didn't get to
         * the end of the list. That means that more items got added
         * to the list than we anticipated. So, forget this iteration,
         * go around the horn again.
         * One would hope this doesn't happen all that often.
         */
        if (NULL != op)
        {
#if defined(DEBUG)
            pt_debug.predictionsFoiled += 1;  /* keep track */
#endif
            continue;  /* make it rethink things */
        }

        /* there's a chance that all ops got blown away */
        if (NULL == pt_tq.head) continue;
        /* if not, we know this is the shortest timeout */
        timeout = pt_tq.head->timeout;

        /*
         * We don't want to wait forever on this poll. So keep
         * the interval down. The operations, if they are timed,
         * still have to timeout, while those that are not timed
         * should persist forever. But they may be aborted. That's
         * what this anxiety is all about.
         */
        if (timeout > mx_select_ticks) timeout = mx_select_ticks;

        if (PR_INTERVAL_NO_TIMEOUT != pt_tq.head->timeout)
            pt_tq.head->timeout -= timeout;
        tv.tv_sec = PR_IntervalToSeconds(timeout);
        tv.tv_usec = PR_IntervalToMicroseconds(timeout) % PR_USEC_PER_SEC;

        rv = select(0, &readSet, &writeSet, &exceptSet, &tv);

        if (0 == rv)  /* poll timed out - what about leading op? */
        {
            if (0 == pt_tq.head->timeout)
            {
                /* 
                 * The leading element of the timed queue has timed
                 * out. Get rid of it. In any case go around the
                 * loop again, computing the polling list, checking
                 * for interrupted operations.
                 */
                PR_Lock(pt_tq.ml);
                do
                {
                    pt_tq.head->result.code = -1;
                    pt_tq.head->syserrno = WSAETIMEDOUT;
                    op = pt_FinishTimedInternal(pt_tq.head);
                } while ((NULL != op) && (0 == op->timeout));
                PR_Unlock(pt_tq.ml);
            }
            continue;
        }

        if (-1 == rv && (WSAGetLastError() == WSAEINTR
                || WSAGetLastError() == WSAEINPROGRESS))
        {
            continue;               /* go around the loop again */
        }

        /*
         * select() says that something in our list is ready for some more
         * action or is an invalid fd. Find it, load up the operation and
         * see what happens.
         */

        PR_ASSERT(rv > 0 || WSAGetLastError() == WSAENOTSOCK);


        /*
         * $$$ There's a problem here. I'm running the operations list
         * and I'm not holding any locks. I don't want to hold the lock
         * and do the operation, so this is really messed up..
         *
         * This may work out okay. The rule is that only this thread,
         * the continuation thread, can remove elements from the list.
         * Therefore, the list is at worst, longer than when we built
         * the polling list.
         */
        op = pt_tq.head;
        for (pollIndex = 0; pollIndex < pollingListUsed; ++pollIndex)
        {
            PRInt16 revents = 0;

            PR_ASSERT(NULL != op);

            /*
             * This one wants attention. Redo the operation.
             * We know that there can only be more elements
             * in the op list than we knew about when we created
             * the poll list. Therefore, we might have to skip
             * a few ops to find the right one to operation on.
             */
            while (pollingList[pollIndex] != op->arg1.osfd )
            {
                op = op->next;
                PR_ASSERT(NULL != op);
            }

            if (FD_ISSET(op->arg1.osfd, &readSet)) {
                revents |= PR_POLL_READ;
            }
            if (FD_ISSET(op->arg1.osfd, &writeSet)) {
                revents |= PR_POLL_WRITE;
            }
            if (FD_ISSET(op->arg1.osfd, &exceptSet)) {
                revents |= PR_POLL_EXCEPT;
            }

            /*
             * Sip over all those not in progress. They'll be
             * pruned next time we build a polling list. Call
             * the continuation function. If it reports completion,
             * finish off the operation.
             */
            if (revents && (pt_continuation_inprogress == op->status)
                && (op->function(op, revents)))
            {
                PR_Lock(pt_tq.ml);
                op = pt_FinishTimedInternal(op);
                PR_Unlock(pt_tq.ml);
            }
        }
    }
    if (NULL != pollingList) PR_DELETE(pollingList);
}  /* ContinuationThread */

Here is the call graph for this function:

Here is the caller graph for this function:

void FlipSlashes ( char *  cp,
int  len 
)

Definition at line 2735 of file ntio.c.

{
    while (--len >= 0) {
        if (cp[0] == '/') {
            cp[0] = PR_DIRECTORY_SEPARATOR;
        }
        cp = _mbsinc(cp);
    }
} /* end FlipSlashes() */

Definition at line 3700 of file ntio.c.

{
   DWORD dwIndex = 0, dwMask;
   BY_HANDLE_FILE_INFORMATION Info;
   TCHAR szDrive[4] = TEXT("C:\\");
   DWORD dwVolumeSerialNumber;
   DWORD oldmode = (DWORD) -1;
   int rv = _PR_REMOTE_FILE;

   if (!GetFileInformationByHandle(hFile, &Info))
      return -1;

   // look to see if the volume serial number has been cached.
   _MD_LOCK(&cachedVolumeLock);
   while(dwIndex <= dwLastCachedDrive)
      if (dwCachedVolumeSerialNumbers[dwIndex++] == Info.dwVolumeSerialNumber)
         return _PR_LOCAL_FILE;
   _MD_UNLOCK(&cachedVolumeLock);

   // volume serial number not found in the cache.  Check removable files.
   // removable drives are noted as a bitmask.  If the bit associated with 
   // a specific drive is set, then we should query its volume serial number
   // as its possible it has changed.
   dwMask = dwRemoveableDrivesToCheck;
   dwIndex = 0;

   while(dwMask)
   {
      while(!(dwMask & 1))
      {
         dwIndex++;
         dwMask = dwMask >> 1;
      }

      szDrive[0] = TEXT('A')+ (TCHAR) dwIndex;

      // Calling GetVolumeInformation on a removeable drive where the
      // disk is currently removed will cause a dialog box to the
      // console.  This is not good.
      // Temporarily disable the SEM_FAILCRITICALERRORS to avoid the
      // dialog.

      oldmode = SetErrorMode(SEM_FAILCRITICALERRORS);

      if (GetVolumeInformation(
                  szDrive,
                  NULL, 0,
                  &dwVolumeSerialNumber,
                  NULL, NULL, NULL, 0)
         )
      {
         if (dwVolumeSerialNumber == Info.dwVolumeSerialNumber)
         {
            _MD_LOCK(&cachedVolumeLock);
            if (dwLastCachedDrive < dwIndex)
               dwLastCachedDrive = dwIndex;
            dwCachedVolumeSerialNumbers[dwIndex] = dwVolumeSerialNumber;
            _MD_UNLOCK(&cachedVolumeLock);
            rv = _PR_LOCAL_FILE;
         }
      }
      if (oldmode != (DWORD) -1) {
          SetErrorMode(oldmode);
          oldmode = (DWORD) -1;
      }

      if (rv == _PR_LOCAL_FILE)
          return _PR_LOCAL_FILE;

      dwIndex++;
      dwMask = dwMask >> 1;
   }

   return _PR_REMOTE_FILE;
}

Here is the caller graph for this function:

Definition at line 3604 of file ntio.c.

{
   TCHAR lpBuffer[_PR_MAX_DRIVES*5];
   DWORD nBufferLength = _PR_MAX_DRIVES*5;
   DWORD nBufferNeeded = GetLogicalDriveStrings(0, NULL);
   DWORD dwIndex = 0;
   DWORD dwDriveType;
   DWORD dwVolumeSerialNumber;
   DWORD dwDriveIndex = 0;
   DWORD oldmode = (DWORD) -1;

   _MD_NEW_LOCK(&cachedVolumeLock);

   nBufferNeeded = GetLogicalDriveStrings(nBufferLength, lpBuffer);
   if (nBufferNeeded == 0 || nBufferNeeded > nBufferLength)
      return PR_FALSE;

   // Calling GetVolumeInformation on a removeable drive where the
   // disk is currently removed will cause a dialog box to the
   // console.  This is not good.
   // Temporarily disable the SEM_FAILCRITICALERRORS to avoid the
   // damn dialog.

   dwCachedVolumeSerialNumbers[dwDriveIndex] = 0;
   oldmode = SetErrorMode(SEM_FAILCRITICALERRORS);

   // now loop through the logical drives
   while(lpBuffer[dwIndex] != TEXT('\0'))
   {
      // skip the floppy drives.  This is *SLOW*
      if ((lpBuffer[dwIndex] == TEXT('A')) || (lpBuffer[dwIndex] == TEXT('B')))
         /* Skip over floppies */;
      else
      {
         dwDriveIndex = (lpBuffer[dwIndex] - TEXT('A'));

         dwDriveType = GetDriveType(&lpBuffer[dwIndex]);

         switch(dwDriveType)
         {
               // Ignore these drive types
            case 0:
            case 1:
            case DRIVE_REMOTE:
            default: // If the drive type is unknown, ignore it.
               break;

               // Removable media drives can have different serial numbers
               // at different times, so cache the current serial number
               // but keep track of them so they can be rechecked if necessary.
            case DRIVE_REMOVABLE:

               // CDROM is a removable media
            case DRIVE_CDROM: 

               // no idea if ramdisks can change serial numbers or not
               // but it doesn't hurt to treat them as removable.
              
            case DRIVE_RAMDISK: 


               // Here is where we keep track of removable drives.
               dwRemoveableDrivesToCheck |= 1 << dwDriveIndex;

               // removable drives fall through to fixed drives and get cached.

            case DRIVE_FIXED:

               // cache volume serial numbers. 
               if (GetVolumeInformation(
                   &lpBuffer[dwIndex],
                   NULL, 0,
                   &dwVolumeSerialNumber,
                   NULL, NULL, NULL, 0)
                  )
                  {
                     if (dwLastCachedDrive < dwDriveIndex)
                        dwLastCachedDrive = dwDriveIndex;
                     dwCachedVolumeSerialNumbers[dwDriveIndex] = dwVolumeSerialNumber;
                  }
 
               break;
         }
      }

      dwIndex += lstrlen(&lpBuffer[dwIndex]) +1;
   }

   if (oldmode != (DWORD) -1) {
       SetErrorMode(oldmode);
       oldmode = (DWORD) -1;
   }

   return PR_TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool IsPrevCharSlash ( const char *  str,
const char *  current 
) [static]

Definition at line 2943 of file ntio.c.

{
    const char *prev;

    if (str >= current)
        return PR_FALSE;
    prev = _mbsdec(str, current);
    return (prev == current - 1) && _PR_IS_SLASH(*prev);
}

Here is the caller graph for this function:

static PRBool IsRootDirectory ( char *  fn,
size_t  buflen 
) [static]

Definition at line 2972 of file ntio.c.

{
    char *p;
    PRBool slashAdded = PR_FALSE;
    PRBool rv = PR_FALSE;

    if (_PR_IS_SLASH(fn[0]) && fn[1] == '\0') {
        return PR_TRUE;
    }

    if (isalpha(fn[0]) && fn[1] == ':' && _PR_IS_SLASH(fn[2])
            && fn[3] == '\0') {
        rv = GetDriveType(fn) > 1 ? PR_TRUE : PR_FALSE;
        return rv;
    }

    /* The UNC root directory */

    if (_PR_IS_SLASH(fn[0]) && _PR_IS_SLASH(fn[1])) {
        /* The 'server' part should have at least one character. */
        p = &fn[2];
        if (*p == '\0' || _PR_IS_SLASH(*p)) {
            return PR_FALSE;
        }

        /* look for the next slash */
        do {
            p = _mbsinc(p);
        } while (*p != '\0' && !_PR_IS_SLASH(*p));
        if (*p == '\0') {
            return PR_FALSE;
        }

        /* The 'share' part should have at least one character. */
        p++;
        if (*p == '\0' || _PR_IS_SLASH(*p)) {
            return PR_FALSE;
        }

        /* look for the final slash */
        do {
            p = _mbsinc(p);
        } while (*p != '\0' && !_PR_IS_SLASH(*p));
        if (_PR_IS_SLASH(*p) && p[1] != '\0') {
            return PR_FALSE;
        }
        if (*p == '\0') {
            /*
             * GetDriveType() doesn't work correctly if the
             * path is of the form \\server\share, so we add
             * a final slash temporarily.
             */
            if ((p + 1) < (fn + buflen)) {
                *p++ = '\\';
                *p = '\0';
                slashAdded = PR_TRUE;
            } else {
                return PR_FALSE; /* name too long */
            }
        }
        rv = GetDriveType(fn) > 1 ? PR_TRUE : PR_FALSE;
        /* restore the 'fn' buffer */
        if (slashAdded) {
            *--p = '\0';
        }
    }
    return rv;
}

Here is the caller graph for this function:

Definition at line 3777 of file ntio.c.

{
    PRThread *me = _PR_MD_CURRENT_THREAD();
       PRBool fWait;
       PRFileDesc *bottom;

       bottom = PR_GetIdentitiesLayer(fd, PR_NSPR_IO_LAYER);
    if (!me->io_suspended || (NULL == bottom) ||
                                   (me->io_fd != bottom->secret->md.osfd)) {
        PR_SetError(PR_INVALID_STATE_ERROR, 0);
        return PR_FAILURE;
    }
       /*
        * The CancelIO operation has to be issued by the same NT thread that
        * issued the I/O operation
        */
       PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || (me->cpu == me->md.thr_bound_cpu));
       if (me->io_pending) {
              if (!CancelIo((HANDLE)bottom->secret->md.osfd)) {
                     PR_SetError(PR_INVALID_STATE_ERROR, GetLastError());
                     return PR_FAILURE;
              }
       }
       _PR_THREAD_LOCK(me);
       fWait = me->io_pending;
       me->io_suspended = PR_FALSE;
       me->state = _PR_IO_WAIT;
       me->md.interrupt_disabled = PR_TRUE;
       _PR_THREAD_UNLOCK(me);
       if (fWait)
              _NT_IO_WAIT(me, PR_INTERVAL_NO_TIMEOUT);
       PR_ASSERT(me->io_suspended ==  PR_FALSE);
       PR_ASSERT(me->io_pending ==  PR_FALSE);

       _PR_THREAD_LOCK(me);
       me->md.interrupt_disabled = PR_FALSE;
       me->md.thr_bound_cpu = NULL;
    me->io_suspended = PR_FALSE;
    me->io_pending = PR_FALSE;
       me->state = _PR_RUNNING;
       _PR_THREAD_UNLOCK(me);
       return PR_SUCCESS;
}

Here is the call graph for this function:

static int pt_Continue ( pt_Continuation op) [static]

Definition at line 4570 of file ntio.c.

{
    PRStatus rv;
    /* Finish filling in the blank slots */
    op->status = pt_continuation_sumbitted;
    op->complete = PR_NewCondVar(pt_tq.ml);

    PR_Lock(pt_tq.ml);  /* we provide the locking */

    pt_InsertTimedInternal(op);  /* insert in the structure */

    PR_NotifyCondVar(pt_tq.new_op);  /* notify the continuation thread */

    while (pt_continuation_done != op->status)  /* wait for completion */
    {
        rv = PR_WaitCondVar(op->complete, PR_INTERVAL_NO_TIMEOUT);
        /*
         * If we get interrupted, we set state the continuation thread will
         * see and allow it to finish the I/O operation w/ error. That way
         * the rule that only the continuation thread is removing elements
         * from the list is still valid.
         *
         * Don't call interrupt on the continuation thread. That'll just
         * piss him off. He's cycling around at least every mx_select_ticks
         * anyhow and should notice the request in there.
         */
        if ((PR_FAILURE == rv)
            && (PR_PENDING_INTERRUPT_ERROR == PR_GetError()))
            op->status = pt_continuation_abort;  /* our status */
    }

    PR_Unlock(pt_tq.ml);  /* we provide the locking */

    PR_DestroyCondVar(op->complete);

    return op->result.code;  /* and the primary answer */
}  /* pt_Continue */

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 4316 of file ntio.c.

{
    pt_Continuation *next;

    /* remove this one from the list */
    if (NULL == op->prev) pt_tq.head = op->next;
    else op->prev->next = op->next;
    if (NULL == op->next) pt_tq.tail = op->prev;
    else op->next->prev = op->prev;

    /* did we happen to hit the timed op? */
    if (op == pt_tq.op) pt_tq.op = op->prev;

    next = op->next;
    op->next = op->prev = NULL;
    op->status = pt_continuation_done;

    pt_tq.op_count -= 1;
#if defined(DEBUG)
    pt_debug.continuationsServed += 1;
#endif
    PR_NotifyCondVar(op->complete);

    return next;
}  /* pt_FinishTimedInternal */

Here is the call graph for this function:

Here is the caller graph for this function:

static void pt_InsertTimedInternal ( pt_Continuation op) [static]

Definition at line 4179 of file ntio.c.

{
    PRInt32 delta = 0;
    pt_Continuation *t_op = NULL;
    PRIntervalTime now = PR_IntervalNow(), op_tmo, qd_tmo;

    /*
     * If this element operation isn't timed, it gets queued at the
     * end of the list (just after pt_tq.tail) and we're
     * finishd early.
     */
    if (PR_INTERVAL_NO_TIMEOUT == op->timeout)
    {
        t_op = pt_tq.tail;  /* put it at the end */
        goto done;
    }

    /*
     * The rest of this routine actaully deals with timed ops.
     */

    if (NULL != pt_tq.op)
    {
        /*
         * To find where in the list to put the new operation, form
         * the absolute time the operations in question will expire.
         *
         * The new operation ('op') will expire at now() + op->timeout.
         *
         * The operation that will time out furthest in the future will
         * do so at pt_tq.epoch + pt_tq.op->timeout.
         *
         * Subsequently earlier timeouts are computed based on the latter
         * knowledge by subracting the timeout deltas that are stored in
         * the operation list. There are operation[n]->timeout ticks
         * between the expiration of operation[n-1] and operation[n].e e 
         *
         * Therefore, the operation[n-1] will expire operation[n]->timeout
         * ticks prior to operation[n].
         *
         * This should be easy!
         */
        t_op = pt_tq.op;  /* running pointer to queued op */
        op_tmo = now + op->timeout;  /* that's in absolute ticks */
        qd_tmo = pt_tq.epoch + t_op->timeout;  /* likewise */

        do
        {
            /*
             * If 'op' expires later than t_op, then insert 'op' just
             * ahead of t_op. Otherwise, compute when operation[n-1]
             * expires and try again.
             *
             * The actual different between the expiriation of 'op'
             * and the current operation what becomes the new operaton's
             * timeout interval. That interval is also subtracted from
             * the interval of the operation immediately following where
             * we stick 'op' (unless the next one isn't timed). The new
             * timeout assigned to 'op' takes into account the values of
             * now() and when the previous intervals were compured.
             */
            delta = op_tmo - qd_tmo;
            if (delta >= 0)
            {
                op->timeout += (now - pt_tq.epoch);
                goto done;
            }

            qd_tmo -= t_op->timeout;  /* previous operaton expiration */
            t_op = t_op->prev;  /* point to previous operation */
            if (NULL != t_op) qd_tmo += t_op->timeout;
        } while (NULL != t_op);

        /*
         * If we got here we backed off the head of the list. That means that
         * this timed entry has to go at the head of the list. This is just
         * about like having an empty timer list.
         */
        delta = op->timeout;  /* $$$ is this right? */
    }

done:

    /*
     * Insert 'op' into the queue just after t_op or if t_op is null,
     * at the head of the list.
     *
     * If t_op is NULL, the list is currently empty and this is pretty
     * easy.
     */
    if (NULL == t_op)
    {
        op->prev = NULL;
        op->next = pt_tq.head;
        pt_tq.head = op;
        if (NULL == pt_tq.tail) pt_tq.tail = op;
        else op->next->prev = op;
    }
    else
    {
        op->prev = t_op;
        op->next = t_op->next;
        if (NULL != op->prev)
            op->prev->next = op;
        if (NULL != op->next)
            op->next->prev = op;
        if (t_op == pt_tq.tail)
            pt_tq.tail = op;
    }

    /*
     * Are we adjusting our epoch, etc? Are we replacing
     * what was previously the element due to expire furthest
     * out in the future? Is this even a timed operation?
     */
    if (PR_INTERVAL_NO_TIMEOUT != op->timeout)
    {
        if ((NULL == pt_tq.op)  /* we're the one and only */
        || (t_op == pt_tq.op))  /* we're replacing */
        {
            pt_tq.op = op;
            pt_tq.epoch = now;
        }
    }

    pt_tq.op_count += 1;

}  /* pt_InsertTimedInternal */

Here is the call graph for this function:

Here is the caller graph for this function:

static PRInt32 pt_RecvFrom ( SOCKET  osfd,
void buf,
PRInt32  amount,
PRInt32  flags,
PRNetAddr addr,
PRIntn *  addr_len,
PRIntervalTime  timeout 
) [static]

Definition at line 4676 of file ntio.c.

{
    PRInt32 bytes = -1, err;
    PRBool fNeedContinue = PR_FALSE;

    bytes = recvfrom(
            osfd, buf, amount, flags,
            (struct sockaddr*)addr, addr_len);
    if (bytes == -1) {
              if ((err = WSAGetLastError()) == WSAEWOULDBLOCK)
        fNeedContinue = PR_TRUE;
              else
                     _PR_MD_MAP_RECVFROM_ERROR(err);
    }

    if (fNeedContinue == PR_TRUE)
    {
        pt_Continuation op;
        op.arg1.osfd = osfd;
        op.arg2.buffer = buf;
        op.arg3.amount = amount;
        op.arg4.flags = flags;
        op.arg5.addr = addr;
        op.timeout = timeout;
        op.function = pt_recvfrom_cont;
        op.event = PR_POLL_READ | PR_POLL_EXCEPT;
        bytes = pt_Continue(&op);
        if (bytes < 0) {
            WSASetLastError(op.syserrno);
                     _PR_MD_MAP_RECVFROM_ERROR(op.syserrno);
        }
    }
    return bytes;
}  /* pt_RecvFrom */

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool pt_recvfrom_cont ( pt_Continuation op,
PRInt16  revents 
) [static]

Definition at line 4627 of file ntio.c.

{
    PRIntn addr_len = sizeof(*(op->arg5.addr));
    op->result.code = recvfrom(
        op->arg1.osfd, op->arg2.buffer, op->arg3.amount,
        op->arg4.flags, (struct sockaddr*)op->arg5.addr, &addr_len);
    op->syserrno = WSAGetLastError();
    return ((-1 == op->result.code) && (WSAEWOULDBLOCK == op->syserrno)) ?
        PR_FALSE : PR_TRUE;
}  /* pt_recvfrom_cont */

Here is the call graph for this function:

Here is the caller graph for this function:

static PRInt32 pt_SendTo ( SOCKET  osfd,
const void buf,
PRInt32  amount,
PRInt32  flags,
const PRNetAddr addr,
PRIntn  addrlen,
PRIntervalTime  timeout 
) [static]

Definition at line 4638 of file ntio.c.

{
    PRInt32 bytes = -1, err;
    PRBool fNeedContinue = PR_FALSE;

    bytes = sendto(
            osfd, buf, amount, flags,
            (struct sockaddr*)addr, PR_NETADDR_SIZE(addr));
    if (bytes == -1) {
              if ((err = WSAGetLastError()) == WSAEWOULDBLOCK)
        fNeedContinue = PR_TRUE;
              else
                     _PR_MD_MAP_SENDTO_ERROR(err);
    }
    if (fNeedContinue == PR_TRUE)
    {
        pt_Continuation op;
        op.arg1.osfd = osfd;
        op.arg2.buffer = (void*)buf;
        op.arg3.amount = amount;
        op.arg4.flags = flags;
        op.arg5.addr = (PRNetAddr*)addr;
        op.timeout = timeout;
        op.result.code = 0;  /* initialize the number sent */
        op.function = pt_sendto_cont;
        op.event = PR_POLL_WRITE | PR_POLL_EXCEPT;
        bytes = pt_Continue(&op);
        if (bytes < 0) {
            WSASetLastError(op.syserrno);
                     _PR_MD_MAP_SENDTO_ERROR(op.syserrno);
        }
    }
    return bytes;
}  /* pt_SendTo */

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool pt_sendto_cont ( pt_Continuation op,
PRInt16  revents 
) [static]

Definition at line 4608 of file ntio.c.

{
    PRIntn bytes = sendto(
        op->arg1.osfd, op->arg2.buffer, op->arg3.amount, op->arg4.flags,
        (struct sockaddr*)op->arg5.addr, sizeof(*(op->arg5.addr)));
    op->syserrno = WSAGetLastError();
    if (bytes > 0)  /* this is progress */
    {
        char *bp = op->arg2.buffer;
        bp += bytes;  /* adjust the buffer pointer */
        op->arg2.buffer = bp;
        op->result.code += bytes;  /* accumulate the number sent */
        op->arg3.amount -= bytes;  /* and reduce the required count */
        return (0 == op->arg3.amount) ? PR_TRUE : PR_FALSE;
    }
    else return ((-1 == bytes) && (WSAEWOULDBLOCK == op->syserrno)) ?
       PR_FALSE : PR_TRUE;
}  /* pt_sendto_cont */

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

struct _MDLock [static]

Definition at line 66 of file ntio.c.

Definition at line 62 of file ntio.c.

const PRTime _pr_filetime_offset = 116444736000000000i64 [static]

Definition at line 111 of file ntio.c.

Definition at line 63 of file ntio.c.

Definition at line 69 of file ntio.c.

Definition at line 70 of file ntio.c.

Definition at line 67 of file ntio.c.

Definition at line 68 of file ntio.c.

Definition at line 3599 of file ntio.c.

DWORD dirAccessTable[] [static]
Initial value:
 {
    FILE_GENERIC_READ,
    FILE_GENERIC_WRITE|FILE_DELETE_CHILD,
    FILE_GENERIC_EXECUTE
}

Definition at line 97 of file ntio.c.

Definition at line 3600 of file ntio.c.

Definition at line 3601 of file ntio.c.

Definition at line 3602 of file ntio.c.

int max_wait_loops = 0 [static]

Definition at line 1060 of file ntio.c.

int missing_completions = 0 [static]

Definition at line 1059 of file ntio.c.

struct pt_TimedQueue pt_tq [static]