MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
my_lib.c
1 /* Copyright (c) 2000, 2013, 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 
17 /* TODO: check for overun of memory for names. */
18 
19 #include "mysys_priv.h"
20 #include <m_string.h>
21 #include <my_dir.h> /* Structs used by my_dir,includes sys/types */
22 #include "mysys_err.h"
23 #if defined(HAVE_DIRENT_H)
24 # include <dirent.h>
25 # define NAMLEN(dirent) strlen((dirent)->d_name)
26 #else
27 # define dirent direct
28 # define NAMLEN(dirent) (dirent)->d_namlen
29 # if defined(HAVE_SYS_NDIR_H)
30 # include <sys/ndir.h>
31 # endif
32 # if defined(HAVE_SYS_DIR_H)
33 # include <sys/dir.h>
34 # endif
35 # if defined(HAVE_NDIR_H)
36 # include <ndir.h>
37 # endif
38 # if defined(_WIN32)
39 # ifdef __BORLANDC__
40 # include <dir.h>
41 # endif
42 # endif
43 #endif
44 
45 #if defined(HAVE_READDIR_R)
46 #define READDIR(A,B,C) ((errno=readdir_r(A,B,&C)) != 0 || !C)
47 #else
48 #define READDIR(A,B,C) (!(C=readdir(A)))
49 #endif
50 
51 /*
52  We are assuming that directory we are reading is either has less than
53  100 files and so can be read in one initial chunk or has more than 1000
54  files and so big increment are suitable.
55 */
56 #define ENTRIES_START_SIZE (8192/sizeof(FILEINFO))
57 #define ENTRIES_INCREMENT (65536/sizeof(FILEINFO))
58 #define NAMES_START_SIZE 32768
59 
60 
61 static int comp_names(struct fileinfo *a,struct fileinfo *b);
62 
63 
64  /* We need this because program don't know with malloc we used */
65 
66 void my_dirend(MY_DIR *buffer)
67 {
68  DBUG_ENTER("my_dirend");
69  if (buffer)
70  {
71  delete_dynamic((DYNAMIC_ARRAY*)((char*)buffer +
72  ALIGN_SIZE(sizeof(MY_DIR))));
73  free_root((MEM_ROOT*)((char*)buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
74  ALIGN_SIZE(sizeof(DYNAMIC_ARRAY))), MYF(0));
75  my_free(buffer);
76  }
77  DBUG_VOID_RETURN;
78 } /* my_dirend */
79 
80 
81  /* Compare in sort of filenames */
82 
83 static int comp_names(struct fileinfo *a, struct fileinfo *b)
84 {
85  return (strcmp(a->name,b->name));
86 } /* comp_names */
87 
88 
89 #if !defined(_WIN32)
90 
91 MY_DIR *my_dir(const char *path, myf MyFlags)
92 {
93  char *buffer;
94  MY_DIR *result= 0;
95  FILEINFO finfo;
96  DYNAMIC_ARRAY *dir_entries_storage;
97  MEM_ROOT *names_storage;
98  DIR *dirp;
99  struct dirent *dp;
100  char tmp_path[FN_REFLEN + 2], *tmp_file;
101  char dirent_tmp[sizeof(struct dirent)+_POSIX_PATH_MAX+1];
102 
103  DBUG_ENTER("my_dir");
104  DBUG_PRINT("my",("path: '%s' MyFlags: %d",path,MyFlags));
105 
106 #if !defined(HAVE_READDIR_R)
107  mysql_mutex_lock(&THR_LOCK_open);
108 #endif
109 
110  dirp = opendir(directory_file_name(tmp_path,(char *) path));
111 #if defined(__amiga__)
112  if ((dirp->dd_fd) < 0) /* Directory doesn't exists */
113  goto error;
114 #endif
115  if (dirp == NULL ||
116  ! (buffer= my_malloc(ALIGN_SIZE(sizeof(MY_DIR)) +
117  ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)) +
118  sizeof(MEM_ROOT), MyFlags)))
119  goto error;
120 
121  dir_entries_storage= (DYNAMIC_ARRAY*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)));
122  names_storage= (MEM_ROOT*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
123  ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)));
124 
125  if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO),
126  ENTRIES_START_SIZE, ENTRIES_INCREMENT))
127  {
128  my_free(buffer);
129  goto error;
130  }
131  init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE);
132 
133  /* MY_DIR structure is allocated and completly initialized at this point */
134  result= (MY_DIR*)buffer;
135 
136  tmp_file=strend(tmp_path);
137 
138  dp= (struct dirent*) dirent_tmp;
139 
140  while (!(READDIR(dirp,(struct dirent*) dirent_tmp,dp)))
141  {
142  if (!(finfo.name= strdup_root(names_storage, dp->d_name)))
143  goto error;
144 
145  if (MyFlags & MY_WANT_STAT)
146  {
147  if (!(finfo.mystat= (MY_STAT*)alloc_root(names_storage,
148  sizeof(MY_STAT))))
149  goto error;
150 
151  memset(finfo.mystat, 0, sizeof(MY_STAT));
152  (void) strmov(tmp_file,dp->d_name);
153  (void) my_stat(tmp_path, finfo.mystat, MyFlags);
154  if (!(finfo.mystat->st_mode & MY_S_IREAD))
155  continue;
156  }
157  else
158  finfo.mystat= NULL;
159 
160  if (push_dynamic(dir_entries_storage, (uchar*)&finfo))
161  goto error;
162  }
163 
164  (void) closedir(dirp);
165 #if !defined(HAVE_READDIR_R)
166  mysql_mutex_unlock(&THR_LOCK_open);
167 #endif
168  result->dir_entry= (FILEINFO *)dir_entries_storage->buffer;
169  result->number_off_files= dir_entries_storage->elements;
170 
171  if (!(MyFlags & MY_DONT_SORT))
172  my_qsort((void *) result->dir_entry, result->number_off_files,
173  sizeof(FILEINFO), (qsort_cmp) comp_names);
174  DBUG_RETURN(result);
175 
176  error:
177 #if !defined(HAVE_READDIR_R)
178  mysql_mutex_unlock(&THR_LOCK_open);
179 #endif
180  my_errno=errno;
181  if (dirp)
182  (void) closedir(dirp);
183  my_dirend(result);
184  if (MyFlags & (MY_FAE | MY_WME))
185  {
186  char errbuf[MYSYS_STRERROR_SIZE];
187  my_error(EE_DIR, MYF(ME_BELL+ME_WAITTANG), path,
188  my_errno, my_strerror(errbuf, sizeof(errbuf), my_errno));
189  }
190  DBUG_RETURN((MY_DIR *) NULL);
191 } /* my_dir */
192 
193 
194 /*
195  * Convert from directory name to filename.
196  * On UNIX, it's simple: just make sure there is a terminating /
197 
198  * Returns pointer to dst;
199  */
200 
201 char * directory_file_name (char * dst, const char *src)
202 {
203  /* Process as Unix format: just remove test the final slash. */
204  char *end;
205  DBUG_ASSERT(strlen(src) < (FN_REFLEN + 1));
206 
207  if (src[0] == 0)
208  src= (char*) "."; /* Use empty as current */
209  end= strnmov(dst, src, FN_REFLEN + 1);
210  if (end[-1] != FN_LIBCHAR)
211  {
212  end[0]=FN_LIBCHAR; /* Add last '/' */
213  end[1]='\0';
214  }
215  return dst;
216 }
217 
218 #else
219 
220 /*
221 *****************************************************************************
222 ** Read long filename using windows rutines
223 *****************************************************************************
224 */
225 
226 MY_DIR *my_dir(const char *path, myf MyFlags)
227 {
228  char *buffer;
229  MY_DIR *result= 0;
230  FILEINFO finfo;
231  DYNAMIC_ARRAY *dir_entries_storage;
232  MEM_ROOT *names_storage;
233 #ifdef __BORLANDC__
234  struct ffblk find;
235 #else
236  struct _finddata_t find;
237 #endif
238  ushort mode;
239  char tmp_path[FN_REFLEN],*tmp_file,attrib;
240 #ifdef _WIN64
241  __int64 handle;
242 #else
243  long handle;
244 #endif
245  DBUG_ENTER("my_dir");
246  DBUG_PRINT("my",("path: '%s' stat: %d MyFlags: %d",path,MyFlags));
247 
248  /* Put LIB-CHAR as last path-character if not there */
249  tmp_file=tmp_path;
250  if (!*path)
251  *tmp_file++ ='.'; /* From current dir */
252  tmp_file= strnmov(tmp_file, path, FN_REFLEN-5);
253  if (tmp_file[-1] == FN_DEVCHAR)
254  *tmp_file++= '.'; /* From current dev-dir */
255  if (tmp_file[-1] != FN_LIBCHAR)
256  *tmp_file++ =FN_LIBCHAR;
257  tmp_file[0]='*'; /* Windows needs this !??? */
258  tmp_file[1]='.';
259  tmp_file[2]='*';
260  tmp_file[3]='\0';
261 
262  if (!(buffer= my_malloc(ALIGN_SIZE(sizeof(MY_DIR)) +
263  ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)) +
264  sizeof(MEM_ROOT), MyFlags)))
265  goto error;
266 
267  dir_entries_storage= (DYNAMIC_ARRAY*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)));
268  names_storage= (MEM_ROOT*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
269  ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)));
270 
271  if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO),
272  ENTRIES_START_SIZE, ENTRIES_INCREMENT))
273  {
274  my_free(buffer);
275  goto error;
276  }
277  init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE);
278 
279  /* MY_DIR structure is allocated and completly initialized at this point */
280  result= (MY_DIR*)buffer;
281 
282 #ifdef __BORLANDC__
283  if ((handle= findfirst(tmp_path,&find,0)) == -1L)
284 #else
285  if ((handle=_findfirst(tmp_path,&find)) == -1L)
286 #endif
287  {
288  DBUG_PRINT("info", ("findfirst returned error, errno: %d", errno));
289  if (errno != EINVAL)
290  goto error;
291  /*
292  Could not read the directory, no read access.
293  Probably because by "chmod -r".
294  continue and return zero files in dir
295  */
296  }
297  else
298  {
299 
300  do
301  {
302 #ifdef __BORLANDC__
303  attrib= find.ff_attrib;
304 #else
305  attrib= find.attrib;
306  /*
307  Do not show hidden and system files which Windows sometimes create.
308  Note. Because Borland's findfirst() is called with the third
309  argument = 0 hidden/system files are excluded from the search.
310  */
311  if (attrib & (_A_HIDDEN | _A_SYSTEM))
312  continue;
313 #endif
314 #ifdef __BORLANDC__
315  if (!(finfo.name= strdup_root(names_storage, find.ff_name)))
316  goto error;
317 #else
318  if (!(finfo.name= strdup_root(names_storage, find.name)))
319  goto error;
320 #endif
321  if (MyFlags & MY_WANT_STAT)
322  {
323  if (!(finfo.mystat= (MY_STAT*)alloc_root(names_storage,
324  sizeof(MY_STAT))))
325  goto error;
326 
327  memset(finfo.mystat, 0, sizeof(MY_STAT));
328 #ifdef __BORLANDC__
329  finfo.mystat->st_size=find.ff_fsize;
330 #else
331  finfo.mystat->st_size=find.size;
332 #endif
333  mode= MY_S_IREAD;
334  if (!(attrib & _A_RDONLY))
335  mode|= MY_S_IWRITE;
336  if (attrib & _A_SUBDIR)
337  mode|= MY_S_IFDIR;
338  finfo.mystat->st_mode= mode;
339 #ifdef __BORLANDC__
340  finfo.mystat->st_mtime= ((uint32) find.ff_ftime);
341 #else
342  finfo.mystat->st_mtime= ((uint32) find.time_write);
343 #endif
344  }
345  else
346  finfo.mystat= NULL;
347 
348  if (push_dynamic(dir_entries_storage, (uchar*)&finfo))
349  goto error;
350  }
351 #ifdef __BORLANDC__
352  while (findnext(&find) == 0);
353 #else
354  while (_findnext(handle,&find) == 0);
355 
356  _findclose(handle);
357 #endif
358  }
359 
360  result->dir_entry= (FILEINFO *)dir_entries_storage->buffer;
361  result->number_off_files= dir_entries_storage->elements;
362 
363  if (!(MyFlags & MY_DONT_SORT))
364  my_qsort((void *) result->dir_entry, result->number_off_files,
365  sizeof(FILEINFO), (qsort_cmp) comp_names);
366  DBUG_PRINT("exit", ("found %d files", result->number_off_files));
367  DBUG_RETURN(result);
368 error:
369  my_errno=errno;
370 #ifndef __BORLANDC__
371  if (handle != -1)
372  _findclose(handle);
373 #endif
374  my_dirend(result);
375  if (MyFlags & MY_FAE+MY_WME)
376  {
377  char errbuf[MYSYS_STRERROR_SIZE];
378  my_error(EE_DIR, MYF(ME_BELL+ME_WAITTANG), path,
379  errno, my_strerror(errbuf, sizeof(errbuf), errno));
380  }
381  DBUG_RETURN((MY_DIR *) NULL);
382 } /* my_dir */
383 
384 #endif /* _WIN32 */
385 
386 /****************************************************************************
387 ** File status
388 ** Note that MY_STAT is assumed to be same as struct stat
389 ****************************************************************************/
390 
391 
392 int my_fstat(File Filedes, MY_STAT *stat_area,
393  myf MyFlags __attribute__((unused)))
394 {
395  DBUG_ENTER("my_fstat");
396  DBUG_PRINT("my",("fd: %d MyFlags: %d", Filedes, MyFlags));
397 #ifdef _WIN32
398  DBUG_RETURN(my_win_fstat(Filedes, stat_area));
399 #else
400  DBUG_RETURN(fstat(Filedes, (struct stat *) stat_area));
401 #endif
402 }
403 
404 
405 MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags)
406 {
407  const int m_used= (stat_area == NULL);
408  DBUG_ENTER("my_stat");
409  DBUG_PRINT("my", ("path: '%s' stat_area: 0x%lx MyFlags: %d", path,
410  (long) stat_area, my_flags));
411 
412  if (m_used)
413  if (!(stat_area= (MY_STAT *) my_malloc(sizeof(MY_STAT), my_flags)))
414  goto error;
415 #ifndef _WIN32
416  if (! stat((char *) path, (struct stat *) stat_area) )
417  DBUG_RETURN(stat_area);
418 #else
419  if (! my_win_stat(path, stat_area) )
420  DBUG_RETURN(stat_area);
421 #endif
422  DBUG_PRINT("error",("Got errno: %d from stat", errno));
423  my_errno= errno;
424  if (m_used) /* Free if new area */
425  my_free(stat_area);
426 
427 error:
428  if (my_flags & (MY_FAE+MY_WME))
429  {
430  char errbuf[MYSYS_STRERROR_SIZE];
431  my_error(EE_STAT, MYF(ME_BELL+ME_WAITTANG), path,
432  my_errno, my_strerror(errbuf, sizeof(errbuf), my_errno));
433  DBUG_RETURN((MY_STAT *) NULL);
434  }
435  DBUG_RETURN((MY_STAT *) NULL);
436 } /* my_stat */