1 // 2 // close.cpp 3 // 4 // Copyright (c) Microsoft Corporation. All rights reserved. 5 // 6 // Defines _close(), which closes a file. 7 // 8 #include <corecrt_internal_lowio.h> 9 #include <corecrt_internal_ptd_propagation.h> 10 11 12 13 // Closes the underlying OS file handle, if and only if nt needs to be closed. 14 // Returns 0 on success; returns the OS error on failure. 15 static DWORD close_os_handle_nolock(int const fh) throw() 16 { 17 // If the underlying handle is INVALID_HANDLE_VALUE, don't try to acutally 18 // close it: 19 if (_get_osfhandle(fh) == (intptr_t)INVALID_HANDLE_VALUE) 20 { 21 return 0; 22 } 23 24 // If the file handle is stdout or stderr, and if stdout and stderr are 25 // mapped to the same OS file handle, skip the CloseHandle without error. 26 // 27 // stdout and stderr are the only handles for which this support is 28 // provided. Other handles may be mapped to the same OS file handle only 29 // at the programmer's risk. 30 bool is_other_std_handle_open = 31 fh == 1 && (_osfile(2) & FOPEN) || 32 fh == 2 && (_osfile(1) & FOPEN); 33 34 if (is_other_std_handle_open && _get_osfhandle(1) == _get_osfhandle(2)) 35 { 36 return 0; 37 } 38 39 // Otherwise, we can go ahead and close the handle: 40 if (CloseHandle(reinterpret_cast<HANDLE>(_get_osfhandle(fh)))) 41 { 42 return 0; 43 } 44 45 return GetLastError(); 46 } 47 48 49 50 // Closes the file associated with the given file handle. On success, returns 0. 51 // On failure, returns -1 and sets errno. 52 extern "C" int __cdecl _close_internal(int const fh, __crt_cached_ptd_host& ptd) 53 { 54 _UCRT_CHECK_FH_CLEAR_OSSERR_RETURN(ptd, fh, EBADF, -1); 55 _UCRT_VALIDATE_CLEAR_OSSERR_RETURN(ptd, (fh >= 0 && (unsigned)fh < (unsigned)_nhandle), EBADF, -1); 56 _UCRT_VALIDATE_CLEAR_OSSERR_RETURN(ptd, (_osfile(fh) & FOPEN), EBADF, -1); 57 58 return __acrt_lowio_lock_fh_and_call(fh, [&]() 59 { 60 if (_osfile(fh) & FOPEN) 61 { 62 return _close_nolock_internal(fh, ptd); 63 } 64 else 65 { 66 ptd.get_errno().set(EBADF); 67 _ASSERTE(("Invalid file descriptor. File possibly closed by a different thread",0)); 68 return -1; 69 } 70 }); 71 } 72 73 extern "C" int __cdecl _close(int const fh) 74 { 75 __crt_cached_ptd_host ptd; 76 return _close_internal(fh, ptd); 77 } 78 79 80 81 extern "C" int __cdecl _close_nolock_internal(int const fh, __crt_cached_ptd_host& ptd) 82 { 83 DWORD const close_os_handle_error = close_os_handle_nolock(fh); 84 85 _free_osfhnd(fh); 86 _osfile(fh) = 0; 87 88 if (close_os_handle_error != 0) 89 { 90 __acrt_errno_map_os_error_ptd(close_os_handle_error, ptd); 91 return -1; 92 } 93 94 return 0; 95 } 96 97 extern "C" int __cdecl _close_nolock(int const fh) 98 { 99 __crt_cached_ptd_host ptd; 100 return _close_nolock_internal(fh, ptd); 101 } 102