/* define normal version that locks/unlocks, validates fh */ int __cdecl _read ( int fh, void *buf, unsigned cnt ) { int r; /* return value */ /* validate handle */ _CHECK_FH_CLEAR_OSSERR_RETURN( fh, EBADF, -1 ); _VALIDATE_CLEAR_OSSERR_RETURN((fh >= 0 && (unsigned)fh < (unsigned)_nhandle), EBADF, -1); _VALIDATE_CLEAR_OSSERR_RETURN((_osfile(fh) & FOPEN), EBADF, -1); _lock_fh(fh); /* lock file */ __try { if ( _osfile(fh) & FOPEN ) r = _read_nolock(fh, buf, cnt); /* read bytes */ else { errno = EBADF; _doserrno = 0; r = -1; _ASSERTE(("Invalid file descriptor. File possibly closed by a different thread",0)); } } __finally { _unlock_fh(fh); /* unlock file */ } return r; }
/* define locking/validating lseek */ long __cdecl _lseek ( int fh, long pos, int mthd ) { int r; /* validate fh */ _CHECK_FH_CLEAR_OSSERR_RETURN( fh, EBADF, -1 ); _VALIDATE_CLEAR_OSSERR_RETURN((fh >= 0 && (unsigned)fh < (unsigned)_nhandle), EBADF, -1); _VALIDATE_CLEAR_OSSERR_RETURN((_osfile(fh) & FOPEN), EBADF, -1); _lock_fh(fh); /* lock file handle */ __try { if ( _osfile(fh) & FOPEN ) r = _lseek_nolock(fh, pos, mthd); /* seek */ else { errno = EBADF; _doserrno = 0; r = -1; _ASSERTE(("Invalid file descriptor. File possibly closed by a different thread",0)); } } __finally { _unlock_fh(fh); /* unlock file handle */ } return r; }
int __cdecl _dup ( int fh ) { int newfh =-1; /* variable for new file handle */ /* validate file handle */ _CHECK_FH_CLEAR_OSSERR_RETURN( fh, EBADF, -1 ); _VALIDATE_CLEAR_OSSERR_RETURN((fh >= 0 && (unsigned)fh < (unsigned)_nhandle), EBADF, -1); _VALIDATE_CLEAR_OSSERR_RETURN((_osfile(fh) & FOPEN), EBADF, -1); _lock_fh(fh); /* lock file handle */ __TRY if ( _osfile(fh) & FOPEN ) newfh = _dup_nolock(fh); else { errno = EBADF; _doserrno = 0; newfh = -1; _ASSERTE(("Invalid file descriptor. File possibly closed by a different thread",0)); } __FINALLY _unlock_fh(fh); __END_TRY_FINALLY return newfh; }
int __cdecl _setmode( int fh, int mode ) { int retval; _VALIDATE_RETURN(((mode == _O_TEXT) || (mode == _O_BINARY) || (mode == _O_WTEXT) || (mode == _O_U8TEXT) || (mode == _O_U16TEXT)), EINVAL, -1); _CHECK_FH_RETURN(fh, EBADF, -1); _VALIDATE_RETURN((fh >= 0 && (unsigned)fh < (unsigned)_nhandle), EBADF, -1); _VALIDATE_RETURN((_osfile(fh) & FOPEN), EBADF, -1); /* lock the file */ _lock_fh(fh); __try { if (_osfile(fh) & FOPEN) /* set the text/binary mode */ { retval = _setmode_nolock(fh, mode); } else { errno = EBADF; _ASSERTE(("Invalid file descriptor. File possibly closed by a different thread", 0)); retval = -1; } } __finally { /* unlock the file */ _unlock_fh(fh); } /* Return to user (_setmode_nolock sets errno, if needed) */ return (retval); }
int __cdecl _dup2 ( int fh1, int fh2 ) { int retcode; /* validate file handles */ _CHECK_FH_CLEAR_OSSERR_RETURN( fh1, EBADF, -1 ); _VALIDATE_CLEAR_OSSERR_RETURN((fh1 >= 0 && (unsigned)fh1 < (unsigned)_nhandle), EBADF, -1); _VALIDATE_CLEAR_OSSERR_RETURN((_osfile(fh1) & FOPEN), EBADF, -1); _CHECK_FH_CLEAR_OSSERR_RETURN( fh2, EBADF, -1 ); _VALIDATE_CLEAR_OSSERR_RETURN(((unsigned)fh2 < _NHANDLE_), EBADF, -1); /* * Make sure there is an ioinfo struct corresponding to fh2. */ if ( (fh2 >= _nhandle) && (extend_ioinfo_arrays(fh2) != 0) ) { errno = ENOMEM; return -1; } /* get the two file handle locks; in order to prevent deadlock, get the lowest handle lock first. */ if ( fh1 < fh2 ) { _lock_fh(fh1); _lock_fh(fh2); } else if ( fh1 > fh2 ) { _lock_fh(fh2); _lock_fh(fh1); } __try { retcode = _dup2_nolock(fh1, fh2); } __finally { _unlock_fh(fh1); _unlock_fh(fh2); } return retcode; }
int __cdecl _eof ( int filedes ) { __int64 here; __int64 end; int retval; _CHECK_FH_CLEAR_OSSERR_RETURN( filedes, EBADF, -1 ); _VALIDATE_CLEAR_OSSERR_RETURN((filedes >= 0 && (unsigned)filedes < (unsigned)_nhandle), EBADF, -1); _VALIDATE_CLEAR_OSSERR_RETURN((_osfile(filedes) & FOPEN), EBADF, -1); /* Lock the file */ _lock_fh(filedes); __try { if ( _osfile(filedes) & FOPEN ) { /* See if the current position equals the end of the file. */ if ( ((here = _lseeki64_nolock(filedes, 0i64, SEEK_CUR)) == -1i64) || ((end = _lseeki64_nolock(filedes, 0i64, SEEK_END)) == -1i64) ) retval = -1; else if ( here == end ) retval = 1; else { _lseeki64_nolock(filedes, here, SEEK_SET); retval = 0; } } else { errno = EBADF; _doserrno = 0; retval = -1; _ASSERTE(("Invalid file descriptor. File possibly closed by a different thread",0)); } } __finally { /* Unlock the file */ _unlock_fh(filedes); } /* Done */ return(retval); }
void __cdecl _wperror ( const wchar_t *wmessage ) { int fh = 2; size_t size = 0; char *amessage; const char *sysmessage; /* convert WCS string into ASCII string */ if ( wmessage && *wmessage ) { _ERRCHECK_EINVAL_ERANGE(wcstombs_s( &size, NULL, 0, wmessage, INT_MAX)); if ( size==0 || (amessage = (char *)_calloc_crt(size, sizeof(char))) == NULL ) return; if ( _ERRCHECK_EINVAL_ERANGE(wcstombs_s(NULL, amessage, size, wmessage, _TRUNCATE)) != 0) { _free_crt(amessage); return; } } else amessage = NULL; _lock_fh( fh ); /* acquire file handle lock */ __try { if ( amessage ) { _write_nolock(fh,(char *)amessage,(unsigned)strlen(amessage)); _write_nolock(fh,": ",2); } _free_crt(amessage); /* note: freeing NULL is legal and benign */ sysmessage = _get_sys_err_msg( errno ); _write_nolock(fh, sysmessage,(unsigned)strlen(sysmessage)); _write_nolock(fh,"\n",1); } __finally { _unlock_fh( fh ); /* release file handle lock */ } }
int __cdecl _commit ( int filedes ) { int retval; /* if filedes out of range, complain */ _CHECK_FH_RETURN( filedes, EBADF, -1 ); _VALIDATE_RETURN((filedes >= 0 && (unsigned)filedes < (unsigned)_nhandle), EBADF, -1); _VALIDATE_RETURN((_osfile(filedes) & FOPEN), EBADF, -1); _lock_fh(filedes); __try { if (_osfile(filedes) & FOPEN) { if ( !FlushFileBuffers((HANDLE)_get_osfhandle(filedes)) ) { retval = GetLastError(); } else { retval = 0; /* return success */ } /* map the OS return code to C errno value and return code */ if (retval == 0) goto good; _doserrno = retval; } errno = EBADF; retval = -1; _ASSERTE(("Invalid file descriptor. File possibly closed by a different thread",0)); good : ; } __finally { _unlock_fh(filedes); } return (retval); }
int __cdecl _commit ( int filedes ) { int retval; /* if filedes out of range, complain */ if ( ((unsigned)filedes >= (unsigned)_nhandle) || !(_osfile(filedes) & FOPEN) ) { errno = EBADF; return (-1); } _lock_fh(filedes); /* if filedes open, try to commit, else fall through to bad */ if (_osfile(filedes) & FOPEN) { if ( !FlushFileBuffers((HANDLE)_get_osfhandle(filedes)) ) { retval = GetLastError(); } else { retval = 0; /* return success */ } /* map the OS return code to C errno value and return code */ if (retval == 0) { goto good; } else { _doserrno = retval; goto bad; } } bad : errno = EBADF; retval = -1; good : _unlock_fh(filedes); return (retval); }
int __cdecl _close ( int fh ) { int r; /* return value */ /* validate file handle */ if ( ((unsigned)fh >= (unsigned)_nhandle) || !(_osfile(fh) & FOPEN) ) { /* bad file handle, set errno and abort */ errno = EBADF; _doserrno = 0; return -1; } _lock_fh(fh); /* lock file */ r = _close_lk(fh); _unlock_fh(fh); /* unlock the file */ return r; }
void __cdecl _wperror ( REG1 const wchar_t *wmessage ) { REG2 int fh = 2; int size; char *amessage; /* convert WCS string into ASCII string */ size = wcslen(wmessage) + 1; if (NULL == (amessage = (char *)_malloc_crt(size * sizeof(char)))) return; if (0 == (wcstombs(amessage, wmessage, size))) { _free_crt (amessage); return; } _lock_fh(fh); /* acquire file handle lock */ if (amessage && *amessage) { _write_lk(fh,(char *)amessage,strlen(amessage)); _write_lk(fh,": ",2); } _free_crt(amessage); amessage = _sys_err_msg( errno ); _write_lk(fh,(char *)amessage,strlen(amessage)); _write_lk(fh,"\n",1); _unlock_fh(fh); /* release file handle lock */ }
int __cdecl _eof ( int filedes ) { long here; long end; int retval; if ( ((unsigned)filedes >= (unsigned)_nhandle) || !(_osfile(filedes) & FOPEN) ) { errno = EBADF; _doserrno = 0; return(-1); } /* Lock the file */ _lock_fh(filedes); /* See if the current position equals the end of the file. */ if ( ((here = _lseek_lk(filedes, 0L, SEEK_CUR)) == -1L) || ((end = _lseek_lk(filedes, 0L, SEEK_END)) == -1L) ) retval = -1; else if ( here == end ) retval = 1; else { _lseek_lk(filedes, here, SEEK_SET); retval = 0; } /* Unlock the file */ _unlock_fh(filedes); /* Done */ return(retval); }
int __cdecl _dup ( int fh ) { ULONG dosretval; /* o.s. return value */ int newfh; /* variable for new file handle */ char fileinfo; /* _osfile info for file */ long new_osfhandle; /* validate file handle */ if ( ((unsigned)fh >= (unsigned)_nhandle) || !(_osfile(fh) & FOPEN) ) { errno = EBADF; _doserrno = 0; /* no o.s. error */ return -1; } _lock_fh(fh); /* lock file handle */ fileinfo = _osfile(fh); /* get file info for file */ /* create duplicate handle */ if ( (newfh = _alloc_osfhnd()) == -1 ) { errno = EMFILE; /* too many files error */ _doserrno = 0L; /* not an OS error */ _unlock_fh(fh); return -1; /* return error to caller */ } /* * duplicate the file handle */ if ( !(DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fh), GetCurrentProcess(), (PHANDLE)&new_osfhandle, 0L, TRUE, DUPLICATE_SAME_ACCESS)) ) { dosretval = GetLastError(); } else { _set_osfhnd(newfh, new_osfhandle); dosretval = 0; } _unlock_fh(newfh); _unlock_fh(fh); /* unlock file handle */ if (dosretval) { /* o.s. error -- map and return */ _dosmaperr(dosretval); return -1; } /* * copy the _osfile value, with the FNOINHERIT bit cleared */ _osfile(newfh) = fileinfo & ~FNOINHERIT; return newfh; }
int __cdecl _pipe ( int phandles[2], unsigned psize, int textmode ) { ULONG dosretval; /* o.s. return value */ HANDLE ReadHandle, WriteHandle; SECURITY_ATTRIBUTES SecurityAttributes; SecurityAttributes.nLength = sizeof(SecurityAttributes); SecurityAttributes.lpSecurityDescriptor = NULL; if (textmode & _O_NOINHERIT) { SecurityAttributes.bInheritHandle = FALSE; } else { SecurityAttributes.bInheritHandle = TRUE; } if (!CreatePipe(&ReadHandle, &WriteHandle, &SecurityAttributes, psize)) { /* o.s. error */ dosretval = GetLastError(); _dosmaperr(dosretval); return -1; } /* now we must allocate C Runtime handles for Read and Write handles */ if ((phandles[0] = _alloc_osfhnd()) != -1) { _osfile(phandles[0]) = (char)(FOPEN | FPIPE | FTEXT); if ((phandles[1] = _alloc_osfhnd()) != -1) { _osfile(phandles[1]) = (char)(FOPEN | FPIPE | FTEXT); if ( (textmode & _O_BINARY) || (((textmode & _O_TEXT) == 0) && (_fmode == _O_BINARY)) ) { /* binary mode */ _osfile(phandles[0]) &= ~FTEXT; _osfile(phandles[1]) &= ~FTEXT; } if ( textmode & _O_NOINHERIT ) { _osfile(phandles[0]) |= FNOINHERIT; _osfile(phandles[1]) |= FNOINHERIT; } _set_osfhnd(phandles[0], (long)ReadHandle); _set_osfhnd(phandles[1], (long)WriteHandle); errno = 0; _unlock_fh(phandles[1]); /* unlock handle */ } else { _osfile(phandles[0]) = 0; errno = EMFILE; /* too many files */ } _unlock_fh(phandles[0]); /* unlock handle */ } else { errno = EMFILE; /* too many files */ } /* If error occurred, close Win32 handles and return -1 */ if (errno != 0) { CloseHandle(ReadHandle); CloseHandle(WriteHandle); _doserrno = 0; /* not an o.s. error */ return -1; } return 0; }
static int __cdecl _dup_nolock( int fh ) { int newfh; /* variable for new file handle */ ULONG dosretval; /* o.s. return value */ char fileinfo; /* _osfile info for file */ intptr_t new_osfhandle; int success = FALSE; fileinfo = _osfile(fh); /* get file info for file */ if ( !(_osfile(fh) & FOPEN) ) return -1; /* create duplicate handle */ if ( (newfh = _alloc_osfhnd()) == -1 ) { errno = EMFILE; /* too many files error */ _doserrno = 0L; /* not an OS error */ return -1; /* return error to caller */ } __TRY /* * duplicate the file handle */ if ( !(DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fh), GetCurrentProcess(), (PHANDLE)&new_osfhandle, 0L, TRUE, DUPLICATE_SAME_ACCESS)) ) { dosretval = GetLastError(); } else { _set_osfhnd(newfh, new_osfhandle); dosretval = 0; } if (dosretval) { /* o.s. error -- map errpr and release handle */ _dosmaperr(dosretval); } else { /* * copy the _osfile value, with the FNOINHERIT bit cleared */ _osfile(newfh) = fileinfo & ~FNOINHERIT; _textmode(newfh) = _textmode(fh); _tm_unicode(newfh) = _tm_unicode(fh); success = TRUE; } __FINALLY if (!success) { _osfile(newfh) &= ~FOPEN; } _unlock_fh(newfh); __END_TRY_FINALLY return success ? newfh : -1; }
FILE * __cdecl _tpopen ( const _TSCHAR *cmdstring, const _TSCHAR *type ) { int phdls[2]; /* I/O handles for pipe */ int ph_open[2]; /* flags, set if correspond phdls is open */ int i1; /* index into phdls[] */ int i2; /* index into phdls[] */ int tm = 0; /* flag indicating text or binary mode */ int stdhdl; /* either STDIN or STDOUT */ HANDLE osfhndsv1; /* used to save _osfhnd(stdhdl) */ long osfhndsv2; /* used to save _osfhnd(phdls[i2]) */ char osfilesv1; /* used to save _osfile(stdhdl) */ char osfilesv2; /* used to save _osfile(phdls[i2]) */ HANDLE oldhnd; /* used to hold OS file handle values... */ HANDLE newhnd; /* ...in calls to DuplicateHandle API */ FILE *pstream; /* stream to be associated with pipe */ HANDLE prochnd; /* handle for current process */ _TSCHAR *cmdexe; /* pathname for the command processor */ int childhnd; /* handle for child process (cmd.exe) */ IDpair *locidpair; /* pointer to IDpair table entry */ /* first check for errors in the arguments */ if ( (cmdstring == NULL) || (type == NULL) || ((*type != 'w') && (*type != _T('r'))) ) goto error1; /* do the _pipe(). note that neither of the resulting handles will * be inheritable. */ if ( *(type + 1) == _T('t') ) tm = _O_TEXT; else if ( *(type + 1) == _T('b') ) tm = _O_BINARY; tm |= _O_NOINHERIT; if ( _pipe( phdls, PSIZE, tm ) == -1 ) goto error1; /* test *type and set stdhdl, i1 and i2 accordingly. */ if ( *type == _T('w') ) { stdhdl = STDIN; i1 = 0; i2 = 1; } else { stdhdl = STDOUT; i1 = 1; i2 = 0; } /* the pipe now exists. the following steps must be carried out before * the child process (cmd.exe) may be spawned: * * 1. save a non-inheritable dup of stdhdl * * 2. force stdhdl to be a dup of ph[i1]. close both ph[i1] and * the original OS handle underlying stdhdl * * 3. associate a stdio-level stream with ph[i2]. */ /* set flags to indicate pipe handles are open. note, these are only * used for error recovery. */ ph_open[ 0 ] = ph_open[ 1 ] = 1; /* get the process handle, it will be needed in some API calls */ prochnd = GetCurrentProcess(); /* MULTI-THREAD: ASSERT LOCK ON STDHDL HERE!!!! */ _lock_fh( stdhdl ); /* save a non-inheritable copy of stdhdl for later restoration. */ oldhnd = (HANDLE)_osfhnd( stdhdl ); if ( (oldhnd == INVALID_HANDLE_VALUE) || !DuplicateHandle( prochnd, oldhnd, prochnd, &osfhndsv1, 0L, FALSE, /* non-inheritable */ DUPLICATE_SAME_ACCESS ) ) { goto error2; } osfilesv1 = _osfile( stdhdl ); /* force stdhdl to an inheritable dup of phdls[i1] (i.e., force * STDIN to the pipe read handle or STDOUT to the pipe write handle) * and close phdls[i1] (so there won't be a stray open handle on the * pipe after a _pclose). also, clear ph_open[i1] flag so that error * recovery won't try to close it again. */ if ( !DuplicateHandle( prochnd, (HANDLE)_osfhnd( phdls[i1] ), prochnd, &newhnd, 0L, TRUE, /* inheritable */ DUPLICATE_SAME_ACCESS ) ) { goto error3; } (void)CloseHandle( (HANDLE)_osfhnd(stdhdl) ); _free_osfhnd( stdhdl ); _set_osfhnd( stdhdl, (long)newhnd ); _osfile( stdhdl ) = _osfile( phdls[i1] ); (void)_close( phdls[i1] ); ph_open[ i1 ] = 0; /* associate a stream with phdls[i2]. note that if there are no * errors, pstream is the return value to the caller. */ if ( (pstream = _tfdopen( phdls[i2], type )) == NULL ) goto error4; /* MULTI-THREAD: ASSERT LOCK ON IDPAIRS HERE!!!! */ _mlock( _POPEN_LOCK ); /* next, set locidpair to a free entry in the idpairs table. */ if ( (locidpair = idtab( NULL )) == NULL ) goto error5; /* temporarily change the osfhnd and osfile entries so that * the child doesn't get any entries for phdls[i2]. */ osfhndsv2 = _osfhnd( phdls[i2] ); _osfhnd( phdls[i2] ) = (long)INVALID_HANDLE_VALUE; osfilesv2 = _osfile( phdls[i2] ); _osfile( phdls[i2] ) = 0; /* spawn the child copy of cmd.exe. the algorithm is adapted from * SYSTEM.C, and behaves the same way. */ if ( ((cmdexe = _tgetenv(_T("COMSPEC"))) == NULL) || (((childhnd = _tspawnl( _P_NOWAIT, cmdexe, cmdexe, _T("/c"), cmdstring, NULL )) == -1) && ((errno == ENOENT) || (errno == EACCES))) ) { /* * either COMSPEC wasn't defined, or the spawn failed because * cmdexe wasn't found or was inaccessible. in either case, try to * spawn "cmd.exe" (Windows NT) or "command.com" (Windows 95) instead * Note that spawnlp is used here so that the path is searched. */ cmdexe = ( _osver & 0x8000 ) ? _T("command.com") : _T("cmd.exe"); childhnd = _tspawnlp( _P_NOWAIT, cmdexe, cmdexe, _T("/c"), cmdstring, NULL); } _osfhnd( phdls[i2] ) = osfhndsv2; _osfile( phdls[i2] ) = osfilesv2; /* check if the last (perhaps only) spawn attempt was successful */ if ( childhnd == -1 ) goto error6; /* restore stdhdl for the current process, set value of *locidpair, * close osfhndsv1 (note that CloseHandle must be used instead of close) * and return pstream to the caller */ (void)DuplicateHandle( prochnd, osfhndsv1, prochnd, &newhnd, 0L, TRUE, /* inheritable */ DUPLICATE_CLOSE_SOURCE | /* close osfhndsv1 */ DUPLICATE_SAME_ACCESS ); (void)CloseHandle( (HANDLE)_osfhnd(stdhdl) ); _free_osfhnd( stdhdl ); _set_osfhnd( stdhdl, (long)newhnd ); _osfile(stdhdl) = osfilesv1; /* MULTI-THREAD: RELEASE LOCK ON STDHDL HERE!!!! */ _unlock_fh( stdhdl ); locidpair->prochnd = childhnd; locidpair->stream = pstream; /* MULTI-THREAD: RELEASE LOCK ON IDPAIRS HERE!!!! */ _munlock( _POPEN_LOCK ); /* all successful calls to _popen return to the caller via this return * statement! */ return( pstream ); /** * error handling code. all detected errors end up here, entering * via a goto one of the labels. note that the logic is currently * a straight fall-thru scheme (e.g., if entered at error5, the * code for error5, error4,...,error1 is all executed). **********************************************************************/ error6: /* make sure locidpair is reusable */ locidpair->stream = NULL; error5: /* close pstream (also, clear ph_open[i2] since the stream * close will also close the pipe handle) */ (void)fclose( pstream ); ph_open[ i2 ] = 0; /* MULTI-THREAD: RELEASE LOCK ON IDPAIRS HERE!!!! */ _munlock(_POPEN_LOCK); error4: /* restore stdhdl */ (void)DuplicateHandle( prochnd, osfhndsv1, prochnd, &newhnd, 0L, TRUE, DUPLICATE_SAME_ACCESS ); (void)CloseHandle( (HANDLE)_osfhnd(stdhdl) ); _free_osfhnd( stdhdl ); _set_osfhnd( stdhdl, (long)newhnd ); _osfile( stdhdl ) = osfilesv1; /* MULTI-THREAD: RELEASE LOCK ON STDHDL HERE!!!! */ _unlock_fh( stdhdl ); error3: /* close osfhndsv1 */ CloseHandle( osfhndsv1 ); error2: /* close handles on pipe (if they are still open) */ if ( ph_open[i1] ) _close( phdls[i1] ); if ( ph_open[i2] ) _close( phdls[i2] ); error1: /* return NULL to the caller indicating failure */ return( NULL ); }
int __cdecl _dup2 ( int fh1, int fh2 ) { ULONG dosretval; /* o.s. return code */ /* validate file handles */ if ( ((unsigned)fh1 >= (unsigned)_nhandle) || !(_osfile(fh1) & FOPEN) || ((unsigned)fh2 >= _NHANDLE_) ) { /* handle out of range */ errno = EBADF; _doserrno = 0; /* not an OS error */ return -1; } /* * Make sure there is an ioinfo struct corresponding to fh2. */ if ( (fh2 >= _nhandle) && (extend_ioinfo_arrays(fh2) != 0) ) { errno = ENOMEM; return -1; } #if defined(_MT) && !defined(DLL_FOR_WIN32S) /* get the two file handle locks; in order to prevent deadlock, get the lowest handle lock first. */ if ( fh1 < fh2 ) { _lock_fh(fh1); _lock_fh(fh2); } else if ( fh1 > fh2 ) { _lock_fh(fh2); _lock_fh(fh1); } /* * Re-test and take care of case of unopened source handle. This is * necessary only in the multi-thread case where the file have been * closed by another thread before the lock was asserted, but after * the initial test above. */ if ( !(_osfile(fh1) & FOPEN) ) { /* * Source handle isn't open, release locks and bail out with * an error. Note that the DuplicateHandle API will not * detect this error since it implies that _osfhnd(fh1) == * INVALID_HANDLE_VALUE, and this is a legal HANDLE value * (it's the HANDLE for the current process). */ _unlock_fh(fh1); _unlock_fh(fh2); errno = EBADF; _doserrno = 0; /* not an OS error */ return -1; } #endif /* * Take of the case of equal handles. */ if ( fh1 == fh2 ) { /* * Since fh1 is known to be open, return 0 indicating success. * This is in conformance with the POSIX specification for * dup2. */ _unlock_fh(fh1); _unlock_fh(fh2); return 0; } /* * if fh2 is open, close it. */ if ( _osfile(fh2) & FOPEN ) /* * close the handle. ignore the possibility of an error - an * error simply means that an OS handle value may remain bound * for the duration of the process. Use _close_lk as we * already own lock */ (void) _close_lk(fh2); /* Duplicate source file onto target file */ { long new_osfhandle; if ( !(DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fh1), GetCurrentProcess(), (PHANDLE)&new_osfhandle, 0L, TRUE, DUPLICATE_SAME_ACCESS) ) ) { dosretval = GetLastError(); } else { _set_osfhnd(fh2, new_osfhandle); dosretval = 0; } } if (dosretval) { _dosmaperr(dosretval); _unlock_fh(fh1); _unlock_fh(fh2); return -1; } /* copy _osfile information */ _osfile(fh2) = _osfile(fh1); /* unlock file handles */ _unlock_fh(fh1); _unlock_fh(fh2); return 0; }