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. */
18
#include "mysys/mysys_priv.h"
19
#include <mystrings/m_string.h>
20
#include "mysys/mysys_err.h"
21
#include "my_dir.h" /* Structs used by my_dir,includes sys/types */
22
#if defined(HAVE_DIRENT_H)
25
# define dirent direct
26
# if defined(HAVE_SYS_NDIR_H)
27
# include <sys/ndir.h>
29
# if defined(HAVE_SYS_DIR_H)
32
# if defined(HAVE_NDIR_H)
37
#if defined(HAVE_READDIR_R)
38
#define READDIR(A,B,C) ((errno=readdir_r(A,B,&C)) != 0 || !C)
40
#error You must have a thread safe readdir()
44
We are assuming that directory we are reading is either has less than
45
100 files and so can be read in one initial chunk or has more than 1000
46
files and so big increment are suitable.
48
#define ENTRIES_START_SIZE (8192/sizeof(FILEINFO))
49
#define ENTRIES_INCREMENT (65536/sizeof(FILEINFO))
50
#define NAMES_START_SIZE 32768
53
static int comp_names(const struct fileinfo *a, const struct fileinfo *b);
54
static char* directory_file_name(char* dst, const char* src);
56
/* We need this because program don't know with malloc we used */
58
void my_dirend(MY_DIR *buffer)
62
delete_dynamic((DYNAMIC_ARRAY*)((char*)buffer +
63
ALIGN_SIZE(sizeof(MY_DIR))));
64
free_root((MEM_ROOT*)((char*)buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
65
ALIGN_SIZE(sizeof(DYNAMIC_ARRAY))), MYF(0));
66
free((unsigned char*) buffer);
72
/* Compare in sort of filenames */
74
static int comp_names(const struct fileinfo *a, const struct fileinfo *b)
76
return (strcmp(a->name,b->name));
80
MY_DIR *my_dir(const char *path, myf MyFlags)
85
DYNAMIC_ARRAY *dir_entries_storage;
86
MEM_ROOT *names_storage;
89
char tmp_path[FN_REFLEN+1],*tmp_file;
90
char dirent_tmp[sizeof(struct dirent)+_POSIX_PATH_MAX+1];
92
dirp = opendir(directory_file_name(tmp_path,(char *) path));
94
! (buffer= (char *) malloc(ALIGN_SIZE(sizeof(MY_DIR)) +
95
ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)) +
99
dir_entries_storage= (DYNAMIC_ARRAY*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)));
100
names_storage= (MEM_ROOT*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
101
ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)));
103
if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO),
104
ENTRIES_START_SIZE, ENTRIES_INCREMENT))
106
free((unsigned char*) buffer);
109
init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE);
111
/* MY_DIR structure is allocated and completly initialized at this point */
112
result= (MY_DIR*)buffer;
114
tmp_file= strchr(tmp_path, '\0');
116
dp= (struct dirent*) dirent_tmp;
118
while (!(READDIR(dirp,(struct dirent*) dirent_tmp,dp)))
120
if (!(finfo.name= strdup_root(names_storage, dp->d_name)))
123
if (MyFlags & MY_WANT_STAT)
125
if (!(finfo.mystat= (struct stat*)alloc_root(names_storage,
126
sizeof(struct stat))))
129
memset(finfo.mystat, 0, sizeof(struct stat));
130
strcpy(tmp_file,dp->d_name);
131
stat(tmp_path, finfo.mystat);
132
if (!(finfo.mystat->st_mode & S_IREAD))
138
if (push_dynamic(dir_entries_storage, (unsigned char*)&finfo))
142
(void) closedir(dirp);
144
result->dir_entry= (FILEINFO *)dir_entries_storage->buffer;
145
result->number_off_files= static_cast<uint>(dir_entries_storage->elements);
147
if (!(MyFlags & MY_DONT_SORT))
148
my_qsort((void *) result->dir_entry, result->number_off_files,
149
sizeof(FILEINFO), (qsort_cmp) comp_names);
156
(void) closedir(dirp);
158
if (MyFlags & (MY_FAE | MY_WME))
159
my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,my_errno);
161
return((MY_DIR *) NULL);
166
* Convert from directory name to filename.
168
* xyzzy:[mukesh.emacs] => xyzzy:[mukesh]emacs.dir.1
169
* xyzzy:[mukesh] => xyzzy:[000000]mukesh.dir.1
170
* On UNIX, it's simple: just make sure there is a terminating /
172
* Returns pointer to dst;
175
static char* directory_file_name(char* dst, const char* src)
177
/* Process as Unix format: just remove test the final slash. */
182
src= (char*) "."; /* Use empty as current */
183
end= strcpy(dst, src)+strlen(src);
184
if (end[-1] != FN_LIBCHAR)
186
end[0]=FN_LIBCHAR; /* Add last '/' */
190
} /* directory_file_name */