starfix: HoR fix!!! wave+team check fix+2 bos jalan...kurang LK nya + PR:lootannya...
[st4rcore.git] / dep / mysqllite / mysys / my_lib.c
blobc18d14fb54989b27869c7f090bfe90c68fba7d64
1 /* Copyright (C) 2000 MySQL AB
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16 /* TODO: check for overun of memory for names. */
17 /* Convert MSDOS-TIME to standar time_t (still needed?) */
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(__WIN__)
39 # include <dos.h>
40 # ifdef __BORLANDC__
41 # include <dir.h>
42 # endif
43 # endif
44 #endif
45 #ifdef VMS
46 #include <rms.h>
47 #include <iodef.h>
48 #include <descrip.h>
49 #endif
51 #if defined(THREAD) && defined(HAVE_READDIR_R)
52 #define READDIR(A,B,C) ((errno=readdir_r(A,B,&C)) != 0 || !C)
53 #else
54 #define READDIR(A,B,C) (!(C=readdir(A)))
55 #endif
58 We are assuming that directory we are reading is either has less than
59 100 files and so can be read in one initial chunk or has more than 1000
60 files and so big increment are suitable.
62 #define ENTRIES_START_SIZE (8192/sizeof(FILEINFO))
63 #define ENTRIES_INCREMENT (65536/sizeof(FILEINFO))
64 #define NAMES_START_SIZE 32768
67 static int comp_names(struct fileinfo *a,struct fileinfo *b);
70 /* We need this because program don't know with malloc we used */
72 void my_dirend(MY_DIR *buffer)
74 DBUG_ENTER("my_dirend");
75 if (buffer)
77 delete_dynamic((DYNAMIC_ARRAY*)((char*)buffer +
78 ALIGN_SIZE(sizeof(MY_DIR))));
79 free_root((MEM_ROOT*)((char*)buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
80 ALIGN_SIZE(sizeof(DYNAMIC_ARRAY))), MYF(0));
81 my_free((uchar*) buffer,MYF(0));
83 DBUG_VOID_RETURN;
84 } /* my_dirend */
87 /* Compare in sort of filenames */
89 static int comp_names(struct fileinfo *a, struct fileinfo *b)
91 return (strcmp(a->name,b->name));
92 } /* comp_names */
95 #if !defined(__WIN__)
97 MY_DIR *my_dir(const char *path, myf MyFlags)
99 char *buffer;
100 MY_DIR *result= 0;
101 FILEINFO finfo;
102 DYNAMIC_ARRAY *dir_entries_storage;
103 MEM_ROOT *names_storage;
104 DIR *dirp;
105 struct dirent *dp;
106 char tmp_path[FN_REFLEN+1],*tmp_file;
107 #ifdef THREAD
108 char dirent_tmp[sizeof(struct dirent)+_POSIX_PATH_MAX+1];
109 #endif
110 DBUG_ENTER("my_dir");
111 DBUG_PRINT("my",("path: '%s' MyFlags: %d",path,MyFlags));
113 #if defined(THREAD) && !defined(HAVE_READDIR_R)
114 pthread_mutex_lock(&THR_LOCK_open);
115 #endif
117 dirp = opendir(directory_file_name(tmp_path,(char *) path));
118 #if defined(__amiga__)
119 if ((dirp->dd_fd) < 0) /* Directory doesn't exists */
120 goto error;
121 #endif
122 if (dirp == NULL ||
123 ! (buffer= my_malloc(ALIGN_SIZE(sizeof(MY_DIR)) +
124 ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)) +
125 sizeof(MEM_ROOT), MyFlags)))
126 goto error;
128 dir_entries_storage= (DYNAMIC_ARRAY*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)));
129 names_storage= (MEM_ROOT*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
130 ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)));
132 if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO),
133 ENTRIES_START_SIZE, ENTRIES_INCREMENT))
135 my_free((uchar*) buffer,MYF(0));
136 goto error;
138 init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE);
140 /* MY_DIR structure is allocated and completly initialized at this point */
141 result= (MY_DIR*)buffer;
143 tmp_file=strend(tmp_path);
145 #ifdef THREAD
146 dp= (struct dirent*) dirent_tmp;
147 #else
148 dp=0;
149 #endif
151 while (!(READDIR(dirp,(struct dirent*) dirent_tmp,dp)))
153 if (!(finfo.name= strdup_root(names_storage, dp->d_name)))
154 goto error;
156 if (MyFlags & MY_WANT_STAT)
158 if (!(finfo.mystat= (MY_STAT*)alloc_root(names_storage,
159 sizeof(MY_STAT))))
160 goto error;
162 bzero(finfo.mystat, sizeof(MY_STAT));
163 VOID(strmov(tmp_file,dp->d_name));
164 VOID(my_stat(tmp_path, finfo.mystat, MyFlags));
165 if (!(finfo.mystat->st_mode & MY_S_IREAD))
166 continue;
168 else
169 finfo.mystat= NULL;
171 if (push_dynamic(dir_entries_storage, (uchar*)&finfo))
172 goto error;
175 (void) closedir(dirp);
176 #if defined(THREAD) && !defined(HAVE_READDIR_R)
177 pthread_mutex_unlock(&THR_LOCK_open);
178 #endif
179 result->dir_entry= (FILEINFO *)dir_entries_storage->buffer;
180 result->number_off_files= dir_entries_storage->elements;
182 if (!(MyFlags & MY_DONT_SORT))
183 my_qsort((void *) result->dir_entry, result->number_off_files,
184 sizeof(FILEINFO), (qsort_cmp) comp_names);
185 DBUG_RETURN(result);
187 error:
188 #if defined(THREAD) && !defined(HAVE_READDIR_R)
189 pthread_mutex_unlock(&THR_LOCK_open);
190 #endif
191 my_errno=errno;
192 if (dirp)
193 (void) closedir(dirp);
194 my_dirend(result);
195 if (MyFlags & (MY_FAE | MY_WME))
196 my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,my_errno);
197 DBUG_RETURN((MY_DIR *) NULL);
198 } /* my_dir */
202 * Convert from directory name to filename.
203 * On VMS:
204 * xyzzy:[mukesh.emacs] => xyzzy:[mukesh]emacs.dir.1
205 * xyzzy:[mukesh] => xyzzy:[000000]mukesh.dir.1
206 * On UNIX, it's simple: just make sure there is a terminating /
208 * Returns pointer to dst;
211 char * directory_file_name (char * dst, const char *src)
213 #ifndef VMS
215 /* Process as Unix format: just remove test the final slash. */
217 char * end;
219 if (src[0] == 0)
220 src= (char*) "."; /* Use empty as current */
221 end=strmov(dst, src);
222 if (end[-1] != FN_LIBCHAR)
224 end[0]=FN_LIBCHAR; /* Add last '/' */
225 end[1]='\0';
227 return dst;
229 #else /* VMS */
231 long slen;
232 long rlen;
233 char * ptr, rptr;
234 char bracket;
235 struct FAB fab = cc$rms_fab;
236 struct NAM nam = cc$rms_nam;
237 char esa[NAM$C_MAXRSS];
239 if (! src[0])
240 src="[.]"; /* Empty is == current dir */
242 slen = strlen (src) - 1;
243 if (src[slen] == FN_C_AFTER_DIR || src[slen] == FN_C_AFTER_DIR_2 ||
244 src[slen] == FN_DEVCHAR)
246 /* VMS style - convert [x.y.z] to [x.y]z, [x] to [000000]x */
247 fab.fab$l_fna = src;
248 fab.fab$b_fns = slen + 1;
249 fab.fab$l_nam = &nam;
250 fab.fab$l_fop = FAB$M_NAM;
252 nam.nam$l_esa = esa;
253 nam.nam$b_ess = sizeof esa;
254 nam.nam$b_nop |= NAM$M_SYNCHK;
256 /* We call SYS$PARSE to handle such things as [--] for us. */
257 if (SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL)
259 slen = nam.nam$b_esl - 1;
260 if (esa[slen] == ';' && esa[slen - 1] == '.')
261 slen -= 2;
262 esa[slen + 1] = '\0';
263 src = esa;
265 if (src[slen] != FN_C_AFTER_DIR && src[slen] != FN_C_AFTER_DIR_2)
267 /* what about when we have logical_name:???? */
268 if (src[slen] == FN_DEVCHAR)
269 { /* Xlate logical name and see what we get */
270 VOID(strmov(dst,src));
271 dst[slen] = 0; /* remove colon */
272 if (!(src = getenv (dst)))
273 return dst; /* Can't translate */
275 /* should we jump to the beginning of this procedure?
276 Good points: allows us to use logical names that xlate
277 to Unix names,
278 Bad points: can be a problem if we just translated to a device
279 name...
280 For now, I'll punt and always expect VMS names, and hope for
281 the best! */
283 slen = strlen (src) - 1;
284 if (src[slen] != FN_C_AFTER_DIR && src[slen] != FN_C_AFTER_DIR_2)
285 { /* no recursion here! */
286 VOID(strmov(dst, src));
287 return(dst);
290 else
291 { /* not a directory spec */
292 VOID(strmov(dst, src));
293 return(dst);
297 bracket = src[slen]; /* End char */
298 if (!(ptr = strchr (src, bracket - 2)))
299 { /* no opening bracket */
300 VOID(strmov (dst, src));
301 return dst;
303 if (!(rptr = strrchr (src, '.')))
304 rptr = ptr;
305 slen = rptr - src;
306 VOID(strmake (dst, src, slen));
308 if (*rptr == '.')
309 { /* Put bracket and add */
310 dst[slen++] = bracket; /* (rptr+1) after this */
312 else
314 /* If we have the top-level of a rooted directory (i.e. xx:[000000]),
315 then translate the device and recurse. */
317 if (dst[slen - 1] == ':'
318 && dst[slen - 2] != ':' /* skip decnet nodes */
319 && strcmp(src + slen, "[000000]") == 0)
321 dst[slen - 1] = '\0';
322 if ((ptr = getenv (dst))
323 && (rlen = strlen (ptr) - 1) > 0
324 && (ptr[rlen] == FN_C_AFTER_DIR || ptr[rlen] == FN_C_AFTER_DIR_2)
325 && ptr[rlen - 1] == '.')
327 VOID(strmov(esa,ptr));
328 esa[rlen - 1] = FN_C_AFTER_DIR;
329 esa[rlen] = '\0';
330 return (directory_file_name (dst, esa));
332 else
333 dst[slen - 1] = ':';
335 VOID(strmov(dst+slen,"[000000]"));
336 slen += 8;
338 VOID(strmov(strmov(dst+slen,rptr+1)-1,".DIR.1"));
339 return dst;
341 VOID(strmov(dst, src));
342 if (dst[slen] == '/' && slen > 1)
343 dst[slen] = 0;
344 return dst;
345 #endif /* VMS */
346 } /* directory_file_name */
348 #else
351 *****************************************************************************
352 ** Read long filename using windows rutines
353 *****************************************************************************
356 MY_DIR *my_dir(const char *path, myf MyFlags)
358 char *buffer;
359 MY_DIR *result= 0;
360 FILEINFO finfo;
361 DYNAMIC_ARRAY *dir_entries_storage;
362 MEM_ROOT *names_storage;
363 #ifdef __BORLANDC__
364 struct ffblk find;
365 #else
366 struct _finddata_t find;
367 #endif
368 ushort mode;
369 char tmp_path[FN_REFLEN],*tmp_file,attrib;
370 #ifdef _WIN64
371 __int64 handle;
372 #else
373 long handle;
374 #endif
375 DBUG_ENTER("my_dir");
376 DBUG_PRINT("my",("path: '%s' stat: %d MyFlags: %d",path,MyFlags));
378 /* Put LIB-CHAR as last path-character if not there */
379 tmp_file=tmp_path;
380 if (!*path)
381 *tmp_file++ ='.'; /* From current dir */
382 tmp_file= strnmov(tmp_file, path, FN_REFLEN-5);
383 if (tmp_file[-1] == FN_DEVCHAR)
384 *tmp_file++= '.'; /* From current dev-dir */
385 if (tmp_file[-1] != FN_LIBCHAR)
386 *tmp_file++ =FN_LIBCHAR;
387 tmp_file[0]='*'; /* Windows needs this !??? */
388 tmp_file[1]='.';
389 tmp_file[2]='*';
390 tmp_file[3]='\0';
392 if (!(buffer= my_malloc(ALIGN_SIZE(sizeof(MY_DIR)) +
393 ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)) +
394 sizeof(MEM_ROOT), MyFlags)))
395 goto error;
397 dir_entries_storage= (DYNAMIC_ARRAY*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)));
398 names_storage= (MEM_ROOT*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
399 ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)));
401 if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO),
402 ENTRIES_START_SIZE, ENTRIES_INCREMENT))
404 my_free((uchar*) buffer,MYF(0));
405 goto error;
407 init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE);
409 /* MY_DIR structure is allocated and completly initialized at this point */
410 result= (MY_DIR*)buffer;
412 #ifdef __BORLANDC__
413 if ((handle= findfirst(tmp_path,&find,0)) == -1L)
414 #else
415 if ((handle=_findfirst(tmp_path,&find)) == -1L)
416 #endif
418 DBUG_PRINT("info", ("findfirst returned error, errno: %d", errno));
419 if (errno != EINVAL)
420 goto error;
422 Could not read the directory, no read access.
423 Probably because by "chmod -r".
424 continue and return zero files in dir
427 else
432 #ifdef __BORLANDC__
433 attrib= find.ff_attrib;
434 #else
435 attrib= find.attrib;
437 Do not show hidden and system files which Windows sometimes create.
438 Note. Because Borland's findfirst() is called with the third
439 argument = 0 hidden/system files are excluded from the search.
441 if (attrib & (_A_HIDDEN | _A_SYSTEM))
442 continue;
443 #endif
444 #ifdef __BORLANDC__
445 if (!(finfo.name= strdup_root(names_storage, find.ff_name)))
446 goto error;
447 #else
448 if (!(finfo.name= strdup_root(names_storage, find.name)))
449 goto error;
450 #endif
451 if (MyFlags & MY_WANT_STAT)
453 if (!(finfo.mystat= (MY_STAT*)alloc_root(names_storage,
454 sizeof(MY_STAT))))
455 goto error;
457 bzero(finfo.mystat, sizeof(MY_STAT));
458 #ifdef __BORLANDC__
459 finfo.mystat->st_size=find.ff_fsize;
460 #else
461 finfo.mystat->st_size=find.size;
462 #endif
463 mode= MY_S_IREAD;
464 if (!(attrib & _A_RDONLY))
465 mode|= MY_S_IWRITE;
466 if (attrib & _A_SUBDIR)
467 mode|= MY_S_IFDIR;
468 finfo.mystat->st_mode= mode;
469 #ifdef __BORLANDC__
470 finfo.mystat->st_mtime= ((uint32) find.ff_ftime);
471 #else
472 finfo.mystat->st_mtime= ((uint32) find.time_write);
473 #endif
475 else
476 finfo.mystat= NULL;
478 if (push_dynamic(dir_entries_storage, (uchar*)&finfo))
479 goto error;
481 #ifdef __BORLANDC__
482 while (findnext(&find) == 0);
483 #else
484 while (_findnext(handle,&find) == 0);
486 _findclose(handle);
487 #endif
490 result->dir_entry= (FILEINFO *)dir_entries_storage->buffer;
491 result->number_off_files= dir_entries_storage->elements;
493 if (!(MyFlags & MY_DONT_SORT))
494 my_qsort((void *) result->dir_entry, result->number_off_files,
495 sizeof(FILEINFO), (qsort_cmp) comp_names);
496 DBUG_PRINT("exit", ("found %d files", result->number_off_files));
497 DBUG_RETURN(result);
498 error:
499 my_errno=errno;
500 #ifndef __BORLANDC__
501 if (handle != -1)
502 _findclose(handle);
503 #endif
504 my_dirend(result);
505 if (MyFlags & MY_FAE+MY_WME)
506 my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,errno);
507 DBUG_RETURN((MY_DIR *) NULL);
508 } /* my_dir */
510 #endif /* __WIN__ */
512 /****************************************************************************
513 ** File status
514 ** Note that MY_STAT is assumed to be same as struct stat
515 ****************************************************************************/
517 int my_fstat(int Filedes, MY_STAT *stat_area,
518 myf MyFlags __attribute__((unused)))
520 DBUG_ENTER("my_fstat");
521 DBUG_PRINT("my",("fd: %d MyFlags: %d", Filedes, MyFlags));
522 DBUG_RETURN(fstat(Filedes, (struct stat *) stat_area));
526 MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags)
528 int m_used;
529 DBUG_ENTER("my_stat");
530 DBUG_PRINT("my", ("path: '%s' stat_area: 0x%lx MyFlags: %d", path,
531 (long) stat_area, my_flags));
533 if ((m_used= (stat_area == NULL)))
534 if (!(stat_area = (MY_STAT *) my_malloc(sizeof(MY_STAT), my_flags)))
535 goto error;
536 if (! stat((char *) path, (struct stat *) stat_area) )
537 DBUG_RETURN(stat_area);
539 DBUG_PRINT("error",("Got errno: %d from stat", errno));
540 my_errno= errno;
541 if (m_used) /* Free if new area */
542 my_free((uchar*) stat_area,MYF(0));
544 error:
545 if (my_flags & (MY_FAE+MY_WME))
547 my_error(EE_STAT, MYF(ME_BELL+ME_WAITTANG),path,my_errno);
548 DBUG_RETURN((MY_STAT *) NULL);
550 DBUG_RETURN((MY_STAT *) NULL);
551 } /* my_stat */