1 // 2 // dup2.cpp 3 // 4 // Copyright (c) Microsoft Corporation. All rights reserved. 5 // 6 // Defines _dup2() and _dup2_nolock, which duplicate lowio file handles 7 // 8 #include <corecrt_internal_lowio.h> 9 #include <corecrt_internal_ptd_propagation.h> 10 11 static int __cdecl _dup2_nolock_internal(int const source_fh, int const target_fh, __crt_cached_ptd_host& ptd) throw() 12 { 13 if ((_osfile(source_fh) & FOPEN) == 0) 14 { 15 // If the source handle is not open, return an error. Noe that the 16 // DuplicateHandle API will not detect this error, because it implies 17 // that _osfhnd(source_fh) == INVALID_HANDLE_VALUE, and this is a 18 // legal HANDLE value to be duplicated. 19 ptd.get_errno().set(EBADF); 20 ptd.get_doserrno().set(0); 21 _ASSERTE(("Invalid file descriptor. File possibly closed by a different thread",0)); 22 return -1; 23 } 24 25 // Duplicate the source file onto the target file: 26 intptr_t new_osfhandle; 27 28 BOOL const result = DuplicateHandle( 29 GetCurrentProcess(), 30 reinterpret_cast<HANDLE>(_get_osfhandle(source_fh)), 31 GetCurrentProcess(), 32 &reinterpret_cast<HANDLE&>(new_osfhandle), 33 0, 34 TRUE, 35 DUPLICATE_SAME_ACCESS); 36 37 if (!result) 38 { 39 __acrt_errno_map_os_error_ptd(GetLastError(), ptd); 40 return -1; 41 } 42 43 // If the target is open, close it once we know the OS handle was duplicated successfully. 44 // We ignore the possibility of an error here: an error simply means that the OS handle 45 // value may remain bound for the duration of the process. 46 if (_osfile(target_fh) & FOPEN) 47 { 48 _close_nolock_internal(target_fh, ptd); 49 } 50 51 __acrt_lowio_set_os_handle(target_fh, new_osfhandle); 52 53 // Copy the _osfile information, with the FNOINHERIT bit cleared: 54 _osfile(target_fh) = _osfile(source_fh) & ~FNOINHERIT; 55 _textmode(target_fh) = _textmode(source_fh); 56 _tm_unicode(target_fh) = _tm_unicode(source_fh); 57 58 return 0; 59 } 60 61 static int __cdecl _dup2_internal(int const source_fh, int const target_fh, __crt_cached_ptd_host& ptd) throw() 62 { 63 _UCRT_CHECK_FH_CLEAR_OSSERR_RETURN(ptd, source_fh, EBADF, -1); 64 _UCRT_VALIDATE_CLEAR_OSSERR_RETURN(ptd, (source_fh >= 0 && (unsigned)source_fh < (unsigned)_nhandle), EBADF, -1); 65 _UCRT_VALIDATE_CLEAR_OSSERR_RETURN(ptd, (_osfile(source_fh) & FOPEN), EBADF, -1); 66 _UCRT_CHECK_FH_CLEAR_OSSERR_RETURN(ptd, target_fh, EBADF, -1); 67 _UCRT_VALIDATE_CLEAR_OSSERR_RETURN(ptd, ((unsigned)target_fh < _NHANDLE_), EBADF, -1); 68 69 // Make sure there is an __crt_lowio_handle_data struct corresponding to the target_fh: 70 if (target_fh >= _nhandle && __acrt_lowio_ensure_fh_exists(target_fh) != 0) 71 { 72 return -1; 73 } 74 75 // If the source and target are the same, return success (we've already 76 // verified that the file handle is open, above). This is for conformance 77 // with the POSIX specification for dup2. 78 if (source_fh == target_fh) 79 { 80 return 0; 81 } 82 83 // Obtain the two file handle locks. In order to prevent deadlock, we 84 // always obtain the lock for the lower-numbered file handle first: 85 if (source_fh < target_fh) 86 { 87 __acrt_lowio_lock_fh(source_fh); 88 __acrt_lowio_lock_fh(target_fh); 89 } 90 else if (source_fh > target_fh) 91 { 92 __acrt_lowio_lock_fh(target_fh); 93 __acrt_lowio_lock_fh(source_fh); 94 } 95 96 int result = 0; 97 98 __try 99 { 100 result = _dup2_nolock_internal(source_fh, target_fh, ptd); 101 } 102 __finally 103 { 104 // The order in which we unlock the file handles does not matter: 105 __acrt_lowio_unlock_fh(source_fh); 106 __acrt_lowio_unlock_fh(target_fh); 107 } 108 __endtry 109 return result; 110 } 111 112 // _dup2() makes the target file handle a duplicate of the source file handle, 113 // so that both handles refer to the same file. If the target handle is open 114 // upon entry, it is closed so that it is not leaked. 115 // 116 // Returns 0 if successful; returns -1 and sets errno on failure. 117 extern "C" int __cdecl _dup2(int const source_fh, int const target_fh) 118 { 119 __crt_cached_ptd_host ptd; 120 return _dup2_internal(source_fh, target_fh, ptd); 121 } 122