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 _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; }
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 _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; }