MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
my_fopen.c
1 /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
15 
16 #include "mysys_priv.h"
17 #include "my_static.h"
18 #include <errno.h>
19 #include "mysys_err.h"
20 
21 #if defined(__FreeBSD__)
22 extern int getosreldate(void);
23 #endif
24 
25 static void make_ftype(char * to,int flag);
26 
27 /*
28  Open a file as stream
29 
30  SYNOPSIS
31  my_fopen()
32  FileName Path-name of file
33  Flags Read | write | append | trunc (like for open())
34  MyFlags Flags for handling errors
35 
36  RETURN
37  0 Error
38  # File handler
39 */
40 
41 FILE *my_fopen(const char *filename, int flags, myf MyFlags)
42 {
43  FILE *fd;
44  char type[5];
45  DBUG_ENTER("my_fopen");
46  DBUG_PRINT("my",("Name: '%s' flags: %d MyFlags: %d",
47  filename, flags, MyFlags));
48 
49  make_ftype(type,flags);
50 
51 #ifdef _WIN32
52  fd= my_win_fopen(filename, type);
53 #else
54  fd= fopen(filename, type);
55 #endif
56  if (fd != 0)
57  {
58  /*
59  The test works if MY_NFILE < 128. The problem is that fileno() is char
60  on some OS (SUNOS). Actually the filename save isn't that important
61  so we can ignore if this doesn't work.
62  */
63 
64  int filedesc= my_fileno(fd);
65  if ((uint)filedesc >= my_file_limit)
66  {
67  thread_safe_increment(my_stream_opened,&THR_LOCK_open);
68  DBUG_RETURN(fd); /* safeguard */
69  }
70  mysql_mutex_lock(&THR_LOCK_open);
71  if ((my_file_info[filedesc].name= (char*)
72  my_strdup(filename,MyFlags)))
73  {
74  my_stream_opened++;
75  my_file_total_opened++;
76  my_file_info[filedesc].type= STREAM_BY_FOPEN;
77  mysql_mutex_unlock(&THR_LOCK_open);
78  DBUG_PRINT("exit",("stream: 0x%lx", (long) fd));
79  DBUG_RETURN(fd);
80  }
81  mysql_mutex_unlock(&THR_LOCK_open);
82  (void) my_fclose(fd,MyFlags);
83  my_errno=ENOMEM;
84  }
85  else
86  my_errno=errno;
87  DBUG_PRINT("error",("Got error %d on open",my_errno));
88  if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))
89  {
90  char errbuf[MYSYS_STRERROR_SIZE];
91  my_error((flags & O_RDONLY) || (flags == O_RDONLY ) ? EE_FILENOTFOUND :
92  EE_CANTCREATEFILE,
93  MYF(ME_BELL+ME_WAITTANG), filename,
94  my_errno, my_strerror(errbuf, sizeof(errbuf), my_errno));
95  }
96  DBUG_RETURN((FILE*) 0);
97 } /* my_fopen */
98 
99 
100 #if defined(_WIN32)
101 
102 static FILE *my_win_freopen(const char *path, const char *mode, FILE *stream)
103 {
104  int handle_fd, fd= _fileno(stream);
105  HANDLE osfh;
106 
107  DBUG_ASSERT(path && stream);
108 
109  /* Services don't have stdout/stderr on Windows, so _fileno returns -1. */
110  if (fd < 0)
111  {
112  if (!freopen(path, mode, stream))
113  return NULL;
114 
115  fd= _fileno(stream);
116  }
117 
118  if ((osfh= CreateFile(path, GENERIC_READ | GENERIC_WRITE,
119  FILE_SHARE_READ | FILE_SHARE_WRITE |
120  FILE_SHARE_DELETE, NULL,
121  OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,
122  NULL)) == INVALID_HANDLE_VALUE)
123  return NULL;
124 
125  if ((handle_fd= _open_osfhandle((intptr_t)osfh,
126  _O_APPEND | _O_TEXT)) == -1)
127  {
128  CloseHandle(osfh);
129  return NULL;
130  }
131 
132  if (_dup2(handle_fd, fd) < 0)
133  {
134  CloseHandle(osfh);
135  return NULL;
136  }
137 
138  _close(handle_fd);
139 
140  return stream;
141 }
142 
143 #elif defined(__FreeBSD__)
144 
145 /* No close operation hook. */
146 
147 static int no_close(void *cookie __attribute__((unused)))
148 {
149  return 0;
150 }
151 
152 /*
153  A hack around a race condition in the implementation of freopen.
154 
155  The race condition steams from the fact that the current fd of
156  the stream is closed before its number is used to duplicate the
157  new file descriptor. This defeats the desired atomicity of the
158  close and duplicate of dup2().
159 
160  See PR number 79887 for reference:
161  http://www.freebsd.org/cgi/query-pr.cgi?pr=79887
162 */
163 
164 static FILE *my_freebsd_freopen(const char *path, const char *mode, FILE *stream)
165 {
166  int old_fd;
167  FILE *result;
168 
169  flockfile(stream);
170 
171  old_fd= fileno(stream);
172 
173  /* Use a no operation close hook to avoid having the fd closed. */
174  stream->_close= no_close;
175 
176  /* Relies on the implicit dup2 to close old_fd. */
177  result= freopen(path, mode, stream);
178 
179  /* If successful, the _close hook was replaced. */
180 
181  if (result == NULL)
182  close(old_fd);
183  else
184  funlockfile(result);
185 
186  return result;
187 }
188 
189 #endif
190 
191 
206 FILE *my_freopen(const char *path, const char *mode, FILE *stream)
207 {
208  FILE *result;
209 
210 #if defined(_WIN32)
211  result= my_win_freopen(path, mode, stream);
212 #elif defined(__FreeBSD__)
213  /*
214  XXX: Once the fix is ported to the stable releases, this should
215  be dependent upon the specific FreeBSD versions. Check at:
216  http://www.freebsd.org/cgi/query-pr.cgi?pr=79887
217  */
218  if (getosreldate() > 900027)
219  result= freopen(path, mode, stream);
220  else
221  result= my_freebsd_freopen(path, mode, stream);
222 #else
223  result= freopen(path, mode, stream);
224 #endif
225 
226  return result;
227 }
228 
229 
230 /* Close a stream */
231 int my_fclose(FILE *fd, myf MyFlags)
232 {
233  int err,file;
234  DBUG_ENTER("my_fclose");
235  DBUG_PRINT("my",("stream: 0x%lx MyFlags: %d", (long) fd, MyFlags));
236 
237  mysql_mutex_lock(&THR_LOCK_open);
238  file= my_fileno(fd);
239 #ifndef _WIN32
240  err= fclose(fd);
241 #else
242  err= my_win_fclose(fd);
243 #endif
244  if(err < 0)
245  {
246  my_errno=errno;
247  if (MyFlags & (MY_FAE | MY_WME))
248  {
249  char errbuf[MYSYS_STRERROR_SIZE];
250  my_error(EE_BADCLOSE, MYF(ME_BELL+ME_WAITTANG), my_filename(file),
251  my_errno, my_strerror(errbuf, sizeof(errbuf), my_errno));
252  }
253  }
254  else
255  my_stream_opened--;
256  if ((uint) file < my_file_limit && my_file_info[file].type != UNOPEN)
257  {
258  my_file_info[file].type = UNOPEN;
259  my_free(my_file_info[file].name);
260  }
261  mysql_mutex_unlock(&THR_LOCK_open);
262  DBUG_RETURN(err);
263 } /* my_fclose */
264 
265 
266  /* Make a stream out of a file handle */
267  /* Name may be 0 */
268 
269 FILE *my_fdopen(File Filedes, const char *name, int Flags, myf MyFlags)
270 {
271  FILE *fd;
272  char type[5];
273  DBUG_ENTER("my_fdopen");
274  DBUG_PRINT("my",("Fd: %d Flags: %d MyFlags: %d",
275  Filedes, Flags, MyFlags));
276 
277  make_ftype(type,Flags);
278 #ifdef _WIN32
279  fd= my_win_fdopen(Filedes, type);
280 #else
281  fd= fdopen(Filedes, type);
282 #endif
283  if (!fd)
284  {
285  my_errno=errno;
286  if (MyFlags & (MY_FAE | MY_WME))
287  {
288  char errbuf[MYSYS_STRERROR_SIZE];
289  my_error(EE_CANT_OPEN_STREAM, MYF(ME_BELL+ME_WAITTANG),
290  my_errno, my_strerror(errbuf, sizeof(errbuf), my_errno));
291  }
292  }
293  else
294  {
295  mysql_mutex_lock(&THR_LOCK_open);
296  my_stream_opened++;
297  if ((uint) Filedes < (uint) my_file_limit)
298  {
299  if (my_file_info[Filedes].type != UNOPEN)
300  {
301  my_file_opened--; /* File is opened with my_open ! */
302  }
303  else
304  {
305  my_file_info[Filedes].name= my_strdup(name,MyFlags);
306  }
307  my_file_info[Filedes].type = STREAM_BY_FDOPEN;
308  }
309  mysql_mutex_unlock(&THR_LOCK_open);
310  }
311 
312  DBUG_PRINT("exit",("stream: 0x%lx", (long) fd));
313  DBUG_RETURN(fd);
314 } /* my_fdopen */
315 
316 
317 /*
318  Make a fopen() typestring from a open() type bitmap
319 
320  SYNOPSIS
321  make_ftype()
322  to String for fopen() is stored here
323  flag Flag used by open()
324 
325  IMPLEMENTATION
326  This routine attempts to find the best possible match
327  between a numeric option and a string option that could be
328  fed to fopen. There is not a 1 to 1 mapping between the two.
329 
330  NOTE
331  On Unix, O_RDONLY is usually 0
332 
333  MAPPING
334  r == O_RDONLY
335  w == O_WRONLY|O_TRUNC|O_CREAT
336  a == O_WRONLY|O_APPEND|O_CREAT
337  r+ == O_RDWR
338  w+ == O_RDWR|O_TRUNC|O_CREAT
339  a+ == O_RDWR|O_APPEND|O_CREAT
340 */
341 
342 static void make_ftype(register char * to, register int flag)
343 {
344  /* check some possible invalid combinations */
345  DBUG_ASSERT((flag & (O_TRUNC | O_APPEND)) != (O_TRUNC | O_APPEND));
346  DBUG_ASSERT((flag & (O_WRONLY | O_RDWR)) != (O_WRONLY | O_RDWR));
347 
348  if ((flag & (O_RDONLY|O_WRONLY)) == O_WRONLY)
349  *to++= (flag & O_APPEND) ? 'a' : 'w';
350  else if (flag & O_RDWR)
351  {
352  /* Add '+' after theese */
353  if (flag & (O_TRUNC | O_CREAT))
354  *to++= 'w';
355  else if (flag & O_APPEND)
356  *to++= 'a';
357  else
358  *to++= 'r';
359  *to++= '+';
360  }
361  else
362  *to++= 'r';
363 
364 #if FILE_BINARY /* If we have binary-files */
365  if (flag & FILE_BINARY)
366  *to++='b';
367 #endif
368  *to='\0';
369 } /* make_ftype */