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"
21
#include <my_dir.h> /* Structs used by my_dir,includes sys/types */
22
#include "mysys_err.h"
23
#if defined(HAVE_DIRENT_H)
25
# define NAMLEN(dirent) strlen((dirent)->d_name)
27
# define dirent direct
28
# define NAMLEN(dirent) (dirent)->d_namlen
29
# if defined(HAVE_SYS_NDIR_H)
30
# include <sys/ndir.h>
32
# if defined(HAVE_SYS_DIR_H)
35
# if defined(HAVE_NDIR_H)
40
#if defined(THREAD) && defined(HAVE_READDIR_R)
41
#define READDIR(A,B,C) ((errno=readdir_r(A,B,&C)) != 0 || !C)
43
#define READDIR(A,B,C) (!(C=readdir(A)))
47
We are assuming that directory we are reading is either has less than
48
100 files and so can be read in one initial chunk or has more than 1000
49
files and so big increment are suitable.
51
#define ENTRIES_START_SIZE (8192/sizeof(FILEINFO))
52
#define ENTRIES_INCREMENT (65536/sizeof(FILEINFO))
53
#define NAMES_START_SIZE 32768
56
static int comp_names(struct fileinfo *a,struct fileinfo *b);
59
/* We need this because program don't know with malloc we used */
61
void my_dirend(MY_DIR *buffer)
63
DBUG_ENTER("my_dirend");
66
delete_dynamic((DYNAMIC_ARRAY*)((char*)buffer +
67
ALIGN_SIZE(sizeof(MY_DIR))));
68
free_root((MEM_ROOT*)((char*)buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
69
ALIGN_SIZE(sizeof(DYNAMIC_ARRAY))), MYF(0));
70
my_free((uchar*) buffer,MYF(0));
76
/* Compare in sort of filenames */
78
static int comp_names(struct fileinfo *a, struct fileinfo *b)
80
return (strcmp(a->name,b->name));
84
MY_DIR *my_dir(const char *path, myf MyFlags)
89
DYNAMIC_ARRAY *dir_entries_storage;
90
MEM_ROOT *names_storage;
93
char tmp_path[FN_REFLEN+1],*tmp_file;
95
char dirent_tmp[sizeof(struct dirent)+_POSIX_PATH_MAX+1];
98
DBUG_PRINT("my",("path: '%s' MyFlags: %d",path,MyFlags));
100
#if defined(THREAD) && !defined(HAVE_READDIR_R)
101
pthread_mutex_lock(&THR_LOCK_open);
104
dirp = opendir(directory_file_name(tmp_path,(char *) path));
106
! (buffer= my_malloc(ALIGN_SIZE(sizeof(MY_DIR)) +
107
ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)) +
108
sizeof(MEM_ROOT), MyFlags)))
111
dir_entries_storage= (DYNAMIC_ARRAY*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)));
112
names_storage= (MEM_ROOT*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
113
ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)));
115
if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO),
116
ENTRIES_START_SIZE, ENTRIES_INCREMENT))
118
my_free((uchar*) buffer,MYF(0));
121
init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE);
123
/* MY_DIR structure is allocated and completly initialized at this point */
124
result= (MY_DIR*)buffer;
126
tmp_file=strend(tmp_path);
129
dp= (struct dirent*) dirent_tmp;
134
while (!(READDIR(dirp,(struct dirent*) dirent_tmp,dp)))
136
if (!(finfo.name= strdup_root(names_storage, dp->d_name)))
139
if (MyFlags & MY_WANT_STAT)
141
if (!(finfo.mystat= (MY_STAT*)alloc_root(names_storage,
145
bzero(finfo.mystat, sizeof(MY_STAT));
146
VOID(strmov(tmp_file,dp->d_name));
147
VOID(my_stat(tmp_path, finfo.mystat, MyFlags));
148
if (!(finfo.mystat->st_mode & MY_S_IREAD))
154
if (push_dynamic(dir_entries_storage, (uchar*)&finfo))
158
(void) closedir(dirp);
159
#if defined(THREAD) && !defined(HAVE_READDIR_R)
160
pthread_mutex_unlock(&THR_LOCK_open);
162
result->dir_entry= (FILEINFO *)dir_entries_storage->buffer;
163
result->number_off_files= dir_entries_storage->elements;
165
if (!(MyFlags & MY_DONT_SORT))
166
my_qsort((void *) result->dir_entry, result->number_off_files,
167
sizeof(FILEINFO), (qsort_cmp) comp_names);
171
#if defined(THREAD) && !defined(HAVE_READDIR_R)
172
pthread_mutex_unlock(&THR_LOCK_open);
176
(void) closedir(dirp);
178
if (MyFlags & (MY_FAE | MY_WME))
179
my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,my_errno);
180
DBUG_RETURN((MY_DIR *) NULL);
185
* Convert from directory name to filename.
187
* xyzzy:[mukesh.emacs] => xyzzy:[mukesh]emacs.dir.1
188
* xyzzy:[mukesh] => xyzzy:[000000]mukesh.dir.1
189
* On UNIX, it's simple: just make sure there is a terminating /
191
* Returns pointer to dst;
194
char * directory_file_name (char * dst, const char *src)
196
/* Process as Unix format: just remove test the final slash. */
201
src= (char*) "."; /* Use empty as current */
202
end=strmov(dst, src);
203
if (end[-1] != FN_LIBCHAR)
205
end[0]=FN_LIBCHAR; /* Add last '/' */
209
} /* directory_file_name */
212
/****************************************************************************
214
** Note that MY_STAT is assumed to be same as struct stat
215
****************************************************************************/
217
int my_fstat(int Filedes, MY_STAT *stat_area,
218
myf MyFlags __attribute__((unused)))
220
DBUG_ENTER("my_fstat");
221
DBUG_PRINT("my",("fd: %d MyFlags: %d", Filedes, MyFlags));
222
DBUG_RETURN(fstat(Filedes, (struct stat *) stat_area));
226
MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags)
229
DBUG_ENTER("my_stat");
230
DBUG_PRINT("my", ("path: '%s' stat_area: 0x%lx MyFlags: %d", path,
231
(long) stat_area, my_flags));
233
if ((m_used= (stat_area == NULL)))
234
if (!(stat_area = (MY_STAT *) my_malloc(sizeof(MY_STAT), my_flags)))
236
if (! stat((char *) path, (struct stat *) stat_area) )
237
DBUG_RETURN(stat_area);
239
DBUG_PRINT("error",("Got errno: %d from stat", errno));
241
if (m_used) /* Free if new area */
242
my_free((uchar*) stat_area,MYF(0));
245
if (my_flags & (MY_FAE+MY_WME))
247
my_error(EE_STAT, MYF(ME_BELL+ME_WAITTANG),path,my_errno);
248
DBUG_RETURN((MY_STAT *) NULL);
250
DBUG_RETURN((MY_STAT *) NULL);