|
1 /*- |
|
2 * Copyright (c) 1990, 1993 |
|
3 * The Regents of the University of California. All rights reserved. |
|
4 * |
|
5 * This code is derived from software contributed to Berkeley by |
|
6 * Chris Torek. |
|
7 * |
|
8 * Redistribution and use in source and binary forms, with or without |
|
9 * modification, are permitted provided that the following conditions |
|
10 * are met: |
|
11 * 1. Redistributions of source code must retain the above copyright |
|
12 * notice, this list of conditions and the following disclaimer. |
|
13 * 2. Redistributions in binary form must reproduce the above copyright |
|
14 * notice, this list of conditions and the following disclaimer in the |
|
15 * documentation and/or other materials provided with the distribution. |
|
16 * 4. Neither the name of the University nor the names of its contributors |
|
17 * may be used to endorse or promote products derived from this software |
|
18 * without specific prior written permission. |
|
19 * |
|
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
|
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
|
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
|
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
|
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|
30 * SUCH DAMAGE. |
|
31 * © Portions copyright (c) 2005 - 2006 Nokia Corporation. All rights reserved. |
|
32 */ |
|
33 |
|
34 #if defined(LIBC_SCCS) && !defined(lint) |
|
35 static char sccsid[] = "@(#)freopen.c 8.1 (Berkeley) 6/4/93"; |
|
36 #endif /* LIBC_SCCS and not lint */ |
|
37 #include <sys/cdefs.h> |
|
38 #ifndef __SYMBIAN32__ |
|
39 __FBSDID("$FreeBSD: src/lib/libc/stdio/freopen.c,v 1.13 2004/05/22 15:19:41 tjr Exp $"); |
|
40 #endif |
|
41 #include "namespace.h" |
|
42 #include <sys/types.h> |
|
43 #include <sys/stat.h> |
|
44 #include <wchar.h> |
|
45 #ifndef DEFFILEMODE |
|
46 #define DEFFILEMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) |
|
47 #endif |
|
48 #include <errno.h> |
|
49 #include <stdio.h> |
|
50 #include <stdlib.h> |
|
51 #include "un-namespace.h" |
|
52 #include <fcntl.h> |
|
53 #include <unistd.h> |
|
54 #include "libc_private.h" |
|
55 #include "local.h" |
|
56 #include "common_def.h" |
|
57 #if (defined(__SYMBIAN32__) && (defined(__WINSCW__) || defined(__WINS__))) |
|
58 #include "libc_wsd_defs.h" |
|
59 #endif |
|
60 |
|
61 #ifdef EMULATOR |
|
62 int *GET_WSD_VAR_NAME(__sdidinit, g)(); |
|
63 #define __sdidinit (*GET_WSD_VAR_NAME(__sdidinit, g)()) |
|
64 #endif //EMULATOR |
|
65 /* |
|
66 Re-direct an existing, open (probably) file to some other file. |
|
67 ANSI is written such that the original file gets closed if at |
|
68 all possible, no matter what. |
|
69 */ |
|
70 |
|
71 EXPORT_C FILE * wfreopen(const wchar_t * file, const wchar_t * mode, FILE *fp) |
|
72 { |
|
73 int f; |
|
74 int dflags, flags, isopen, oflags, sverrno, wantfd; |
|
75 char destmode[4]; |
|
76 size_t siz; |
|
77 |
|
78 destmode[0] = '\0'; |
|
79 if(mode==NULL) |
|
80 { |
|
81 errno = EINVAL; |
|
82 (void) fclose(fp); |
|
83 return (NULL); |
|
84 } |
|
85 siz = wcstombs(destmode, mode, 4); |
|
86 |
|
87 |
|
88 if ((flags = __sflags(destmode, &oflags)) == 0) { |
|
89 (void) fclose(fp); |
|
90 return (NULL); |
|
91 } |
|
92 |
|
93 FLOCKFILE(fp); |
|
94 |
|
95 if (!__sdidinit) |
|
96 __sinit(); |
|
97 |
|
98 /* |
|
99 * If the filename is a NULL pointer, the caller is asking us to |
|
100 * re-open the same file with a different mode. We allow this only |
|
101 * if the modes are compatible. |
|
102 */ |
|
103 if (file == NULL) { |
|
104 /* See comment below regarding freopen() of closed files. */ |
|
105 if (fp->_flags == 0) { |
|
106 FUNLOCKFILE(fp); |
|
107 errno = EINVAL; |
|
108 return (NULL); |
|
109 } |
|
110 if ((dflags = _fcntl(fp->_file, F_GETFL)) < 0) { |
|
111 sverrno = errno; |
|
112 fclose(fp); |
|
113 FUNLOCKFILE(fp); |
|
114 errno = sverrno; |
|
115 return (NULL); |
|
116 } |
|
117 if ((dflags & O_ACCMODE) != O_RDWR && (dflags & O_ACCMODE) != |
|
118 (oflags & O_ACCMODE)) { |
|
119 fclose(fp); |
|
120 FUNLOCKFILE(fp); |
|
121 errno = EINVAL; |
|
122 return (NULL); |
|
123 } |
|
124 if ((oflags ^ dflags) & O_APPEND) { |
|
125 dflags &= ~O_APPEND; |
|
126 dflags |= oflags & O_APPEND; |
|
127 if (_fcntl(fp->_file, F_SETFL, dflags) < 0) { |
|
128 sverrno = errno; |
|
129 fclose(fp); |
|
130 FUNLOCKFILE(fp); |
|
131 errno = sverrno; |
|
132 return (NULL); |
|
133 } |
|
134 } |
|
135 if (oflags & O_TRUNC) |
|
136 ftruncate(fp->_file, 0); |
|
137 if (_fseeko(fp, 0, oflags & O_APPEND ? SEEK_END : SEEK_SET, |
|
138 0) < 0 && errno != ESPIPE) { |
|
139 sverrno = errno; |
|
140 fclose(fp); |
|
141 FUNLOCKFILE(fp); |
|
142 errno = sverrno; |
|
143 return (NULL); |
|
144 } |
|
145 f = fp->_file; |
|
146 isopen = 0; |
|
147 wantfd = -1; |
|
148 |
|
149 } |
|
150 else |
|
151 { |
|
152 /* |
|
153 * There are actually programs that depend on being able to "freopen" |
|
154 * descriptors that weren't originally open. Keep this from breaking. |
|
155 * Remember whether the stream was open to begin with, and which file |
|
156 * descriptor (if any) was associated with it. If it was attached to |
|
157 * a descriptor, defer closing it; freopen("/dev/stdin", "r", stdin) |
|
158 * should work. This is unnecessary if it was not a Unix file. |
|
159 */ |
|
160 if (fp->_flags == 0) { |
|
161 fp->_flags = __SEOF; /* hold on to it */ |
|
162 isopen = 0; |
|
163 wantfd = -1; |
|
164 } |
|
165 else { |
|
166 /* flush the stream; ANSI doesn't require this. */ |
|
167 if (fp->_flags & __SWR) |
|
168 (void) __sflush(fp); |
|
169 /* if close is NULL, closing is a no-op, hence pointless */ |
|
170 isopen = fp->_close != NULL; |
|
171 if ((wantfd = fp->_file) < 0 && isopen) { |
|
172 (void) (*fp->_close)(fp->_cookie); |
|
173 isopen = 0; |
|
174 } |
|
175 } |
|
176 /* Get a new descriptor to refer to the new file. */ |
|
177 f = wopen(file, oflags, DEFFILEMODE); |
|
178 if (f < 0 && isopen) { |
|
179 /* If out of fd's close the old one and try again. */ |
|
180 if (errno == ENFILE || errno == EMFILE) { |
|
181 (void) (*fp->_close)(fp->_cookie); |
|
182 isopen = 0; |
|
183 f = wopen(file, oflags, DEFFILEMODE); |
|
184 } |
|
185 } |
|
186 sverrno = errno; |
|
187 } |
|
188 |
|
189 /* |
|
190 * Finish closing fp. Even if the open succeeded above, we cannot |
|
191 * keep fp->_base: it may be the wrong size. This loses the effect |
|
192 * of any setbuffer calls, but stdio has always done this before. |
|
193 */ |
|
194 if (isopen) |
|
195 (void) (*fp->_close)(fp->_cookie); |
|
196 if (fp->_flags & __SMBF) |
|
197 { |
|
198 #ifdef __SYMBIAN32__ |
|
199 BackendFree((char *)fp->_bf._base); |
|
200 #else |
|
201 free((char *)fp->_bf._base); |
|
202 #endif//__SYMBIAN32__ |
|
203 } |
|
204 |
|
205 fp->_w = 0; |
|
206 fp->_r = 0; |
|
207 fp->_p = NULL; |
|
208 fp->_bf._base = NULL; |
|
209 fp->_bf._size = 0; |
|
210 fp->_lbfsize = 0; |
|
211 if (HASUB(fp)) |
|
212 FREEUB(fp); |
|
213 fp->_ub._size = 0; |
|
214 if (HASLB(fp)) |
|
215 FREELB(fp); |
|
216 fp->_lb._size = 0; |
|
217 fp->_extra->orientation = 0; |
|
218 memset(&fp->_extra->mbstate, 0, sizeof(mbstate_t)); |
|
219 |
|
220 if (f < 0) { /* did not get it after all */ |
|
221 fp->_flags = 0; /* set it free */ |
|
222 errno = sverrno; /* restore in case _close clobbered */ |
|
223 FUNLOCKFILE(fp); |
|
224 return (NULL); |
|
225 } |
|
226 #ifndef __SYMBIAN32__ |
|
227 /* |
|
228 * If reopening something that was open before on a real file, try |
|
229 * to maintain the descriptor. Various C library routines (perror) |
|
230 * assume stderr is always fd STDERR_FILENO, even if being freopen'd. |
|
231 */ |
|
232 if (wantfd >= 0 && f != wantfd) { |
|
233 if (dup2(f, wantfd) >= 0) { |
|
234 (void)_close(f); |
|
235 f = wantfd; |
|
236 } |
|
237 } |
|
238 #else |
|
239 if (wantfd >= 0 && f > wantfd){ |
|
240 if (dup2(f, wantfd) >= 0) { |
|
241 (void)_close(f); |
|
242 f = wantfd; |
|
243 } |
|
244 } |
|
245 #endif |
|
246 |
|
247 fp->_flags = flags; |
|
248 fp->_file = f; |
|
249 fp->_cookie = fp; |
|
250 fp->_read = __sread; |
|
251 fp->_write = __swrite; |
|
252 fp->_seek = __sseek; |
|
253 fp->_close = __sclose; |
|
254 #ifdef __SYMBIAN32__ |
|
255 if (oflags & O_TEXT) { |
|
256 fp->_extra->fmode = 't'; |
|
257 } |
|
258 else { |
|
259 fp->_extra->fmode = 'b'; |
|
260 } |
|
261 #endif |
|
262 FUNLOCKFILE(fp); |
|
263 return (fp); |
|
264 } |