Reactos
1//
2// dup.cpp
3//
4// Copyright (c) Microsoft Corporation. All rights reserved.
5//
6// Defines _dup() and _dup_nolock, which duplicate lowio file handles
7//
8#include <corecrt_internal_lowio.h>
9#include <corecrt_internal_ptd_propagation.h>
10
11static int __cdecl duplicate_osfhnd(int const fh, int const new_fh, __crt_cached_ptd_host& ptd) throw()
12{
13 // Duplicate the file handle:
14 intptr_t new_osfhandle;
15
16 BOOL const result = DuplicateHandle(
17 GetCurrentProcess(),
18 reinterpret_cast<HANDLE>(_get_osfhandle(fh)),
19 GetCurrentProcess(),
20 &reinterpret_cast<HANDLE&>(new_osfhandle),
21 0L,
22 TRUE,
23 DUPLICATE_SAME_ACCESS);
24
25 if (!result)
26 {
27 __acrt_errno_map_os_error_ptd(GetLastError(), ptd);
28 return -1;
29 }
30
31 // Duplicate the handle state:
32 __acrt_lowio_set_os_handle(new_fh, new_osfhandle);
33 _osfile(new_fh) = _osfile(fh) & ~FNOINHERIT;
34 _textmode(new_fh) = _textmode(fh);
35 _tm_unicode(new_fh) = _tm_unicode(fh);
36 return new_fh;
37}
38
39static int __cdecl _dup_nolock_internal(int const fh, __crt_cached_ptd_host& ptd) throw()
40{
41 if ((_osfile(fh) & FOPEN) == 0)
42 {
43 ptd.get_errno().set(EBADF);
44 ptd.get_doserrno().set(0);
45 _ASSERTE(("Invalid file descriptor. File possibly closed by a different thread", 0));
46 return -1;
47 }
48
49 // Allocate a duplicate handle
50 int const new_fh = _alloc_osfhnd();
51 if (new_fh == -1)
52 {
53 ptd.get_errno().set(EMFILE);
54 ptd.get_doserrno().set(0);
55 return -1;
56 }
57
58 int return_value = -1;
59 __try
60 {
61 return_value = duplicate_osfhnd(fh, new_fh, ptd);
62 }
63 __finally
64 {
65 // The handle returned by _alloc_osfhnd is both open and locked. If we
66 // failed to duplicate the handle, we need to abandon the handle by
67 // unsetting the open flag. We always need to unlock the handle:
68 if (return_value == -1)
69 {
70 _osfile(new_fh) &= ~FOPEN;
71 }
72
73 __acrt_lowio_unlock_fh(new_fh);
74 }
75 __endtry
76 return return_value;
77}
78
79static int __cdecl _dup_internal(int const fh, __crt_cached_ptd_host& ptd)
80{
81 _UCRT_CHECK_FH_CLEAR_OSSERR_RETURN(ptd, fh, EBADF, -1);
82 _UCRT_VALIDATE_CLEAR_OSSERR_RETURN(ptd, (fh >= 0 && (unsigned)fh < (unsigned)_nhandle), EBADF, -1);
83 _UCRT_VALIDATE_CLEAR_OSSERR_RETURN(ptd, (_osfile(fh) & FOPEN), EBADF, -1);
84
85 return __acrt_lowio_lock_fh_and_call(fh, [&](){
86 return _dup_nolock_internal(fh, ptd);
87 });
88}
89
90// _dup() duplicates a file handle and returns the duplicate. If the function
91// fails, -1 is returned and errno is set.
92extern "C" int __cdecl _dup(int const fh)
93{
94 __crt_cached_ptd_host ptd;
95 return _dup_internal(fh, ptd);
96}