xref: /reactos/sdk/lib/ucrt/stdio/freopen.cpp (revision a6a07059)
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