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 <mystrings/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)
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(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(const struct fileinfo *a, const struct fileinfo *b);
59
/* We need this because program don't know with malloc we used */
61
void my_dirend(MY_DIR *buffer)
65
delete_dynamic((DYNAMIC_ARRAY*)((char*)buffer +
66
ALIGN_SIZE(sizeof(MY_DIR))));
67
free_root((MEM_ROOT*)((char*)buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
68
ALIGN_SIZE(sizeof(DYNAMIC_ARRAY))), MYF(0));
69
my_free((uchar*) buffer,MYF(0));
75
/* Compare in sort of filenames */
77
static int comp_names(const struct fileinfo *a, const struct fileinfo *b)
79
return (strcmp(a->name,b->name));
83
MY_DIR *my_dir(const char *path, myf MyFlags)
88
DYNAMIC_ARRAY *dir_entries_storage;
89
MEM_ROOT *names_storage;
92
char tmp_path[FN_REFLEN+1],*tmp_file;
93
char dirent_tmp[sizeof(struct dirent)+_POSIX_PATH_MAX+1];
95
#if !defined(HAVE_READDIR_R)
96
pthread_mutex_lock(&THR_LOCK_open);
99
dirp = opendir(directory_file_name(tmp_path,(char *) path));
101
! (buffer= my_malloc(ALIGN_SIZE(sizeof(MY_DIR)) +
102
ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)) +
103
sizeof(MEM_ROOT), MyFlags)))
106
dir_entries_storage= (DYNAMIC_ARRAY*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)));
107
names_storage= (MEM_ROOT*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)) +
108
ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)));
110
if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO),
111
ENTRIES_START_SIZE, ENTRIES_INCREMENT))
113
my_free((uchar*) buffer,MYF(0));
116
init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE);
118
/* MY_DIR structure is allocated and completly initialized at this point */
119
result= (MY_DIR*)buffer;
121
tmp_file=strend(tmp_path);
123
dp= (struct dirent*) dirent_tmp;
125
while (!(READDIR(dirp,(struct dirent*) dirent_tmp,dp)))
127
if (!(finfo.name= strdup_root(names_storage, dp->d_name)))
130
if (MyFlags & MY_WANT_STAT)
132
if (!(finfo.mystat= (struct stat*)alloc_root(names_storage,
133
sizeof(struct stat))))
136
memset(finfo.mystat, 0, sizeof(struct stat));
137
VOID(stpcpy(tmp_file,dp->d_name));
138
VOID(stat(tmp_path, finfo.mystat));
139
if (!(finfo.mystat->st_mode & S_IREAD))
145
if (push_dynamic(dir_entries_storage, (uchar*)&finfo))
149
(void) closedir(dirp);
150
#if !defined(HAVE_READDIR_R)
151
pthread_mutex_unlock(&THR_LOCK_open);
153
result->dir_entry= (FILEINFO *)dir_entries_storage->buffer;
154
result->number_off_files= dir_entries_storage->elements;
156
if (!(MyFlags & MY_DONT_SORT))
157
my_qsort((void *) result->dir_entry, result->number_off_files,
158
sizeof(FILEINFO), (qsort_cmp) comp_names);
162
#if !defined(HAVE_READDIR_R)
163
pthread_mutex_unlock(&THR_LOCK_open);
167
(void) closedir(dirp);
169
if (MyFlags & (MY_FAE | MY_WME))
170
my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,my_errno);
171
return((MY_DIR *) NULL);
176
* Convert from directory name to filename.
178
* xyzzy:[mukesh.emacs] => xyzzy:[mukesh]emacs.dir.1
179
* xyzzy:[mukesh] => xyzzy:[000000]mukesh.dir.1
180
* On UNIX, it's simple: just make sure there is a terminating /
182
* Returns pointer to dst;
185
char * directory_file_name (char * dst, const char *src)
187
/* Process as Unix format: just remove test the final slash. */
192
src= (char*) "."; /* Use empty as current */
193
end=stpcpy(dst, src);
194
if (end[-1] != FN_LIBCHAR)
196
end[0]=FN_LIBCHAR; /* Add last '/' */
200
} /* directory_file_name */