~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000 MySQL AB
2
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.
6
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.
11
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 */
15
16
/* TODO: check for overun of memory for names. */
17
/*	 Convert MSDOS-TIME to standar time_t (still needed?) */
18
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
#endif
39
40
#if defined(THREAD) && defined(HAVE_READDIR_R)
41
#define READDIR(A,B,C) ((errno=readdir_r(A,B,&C)) != 0 || !C)
42
#else
43
#define READDIR(A,B,C) (!(C=readdir(A)))
44
#endif
45
46
/*
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.
50
*/
51
#define ENTRIES_START_SIZE (8192/sizeof(FILEINFO))
52
#define ENTRIES_INCREMENT  (65536/sizeof(FILEINFO))
53
#define NAMES_START_SIZE   32768
54
55
56
static int	comp_names(struct fileinfo *a,struct fileinfo *b);
57
58
59
	/* We need this because program don't know with malloc we used */
60
61
void my_dirend(MY_DIR *buffer)
62
{
63
  DBUG_ENTER("my_dirend");
64
  if (buffer)
65
  {
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));
71
  }
72
  DBUG_VOID_RETURN;
73
} /* my_dirend */
74
75
76
	/* Compare in sort of filenames */
77
78
static int comp_names(struct fileinfo *a, struct fileinfo *b)
79
{
80
  return (strcmp(a->name,b->name));
81
} /* comp_names */
82
83
84
MY_DIR	*my_dir(const char *path, myf MyFlags)
85
{
86
  char          *buffer;
87
  MY_DIR        *result= 0;
88
  FILEINFO      finfo;
89
  DYNAMIC_ARRAY *dir_entries_storage;
90
  MEM_ROOT      *names_storage;
91
  DIR		*dirp;
92
  struct dirent *dp;
93
  char		tmp_path[FN_REFLEN+1],*tmp_file;
94
#ifdef THREAD
95
  char	dirent_tmp[sizeof(struct dirent)+_POSIX_PATH_MAX+1];
96
#endif
97
  DBUG_ENTER("my_dir");
98
  DBUG_PRINT("my",("path: '%s' MyFlags: %d",path,MyFlags));
99
100
#if defined(THREAD) && !defined(HAVE_READDIR_R)
101
  pthread_mutex_lock(&THR_LOCK_open);
102
#endif
103
104
  dirp = opendir(directory_file_name(tmp_path,(char *) path));
105
  if (dirp == NULL || 
106
      ! (buffer= my_malloc(ALIGN_SIZE(sizeof(MY_DIR)) + 
107
                           ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)) +
108
                           sizeof(MEM_ROOT), MyFlags)))
109
    goto error;
110
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)));
114
  
115
  if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO),
116
                            ENTRIES_START_SIZE, ENTRIES_INCREMENT))
117
  {
118
    my_free((uchar*) buffer,MYF(0));
119
    goto error;
120
  }
121
  init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE);
122
  
123
  /* MY_DIR structure is allocated and completly initialized at this point */
124
  result= (MY_DIR*)buffer;
125
126
  tmp_file=strend(tmp_path);
127
128
#ifdef THREAD
129
  dp= (struct dirent*) dirent_tmp;
130
#else
131
  dp=0;
132
#endif
133
  
134
  while (!(READDIR(dirp,(struct dirent*) dirent_tmp,dp)))
135
  {
136
    if (!(finfo.name= strdup_root(names_storage, dp->d_name)))
137
      goto error;
138
    
139
    if (MyFlags & MY_WANT_STAT)
140
    {
15 by brian
Fix for stat, NETWARE removal
141
      if (!(finfo.mystat= (struct stat*)alloc_root(names_storage, 
142
                                               sizeof(struct stat))))
1 by brian
clean slate
143
        goto error;
144
      
15 by brian
Fix for stat, NETWARE removal
145
      bzero(finfo.mystat, sizeof(struct stat));
1 by brian
clean slate
146
      VOID(strmov(tmp_file,dp->d_name));
15 by brian
Fix for stat, NETWARE removal
147
      VOID(stat(tmp_path, finfo.mystat));
1 by brian
clean slate
148
      if (!(finfo.mystat->st_mode & MY_S_IREAD))
149
        continue;
150
    }
151
    else
152
      finfo.mystat= NULL;
153
154
    if (push_dynamic(dir_entries_storage, (uchar*)&finfo))
155
      goto error;
156
  }
157
158
  (void) closedir(dirp);
159
#if defined(THREAD) && !defined(HAVE_READDIR_R)
160
  pthread_mutex_unlock(&THR_LOCK_open);
161
#endif
162
  result->dir_entry= (FILEINFO *)dir_entries_storage->buffer;
163
  result->number_off_files= dir_entries_storage->elements;
164
  
165
  if (!(MyFlags & MY_DONT_SORT))
166
    my_qsort((void *) result->dir_entry, result->number_off_files,
167
          sizeof(FILEINFO), (qsort_cmp) comp_names);
168
  DBUG_RETURN(result);
169
170
 error:
171
#if defined(THREAD) && !defined(HAVE_READDIR_R)
172
  pthread_mutex_unlock(&THR_LOCK_open);
173
#endif
174
  my_errno=errno;
175
  if (dirp)
176
    (void) closedir(dirp);
177
  my_dirend(result);
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);
181
} /* my_dir */
182
183
184
/*
185
 * Convert from directory name to filename.
186
 * On VMS:
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 /
190
191
 * Returns pointer to dst;
192
 */
193
194
char * directory_file_name (char * dst, const char *src)
195
{
196
  /* Process as Unix format: just remove test the final slash. */
197
198
  char * end;
199
200
  if (src[0] == 0)
201
    src= (char*) ".";				/* Use empty as current */
202
  end=strmov(dst, src);
203
  if (end[-1] != FN_LIBCHAR)
204
  {
205
    end[0]=FN_LIBCHAR;				/* Add last '/' */
206
    end[1]='\0';
207
  }
208
  return dst;
209
} /* directory_file_name */
210