/* now define version that doesn't lock/unlock, validate fh */ int __cdecl _close_lk ( int fh ) { DWORD dosretval; #else /* now define normal version */ int __cdecl _close ( int fh ) { DWORD dosretval; /* validate file handle */ if ( ((unsigned)fh >= (unsigned)_nhandle) || !(_osfile(fh) & FOPEN) ) { /* bad file handle, set errno and abort */ errno = EBADF; _doserrno = 0; /* no o.s. error */ return -1; } #endif /* * Close the underlying OS file handle. Note that if fh is STDOUT * or STDERR, and if STDOUT and STDERR are mapped to the same OS * file handle, the close is skipped (without error). STDOUT and * STDERR are the only handles for which this support is provided. * Other handles are mapped to the same OS file handle only at the * programmer's risk. */ if ( ( ((fh == 1) || (fh == 2)) && (_get_osfhandle(1) == _get_osfhandle(2)) ) || CloseHandle( (HANDLE)_get_osfhandle(fh) ) ) { dosretval = 0L; } else dosretval = GetLastError(); _free_osfhnd(fh); if (dosretval) { /* OS error */ _dosmaperr(dosretval); return -1; } _osfile(fh) = 0; /* clear file flags */ return 0; /* good return */ }
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; }
extern "C" int __cdecl _close_nolock(int const fh) { DWORD const close_os_handle_error = close_os_handle_nolock(fh); _free_osfhnd(fh); _osfile(fh) = 0; if (close_os_handle_error != 0) { __acrt_errno_map_os_error(close_os_handle_error); return -1; } return 0; }
int close(int fh) { if (folly::portability::sockets::is_fh_socket(fh)) { SOCKET h = (SOCKET)_get_osfhandle(fh); // If we were to just call _close on the descriptor, it would // close the HANDLE, but it wouldn't free any of the resources // associated to the SOCKET, and we can't call _close after // calling closesocket, because closesocket has already closed // the HANDLE, and _close would attempt to close the HANDLE // again, resulting in a double free. // Luckily though, there is a function in the internals of the // CRT that is used to free only the file descriptor, so we // can call that to avoid leaking the file descriptor itself. auto c = closesocket(h); _free_osfhnd(fh); return c; } return _close(fh); }
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 ); }