/* * WIN32_strerror with argument for late notification */ const char * WIN32_strerror(int err) { static char xbstrerror_buf[BUFSIZ]; if (err < 0 || err >= sys_nerr) strncpy(xbstrerror_buf, wsastrerror(err), BUFSIZ); else strncpy(xbstrerror_buf, strerror(err), BUFSIZ); return xbstrerror_buf; } int WIN32_Close_FD_Socket(int fd) { int result = 0; if (closesocket(_get_osfhandle(fd)) == SOCKET_ERROR) { errno = WSAGetLastError(); result = 1; } _free_osfhnd(fd); _osfile(fd) = 0; return result; } #if defined(__MINGW32__) /* MinGW environment */ int _free_osfhnd(int filehandle) { if (((unsigned) filehandle < SQUID_MAXFD) && (_osfile(filehandle) & FOPEN) && (_osfhnd(filehandle) != (long) INVALID_HANDLE_VALUE)) { switch (filehandle) { case 0: SetStdHandle(STD_INPUT_HANDLE, NULL); break; case 1: SetStdHandle(STD_OUTPUT_HANDLE, NULL); break; case 2: SetStdHandle(STD_ERROR_HANDLE, NULL); break; } _osfhnd(filehandle) = (long) INVALID_HANDLE_VALUE; return (0); } else { errno = EBADF; /* bad handle */ _doserrno = 0L; /* not an OS error */ return -1; } }
int __cdecl __initstdio(void) { int i; #ifndef CRTDLL /* * If the user has not supplied a definition of _nstream, set it * to _NSTREAM_. If the user has supplied a value that is too small * set _nstream to the minimum acceptable value (_IOB_ENTRIES). */ if (_nstream == 0) { _nstream = _NSTREAM_; } else if (_nstream < _IOB_ENTRIES) { _nstream = _IOB_ENTRIES; } #endif /* CRTDLL */ /* * Allocate the __piob array. Try for _nstream entries first. If this * fails then reset _nstream to _IOB_ENTRIES and try again. If it * still fails, bail out with an RTE. */ if ((__piob = (void**)_calloc_crt(_nstream, sizeof(void*))) == NULL) { _nstream = _IOB_ENTRIES; if ((__piob = (void**)_calloc_crt(_nstream, sizeof(void*))) == NULL) { return _RT_STDIOINIT; } } /* * Initialize the first _IOB_ENTRIES to point to the corresponding * entries in _iob[]. */ for (i = 0 ; i < _IOB_ENTRIES ; i++) { __piob[i] = (void*)&_iob[i]; } for (i = 0 ; i < 3 ; i++) { if ((_osfhnd(i) == (intptr_t)INVALID_HANDLE_VALUE) || (_osfhnd(i) == _NO_CONSOLE_FILENO) || (_osfhnd(i) == 0)) { /* * For stdin, stdout & stderr, we use _NO_CONSOLE_FILENO (a value * different from _INVALID_HANDLE_VALUE to distinguish between * a failure in opening a file & a program run without a console. */ _iob[i]._file = _NO_CONSOLE_FILENO; } } return 0; }
int ficlFileTruncate(ficlFile *ff, ficlUnsigned size) { HANDLE hFile = (HANDLE)_osfhnd(_fileno(ff->f)); if (SetFilePointer(hFile, size, NULL, FILE_BEGIN) != size) return 0; return !SetEndOfFile(hFile); }
int my_fclose (FILE *pf) { int osf; if (!wsock_started) /* No WinSock? */ return(fclose(pf)); /* Then not a socket. */ osf = TO_SOCKET(win32_fileno(pf));/* Get it now before it's gone! */ if (osf != -1) { int err; win32_fflush(pf); err = closesocket(osf); if (err == 0) { assert(_osfhnd(win32_fileno(pf)) == osf); /* catch a bad ioinfo struct def */ /* don't close freed handle */ _set_osfhnd(win32_fileno(pf), INVALID_HANDLE_VALUE); return fclose(pf); } else if (err == SOCKET_ERROR) { err = get_last_socket_error(); if (err != ENOTSOCK) { (void)fclose(pf); errno = err; return EOF; } } } return fclose(pf); }
// This function handles the case where the file is open in UTF-8 text mode and // the translated UTF-16 form of the text has a different number of characters // than the original UTF-8 text (remember: when reading a file in UTF-8 mode, the // lowio library converts the UTF-8 to UTF-16). static __int64 __cdecl common_ftell_translated_utf8_nolock( __crt_stdio_stream const stream, __int64 const lowio_position ) throw() { int const fh = _fileno(stream.public_stream()); // If the buffer has been exhausted, then the current lowio position is also // the current stdio position: if (stream->_cnt == 0) return lowio_position; __int64 const current_buffer_position = (stream->_ptr - stream->_base) / static_cast<__int64>(sizeof(wchar_t)); // Otherwise, we have to re-read the buffer, in binary mode, so that we can // analyze the original UTF-8 text to compute the actual position in the // file. To do this, we seek the lowio pointer back to the beginning of // the stdio buffer, re-read the buffer, then seek the lowio pointer back // to its original location: __int64 const base_buffer_position = _lseeki64(fh, _startpos(fh), SEEK_SET); if (base_buffer_position != _startpos(fh)) return -1; DWORD bytes_read; char raw_buffer[_INTERNAL_BUFSIZ]; if (!ReadFile(reinterpret_cast<HANDLE>(_osfhnd(fh)), raw_buffer, _INTERNAL_BUFSIZ, &bytes_read, nullptr)) return -1; // Seek back to where we were, to ensure the stdio stream is left in a // consistent state (and "unmodified" from before the call): if (_lseeki64(fh, lowio_position, SEEK_SET) < 0) return -1; // This should not normally happen: we should always read enough bytes: if (current_buffer_position > static_cast<__int64>(bytes_read)) return -1; // Scan the raw, untranslated buffer to find the current position, updating // the file pointer to account for newline translation in the buffer: char const* const raw_first = raw_buffer; #pragma warning(disable:__WARNING_UNUSED_POINTER_ASSIGNMENT) // 28930 char const* const raw_last = raw_buffer + bytes_read; char const* raw_it = raw_first; for (__int64 i = 0; i != current_buffer_position && raw_it < raw_last; ++i, ++raw_it) { if (*raw_it == CR) { if (raw_it < raw_last - 1 && *(raw_it + 1) == LF) ++raw_it; } else { raw_it += _utf8_no_of_trailbytes(*raw_it); } } return base_buffer_position + (raw_it - raw_first); }
void __cdecl __initstdio(void) { int i; #ifndef CRTDLL /* * If the user has not supplied a definition of _nstream, set it * to _NSTREAM_. If the user has supplied a value that is too small * set _nstream to the minimum acceptable value (_IOB_ENTRIES). */ if ( _nstream == 0 ) _nstream = _NSTREAM_; else if ( _nstream < _IOB_ENTRIES ) _nstream = _IOB_ENTRIES; #endif /* CRTDLL */ /* * Allocate the __piob array. Try for _nstream entries first. If this * fails then reset _nstream to _IOB_ENTRIES and try again. If it * still fails, bail out with an RTE. */ if ( (__piob = (void **)_calloc_crt( _nstream, sizeof(void *) )) == NULL ) { _nstream = _IOB_ENTRIES; if ( (__piob = (void **)_calloc_crt( _nstream, sizeof(void *) )) == NULL ) _amsg_exit( _RT_STDIOINIT ); } /* * Initialize the first _IOB_ENTRIES to point to the corresponding * entries in _iob[]. */ for ( i = 0 ; i < _IOB_ENTRIES ; i++ ) __piob[i] = (void *)&_iob[i]; for ( i = 0 ; i < 3 ; i++ ) { if ( (_osfhnd(i) == (long)INVALID_HANDLE_VALUE) || (_osfhnd(i) == 0L) ) { _iob[i]._file = -1; } } }
void __cdecl __wrt2err ( char *msg ) { unsigned long length; /* length of string to write */ unsigned long numwritten; /* number of bytes written */ length = *msg++; /* 1st byte is length */ /* write the message to stderr */ WriteFile((HANDLE)_osfhnd(2), msg, length, &numwritten, NULL); }
/* now define version that doesn't lock/unlock, validate fh */ int __cdecl _read_nolock ( int fh, void *inputbuf, unsigned cnt ) { int bytes_read; /* number of bytes read */ char *buffer; /* buffer to read to */ int os_read; /* bytes read on OS call */ char *p, *q; /* pointers into buffer */ wchar_t *pu, *qu; /* wchar_t pointers into buffer for UTF16 */ char peekchr; /* peek-ahead character */ wchar_t wpeekchr; /* peek-ahead wchar_t */ __int64 filepos; /* file position after seek */ ULONG dosretval; /* o.s. return value */ char tmode; /* textmode - ANSI/UTF-8/UTF-16 */ void *buf; /* buffer to read to */ int retval = -2; /* return value */ unsigned inputsize = cnt; /* 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); bytes_read = 0; /* nothing read yet */ if (cnt == 0 || (_osfile(fh) & FEOFLAG)) { /* nothing to read or at EOF, so return 0 read */ return 0; } _VALIDATE_CLEAR_OSSERR_RETURN( (inputbuf != NULL), EINVAL, -1 ); tmode = _textmode(fh); switch(tmode) { case __IOINFO_TM_UTF8 : /* For a UTF-8 file, we need 2 buffers, because after reading we need to convert it into UNICODE - MultiByteToWideChar doesn't do in-place conversions. */ /* MultiByte To WideChar conversion may double the size of the buffer required & hence we divide cnt by 2 */ /* * Since we are reading UTF8 stream, cnt bytes read may vary * from cnt wchar_t characters to cnt/4 wchar_t characters. For * this reason if we need to read cnt characters, we will * allocate MBCS buffer of cnt. In case cnt is 0, we will * have 4 as minimum value. This will make sure we don't * overflow for reading from pipe case. * * * In this case the numbers of wchar_t characters that we can * read is cnt/2. This means that the buffer size that we will * require is cnt/2. */ /* For UTF8 we want the count to be an even number */ _VALIDATE_CLEAR_OSSERR_RETURN(((cnt & 1) == 0), EINVAL, -1); cnt = (cnt/2) < 4 ? 4 : (cnt/2); buf = _malloc_crt(cnt); if(!buf) { errno = ENOMEM; _doserrno = E_nomem; return -1; } break; case __IOINFO_TM_UTF16LE : /* For UTF16 the count always needs to be an even number */ _VALIDATE_CLEAR_OSSERR_RETURN(((cnt & 1) == 0), EINVAL, -1); cnt &= (~1); /* Fall Through to default */ default : /* For non-UTF8 files, we need only 1 buffer - make buf point to the users input buffer */ buf = inputbuf; } buffer = buf; if ((_osfile(fh) & (FPIPE|FDEV)) && _pipech(fh) != LF && cnt != 0) { /* a pipe/device and pipe lookahead non-empty: read the lookahead * char */ *buffer++ = _pipech(fh); ++bytes_read; --cnt; _pipech(fh) = LF; /* mark as empty */ /* For UTF16, there maybe one more look ahead char. For UTF8, there maybe 2 more look ahead chars */ if((tmode != __IOINFO_TM_ANSI) && (_pipech2(fh)[0] != LF) && cnt != 0) { *buffer++ = _pipech2(fh)[0]; ++bytes_read; --cnt; _pipech2(fh)[0] = LF; /* mark as empty */ if((tmode == __IOINFO_TM_UTF8) && (_pipech2(fh)[1] != LF) && cnt != 0) { *buffer++ = _pipech2(fh)[1]; ++bytes_read; --cnt; _pipech2(fh)[1] = LF; /* mark as empty */ } } } /* read the data */ if ( !ReadFile( (HANDLE)_osfhnd(fh), buffer, cnt, (LPDWORD)&os_read, NULL ) || os_read < 0 || (size_t)os_read > cnt) { /* ReadFile has reported an error. recognize two special cases. * * 1. map ERROR_ACCESS_DENIED to EBADF * * 2. just return 0 if ERROR_BROKEN_PIPE has occurred. it * means the handle is a read-handle on a pipe for which * all write-handles have been closed and all data has been * read. */ if ( (dosretval = GetLastError()) == ERROR_ACCESS_DENIED ) { /* wrong read/write mode should return EBADF, not EACCES */ errno = EBADF; _doserrno = dosretval; retval = -1; goto error_return; } else if ( dosretval == ERROR_BROKEN_PIPE ) { retval = 0; goto error_return; } else { _dosmaperr(dosretval); retval = -1; goto error_return; } } bytes_read += os_read; /* update bytes read */ if (_osfile(fh) & FTEXT) { /* now must translate CR-LFs to LFs in the buffer */ /* For ANSI & UTF8, we read byte by byte. For UTF16, we need to read 2 bytes (wchar_t's) at a time */ if(tmode != __IOINFO_TM_UTF16LE) { /* set CRLF flag to indicate LF at beginning of buffer */ if ( (os_read != 0) && (*(char *)buf == LF) ) _osfile(fh) |= FCRLF; else _osfile(fh) &= ~FCRLF; /* convert chars in the buffer: p is src, q is dest */ p = q = buf; while (p < (char *)buf + bytes_read) { if (*p == CTRLZ) { /* if fh is not a device, set ctrl-z flag */ if ( !(_osfile(fh) & FDEV) ) _osfile(fh) |= FEOFLAG; else *q++ = *p++; break; /* stop translating */ } else if (*p != CR) *q++ = *p++; else { /* *p is CR, so must check next char for LF */ if (p < (char *)buf + bytes_read - 1) { if (*(p+1) == LF) { p += 2; *q++ = LF; /* convert CR-LF to LF */ } else *q++ = *p++; /* store char normally */ } else { /* This is the hard part. We found a CR at end of buffer. We must peek ahead to see if next char is an LF. */ ++p; dosretval = 0; if ( !ReadFile( (HANDLE)_osfhnd(fh), &peekchr, 1, (LPDWORD)&os_read, NULL ) ) dosretval = GetLastError(); if (dosretval != 0 || os_read == 0) { /* couldn't read ahead, store CR */ *q++ = CR; } else { /* * peekchr now has the extra character -- we now * have several possibilities: * * 1. disk file and char is not LF; just seek * back and copy CR * 2. disk file and char is LF; seek back and * discard CR * 3. disk file, char is LF but this is a * one-byte read: store LF, don't seek back * 4. pipe/device and char is LF; store LF. * 5. pipe/device and char isn't LF, store CR * and put char in pipe lookahead buffer. */ if (_osfile(fh) & (FDEV|FPIPE)) { /* non-seekable device */ if (peekchr == LF) *q++ = LF; else { *q++ = CR; _pipech(fh) = peekchr; } } else { /* disk file */ if (q == buf && peekchr == LF) { /* nothing read yet; must make some progress */ *q++ = LF; } else { /* seek back */ filepos = _lseeki64_nolock(fh, -1i64, FILE_CURRENT); if (peekchr != LF) *q++ = CR; } } } } } } /* we now change bytes_read to reflect the true number of chars in the buffer */ bytes_read = (int)(q - (char *)buf); if((tmode == __IOINFO_TM_UTF8) && (bytes_read != 0)) { /* UTF8 reads need to be converted into UTF16 */ --q; /* q has gone beyond the last char */ /* * If the last byte is a standalone UTF-8 char. We then * take the whole buffer. Otherwise we skip back till we * come to a lead byte. If the leadbyte forms a complete * UTF-8 character will the remaining part of the buffer, * then again we take the whole buffer. If not, we skip to * one byte which should be the final trail byte of the * previous UTF-8 char or a standalone UTF-8 character */ if(_utf8_is_independent(*q)) { ++q; /* * Final byte is standalone, we reset q, because we * will now consider the full buffer which we have read */ } else { int ctr = 1; int cnt_trailbytes; while(!_utf8_is_leadbyte(*q) && ctr <= 4 && q >= (char *)buf) { --q; ++ctr; } cnt_trailbytes = _utf8_no_of_trailbytes(*q); if(cnt_trailbytes == 0) { /* * Should have exited the while by finding a lead * byte else, the file has incorrect UTF-8 chars */ errno = EILSEQ; retval = -1; goto error_return; } if(cnt_trailbytes + 1 == ctr) { /* * The leadbyte + the remaining bytes form a full * set */ q += ctr; } else { /* Seek back */ if (_osfile(fh) & (FDEV|FPIPE)) { /* * non-seekable device. Put the extra chars in * _pipech & _pipech2. We would have a maximum * of 3 extra chars */ _pipech(fh) = *q; ++q; if(ctr >= 2) { _pipech2(fh)[0] = *q; ++q; } if(ctr == 3) { _pipech2(fh)[1] = *q; ++q; } /* * We need to point q back to beyond whatever * we actually took in. */ q -= ctr; } else { /* We have read extra chars, so we seek back */ filepos = _lseeki64_nolock(fh, -ctr, FILE_CURRENT); } } } bytes_read = (int)(q - (char *)buf); bytes_read = MultiByteToWideChar( CP_UTF8, 0, buf, bytes_read, inputbuf, inputsize/2); if(!bytes_read) { _dosmaperr(GetLastError()); retval = -1; goto error_return; } /* MultiByteToWideChar returns no of wchar_t's. Double it */ bytes_read = bytes_read*2; } } else { /* set CRLF flag to indicate LF at beginning of buffer */ if ( (os_read != 0) && (*(wchar_t *)buf == LF) ) _osfile(fh) |= FCRLF; else _osfile(fh) &= ~FCRLF; /* convert chars in the buffer: pu is src, qu is dest */ pu = qu = (wchar_t *)buf; while ((char *)pu < (char *)buf + bytes_read) { if (*pu == CTRLZ) { /* if fh is not a device, set ctrl-z flag */ if ( !(_osfile(fh) & FDEV) ) _osfile(fh) |= FEOFLAG; else *qu++ = *pu++; break; /* stop translating */ } else if (*pu != CR) *qu++ = *pu++; else { /* *pu is CR, so must check next wchar_t for LF */ if ((char *)pu < (char *)buf + bytes_read - 2) { if (*(pu+1) == LF) { pu += 2; *qu++ = LF; /* convert CR-LF to LF */ } else *qu++ = *pu++; /* store char normally */ } else { /* This is the hard part. We found a CR at end of buffer. We must peek ahead to see if next wchar_t is an LF. */ ++pu; dosretval = 0; if ( !ReadFile( (HANDLE)_osfhnd(fh), &wpeekchr, 2, (LPDWORD)&os_read, NULL ) ) dosretval = GetLastError(); if (dosretval != 0 || os_read == 0) { /* couldn't read ahead, store CR */ *qu++ = CR; } else { /* * peekchr now has the extra character -- we * now have several possibilities: * 1. wchar_t is not LF; just seek back and * copy CR * 2. wchar_t is LF; seek back and discard CR * 3. disk file, wchar_t is LF but this is a * one-byte read: store LF, don't seek back. */ if (_osfile(fh) & (FDEV|FPIPE)) { /* non-seekable device */ if (wpeekchr == LF) *qu++ = LF; else { char * pwpeekchr = (char *)&wpeekchr; *qu++ = CR; _pipech(fh) = *pwpeekchr; ++pwpeekchr; _pipech2(fh)[0] = *pwpeekchr; _pipech2(fh)[1] = LF; /* Mark as empty */ } } else { if ((char *)qu == buf && wpeekchr == LF) { /* nothing read yet; must make some progress */ *qu++ = LF; } else { /* seek back */ filepos = _lseeki64_nolock(fh, -2, FILE_CURRENT); if (wpeekchr != LF) *qu++ = CR; } } } } } } /* we now change bytes_read to reflect the true number of chars in the buffer */ bytes_read = (int)((char *)qu - (char *)buf); } } error_return: if(buf != inputbuf) { free(buf); } return (retval == -2) ? bytes_read : retval ; }
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 ); }
/* now define version that doesn't lock/unlock, validate fh */ int __cdecl _write_nolock ( int fh, const void *buf, unsigned cnt ) { int lfcount; /* count of line feeds */ int charcount; /* count of chars written so far */ int written; /* count of chars written on this write */ ULONG dosretval; /* o.s. return value */ char tmode ; /* textmode - ANSI or UTF-16 */ BOOL toConsole = 0; /* true when writing to console */ BOOL isCLocale = 0; /* true when locale handle is C locale */ lfcount = charcount = 0; /* nothing written yet */ if (cnt == 0) return 0; /* nothing to do */ _VALIDATE_CLEAR_OSSERR_RETURN( (buf != NULL), EINVAL, -1 ); tmode = _textmode(fh); if(tmode == __IOINFO_TM_UTF16LE || tmode == __IOINFO_TM_UTF8) { /* For a UTF-16 file, the count must always be an even number */ _VALIDATE_CLEAR_OSSERR_RETURN(((cnt & 1) == 0), EINVAL, -1); } if (_osfile(fh) & FAPPEND) { /* appending - seek to end of file; ignore error, because maybe file doesn't allow seeking */ #if _INTEGRAL_MAX_BITS >= 64 (void)_lseeki64_nolock(fh, 0, FILE_END); #else /* _INTEGRAL_MAX_BITS >= 64 */ (void)_lseek_nolock(fh, 0, FILE_END); #endif /* _INTEGRAL_MAX_BITS >= 64 */ } /* check for text mode with LF's in the buffer */ /* * Note that in case the handle belongs to Console, write file will * generate garbage output. For user to print these characters * correctly, we will need to print ANSI. * * Also note that in case of printing to Console, we still have to * convert the characters to console codepage. */ if (_isatty(fh) && (_osfile(fh) & FTEXT)) { DWORD dwMode; _ptiddata ptd = _getptd(); isCLocale = (ptd->ptlocinfo->lc_handle[LC_CTYPE] == _CLOCALEHANDLE); toConsole = GetConsoleMode((HANDLE)_osfhnd(fh), &dwMode); } /* don't need double conversion if it's ANSI mode C locale */ if (toConsole && !(isCLocale && (tmode == __IOINFO_TM_ANSI))) { UINT consoleCP = GetConsoleCP(); char mboutbuf[MB_LEN_MAX]; wchar_t tmpchar; int size = 0; int written = 0; char *pch; for (pch = (char *)buf; (unsigned)(pch - (char *)buf) < cnt; ) { BOOL bCR; if (tmode == __IOINFO_TM_ANSI) { bCR = *pch == LF; /* * Here we need to do double convert. i.e. convert from * multibyte to unicode and then from unicode to multibyte in * Console codepage. */ if (!isleadbyte(*pch)) { if (mbtowc(&tmpchar, pch, 1) == -1) { break; } } else if ((cnt - (pch - (char*)buf)) > 1) { if (mbtowc(&tmpchar, pch, 2) == -1) { break; } /* * Increment pch to accomodate DBCS character. */ ++pch; } else { break; } ++pch; } else if (tmode == __IOINFO_TM_UTF8 || tmode == __IOINFO_TM_UTF16LE) { /* * Note that bCR set above is not valid in case of UNICODE * stream. We need to set it using unicode character. */ tmpchar = *(wchar_t *)pch; bCR = tmpchar == LF; pch += 2; } if (tmode == __IOINFO_TM_ANSI) { if( (size = WideCharToMultiByte(consoleCP, 0, &tmpchar, 1, mboutbuf, sizeof(mboutbuf), NULL, NULL)) == 0) { break; } else { if ( WriteFile( (HANDLE)_osfhnd(fh), mboutbuf, size, (LPDWORD)&written, NULL) ) { charcount += written; if (written < size) break; } else { dosretval = GetLastError(); break; } } if (bCR) { size = 1; mboutbuf[0] = CR; if (WriteFile((HANDLE)_osfhnd(fh), mboutbuf, size, (LPDWORD)&written, NULL) ) { if (written < size) break; lfcount ++; charcount++; } else { dosretval = GetLastError(); break; } } } else if ( tmode == __IOINFO_TM_UTF8 || tmode == __IOINFO_TM_UTF16LE) { if ( _putwch_nolock(tmpchar) == tmpchar ) { charcount++; } else { dosretval = GetLastError(); break; } if (bCR) /* emit carriage return */ { size = 1; tmpchar = CR; if ( _putwch_nolock(tmpchar) == tmpchar ) { charcount++; lfcount++; } else { dosretval = GetLastError(); break; } } } } } else if ( _osfile(fh) & FTEXT ) { /* text mode, translate LF's to CR/LF's on output */ dosretval = 0; /* no OS error yet */ if(tmode == __IOINFO_TM_ANSI) { char ch; /* current character */ char *p = NULL, *q = NULL; /* pointers into buf and lfbuf resp. */ char lfbuf[BUF_SIZE]; p = (char *)buf; /* start at beginning of buffer */ while ( (unsigned)(p - (char *)buf) < cnt ) { q = lfbuf; /* start at beginning of lfbuf */ /* fill the lf buf, except maybe last char */ while ( q - lfbuf < sizeof(lfbuf) - 1 && (unsigned)(p - (char *)buf) < cnt ) { ch = *p++; if ( ch == LF ) { ++lfcount; *q++ = CR; } *q++ = ch; } /* write the lf buf and update total */ if ( WriteFile( (HANDLE)_osfhnd(fh), lfbuf, (int)(q - lfbuf), (LPDWORD)&written, NULL) ) { charcount += written; if (written < q - lfbuf) break; } else { dosretval = GetLastError(); break; } } } else if ( tmode == __IOINFO_TM_UTF16LE ){ char lfbuf[BUF_SIZE]; wchar_t wch; /* current wide char */ wchar_t *pu = (wchar_t *)buf; wchar_t *qu = NULL; while ( (unsigned)((char *)pu - (char *)buf) < cnt ) { qu = (wchar_t *)lfbuf; /* start at beginning of lfbuf */ /* fill the lf buf, except maybe last wchar_t */ while ( (((char *)qu - lfbuf) < (sizeof(lfbuf) - 2)) && ((unsigned)((char *)pu - (char *)buf) < cnt )) { wch = *pu++; if ( wch == LF ) { lfcount+=2; *qu++ = CR; } *qu++ = wch; } /* write the lf buf and update total */ if ( WriteFile( (HANDLE)_osfhnd(fh), lfbuf, (int)((char*)qu - lfbuf), (LPDWORD)&written, NULL) ) { charcount += written; if (written < ((char *)qu - lfbuf)) break; } else { dosretval = GetLastError(); break; } } } else { /* * Let's divide the lfbuf in 1:2 wher 1 is for storing * widecharacters and 2 if for converting it to UTF8. This takes * into account the worst case scenario where all the UTF8 * characters are 4 byte long. */ char utf8_buf[(BUF_SIZE*2)/3]; wchar_t utf16_buf[BUF_SIZE/6]; wchar_t wch; /* current wide char */ wchar_t *pu = (wchar_t *)buf; wchar_t *qu = NULL; pu = (wchar_t *)buf; while ((unsigned)((char *)pu - (char *)buf) < cnt) { int bytes_converted = 0; qu = utf16_buf; /* start at beginning of lfbuf */ while ( (((char *)qu - (char *)utf16_buf) < (sizeof(utf16_buf) - 2)) && ((unsigned)((char *)pu - (char *)buf) < cnt )) { wch = *pu++; if ( wch == LF ) { /* no need to count the linefeeds here: we calculate the written chars in another way */ *qu++ = CR; } *qu++ = wch; } bytes_converted = WideCharToMultiByte( CP_UTF8, 0, utf16_buf, ((int)((char *)qu - (char *)utf16_buf))/2, utf8_buf, sizeof(utf8_buf), NULL, NULL); if (bytes_converted == 0) { dosretval = GetLastError(); break; } else { /* * Here we need to make every attempt to write all the * converted characters. The resaon behind this is, * incase half the bytes of a UTF8 character is * written, it may currupt whole of the stream or file. * * The loop below will make sure we exit only if all * the bytes converted are written (which makes sure no * partial MBCS is written) or there was some error in * the stream. */ int bytes_written = 0; do { if (WriteFile( (HANDLE)_osfhnd(fh), utf8_buf + bytes_written, bytes_converted - bytes_written, &written, NULL)) { bytes_written += written; } else { dosretval = GetLastError(); break; } } while ( bytes_converted > bytes_written); /* * Only way the condition below could be true is if * there was en error. In case of error we need to * break this loop as well. */ if (bytes_converted > bytes_written) { break; } /* if this chunk has been committed successfully, update charcount */ charcount = (int)((char *)pu - (char *)buf); } } } } else { /* binary mode, no translation */ if ( WriteFile( (HANDLE)_osfhnd(fh), (LPVOID)buf, cnt, (LPDWORD)&written, NULL) ) { dosretval = 0; charcount = written; } else dosretval = GetLastError(); } if (charcount == 0) { /* If nothing was written, first check if an o.s. error, otherwise we return -1 and set errno to ENOSPC, unless a device and first char was CTRL-Z */ if (dosretval != 0) { /* o.s. error happened, map error */ if (dosretval == ERROR_ACCESS_DENIED) { /* wrong read/write mode should return EBADF, not EACCES */ errno = EBADF; _doserrno = dosretval; } else _dosmaperr(dosretval); return -1; } else if ((_osfile(fh) & FDEV) && *(char *)buf == CTRLZ) return 0; else { errno = ENOSPC; _doserrno = 0; /* no o.s. error */ return -1; } } else /* return adjusted bytes written */ return charcount - lfcount; }
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 newhnd; /* ...in calls to DuplicateHandle API */ FILE *pstream = NULL; /* stream to be associated with pipe */ HANDLE prochnd; /* handle for current process */ _TSCHAR *cmdexe; /* pathname for the command processor */ _TSCHAR *envbuf = NULL; /* buffer for the env variable */ intptr_t childhnd; /* handle for child process (cmd.exe) */ IDpair *locidpair; /* pointer to IDpair table entry */ _TSCHAR *buf = NULL, *pfin, *env; _TSCHAR *CommandLine; size_t CommandLineSize = 0; _TSCHAR _type[3] = {0, 0, 0}; /* Info for spawning the child. */ STARTUPINFO StartupInfo; /* Info for spawning a child */ BOOL childstatus = 0; PROCESS_INFORMATION ProcessInfo; /* child process information */ errno_t save_errno; int fh_lock_held = 0; int popen_lock_held = 0; /* first check for errors in the arguments */ _VALIDATE_RETURN((cmdstring != NULL), EINVAL,NULL); _VALIDATE_RETURN((type != NULL), EINVAL,NULL); while (*type == _T(' ')) { type++; } _VALIDATE_RETURN(((*type == _T('w')) || (*type == _T('r'))), EINVAL,NULL); _type[0] = *type; ++type; while (*type == _T(' ')) { ++type; } _VALIDATE_RETURN(((*type == 0) || (*type == _T('t')) || (*type == _T('b'))), EINVAL, NULL); _type[1] = *type; /* 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[0] and set stdhdl, i1 and i2 accordingly. */ if ( _type[0] == _T('w') ) { stdhdl = STDIN; i1 = 0; i2 = 1; } else { stdhdl = STDOUT; i1 = 1; i2 = 0; } /* ASSERT LOCK FOR IDPAIRS HERE!!!! */ if ( !_mtinitlocknum( _POPEN_LOCK )) { _close( phdls[0] ); _close( phdls[1] ); return NULL; } _mlock( _POPEN_LOCK ); __try { /* 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(); if ( !DuplicateHandle( prochnd, (HANDLE)_osfhnd( phdls[i1] ), prochnd, &newhnd, 0L, TRUE, /* inheritable */ DUPLICATE_SAME_ACCESS ) ) { goto error2; } (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 error2; /* next, set locidpair to a free entry in the idpairs table. */ if ( (locidpair = idtab( NULL )) == NULL ) goto error3; /* Find what to use. command.com or cmd.exe */ if ( (_ERRCHECK_EINVAL(_tdupenv_s_crt(&envbuf, NULL, _T("COMSPEC"))) != 0) || (envbuf == NULL) ) { unsigned int osver = 0; _get_osver(&osver); cmdexe = ( osver & 0x8000 ) ? _T("command.com") : _T("cmd.exe"); } else { cmdexe = envbuf; } /* * Initialise the variable for passing to CreateProcess */ memset(&StartupInfo, 0, sizeof(StartupInfo)); StartupInfo.cb = sizeof(StartupInfo); /* Used by os for duplicating the Handles. */ StartupInfo.dwFlags = STARTF_USESTDHANDLES; StartupInfo.hStdInput = stdhdl == STDIN ? (HANDLE) newhnd : (HANDLE) _osfhnd(0); StartupInfo.hStdOutput = stdhdl == STDOUT ? (HANDLE) newhnd : (HANDLE) _osfhnd(1); StartupInfo.hStdError = (HANDLE) _osfhnd(2); CommandLineSize = _tcslen(cmdexe) + _tcslen(_T(" /c ")) + (_tcslen(cmdstring)) +1; if ((CommandLine = _calloc_crt( CommandLineSize, sizeof(_TSCHAR))) == NULL) goto error3; _ERRCHECK(_tcscpy_s(CommandLine, CommandLineSize, cmdexe)); _ERRCHECK(_tcscat_s(CommandLine, CommandLineSize, _T(" /c "))); _ERRCHECK(_tcscat_s(CommandLine, CommandLineSize, cmdstring)); /* Check if cmdexe can be accessed. If yes CreateProcess else try * searching path. */ save_errno = errno; if (_taccess_s(cmdexe, 0) == 0) { childstatus = CreateProcess( (LPTSTR) cmdexe, (LPTSTR) CommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &StartupInfo, &ProcessInfo ); } else { TCHAR* envPath = NULL; size_t envPathSize = 0; if ((buf = _calloc_crt(_MAX_PATH, sizeof(_TSCHAR))) == NULL) { _free_crt(buf); _free_crt(CommandLine); _free_crt(envbuf); cmdexe = NULL; errno = save_errno; goto error3; } if (_ERRCHECK_EINVAL(_tdupenv_s_crt(&envPath, NULL, _T("PATH"))) != 0) { _free_crt(envPath); _free_crt(buf); _free_crt(CommandLine); _free_crt(envbuf); cmdexe = NULL; errno = save_errno; goto error3; } env = envPath; #ifdef WPRFLAG while ( (env = _wgetpath(env, buf, _MAX_PATH -1)) && (*buf) ) { #else /* WPRFLAG */ while ( (env = _getpath(env, buf, _MAX_PATH -1)) && (*buf) ) { #endif /* WPRFLAG */ pfin = buf + _tcslen(buf) -1; #ifdef _MBCS if (*pfin == SLASHCHAR) { if (pfin != _mbsrchr(buf, SLASHCHAR)) _ERRCHECK(strcat_s(buf, _MAX_PATH, SLASH)); } else if (*pfin != XSLASHCHAR) _ERRCHECK(strcat_s(buf, _MAX_PATH, SLASH)); #else /* _MBCS */ if (*pfin != SLASHCHAR && *pfin != XSLASHCHAR) _ERRCHECK(_tcscat_s(buf, _MAX_PATH, SLASH)); #endif /* _MBCS */ /* check that the final path will be of legal size. if so, * build it. otherwise, return to the caller (return value * and errno rename set from initial call to _spawnve()). */ if ( (_tcslen(buf) + _tcslen(cmdexe)) < _MAX_PATH ) _ERRCHECK(_tcscat_s(buf, _MAX_PATH, cmdexe)); else break; /* Check if buf can be accessed. If yes CreateProcess else try * again. */ if (_taccess_s(buf, 0) == 0) { childstatus = CreateProcess( (LPTSTR) buf, CommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &StartupInfo, &ProcessInfo ); break; } } _free_crt(envPath); _free_crt(buf); } _free_crt(CommandLine); _free_crt(envbuf); cmdexe = NULL; CloseHandle((HANDLE)newhnd); CloseHandle((HANDLE)ProcessInfo.hThread); errno = save_errno; /* check if the CreateProcess was sucessful. */ if ( childstatus) childhnd = (intptr_t)ProcessInfo.hProcess; else goto error4; locidpair->prochnd = childhnd; locidpair->stream = pstream; /* success, return the stream to the caller */ goto done; /** * 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 error4, the * code for error4, error3,...,error1 is all executed). **********************************************************************/ error4: /* make sure locidpair is reusable */ locidpair->stream = NULL; error3: /* close pstream (also, clear ph_open[i2] since the stream * close will also close the pipe handle) */ (void)fclose( pstream ); ph_open[ i2 ] = 0; pstream = NULL; error2: /* close handles on pipe (if they are still open) */ if ( ph_open[i1] ) _close( phdls[i1] ); if ( ph_open[i2] ) _close( phdls[i2] ); done: ;} __finally { _munlock(_POPEN_LOCK); } error1: return pstream; } #ifndef _UNICODE /*** *int _pclose(pstream) - wait on a child command and close the stream on the * associated pipe * *Purpose: * Closes pstream then waits on the associated child command. The * argument, pstream, must be the return value from a previous call to * _popen. _pclose first looks up the process handle of child command * started by that _popen and does a cwait on it. Then, it closes pstream * and returns the exit status of the child command to the caller. * *Entry: * FILE *pstream - file stream returned by a previous call to _popen * *Exit: * If successful, _pclose returns the exit status of the child command. * The format of the return value is that same as for cwait, except that * the low order and high order bytes are swapped. * * If an error occurs, -1 is returned. * *Exceptions: * *******************************************************************************/ int __cdecl _pclose ( FILE *pstream ) { IDpair *locidpair; /* pointer to entry in idpairs table */ int termstat; /* termination status word */ int retval = -1; /* return value (to caller) */ errno_t save_errno; _VALIDATE_RETURN((pstream != NULL), EINVAL, -1); if (!_mtinitlocknum(_POPEN_LOCK)) return -1; _mlock(_POPEN_LOCK); __try { if ((locidpair = idtab(pstream)) == NULL) { /* invalid pstream, exit with retval == -1 */ errno = EBADF; goto done; } /* close pstream */ (void)fclose(pstream); /* wait on the child (copy of the command processor) and all of its * children. */ save_errno = errno; errno = 0; if ( (_cwait(&termstat, locidpair->prochnd, _WAIT_GRANDCHILD) != -1) || (errno == EINTR) ) retval = termstat; errno = save_errno; /* Mark the IDpairtable entry as free (note: prochnd was closed by the * preceding call to _cwait). */ locidpair->stream = NULL; locidpair->prochnd = 0; /* only return path! */ done: ; } __finally { _munlock(_POPEN_LOCK); } return(retval); }