1 // 2 // freopen.cpp 3 // 4 // Copyright (c) Microsoft Corporation. All rights reserved. 5 // 6 // Defines the freopen() family of functions, which is used to close a stream 7 // and associate it with a new file (typically used for redirecting the 8 // standard streams). 9 // 10 #include <corecrt_internal_stdio.h> 11 12 13 14 // Reopens a stream to a new file. If the 'stream' is open, it is closed. The 15 // new file, named by 'file_name', is then opened, and 'stream' is associated 16 // with that file. The provided 'mode' and 'share_flag' are used when opening 17 // the new file. The resulting FILE* is returned via 'result'. 18 // 19 // Returns 0 on success; returns an error code on failure. 20 template <typename Character> 21 static errno_t __cdecl common_freopen( 22 FILE** const result, 23 Character const* const file_name, 24 Character const* const mode, 25 __crt_stdio_stream const stream, 26 int const share_flag 27 ) throw() 28 { 29 typedef __acrt_stdio_char_traits<Character> stdio_traits; 30 31 _VALIDATE_RETURN_ERRCODE(result != nullptr, EINVAL); 32 *result = nullptr; 33 34 // C11 7.21.5.4/3: "If filename is a null pointer, the freopen function 35 // attempts to change the mode of the stream to that specified by mode, as 36 // if the name of the file currently associated with the stream had been 37 // used. It is implementation-defined which changes of mode are permitted 38 // (if any), and under what circumstances." 39 // 40 // In our implementation, we do not currently support changing the mode 41 // in this way. In the future, we might consider use of ReOpenFile to 42 // implement support for changing the mode. 43 _VALIDATE_RETURN_ERRCODE_NOEXC(file_name != nullptr, EBADF); 44 45 _VALIDATE_RETURN_ERRCODE(mode != nullptr, EINVAL); 46 _VALIDATE_RETURN_ERRCODE(stream.valid() , EINVAL); 47 48 // Just as in the common_fsopen function, we do not hard-validate empty 49 // 'file_name' strings in this function: 50 _VALIDATE_RETURN_ERRCODE_NOEXC(*file_name != 0, EINVAL); 51 52 errno_t return_value = 0; 53 54 _lock_file(stream.public_stream()); 55 __try 56 { 57 // If the stream is in use, try to close it, ignoring possible errors: 58 if (stream.is_in_use()) 59 _fclose_nolock(stream.public_stream()); 60 61 stream->_ptr = nullptr; 62 stream->_base = nullptr; 63 stream->_cnt = 0; 64 stream.unset_flags(-1); 65 66 // We may have called fclose above, which will deallocate the stream. 67 // We still hold the lock on the stream, though, so we can just reset 68 // the allocated flag to retain ownership. 69 stream.set_flags(_IOALLOCATED); 70 71 *result = stdio_traits::open_file(file_name, mode, share_flag, stream.public_stream()); 72 if (*result == nullptr) 73 { 74 stream.unset_flags(_IOALLOCATED); 75 return_value = errno; 76 } 77 } 78 __finally 79 { 80 _unlock_file(stream.public_stream()); 81 } 82 __endtry 83 84 return return_value; 85 } 86 87 88 89 extern "C" FILE* __cdecl freopen( 90 char const* const file_name, 91 char const* const mode, 92 FILE* const public_stream 93 ) 94 { 95 FILE* result_stream = nullptr; 96 common_freopen(&result_stream, file_name, mode, __crt_stdio_stream(public_stream), _SH_DENYNO); 97 return result_stream; 98 } 99 100 extern "C" errno_t __cdecl freopen_s( 101 FILE** const result, 102 char const* const file_name, 103 char const* const mode, 104 FILE* const public_stream 105 ) 106 { 107 return common_freopen(result, file_name, mode, __crt_stdio_stream(public_stream), _SH_SECURE); 108 } 109 110 extern "C" FILE* __cdecl _wfreopen( 111 wchar_t const* const file_name, 112 wchar_t const* const mode, 113 FILE* const public_stream 114 ) 115 { 116 FILE* result_stream = nullptr; 117 common_freopen(&result_stream, file_name, mode, __crt_stdio_stream(public_stream), _SH_DENYNO); 118 return result_stream; 119 } 120 121 extern "C" errno_t __cdecl _wfreopen_s( 122 FILE** const result, 123 wchar_t const* const file_name, 124 wchar_t const* const mode, 125 FILE* const public_stream 126 ) 127 { 128 return common_freopen(result, file_name, mode, __crt_stdio_stream(public_stream), _SH_SECURE); 129 } 130