1 | /* Copyright (c) 2000, 2012, Oracle and/or its affiliates |
2 | Copyright (c) 1985, 2011, Monty Program Ab |
3 | |
4 | This program is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by |
6 | the Free Software Foundation; version 2 of the License. |
7 | |
8 | This program is distributed in the hope that it will be useful, |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | GNU General Public License for more details. |
12 | |
13 | You should have received a copy of the GNU General Public License |
14 | along with this program; if not, write to the Free Software |
15 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ |
16 | |
17 | #include "mysys_priv.h" |
18 | #include "my_static.h" |
19 | #include <errno.h> |
20 | #include "mysys_err.h" |
21 | |
22 | static void make_ftype(char * to,int flag); |
23 | |
24 | /* |
25 | Open a file as stream |
26 | |
27 | SYNOPSIS |
28 | my_fopen() |
29 | FileName Path-name of file |
30 | Flags Read | write | append | trunc (like for open()) |
31 | MyFlags Flags for handling errors |
32 | |
33 | RETURN |
34 | 0 Error |
35 | # File handler |
36 | */ |
37 | |
38 | FILE *my_fopen(const char *filename, int flags, myf MyFlags) |
39 | { |
40 | FILE *fd; |
41 | char type[10]; |
42 | DBUG_ENTER("my_fopen" ); |
43 | DBUG_PRINT("my" ,("Name: '%s' flags: %d MyFlags: %lu" , |
44 | filename, flags, MyFlags)); |
45 | |
46 | make_ftype(type,flags); |
47 | |
48 | #ifdef _WIN32 |
49 | fd= my_win_fopen(filename, type); |
50 | #else |
51 | fd= fopen(filename, type); |
52 | #endif |
53 | if (fd != 0) |
54 | { |
55 | /* |
56 | The test works if MY_NFILE < 128. The problem is that fileno() is char |
57 | on some OS (SUNOS). Actually the filename save isn't that important |
58 | so we can ignore if this doesn't work. |
59 | */ |
60 | |
61 | int filedesc= my_fileno(fd); |
62 | if ((uint)filedesc >= my_file_limit) |
63 | { |
64 | statistic_increment(my_stream_opened,&THR_LOCK_open); |
65 | DBUG_RETURN(fd); /* safeguard */ |
66 | } |
67 | my_file_info[filedesc].name= (char*) my_strdup(filename,MyFlags); |
68 | statistic_increment(my_stream_opened, &THR_LOCK_open); |
69 | statistic_increment(my_file_total_opened, &THR_LOCK_open); |
70 | my_file_info[filedesc].type= STREAM_BY_FOPEN; |
71 | DBUG_PRINT("exit" ,("stream: %p" , fd)); |
72 | DBUG_RETURN(fd); |
73 | } |
74 | else |
75 | my_errno=errno; |
76 | DBUG_PRINT("error" ,("Got error %d on open" ,my_errno)); |
77 | if (MyFlags & (MY_FFNF | MY_FAE | MY_WME)) |
78 | my_error((flags & O_RDONLY) ? EE_FILENOTFOUND : EE_CANTCREATEFILE, |
79 | MYF(ME_BELL+ME_WAITTANG), filename, my_errno); |
80 | DBUG_RETURN((FILE*) 0); |
81 | } /* my_fopen */ |
82 | |
83 | |
84 | #if defined(_WIN32) |
85 | |
86 | static FILE *my_win_freopen(const char *path, const char *mode, FILE *stream) |
87 | { |
88 | int handle_fd, fd= _fileno(stream); |
89 | HANDLE osfh; |
90 | |
91 | DBUG_ASSERT(path && stream); |
92 | DBUG_ASSERT(strchr(mode, 'a')); /* We use FILE_APPEND_DATA below */ |
93 | |
94 | /* Services don't have stdout/stderr on Windows, so _fileno returns -1. */ |
95 | if (fd < 0) |
96 | { |
97 | if (!freopen(path, mode, stream)) |
98 | return NULL; |
99 | |
100 | fd= _fileno(stream); |
101 | } |
102 | |
103 | if ((osfh= CreateFile(path, GENERIC_READ | FILE_APPEND_DATA, |
104 | FILE_SHARE_READ | FILE_SHARE_WRITE | |
105 | FILE_SHARE_DELETE, NULL, |
106 | OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, |
107 | NULL)) == INVALID_HANDLE_VALUE) |
108 | return NULL; |
109 | |
110 | if ((handle_fd= _open_osfhandle((intptr_t)osfh, _O_TEXT)) == -1) |
111 | { |
112 | CloseHandle(osfh); |
113 | return NULL; |
114 | } |
115 | |
116 | if (_dup2(handle_fd, fd) < 0) |
117 | { |
118 | CloseHandle(osfh); |
119 | return NULL; |
120 | } |
121 | |
122 | _close(handle_fd); |
123 | |
124 | return stream; |
125 | } |
126 | |
127 | #endif |
128 | |
129 | |
130 | /** |
131 | Change the file associated with a file stream. |
132 | |
133 | @param path Path to file. |
134 | @param mode Mode of the stream. |
135 | @param stream File stream. |
136 | |
137 | @note |
138 | This function is used to redirect stdout and stderr to a file and |
139 | subsequently to close and reopen that file for log rotation. |
140 | |
141 | @retval A FILE pointer on success. Otherwise, NULL. |
142 | */ |
143 | |
144 | FILE *my_freopen(const char *path, const char *mode, FILE *stream) |
145 | { |
146 | FILE *result; |
147 | |
148 | #if defined(_WIN32) |
149 | result= my_win_freopen(path, mode, stream); |
150 | #else |
151 | result= freopen(path, mode, stream); |
152 | #endif |
153 | |
154 | return result; |
155 | } |
156 | |
157 | |
158 | /* Close a stream */ |
159 | int my_fclose(FILE *fd, myf MyFlags) |
160 | { |
161 | int err,file; |
162 | char *name= NULL; |
163 | DBUG_ENTER("my_fclose" ); |
164 | DBUG_PRINT("my" ,("stream: %p MyFlags: %lu" , fd, MyFlags)); |
165 | |
166 | file= my_fileno(fd); |
167 | if ((uint) file < my_file_limit && my_file_info[file].type != UNOPEN) |
168 | { |
169 | name= my_file_info[file].name; |
170 | my_file_info[file].name= NULL; |
171 | my_file_info[file].type= UNOPEN; |
172 | } |
173 | #ifndef _WIN32 |
174 | do |
175 | { |
176 | err= fclose(fd); |
177 | } while (err == -1 && errno == EINTR); |
178 | #else |
179 | err= my_win_fclose(fd); |
180 | #endif |
181 | if(err < 0) |
182 | { |
183 | my_errno=errno; |
184 | if (MyFlags & (MY_FAE | MY_WME)) |
185 | my_error(EE_BADCLOSE, MYF(ME_BELL+ME_WAITTANG), |
186 | name,errno); |
187 | } |
188 | else |
189 | statistic_decrement(my_stream_opened, &THR_LOCK_open); |
190 | |
191 | if (name) |
192 | { |
193 | my_free(name); |
194 | } |
195 | DBUG_RETURN(err); |
196 | } /* my_fclose */ |
197 | |
198 | |
199 | /* Make a stream out of a file handle */ |
200 | /* Name may be 0 */ |
201 | |
202 | FILE *my_fdopen(File Filedes, const char *name, int Flags, myf MyFlags) |
203 | { |
204 | FILE *fd; |
205 | char type[5]; |
206 | DBUG_ENTER("my_fdopen" ); |
207 | DBUG_PRINT("my" ,("fd: %d Flags: %d MyFlags: %lu" , |
208 | Filedes, Flags, MyFlags)); |
209 | |
210 | make_ftype(type,Flags); |
211 | #ifdef _WIN32 |
212 | fd= my_win_fdopen(Filedes, type); |
213 | #else |
214 | fd= fdopen(Filedes, type); |
215 | #endif |
216 | if (!fd) |
217 | { |
218 | my_errno=errno; |
219 | if (MyFlags & (MY_FAE | MY_WME)) |
220 | my_error(EE_CANT_OPEN_STREAM, MYF(ME_BELL+ME_WAITTANG),errno); |
221 | } |
222 | else |
223 | { |
224 | statistic_increment(my_stream_opened, &THR_LOCK_open); |
225 | if ((uint) Filedes < (uint) my_file_limit) |
226 | { |
227 | if (my_file_info[Filedes].type != UNOPEN) |
228 | { |
229 | statistic_decrement(my_file_opened, &THR_LOCK_open); /* File is opened with my_open ! */ |
230 | } |
231 | else |
232 | { |
233 | my_file_info[Filedes].name= my_strdup(name,MyFlags); |
234 | } |
235 | my_file_info[Filedes].type = STREAM_BY_FDOPEN; |
236 | } |
237 | } |
238 | |
239 | DBUG_PRINT("exit" ,("stream: %p" , fd)); |
240 | DBUG_RETURN(fd); |
241 | } /* my_fdopen */ |
242 | |
243 | |
244 | /* |
245 | Make a fopen() typestring from a open() type bitmap |
246 | |
247 | SYNOPSIS |
248 | make_ftype() |
249 | to String for fopen() is stored here |
250 | flag Flag used by open() |
251 | |
252 | IMPLEMENTATION |
253 | This routine attempts to find the best possible match |
254 | between a numeric option and a string option that could be |
255 | fed to fopen. There is not a 1 to 1 mapping between the two. |
256 | |
257 | NOTE |
258 | On Unix, O_RDONLY is usually 0 |
259 | |
260 | MAPPING |
261 | r == O_RDONLY |
262 | w == O_WRONLY|O_TRUNC|O_CREAT |
263 | a == O_WRONLY|O_APPEND|O_CREAT |
264 | r+ == O_RDWR |
265 | w+ == O_RDWR|O_TRUNC|O_CREAT |
266 | a+ == O_RDWR|O_APPEND|O_CREAT |
267 | b == FILE_BINARY |
268 | e == O_CLOEXEC |
269 | */ |
270 | |
271 | static void make_ftype(register char * to, register int flag) |
272 | { |
273 | /* check some possible invalid combinations */ |
274 | DBUG_ASSERT((flag & (O_TRUNC | O_APPEND)) != (O_TRUNC | O_APPEND)); |
275 | DBUG_ASSERT((flag & (O_WRONLY | O_RDWR)) != (O_WRONLY | O_RDWR)); |
276 | |
277 | if ((flag & (O_RDONLY|O_WRONLY)) == O_WRONLY) |
278 | *to++= (flag & O_APPEND) ? 'a' : 'w'; |
279 | else if (flag & O_RDWR) |
280 | { |
281 | /* Add '+' after theese */ |
282 | if (flag & (O_TRUNC | O_CREAT)) |
283 | *to++= 'w'; |
284 | else if (flag & O_APPEND) |
285 | *to++= 'a'; |
286 | else |
287 | *to++= 'r'; |
288 | *to++= '+'; |
289 | } |
290 | else |
291 | *to++= 'r'; |
292 | |
293 | if (flag & FILE_BINARY) |
294 | *to++='b'; |
295 | |
296 | if (O_CLOEXEC) |
297 | *to++= 'e'; |
298 | |
299 | *to='\0'; |
300 | } /* make_ftype */ |
301 | |