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; either version 2 of the License, or
6
(at your option) any later version.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
17
/* TODO: check for overun of memory for names. */
18
/* Convert MSDOS-TIME to standar time_t */
20
#define USES_TYPES /* sys/types is included */
21
#include "mysys_priv.h"
23
#include <my_dir.h> /* Structs used by my_dir,includes sys/types */
24
#include "mysys_err.h"
25
#if defined(HAVE_DIRENT_H)
27
# define NAMLEN(dirent) strlen((dirent)->d_name)
30
# define dirent direct
32
# define NAMLEN(dirent) (dirent)->d_namlen
33
# if defined(HAVE_SYS_NDIR_H)
34
# include <sys/ndir.h>
36
# if defined(HAVE_SYS_DIR_H)
39
# if defined(HAVE_NDIR_H)
42
# if defined(MSDOS) || defined(__WIN__)
56
#include "my_os2dirsrch.h"
59
#if defined(THREAD) && defined(HAVE_READDIR_R)
60
#define READDIR(A,B,C) ((errno=readdir_r(A,B,&C)) != 0 || !C)
62
#define READDIR(A,B,C) (!(C=readdir(A)))
66
We are assuming that directory we are reading is either has less than
67
100 files and so can be read in one initial chunk or has more than 1000
68
files and so big increment are suitable.
70
#define ENTRIES_START_SIZE (8192/sizeof(FILEINFO))
71
#define ENTRIES_INCREMENT (65536/sizeof(FILEINFO))
72
#define NAMES_START_SIZE 32768
74
namespace mysql_parser
79
static int comp_names(struct fileinfo *a,struct fileinfo *b);
82
/* We need this because program don't know with malloc we used */
85
void my_dirend(MY_DIR *buffer)
87
DBUG_ENTER("my_dirend");
90
delete_dynamic((DYNAMIC_ARRAY*)((char*)buffer +
91
ALIGN_SIZE(sizeof(MY_DIR))));
92
free_root((MEM_ROOT*)((char*)buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
93
ALIGN_SIZE(sizeof(DYNAMIC_ARRAY))), MYF(0));
94
my_free((gptr) buffer,MYF(0));
100
/* Compare in sort of filenames */
102
static int comp_names(struct fileinfo *a, struct fileinfo *b)
104
return (strcmp(a->name,b->name));
108
#if !defined(MSDOS) && !defined(__WIN__)
110
MY_DIR *my_dir(const char *path, myf MyFlags)
115
DYNAMIC_ARRAY *dir_entries_storage;
118
char tmp_path[FN_REFLEN+1],*tmp_file;
120
char dirent_tmp[sizeof(struct dirent)+_POSIX_PATH_MAX+1];
122
DBUG_ENTER("my_dir");
123
DBUG_PRINT("my",("path: '%s' MyFlags: %d",path,MyFlags));
125
#if defined(THREAD) && !defined(HAVE_READDIR_R)
126
pthread_mutex_lock(&THR_LOCK_open);
129
dirp = opendir(directory_file_name(tmp_path,(my_string) path));
130
#if defined(__amiga__)
131
if ((dirp->dd_fd) < 0) /* Directory doesn't exists */
135
! (buffer= my_malloc(ALIGN_SIZE(sizeof(MY_DIR)) +
136
ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)),
140
dir_entries_storage= (DYNAMIC_ARRAY*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)));
142
if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO),
143
ENTRIES_START_SIZE, ENTRIES_INCREMENT))
145
my_free((gptr) buffer,MYF(0));
149
/* MY_DIR structure is allocated and completly initialized at this point */
150
result= (MY_DIR*)buffer;
152
tmp_file=strend(tmp_path);
155
dp= (struct dirent*) dirent_tmp;
160
while (!(READDIR(dirp,(struct dirent*) dirent_tmp,dp)))
162
if (!(finfo.name= strdup_root(dp->d_name)))
165
if (MyFlags & MY_WANT_STAT)
167
if (!(finfo.mystat= (MY_STAT*)alloc_root(sizeof(MY_STAT))))
170
bzero(finfo.mystat, sizeof(MY_STAT));
171
VOID(strmov(tmp_file,dp->d_name));
172
VOID(my_stat(tmp_path, finfo.mystat, MyFlags));
173
if (!(finfo.mystat->st_mode & MY_S_IREAD))
179
if (push_dynamic(dir_entries_storage, (gptr)&finfo))
183
(void) closedir(dirp);
184
#if defined(THREAD) && !defined(HAVE_READDIR_R)
185
pthread_mutex_unlock(&THR_LOCK_open);
187
result->dir_entry= (FILEINFO *)dir_entries_storage->buffer;
188
result->number_off_files= dir_entries_storage->elements;
190
if (!(MyFlags & MY_DONT_SORT))
191
qsort((void *) result->dir_entry, result->number_off_files,
192
sizeof(FILEINFO), (qsort_cmp) comp_names);
196
#if defined(THREAD) && !defined(HAVE_READDIR_R)
197
pthread_mutex_unlock(&THR_LOCK_open);
201
(void) closedir(dirp);
203
if (MyFlags & (MY_FAE | MY_WME))
204
my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,my_errno);
205
DBUG_RETURN((MY_DIR *) NULL);
210
* Convert from directory name to filename.
212
* xyzzy:[mukesh.emacs] => xyzzy:[mukesh]emacs.dir.1
213
* xyzzy:[mukesh] => xyzzy:[000000]mukesh.dir.1
214
* On UNIX, it's simple: just make sure there is a terminating /
216
* Returns pointer to dst;
219
my_string directory_file_name (my_string dst, const char *src)
223
/* Process as Unix format: just remove test the final slash. */
228
src= (char*) "."; /* Use empty as current */
229
end=strmov(dst, src);
230
if (end[-1] != FN_LIBCHAR)
232
end[0]=FN_LIBCHAR; /* Add last '/' */
243
struct FAB fab = cc$rms_fab;
244
struct NAM nam = cc$rms_nam;
245
char esa[NAM$C_MAXRSS];
248
src="[.]"; /* Empty is == current dir */
250
slen = strlen (src) - 1;
251
if (src[slen] == FN_C_AFTER_DIR || src[slen] == FN_C_AFTER_DIR_2 ||
252
src[slen] == FN_DEVCHAR)
254
/* VMS style - convert [x.y.z] to [x.y]z, [x] to [000000]x */
256
fab.fab$b_fns = slen + 1;
257
fab.fab$l_nam = &nam;
258
fab.fab$l_fop = FAB$M_NAM;
261
nam.nam$b_ess = sizeof esa;
262
nam.nam$b_nop |= NAM$M_SYNCHK;
264
/* We call SYS$PARSE to handle such things as [--] for us. */
265
if (SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL)
267
slen = nam.nam$b_esl - 1;
268
if (esa[slen] == ';' && esa[slen - 1] == '.')
270
esa[slen + 1] = '\0';
273
if (src[slen] != FN_C_AFTER_DIR && src[slen] != FN_C_AFTER_DIR_2)
275
/* what about when we have logical_name:???? */
276
if (src[slen] == FN_DEVCHAR)
277
{ /* Xlate logical name and see what we get */
278
VOID(strmov(dst,src));
279
dst[slen] = 0; /* remove colon */
280
if (!(src = getenv (dst)))
281
return dst; /* Can't translate */
283
/* should we jump to the beginning of this procedure?
284
Good points: allows us to use logical names that xlate
286
Bad points: can be a problem if we just translated to a device
288
For now, I'll punt and always expect VMS names, and hope for
291
slen = strlen (src) - 1;
292
if (src[slen] != FN_C_AFTER_DIR && src[slen] != FN_C_AFTER_DIR_2)
293
{ /* no recursion here! */
294
VOID(strmov(dst, src));
299
{ /* not a directory spec */
300
VOID(strmov(dst, src));
305
bracket = src[slen]; /* End char */
306
if (!(ptr = strchr (src, bracket - 2)))
307
{ /* no opening bracket */
308
VOID(strmov (dst, src));
311
if (!(rptr = strrchr (src, '.')))
314
VOID(strmake (dst, src, slen));
317
{ /* Put bracket and add */
318
dst[slen++] = bracket; /* (rptr+1) after this */
322
/* If we have the top-level of a rooted directory (i.e. xx:[000000]),
323
then translate the device and recurse. */
325
if (dst[slen - 1] == ':'
326
&& dst[slen - 2] != ':' /* skip decnet nodes */
327
&& strcmp(src + slen, "[000000]") == 0)
329
dst[slen - 1] = '\0';
330
if ((ptr = getenv (dst))
331
&& (rlen = strlen (ptr) - 1) > 0
332
&& (ptr[rlen] == FN_C_AFTER_DIR || ptr[rlen] == FN_C_AFTER_DIR_2)
333
&& ptr[rlen - 1] == '.')
335
VOID(strmov(esa,ptr));
336
esa[rlen - 1] = FN_C_AFTER_DIR;
338
return (directory_file_name (dst, esa));
343
VOID(strmov(dst+slen,"[000000]"));
346
VOID(strmov(strmov(dst+slen,rptr+1)-1,".DIR.1"));
349
VOID(strmov(dst, src));
350
if (dst[slen] == '/' && slen > 1)
354
} /* directory_file_name */
359
*****************************************************************************
360
** Read long filename using windows rutines
361
*****************************************************************************
365
MY_DIR *my_dir(const char *path, myf MyFlags)
370
DYNAMIC_ARRAY *dir_entries_storage;
371
MEM_ROOT *names_storage;
375
struct _finddata_t find;
378
char tmp_path[FN_REFLEN],*tmp_file,attrib;
384
DBUG_ENTER("my_dir");
385
DBUG_PRINT("my",("path: '%s' stat: %d MyFlags: %d",path,MyFlags));
387
/* Put LIB-CHAR as last path-character if not there */
391
*tmp_file++ ='.'; /* From current dir */
392
tmp_file= strmov(tmp_file,path);
393
if (tmp_file[-1] == FN_DEVCHAR)
394
*tmp_file++= '.'; /* From current dev-dir */
395
if (tmp_file[-1] != FN_LIBCHAR)
396
*tmp_file++ =FN_LIBCHAR;
397
tmp_file[0]='*'; /* MSDOS needs this !??? */
402
if (!(buffer= my_malloc(ALIGN_SIZE(sizeof(MY_DIR)) +
403
ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)) +
404
sizeof(MEM_ROOT), MyFlags)))
407
dir_entries_storage= (DYNAMIC_ARRAY*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)));
408
names_storage= (MEM_ROOT*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
409
ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)));
411
if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO),
412
ENTRIES_START_SIZE, ENTRIES_INCREMENT))
414
my_free((gptr) buffer,MYF(0));
417
init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE);
419
/* MY_DIR structure is allocated and completly initialized at this point */
420
result= (MY_DIR*)buffer;
423
if ((handle= findfirst(tmp_path,&find,0)) == -1L)
425
if ((handle=_findfirst(tmp_path,&find)) == -1L)
428
DBUG_PRINT("info", ("find_first returned error"));
432
Could not read the directory, no read access.
433
Probably because by "chmod -r".
434
continue and return zero files in dir
441
attrib= find.ff_attrib;
445
Do not show hidden and system files which Windows sometimes create.
446
Note. Because Borland's findfirst() is called with the third
447
argument = 0 hidden/system files are excluded from the search.
449
if (attrib & (_A_HIDDEN | _A_SYSTEM))
453
if (!(finfo.name= strdup_root(names_storage, find.ff_name)))
456
if (!(finfo.name= strdup_root(names_storage, find.name)))
459
if (MyFlags & MY_WANT_STAT)
461
if (!(finfo.mystat= (MY_STAT*)alloc_root(names_storage,
465
bzero(finfo.mystat, sizeof(MY_STAT));
467
finfo.mystat->st_size=find.ff_fsize;
469
finfo.mystat->st_size=find.size;
472
if (!(attrib & _A_RDONLY))
474
if (attrib & _A_SUBDIR)
476
finfo.mystat->st_mode=mode;
478
finfo.mystat->st_mtime=((uint32) find.ff_ftime);
480
finfo.mystat->st_mtime=((uint32) find.time_write);
486
if (push_dynamic(dir_entries_storage, (gptr)&finfo))
490
} while (findnext(&find) == 0);
492
} while (_findnext(handle,&find) == 0);
497
result->dir_entry= (FILEINFO *)dir_entries_storage->buffer;
498
result->number_off_files= dir_entries_storage->elements;
500
if (!(MyFlags & MY_DONT_SORT))
501
qsort((void *) result->dir_entry, result->number_off_files,
502
sizeof(FILEINFO), (qsort_cmp) comp_names);
511
if (MyFlags & MY_FAE+MY_WME)
512
my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,errno);
513
DBUG_RETURN((MY_DIR *) NULL);
518
#else /* MSDOS and not WIN32 */
521
/******************************************************************************
522
** At MSDOS you always get stat of files, but time is in packed MSDOS-format
523
******************************************************************************/
525
MY_DIR *my_dir(const char* path, myf MyFlags)
530
DYNAMIC_ARRAY *dir_entries_storage;
531
MEM_ROOT *names_storage;
534
char tmp_path[FN_REFLEN],*tmp_file,attrib;
535
DBUG_ENTER("my_dir");
536
DBUG_PRINT("my",("path: '%s' stat: %d MyFlags: %d",path,MyFlags));
538
/* Put LIB-CHAR as last path-character if not there */
542
*tmp_file++ ='.'; /* From current dir */
543
tmp_file= strmov(tmp_file,path);
544
if (tmp_file[-1] == FN_DEVCHAR)
545
*tmp_file++= '.'; /* From current dev-dir */
546
if (tmp_file[-1] != FN_LIBCHAR)
547
*tmp_file++ =FN_LIBCHAR;
548
tmp_file[0]='*'; /* MSDOS needs this !??? */
553
if (_dos_findfirst(tmp_path,_A_NORMAL | _A_SUBDIR, &find))
556
if (!(buffer= my_malloc(ALIGN_SIZE(sizeof(MY_DIR)) +
557
ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)) +
558
sizeof(MEM_ROOT), MyFlags)))
561
dir_entries_storage= (DYNAMIC_ARRAY*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)));
562
names_storage= (MEM_ROOT*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
563
ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)));
565
if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO),
566
ENTRIES_START_SIZE, ENTRIES_INCREMENT))
568
my_free((gptr) buffer,MYF(0));
571
init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE);
573
/* MY_DIR structure is allocated and completly initialized at this point */
574
result= (MY_DIR*)buffer;
578
if (!(finfo.name= strdup_root(names_storage, find.name)))
581
if (MyFlags & MY_WANT_STAT)
583
if (!(finfo.mystat= (MY_STAT*)alloc_root(names_storage,
587
bzero(finfo.mystat, sizeof(MY_STAT));
588
finfo.mystat->st_size= find.size;
589
mode= MY_S_IREAD; attrib= find.attrib;
590
if (!(attrib & _A_RDONLY))
592
if (attrib & _A_SUBDIR)
594
finfo.mystat->st_mode= mode;
595
finfo.mystat->st_mtime= ((uint32) find.wr_date << 16) + find.wr_time;
600
if (push_dynamic(dir_entries_storage, (gptr)&finfo))
603
} while (_dos_findnext(&find) == 0);
605
result->dir_entry= (FILEINFO *)dir_entries_storage->buffer;
606
result->number_off_files= dir_entries_storage->elements;
608
if (!(MyFlags & MY_DONT_SORT))
609
qsort((void *) result->dir_entry, result->number_off_files,
610
sizeof(FILEINFO), (qsort_cmp) comp_names);
615
if (MyFlags & MY_FAE+MY_WME)
616
my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,errno);
617
DBUG_RETURN((MY_DIR *) NULL);
620
#endif /* WIN32 && MSDOS */
622
/****************************************************************************
624
** Note that MY_STAT is assumed to be same as struct stat
625
****************************************************************************/
627
int my_fstat(int Filedes, MY_STAT *stat_area,
628
myf MyFlags __attribute__((unused)))
630
DBUG_ENTER("my_fstat");
631
DBUG_PRINT("my",("fd: %d MyFlags: %d",Filedes,MyFlags));
632
DBUG_RETURN(fstat(Filedes, (struct stat *) stat_area));
636
MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags)
639
DBUG_ENTER("my_stat");
640
DBUG_PRINT("my", ("path: '%s', stat_area: 0x%lx, MyFlags: %d", path,
641
(byte *) stat_area, my_flags));
643
if ((m_used= (stat_area == NULL)))
644
if (!(stat_area = (MY_STAT *) my_malloc(sizeof(MY_STAT), my_flags)))
646
if (! stat((my_string) path, (struct stat *) stat_area) )
647
DBUG_RETURN(stat_area);
649
DBUG_PRINT("error",("Got errno: %d from stat", errno));
651
if (m_used) /* Free if new area */
652
my_free((gptr) stat_area,MYF(0));
655
if (my_flags & (MY_FAE+MY_WME))
657
// my_error(EE_STAT, MYF(ME_BELL+ME_WAITTANG),path,my_errno);
658
DBUG_RETURN((MY_STAT *) NULL);
660
DBUG_RETURN((MY_STAT *) NULL);
663
} // namespace mysql_parser