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)
51 #if defined(THREAD) && defined(HAVE_READDIR_R)
52 #define READDIR(A,B,C) ((errno=readdir_r(A,B,&C)) != 0 || !C)
54 #define READDIR(A,B,C) (!(C=readdir(A)))
58 We are assuming that directory we are reading is either has less than
59 100 files and so can be read in one initial chunk or has more than 1000
60 files and so big increment are suitable.
62 #define ENTRIES_START_SIZE (8192/sizeof(FILEINFO))
63 #define ENTRIES_INCREMENT (65536/sizeof(FILEINFO))
64 #define NAMES_START_SIZE 32768
67 static int comp_names(struct fileinfo
*a
,struct fileinfo
*b
);
70 /* We need this because program don't know with malloc we used */
72 void my_dirend(MY_DIR
*buffer
)
74 DBUG_ENTER("my_dirend");
77 delete_dynamic((DYNAMIC_ARRAY
*)((char*)buffer
+
78 ALIGN_SIZE(sizeof(MY_DIR
))));
79 free_root((MEM_ROOT
*)((char*)buffer
+ ALIGN_SIZE(sizeof(MY_DIR
)) +
80 ALIGN_SIZE(sizeof(DYNAMIC_ARRAY
))), MYF(0));
81 my_free((uchar
*) buffer
,MYF(0));
87 /* Compare in sort of filenames */
89 static int comp_names(struct fileinfo
*a
, struct fileinfo
*b
)
91 return (strcmp(a
->name
,b
->name
));
97 MY_DIR
*my_dir(const char *path
, myf MyFlags
)
102 DYNAMIC_ARRAY
*dir_entries_storage
;
103 MEM_ROOT
*names_storage
;
106 char tmp_path
[FN_REFLEN
+1],*tmp_file
;
108 char dirent_tmp
[sizeof(struct dirent
)+_POSIX_PATH_MAX
+1];
110 DBUG_ENTER("my_dir");
111 DBUG_PRINT("my",("path: '%s' MyFlags: %d",path
,MyFlags
));
113 #if defined(THREAD) && !defined(HAVE_READDIR_R)
114 pthread_mutex_lock(&THR_LOCK_open
);
117 dirp
= opendir(directory_file_name(tmp_path
,(char *) path
));
118 #if defined(__amiga__)
119 if ((dirp
->dd_fd
) < 0) /* Directory doesn't exists */
123 ! (buffer
= my_malloc(ALIGN_SIZE(sizeof(MY_DIR
)) +
124 ALIGN_SIZE(sizeof(DYNAMIC_ARRAY
)) +
125 sizeof(MEM_ROOT
), MyFlags
)))
128 dir_entries_storage
= (DYNAMIC_ARRAY
*)(buffer
+ ALIGN_SIZE(sizeof(MY_DIR
)));
129 names_storage
= (MEM_ROOT
*)(buffer
+ ALIGN_SIZE(sizeof(MY_DIR
)) +
130 ALIGN_SIZE(sizeof(DYNAMIC_ARRAY
)));
132 if (my_init_dynamic_array(dir_entries_storage
, sizeof(FILEINFO
),
133 ENTRIES_START_SIZE
, ENTRIES_INCREMENT
))
135 my_free((uchar
*) buffer
,MYF(0));
138 init_alloc_root(names_storage
, NAMES_START_SIZE
, NAMES_START_SIZE
);
140 /* MY_DIR structure is allocated and completly initialized at this point */
141 result
= (MY_DIR
*)buffer
;
143 tmp_file
=strend(tmp_path
);
146 dp
= (struct dirent
*) dirent_tmp
;
151 while (!(READDIR(dirp
,(struct dirent
*) dirent_tmp
,dp
)))
153 if (!(finfo
.name
= strdup_root(names_storage
, dp
->d_name
)))
156 if (MyFlags
& MY_WANT_STAT
)
158 if (!(finfo
.mystat
= (MY_STAT
*)alloc_root(names_storage
,
162 bzero(finfo
.mystat
, sizeof(MY_STAT
));
163 VOID(strmov(tmp_file
,dp
->d_name
));
164 VOID(my_stat(tmp_path
, finfo
.mystat
, MyFlags
));
165 if (!(finfo
.mystat
->st_mode
& MY_S_IREAD
))
171 if (push_dynamic(dir_entries_storage
, (uchar
*)&finfo
))
175 (void) closedir(dirp
);
176 #if defined(THREAD) && !defined(HAVE_READDIR_R)
177 pthread_mutex_unlock(&THR_LOCK_open
);
179 result
->dir_entry
= (FILEINFO
*)dir_entries_storage
->buffer
;
180 result
->number_off_files
= dir_entries_storage
->elements
;
182 if (!(MyFlags
& MY_DONT_SORT
))
183 my_qsort((void *) result
->dir_entry
, result
->number_off_files
,
184 sizeof(FILEINFO
), (qsort_cmp
) comp_names
);
188 #if defined(THREAD) && !defined(HAVE_READDIR_R)
189 pthread_mutex_unlock(&THR_LOCK_open
);
193 (void) closedir(dirp
);
195 if (MyFlags
& (MY_FAE
| MY_WME
))
196 my_error(EE_DIR
,MYF(ME_BELL
+ME_WAITTANG
),path
,my_errno
);
197 DBUG_RETURN((MY_DIR
*) NULL
);
202 * Convert from directory name to filename.
204 * xyzzy:[mukesh.emacs] => xyzzy:[mukesh]emacs.dir.1
205 * xyzzy:[mukesh] => xyzzy:[000000]mukesh.dir.1
206 * On UNIX, it's simple: just make sure there is a terminating /
208 * Returns pointer to dst;
211 char * directory_file_name (char * dst
, const char *src
)
215 /* Process as Unix format: just remove test the final slash. */
220 src
= (char*) "."; /* Use empty as current */
221 end
=strmov(dst
, src
);
222 if (end
[-1] != FN_LIBCHAR
)
224 end
[0]=FN_LIBCHAR
; /* Add last '/' */
235 struct FAB fab
= cc$rms_fab
;
236 struct NAM nam
= cc$rms_nam
;
237 char esa
[NAM$C_MAXRSS
];
240 src
="[.]"; /* Empty is == current dir */
242 slen
= strlen (src
) - 1;
243 if (src
[slen
] == FN_C_AFTER_DIR
|| src
[slen
] == FN_C_AFTER_DIR_2
||
244 src
[slen
] == FN_DEVCHAR
)
246 /* VMS style - convert [x.y.z] to [x.y]z, [x] to [000000]x */
248 fab
.fab$b_fns
= slen
+ 1;
249 fab
.fab$l_nam
= &nam
;
250 fab
.fab$l_fop
= FAB$M_NAM
;
253 nam
.nam$b_ess
= sizeof esa
;
254 nam
.nam$b_nop
|= NAM$M_SYNCHK
;
256 /* We call SYS$PARSE to handle such things as [--] for us. */
257 if (SYS$
PARSE(&fab
, 0, 0) == RMS$_NORMAL
)
259 slen
= nam
.nam$b_esl
- 1;
260 if (esa
[slen
] == ';' && esa
[slen
- 1] == '.')
262 esa
[slen
+ 1] = '\0';
265 if (src
[slen
] != FN_C_AFTER_DIR
&& src
[slen
] != FN_C_AFTER_DIR_2
)
267 /* what about when we have logical_name:???? */
268 if (src
[slen
] == FN_DEVCHAR
)
269 { /* Xlate logical name and see what we get */
270 VOID(strmov(dst
,src
));
271 dst
[slen
] = 0; /* remove colon */
272 if (!(src
= getenv (dst
)))
273 return dst
; /* Can't translate */
275 /* should we jump to the beginning of this procedure?
276 Good points: allows us to use logical names that xlate
278 Bad points: can be a problem if we just translated to a device
280 For now, I'll punt and always expect VMS names, and hope for
283 slen
= strlen (src
) - 1;
284 if (src
[slen
] != FN_C_AFTER_DIR
&& src
[slen
] != FN_C_AFTER_DIR_2
)
285 { /* no recursion here! */
286 VOID(strmov(dst
, src
));
291 { /* not a directory spec */
292 VOID(strmov(dst
, src
));
297 bracket
= src
[slen
]; /* End char */
298 if (!(ptr
= strchr (src
, bracket
- 2)))
299 { /* no opening bracket */
300 VOID(strmov (dst
, src
));
303 if (!(rptr
= strrchr (src
, '.')))
306 VOID(strmake (dst
, src
, slen
));
309 { /* Put bracket and add */
310 dst
[slen
++] = bracket
; /* (rptr+1) after this */
314 /* If we have the top-level of a rooted directory (i.e. xx:[000000]),
315 then translate the device and recurse. */
317 if (dst
[slen
- 1] == ':'
318 && dst
[slen
- 2] != ':' /* skip decnet nodes */
319 && strcmp(src
+ slen
, "[000000]") == 0)
321 dst
[slen
- 1] = '\0';
322 if ((ptr
= getenv (dst
))
323 && (rlen
= strlen (ptr
) - 1) > 0
324 && (ptr
[rlen
] == FN_C_AFTER_DIR
|| ptr
[rlen
] == FN_C_AFTER_DIR_2
)
325 && ptr
[rlen
- 1] == '.')
327 VOID(strmov(esa
,ptr
));
328 esa
[rlen
- 1] = FN_C_AFTER_DIR
;
330 return (directory_file_name (dst
, esa
));
335 VOID(strmov(dst
+slen
,"[000000]"));
338 VOID(strmov(strmov(dst
+slen
,rptr
+1)-1,".DIR.1"));
341 VOID(strmov(dst
, src
));
342 if (dst
[slen
] == '/' && slen
> 1)
346 } /* directory_file_name */
351 *****************************************************************************
352 ** Read long filename using windows rutines
353 *****************************************************************************
356 MY_DIR
*my_dir(const char *path
, myf MyFlags
)
361 DYNAMIC_ARRAY
*dir_entries_storage
;
362 MEM_ROOT
*names_storage
;
366 struct _finddata_t find
;
369 char tmp_path
[FN_REFLEN
],*tmp_file
,attrib
;
375 DBUG_ENTER("my_dir");
376 DBUG_PRINT("my",("path: '%s' stat: %d MyFlags: %d",path
,MyFlags
));
378 /* Put LIB-CHAR as last path-character if not there */
381 *tmp_file
++ ='.'; /* From current dir */
382 tmp_file
= strnmov(tmp_file
, path
, FN_REFLEN
-5);
383 if (tmp_file
[-1] == FN_DEVCHAR
)
384 *tmp_file
++= '.'; /* From current dev-dir */
385 if (tmp_file
[-1] != FN_LIBCHAR
)
386 *tmp_file
++ =FN_LIBCHAR
;
387 tmp_file
[0]='*'; /* Windows needs this !??? */
392 if (!(buffer
= my_malloc(ALIGN_SIZE(sizeof(MY_DIR
)) +
393 ALIGN_SIZE(sizeof(DYNAMIC_ARRAY
)) +
394 sizeof(MEM_ROOT
), MyFlags
)))
397 dir_entries_storage
= (DYNAMIC_ARRAY
*)(buffer
+ ALIGN_SIZE(sizeof(MY_DIR
)));
398 names_storage
= (MEM_ROOT
*)(buffer
+ ALIGN_SIZE(sizeof(MY_DIR
)) +
399 ALIGN_SIZE(sizeof(DYNAMIC_ARRAY
)));
401 if (my_init_dynamic_array(dir_entries_storage
, sizeof(FILEINFO
),
402 ENTRIES_START_SIZE
, ENTRIES_INCREMENT
))
404 my_free((uchar
*) buffer
,MYF(0));
407 init_alloc_root(names_storage
, NAMES_START_SIZE
, NAMES_START_SIZE
);
409 /* MY_DIR structure is allocated and completly initialized at this point */
410 result
= (MY_DIR
*)buffer
;
413 if ((handle
= findfirst(tmp_path
,&find
,0)) == -1L)
415 if ((handle
=_findfirst(tmp_path
,&find
)) == -1L)
418 DBUG_PRINT("info", ("findfirst returned error, errno: %d", errno
));
422 Could not read the directory, no read access.
423 Probably because by "chmod -r".
424 continue and return zero files in dir
433 attrib
= find
.ff_attrib
;
437 Do not show hidden and system files which Windows sometimes create.
438 Note. Because Borland's findfirst() is called with the third
439 argument = 0 hidden/system files are excluded from the search.
441 if (attrib
& (_A_HIDDEN
| _A_SYSTEM
))
445 if (!(finfo
.name
= strdup_root(names_storage
, find
.ff_name
)))
448 if (!(finfo
.name
= strdup_root(names_storage
, find
.name
)))
451 if (MyFlags
& MY_WANT_STAT
)
453 if (!(finfo
.mystat
= (MY_STAT
*)alloc_root(names_storage
,
457 bzero(finfo
.mystat
, sizeof(MY_STAT
));
459 finfo
.mystat
->st_size
=find
.ff_fsize
;
461 finfo
.mystat
->st_size
=find
.size
;
464 if (!(attrib
& _A_RDONLY
))
466 if (attrib
& _A_SUBDIR
)
468 finfo
.mystat
->st_mode
= mode
;
470 finfo
.mystat
->st_mtime
= ((uint32
) find
.ff_ftime
);
472 finfo
.mystat
->st_mtime
= ((uint32
) find
.time_write
);
478 if (push_dynamic(dir_entries_storage
, (uchar
*)&finfo
))
482 while (findnext(&find
) == 0);
484 while (_findnext(handle
,&find
) == 0);
490 result
->dir_entry
= (FILEINFO
*)dir_entries_storage
->buffer
;
491 result
->number_off_files
= dir_entries_storage
->elements
;
493 if (!(MyFlags
& MY_DONT_SORT
))
494 my_qsort((void *) result
->dir_entry
, result
->number_off_files
,
495 sizeof(FILEINFO
), (qsort_cmp
) comp_names
);
496 DBUG_PRINT("exit", ("found %d files", result
->number_off_files
));
505 if (MyFlags
& MY_FAE
+MY_WME
)
506 my_error(EE_DIR
,MYF(ME_BELL
+ME_WAITTANG
),path
,errno
);
507 DBUG_RETURN((MY_DIR
*) NULL
);
512 /****************************************************************************
514 ** Note that MY_STAT is assumed to be same as struct stat
515 ****************************************************************************/
517 int my_fstat(int Filedes
, MY_STAT
*stat_area
,
518 myf MyFlags
__attribute__((unused
)))
520 DBUG_ENTER("my_fstat");
521 DBUG_PRINT("my",("fd: %d MyFlags: %d", Filedes
, MyFlags
));
522 DBUG_RETURN(fstat(Filedes
, (struct stat
*) stat_area
));
526 MY_STAT
*my_stat(const char *path
, MY_STAT
*stat_area
, myf my_flags
)
529 DBUG_ENTER("my_stat");
530 DBUG_PRINT("my", ("path: '%s' stat_area: 0x%lx MyFlags: %d", path
,
531 (long) stat_area
, my_flags
));
533 if ((m_used
= (stat_area
== NULL
)))
534 if (!(stat_area
= (MY_STAT
*) my_malloc(sizeof(MY_STAT
), my_flags
)))
536 if (! stat((char *) path
, (struct stat
*) stat_area
) )
537 DBUG_RETURN(stat_area
);
539 DBUG_PRINT("error",("Got errno: %d from stat", errno
));
541 if (m_used
) /* Free if new area */
542 my_free((uchar
*) stat_area
,MYF(0));
545 if (my_flags
& (MY_FAE
+MY_WME
))
547 my_error(EE_STAT
, MYF(ME_BELL
+ME_WAITTANG
),path
,my_errno
);
548 DBUG_RETURN((MY_STAT
*) NULL
);
550 DBUG_RETURN((MY_STAT
*) NULL
);