mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / mysys / my_lib.c
blob8bd9a2891764546cfe6d54418f26622acb9c2b57
1 /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
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.
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.
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.
17 /* TODO: check for overun of memory for names. */
18 /* Convert MSDOS-TIME to standar time_t (still needed?) */
20 #include "mysys_priv.h"
21 #include <m_string.h>
22 #include <my_dir.h> /* Structs used by my_dir,includes sys/types */
23 #include "mysys_err.h"
24 #if defined(HAVE_DIRENT_H)
25 # include <dirent.h>
26 # define NAMLEN(dirent) strlen((dirent)->d_name)
27 #else
28 # define dirent direct
29 # define NAMLEN(dirent) (dirent)->d_namlen
30 # if defined(HAVE_SYS_NDIR_H)
31 # include <sys/ndir.h>
32 # endif
33 # if defined(HAVE_SYS_DIR_H)
34 # include <sys/dir.h>
35 # endif
36 # if defined(HAVE_NDIR_H)
37 # include <ndir.h>
38 # endif
39 # if defined(__WIN__)
40 # include <dos.h>
41 # ifdef __BORLANDC__
42 # include <dir.h>
43 # endif
44 # endif
45 #endif
46 #ifdef VMS
47 #include <rms.h>
48 #include <iodef.h>
49 #include <descrip.h>
50 #endif
52 #if defined(THREAD) && defined(HAVE_READDIR_R)
53 #define READDIR(A,B,C) ((errno=readdir_r(A,B,&C)) != 0 || !C)
54 #else
55 #define READDIR(A,B,C) (!(C=readdir(A)))
56 #endif
59 We are assuming that directory we are reading is either has less than
60 100 files and so can be read in one initial chunk or has more than 1000
61 files and so big increment are suitable.
63 #define ENTRIES_START_SIZE (8192/sizeof(FILEINFO))
64 #define ENTRIES_INCREMENT (65536/sizeof(FILEINFO))
65 #define NAMES_START_SIZE 32768
68 static int comp_names(struct fileinfo *a,struct fileinfo *b);
71 /* We need this because program don't know with malloc we used */
73 void my_dirend(MY_DIR *buffer)
75 DBUG_ENTER("my_dirend");
76 if (buffer)
78 delete_dynamic((DYNAMIC_ARRAY*)((char*)buffer +
79 ALIGN_SIZE(sizeof(MY_DIR))));
80 free_root((MEM_ROOT*)((char*)buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
81 ALIGN_SIZE(sizeof(DYNAMIC_ARRAY))), MYF(0));
82 my_free((uchar*) buffer,MYF(0));
84 DBUG_VOID_RETURN;
85 } /* my_dirend */
88 /* Compare in sort of filenames */
90 static int comp_names(struct fileinfo *a, struct fileinfo *b)
92 return (strcmp(a->name,b->name));
93 } /* comp_names */
96 #if !defined(__WIN__)
98 MY_DIR *my_dir(const char *path, myf MyFlags)
100 char *buffer;
101 MY_DIR *result= 0;
102 FILEINFO finfo;
103 DYNAMIC_ARRAY *dir_entries_storage;
104 MEM_ROOT *names_storage;
105 DIR *dirp;
106 struct dirent *dp;
107 char tmp_path[FN_REFLEN + 2], *tmp_file;
108 #ifdef THREAD
109 char dirent_tmp[sizeof(struct dirent)+_POSIX_PATH_MAX+1];
110 #endif
111 DBUG_ENTER("my_dir");
112 DBUG_PRINT("my",("path: '%s' MyFlags: %d",path,MyFlags));
114 #if defined(THREAD) && !defined(HAVE_READDIR_R)
115 pthread_mutex_lock(&THR_LOCK_open);
116 #endif
118 dirp = opendir(directory_file_name(tmp_path,(char *) path));
119 #if defined(__amiga__)
120 if ((dirp->dd_fd) < 0) /* Directory doesn't exists */
121 goto error;
122 #endif
123 if (dirp == NULL ||
124 ! (buffer= my_malloc(ALIGN_SIZE(sizeof(MY_DIR)) +
125 ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)) +
126 sizeof(MEM_ROOT), MyFlags)))
127 goto error;
129 dir_entries_storage= (DYNAMIC_ARRAY*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)));
130 names_storage= (MEM_ROOT*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
131 ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)));
133 if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO),
134 ENTRIES_START_SIZE, ENTRIES_INCREMENT))
136 my_free((uchar*) buffer,MYF(0));
137 goto error;
139 init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE);
141 /* MY_DIR structure is allocated and completly initialized at this point */
142 result= (MY_DIR*)buffer;
144 tmp_file=strend(tmp_path);
146 #ifdef THREAD
147 dp= (struct dirent*) dirent_tmp;
148 #else
149 dp=0;
150 #endif
152 while (!(READDIR(dirp,(struct dirent*) dirent_tmp,dp)))
154 if (!(finfo.name= strdup_root(names_storage, dp->d_name)))
155 goto error;
157 if (MyFlags & MY_WANT_STAT)
159 if (!(finfo.mystat= (MY_STAT*)alloc_root(names_storage,
160 sizeof(MY_STAT))))
161 goto error;
163 bzero(finfo.mystat, sizeof(MY_STAT));
164 VOID(strmov(tmp_file,dp->d_name));
165 VOID(my_stat(tmp_path, finfo.mystat, MyFlags));
166 if (!(finfo.mystat->st_mode & MY_S_IREAD))
167 continue;
169 else
170 finfo.mystat= NULL;
172 if (push_dynamic(dir_entries_storage, (uchar*)&finfo))
173 goto error;
176 (void) closedir(dirp);
177 #if defined(THREAD) && !defined(HAVE_READDIR_R)
178 pthread_mutex_unlock(&THR_LOCK_open);
179 #endif
180 result->dir_entry= (FILEINFO *)dir_entries_storage->buffer;
181 result->number_off_files= dir_entries_storage->elements;
183 if (!(MyFlags & MY_DONT_SORT))
184 my_qsort((void *) result->dir_entry, result->number_off_files,
185 sizeof(FILEINFO), (qsort_cmp) comp_names);
186 DBUG_RETURN(result);
188 error:
189 #if defined(THREAD) && !defined(HAVE_READDIR_R)
190 pthread_mutex_unlock(&THR_LOCK_open);
191 #endif
192 my_errno=errno;
193 if (dirp)
194 (void) closedir(dirp);
195 my_dirend(result);
196 if (MyFlags & (MY_FAE | MY_WME))
197 my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,my_errno);
198 DBUG_RETURN((MY_DIR *) NULL);
199 } /* my_dir */
203 * Convert from directory name to filename.
204 * On VMS:
205 * xyzzy:[mukesh.emacs] => xyzzy:[mukesh]emacs.dir.1
206 * xyzzy:[mukesh] => xyzzy:[000000]mukesh.dir.1
207 * On UNIX, it's simple: just make sure there is a terminating /
209 * Returns pointer to dst;
212 char * directory_file_name (char * dst, const char *src)
214 #ifndef VMS
216 /* Process as Unix format: just remove test the final slash. */
218 char * end;
219 DBUG_ASSERT(strlen(src) < (FN_REFLEN + 1));
221 if (src[0] == 0)
222 src= (char*) "."; /* Use empty as current */
223 end= strnmov(dst, src, FN_REFLEN + 1);
224 if (end[-1] != FN_LIBCHAR)
226 end[0]=FN_LIBCHAR; /* Add last '/' */
227 end[1]='\0';
229 return dst;
231 #else /* VMS */
233 long slen;
234 long rlen;
235 char * ptr, rptr;
236 char bracket;
237 struct FAB fab = cc$rms_fab;
238 struct NAM nam = cc$rms_nam;
239 char esa[NAM$C_MAXRSS];
241 if (! src[0])
242 src="[.]"; /* Empty is == current dir */
244 slen = strlen (src) - 1;
245 if (src[slen] == FN_C_AFTER_DIR || src[slen] == FN_C_AFTER_DIR_2 ||
246 src[slen] == FN_DEVCHAR)
248 /* VMS style - convert [x.y.z] to [x.y]z, [x] to [000000]x */
249 fab.fab$l_fna = src;
250 fab.fab$b_fns = slen + 1;
251 fab.fab$l_nam = &nam;
252 fab.fab$l_fop = FAB$M_NAM;
254 nam.nam$l_esa = esa;
255 nam.nam$b_ess = sizeof esa;
256 nam.nam$b_nop |= NAM$M_SYNCHK;
258 /* We call SYS$PARSE to handle such things as [--] for us. */
259 if (SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL)
261 slen = nam.nam$b_esl - 1;
262 if (esa[slen] == ';' && esa[slen - 1] == '.')
263 slen -= 2;
264 esa[slen + 1] = '\0';
265 src = esa;
267 if (src[slen] != FN_C_AFTER_DIR && src[slen] != FN_C_AFTER_DIR_2)
269 /* what about when we have logical_name:???? */
270 if (src[slen] == FN_DEVCHAR)
271 { /* Xlate logical name and see what we get */
272 VOID(strmov(dst,src));
273 dst[slen] = 0; /* remove colon */
274 if (!(src = getenv (dst)))
275 return dst; /* Can't translate */
277 /* should we jump to the beginning of this procedure?
278 Good points: allows us to use logical names that xlate
279 to Unix names,
280 Bad points: can be a problem if we just translated to a device
281 name...
282 For now, I'll punt and always expect VMS names, and hope for
283 the best! */
285 slen = strlen (src) - 1;
286 if (src[slen] != FN_C_AFTER_DIR && src[slen] != FN_C_AFTER_DIR_2)
287 { /* no recursion here! */
288 VOID(strmov(dst, src));
289 return(dst);
292 else
293 { /* not a directory spec */
294 VOID(strmov(dst, src));
295 return(dst);
299 bracket = src[slen]; /* End char */
300 if (!(ptr = strchr (src, bracket - 2)))
301 { /* no opening bracket */
302 VOID(strmov (dst, src));
303 return dst;
305 if (!(rptr = strrchr (src, '.')))
306 rptr = ptr;
307 slen = rptr - src;
308 VOID(strmake (dst, src, slen));
310 if (*rptr == '.')
311 { /* Put bracket and add */
312 dst[slen++] = bracket; /* (rptr+1) after this */
314 else
316 /* If we have the top-level of a rooted directory (i.e. xx:[000000]),
317 then translate the device and recurse. */
319 if (dst[slen - 1] == ':'
320 && dst[slen - 2] != ':' /* skip decnet nodes */
321 && strcmp(src + slen, "[000000]") == 0)
323 dst[slen - 1] = '\0';
324 if ((ptr = getenv (dst))
325 && (rlen = strlen (ptr) - 1) > 0
326 && (ptr[rlen] == FN_C_AFTER_DIR || ptr[rlen] == FN_C_AFTER_DIR_2)
327 && ptr[rlen - 1] == '.')
329 VOID(strmov(esa,ptr));
330 esa[rlen - 1] = FN_C_AFTER_DIR;
331 esa[rlen] = '\0';
332 return (directory_file_name (dst, esa));
334 else
335 dst[slen - 1] = ':';
337 VOID(strmov(dst+slen,"[000000]"));
338 slen += 8;
340 VOID(strmov(strmov(dst+slen,rptr+1)-1,".DIR.1"));
341 return dst;
343 VOID(strmov(dst, src));
344 if (dst[slen] == '/' && slen > 1)
345 dst[slen] = 0;
346 return dst;
347 #endif /* VMS */
348 } /* directory_file_name */
350 #else
353 *****************************************************************************
354 ** Read long filename using windows rutines
355 *****************************************************************************
358 MY_DIR *my_dir(const char *path, myf MyFlags)
360 char *buffer;
361 MY_DIR *result= 0;
362 FILEINFO finfo;
363 DYNAMIC_ARRAY *dir_entries_storage;
364 MEM_ROOT *names_storage;
365 #ifdef __BORLANDC__
366 struct ffblk find;
367 #else
368 struct _finddata_t find;
369 #endif
370 ushort mode;
371 char tmp_path[FN_REFLEN],*tmp_file,attrib;
372 #ifdef _WIN64
373 __int64 handle;
374 #else
375 long handle;
376 #endif
377 DBUG_ENTER("my_dir");
378 DBUG_PRINT("my",("path: '%s' stat: %d MyFlags: %d",path,MyFlags));
380 /* Put LIB-CHAR as last path-character if not there */
381 tmp_file=tmp_path;
382 if (!*path)
383 *tmp_file++ ='.'; /* From current dir */
384 tmp_file= strnmov(tmp_file, path, FN_REFLEN-5);
385 if (tmp_file[-1] == FN_DEVCHAR)
386 *tmp_file++= '.'; /* From current dev-dir */
387 if (tmp_file[-1] != FN_LIBCHAR)
388 *tmp_file++ =FN_LIBCHAR;
389 tmp_file[0]='*'; /* Windows needs this !??? */
390 tmp_file[1]='.';
391 tmp_file[2]='*';
392 tmp_file[3]='\0';
394 if (!(buffer= my_malloc(ALIGN_SIZE(sizeof(MY_DIR)) +
395 ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)) +
396 sizeof(MEM_ROOT), MyFlags)))
397 goto error;
399 dir_entries_storage= (DYNAMIC_ARRAY*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)));
400 names_storage= (MEM_ROOT*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
401 ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)));
403 if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO),
404 ENTRIES_START_SIZE, ENTRIES_INCREMENT))
406 my_free((uchar*) buffer,MYF(0));
407 goto error;
409 init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE);
411 /* MY_DIR structure is allocated and completly initialized at this point */
412 result= (MY_DIR*)buffer;
414 #ifdef __BORLANDC__
415 if ((handle= findfirst(tmp_path,&find,0)) == -1L)
416 #else
417 if ((handle=_findfirst(tmp_path,&find)) == -1L)
418 #endif
420 DBUG_PRINT("info", ("findfirst returned error, errno: %d", errno));
421 if (errno != EINVAL)
422 goto error;
424 Could not read the directory, no read access.
425 Probably because by "chmod -r".
426 continue and return zero files in dir
429 else
434 #ifdef __BORLANDC__
435 attrib= find.ff_attrib;
436 #else
437 attrib= find.attrib;
439 Do not show hidden and system files which Windows sometimes create.
440 Note. Because Borland's findfirst() is called with the third
441 argument = 0 hidden/system files are excluded from the search.
443 if (attrib & (_A_HIDDEN | _A_SYSTEM))
444 continue;
445 #endif
446 #ifdef __BORLANDC__
447 if (!(finfo.name= strdup_root(names_storage, find.ff_name)))
448 goto error;
449 #else
450 if (!(finfo.name= strdup_root(names_storage, find.name)))
451 goto error;
452 #endif
453 if (MyFlags & MY_WANT_STAT)
455 if (!(finfo.mystat= (MY_STAT*)alloc_root(names_storage,
456 sizeof(MY_STAT))))
457 goto error;
459 bzero(finfo.mystat, sizeof(MY_STAT));
460 #ifdef __BORLANDC__
461 finfo.mystat->st_size=find.ff_fsize;
462 #else
463 finfo.mystat->st_size=find.size;
464 #endif
465 mode= MY_S_IREAD;
466 if (!(attrib & _A_RDONLY))
467 mode|= MY_S_IWRITE;
468 if (attrib & _A_SUBDIR)
469 mode|= MY_S_IFDIR;
470 finfo.mystat->st_mode= mode;
471 #ifdef __BORLANDC__
472 finfo.mystat->st_mtime= ((uint32) find.ff_ftime);
473 #else
474 finfo.mystat->st_mtime= ((uint32) find.time_write);
475 #endif
477 else
478 finfo.mystat= NULL;
480 if (push_dynamic(dir_entries_storage, (uchar*)&finfo))
481 goto error;
483 #ifdef __BORLANDC__
484 while (findnext(&find) == 0);
485 #else
486 while (_findnext(handle,&find) == 0);
488 _findclose(handle);
489 #endif
492 result->dir_entry= (FILEINFO *)dir_entries_storage->buffer;
493 result->number_off_files= dir_entries_storage->elements;
495 if (!(MyFlags & MY_DONT_SORT))
496 my_qsort((void *) result->dir_entry, result->number_off_files,
497 sizeof(FILEINFO), (qsort_cmp) comp_names);
498 DBUG_PRINT("exit", ("found %d files", result->number_off_files));
499 DBUG_RETURN(result);
500 error:
501 my_errno=errno;
502 #ifndef __BORLANDC__
503 if (handle != -1)
504 _findclose(handle);
505 #endif
506 my_dirend(result);
507 if (MyFlags & MY_FAE+MY_WME)
508 my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,errno);
509 DBUG_RETURN((MY_DIR *) NULL);
510 } /* my_dir */
512 #endif /* __WIN__ */
514 /****************************************************************************
515 ** File status
516 ** Note that MY_STAT is assumed to be same as struct stat
517 ****************************************************************************/
519 int my_fstat(int Filedes, MY_STAT *stat_area,
520 myf MyFlags __attribute__((unused)))
522 DBUG_ENTER("my_fstat");
523 DBUG_PRINT("my",("fd: %d MyFlags: %d", Filedes, MyFlags));
524 DBUG_RETURN(fstat(Filedes, (struct stat *) stat_area));
528 MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags)
530 int m_used;
531 DBUG_ENTER("my_stat");
532 DBUG_PRINT("my", ("path: '%s' stat_area: 0x%lx MyFlags: %d", path,
533 (long) stat_area, my_flags));
535 if ((m_used= (stat_area == NULL)))
536 if (!(stat_area = (MY_STAT *) my_malloc(sizeof(MY_STAT), my_flags)))
537 goto error;
538 if (! stat((char *) path, (struct stat *) stat_area) )
539 DBUG_RETURN(stat_area);
541 DBUG_PRINT("error",("Got errno: %d from stat", errno));
542 my_errno= errno;
543 if (m_used) /* Free if new area */
544 my_free((uchar*) stat_area,MYF(0));
546 error:
547 if (my_flags & (MY_FAE+MY_WME))
549 my_error(EE_STAT, MYF(ME_BELL+ME_WAITTANG),path,my_errno);
550 DBUG_RETURN((MY_STAT *) NULL);
552 DBUG_RETURN((MY_STAT *) NULL);
553 } /* my_stat */