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; }
/* 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; }
/* 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; }
// Locks or unlocks the requested number of bytes in the specified file. // // Note that this function acquires the lock for the specified file and holds // this lock for the entire duration of the call, even during the one second // delays between calls into the operating system. This is to prevent other // threads from changing the file during the call. // // Returns 0 on success; returns -1 and sets errno on failure. extern "C" int __cdecl _locking(int const fh, int const locking_mode, long const number_of_bytes) { _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); _VALIDATE_CLEAR_OSSERR_RETURN(number_of_bytes >= 0, EINVAL, -1); __acrt_lowio_lock_fh(fh); int result = -1; __try { if ((_osfile(fh) & FOPEN) == 0) { errno = EBADF; _doserrno = 0; _ASSERTE(("Invalid file descriptor. File possibly closed by a different thread",0)); __leave; } result = locking_nolock(fh, locking_mode, number_of_bytes); } __finally { __acrt_lowio_unlock_fh(fh); } return result; }
static Integer __cdecl common_lseek(int const fh, Integer const offset, int const origin) throw() { _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); __acrt_lowio_lock_fh(fh); Integer result = -1; __try { if ((_osfile(fh) & FOPEN) == 0) { errno = EBADF; _doserrno = 0; _ASSERTE(("Invalid file descriptor. File possibly closed by a different thread",0)); __leave; } result = common_lseek_nolock(fh, offset, origin); } __finally { __acrt_lowio_unlock_fh(fh); } return result; }
// _dup2() makes the target file handle a duplicate of the source file handle, // so that both handles refer to the same file. If the target handle is open // upon entry, it is closed so that it is not leaked. // // Returns 0 if successful; returns -1 and sets errno on failure. extern "C" int __cdecl _dup2(int const source_fh, int const target_fh) { _CHECK_FH_CLEAR_OSSERR_RETURN( source_fh, EBADF, -1 ); _VALIDATE_CLEAR_OSSERR_RETURN((source_fh >= 0 && (unsigned)source_fh < (unsigned)_nhandle), EBADF, -1); _VALIDATE_CLEAR_OSSERR_RETURN((_osfile(source_fh) & FOPEN), EBADF, -1); _CHECK_FH_CLEAR_OSSERR_RETURN( target_fh, EBADF, -1 ); _VALIDATE_CLEAR_OSSERR_RETURN(((unsigned)target_fh < _NHANDLE_), EBADF, -1); // Make sure there is an __crt_lowio_handle_data struct corresponding to the target_fh: if (target_fh >= _nhandle && __acrt_lowio_ensure_fh_exists(target_fh) != 0) return -1; // If the source and target are the same, return success (we've already // verified that the file handle is open, above). This is for conformance // with the POSIX specification for dup2. if (source_fh == target_fh) return 0; // Obtain the two file handle locks. In order to prevent deadlock, we // always obtain the lock for the lower-numbered file handle first: if (source_fh < target_fh) { __acrt_lowio_lock_fh(source_fh); __acrt_lowio_lock_fh(target_fh); } else if (source_fh > target_fh) { __acrt_lowio_lock_fh(target_fh); __acrt_lowio_lock_fh(source_fh); } int result = 0; __try { result = dup2_nolock(source_fh, target_fh); } __finally { // The order in which we unlock the file handles does not matter: __acrt_lowio_unlock_fh(source_fh); __acrt_lowio_unlock_fh(target_fh); } return result; }
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); }
// Closes the file associated with the given file handle. On success, returns 0. // On failure, returns -1 and sets errno. extern "C" int __cdecl _close(int const 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); return __acrt_lowio_lock_fh_and_call(fh, [&]() { if (_osfile(fh) & FOPEN) { return _close_nolock(fh); } else { errno = EBADF; _ASSERTE(("Invalid file descriptor. File possibly closed by a different thread",0)); return -1; } }); }
/* 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 ; }