1 /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 /* TODO: check for overun of memory for names. */
18 /* Convert MSDOS-TIME to standar time_t (still needed?) */
20 #include "mysys_priv.h"
22 #include <my_dir.h> /* Structs used by my_dir,includes sys/types */
23 #include "mysys_err.h"
24 #if defined(HAVE_DIRENT_H)
26 # define NAMLEN(dirent) strlen((dirent)->d_name)
28 # define dirent direct
29 # define NAMLEN(dirent) (dirent)->d_namlen
30 # if defined(HAVE_SYS_NDIR_H)
31 # include <sys/ndir.h>
33 # if defined(HAVE_SYS_DIR_H)
36 # if defined(HAVE_NDIR_H)
52 #if defined(THREAD) && defined(HAVE_READDIR_R)
53 #define READDIR(A,B,C) ((errno=readdir_r(A,B,&C)) != 0 || !C)
55 #define READDIR(A,B,C) (!(C=readdir(A)))
59 We are assuming that directory we are reading is either has less than
60 100 files and so can be read in one initial chunk or has more than 1000
61 files and so big increment are suitable.
63 #define ENTRIES_START_SIZE (8192/sizeof(FILEINFO))
64 #define ENTRIES_INCREMENT (65536/sizeof(FILEINFO))
65 #define NAMES_START_SIZE 32768
68 static int comp_names(struct fileinfo
*a
,struct fileinfo
*b
);
71 /* We need this because program don't know with malloc we used */
73 void my_dirend(MY_DIR
*buffer
)
75 DBUG_ENTER("my_dirend");
78 delete_dynamic((DYNAMIC_ARRAY
*)((char*)buffer
+
79 ALIGN_SIZE(sizeof(MY_DIR
))));
80 free_root((MEM_ROOT
*)((char*)buffer
+ ALIGN_SIZE(sizeof(MY_DIR
)) +
81 ALIGN_SIZE(sizeof(DYNAMIC_ARRAY
))), MYF(0));
82 my_free((uchar
*) buffer
,MYF(0));
88 /* Compare in sort of filenames */
90 static int comp_names(struct fileinfo
*a
, struct fileinfo
*b
)
92 return (strcmp(a
->name
,b
->name
));
98 MY_DIR
*my_dir(const char *path
, myf MyFlags
)
103 DYNAMIC_ARRAY
*dir_entries_storage
;
104 MEM_ROOT
*names_storage
;
107 char tmp_path
[FN_REFLEN
+ 2], *tmp_file
;
109 char dirent_tmp
[sizeof(struct dirent
)+_POSIX_PATH_MAX
+1];
111 DBUG_ENTER("my_dir");
112 DBUG_PRINT("my",("path: '%s' MyFlags: %d",path
,MyFlags
));
114 #if defined(THREAD) && !defined(HAVE_READDIR_R)
115 pthread_mutex_lock(&THR_LOCK_open
);
118 dirp
= opendir(directory_file_name(tmp_path
,(char *) path
));
119 #if defined(__amiga__)
120 if ((dirp
->dd_fd
) < 0) /* Directory doesn't exists */
124 ! (buffer
= my_malloc(ALIGN_SIZE(sizeof(MY_DIR
)) +
125 ALIGN_SIZE(sizeof(DYNAMIC_ARRAY
)) +
126 sizeof(MEM_ROOT
), MyFlags
)))
129 dir_entries_storage
= (DYNAMIC_ARRAY
*)(buffer
+ ALIGN_SIZE(sizeof(MY_DIR
)));
130 names_storage
= (MEM_ROOT
*)(buffer
+ ALIGN_SIZE(sizeof(MY_DIR
)) +
131 ALIGN_SIZE(sizeof(DYNAMIC_ARRAY
)));
133 if (my_init_dynamic_array(dir_entries_storage
, sizeof(FILEINFO
),
134 ENTRIES_START_SIZE
, ENTRIES_INCREMENT
))
136 my_free((uchar
*) buffer
,MYF(0));
139 init_alloc_root(names_storage
, NAMES_START_SIZE
, NAMES_START_SIZE
);
141 /* MY_DIR structure is allocated and completly initialized at this point */
142 result
= (MY_DIR
*)buffer
;
144 tmp_file
=strend(tmp_path
);
147 dp
= (struct dirent
*) dirent_tmp
;
152 while (!(READDIR(dirp
,(struct dirent
*) dirent_tmp
,dp
)))
154 if (!(finfo
.name
= strdup_root(names_storage
, dp
->d_name
)))
157 if (MyFlags
& MY_WANT_STAT
)
159 if (!(finfo
.mystat
= (MY_STAT
*)alloc_root(names_storage
,
163 bzero(finfo
.mystat
, sizeof(MY_STAT
));
164 VOID(strmov(tmp_file
,dp
->d_name
));
165 VOID(my_stat(tmp_path
, finfo
.mystat
, MyFlags
));
166 if (!(finfo
.mystat
->st_mode
& MY_S_IREAD
))
172 if (push_dynamic(dir_entries_storage
, (uchar
*)&finfo
))
176 (void) closedir(dirp
);
177 #if defined(THREAD) && !defined(HAVE_READDIR_R)
178 pthread_mutex_unlock(&THR_LOCK_open
);
180 result
->dir_entry
= (FILEINFO
*)dir_entries_storage
->buffer
;
181 result
->number_off_files
= dir_entries_storage
->elements
;
183 if (!(MyFlags
& MY_DONT_SORT
))
184 my_qsort((void *) result
->dir_entry
, result
->number_off_files
,
185 sizeof(FILEINFO
), (qsort_cmp
) comp_names
);
189 #if defined(THREAD) && !defined(HAVE_READDIR_R)
190 pthread_mutex_unlock(&THR_LOCK_open
);
194 (void) closedir(dirp
);
196 if (MyFlags
& (MY_FAE
| MY_WME
))
197 my_error(EE_DIR
,MYF(ME_BELL
+ME_WAITTANG
),path
,my_errno
);
198 DBUG_RETURN((MY_DIR
*) NULL
);
203 * Convert from directory name to filename.
205 * xyzzy:[mukesh.emacs] => xyzzy:[mukesh]emacs.dir.1
206 * xyzzy:[mukesh] => xyzzy:[000000]mukesh.dir.1
207 * On UNIX, it's simple: just make sure there is a terminating /
209 * Returns pointer to dst;
212 char * directory_file_name (char * dst
, const char *src
)
216 /* Process as Unix format: just remove test the final slash. */
219 DBUG_ASSERT(strlen(src
) < (FN_REFLEN
+ 1));
222 src
= (char*) "."; /* Use empty as current */
223 end
= strnmov(dst
, src
, FN_REFLEN
+ 1);
224 if (end
[-1] != FN_LIBCHAR
)
226 end
[0]=FN_LIBCHAR
; /* Add last '/' */
237 struct FAB fab
= cc$rms_fab
;
238 struct NAM nam
= cc$rms_nam
;
239 char esa
[NAM$C_MAXRSS
];
242 src
="[.]"; /* Empty is == current dir */
244 slen
= strlen (src
) - 1;
245 if (src
[slen
] == FN_C_AFTER_DIR
|| src
[slen
] == FN_C_AFTER_DIR_2
||
246 src
[slen
] == FN_DEVCHAR
)
248 /* VMS style - convert [x.y.z] to [x.y]z, [x] to [000000]x */
250 fab
.fab$b_fns
= slen
+ 1;
251 fab
.fab$l_nam
= &nam
;
252 fab
.fab$l_fop
= FAB$M_NAM
;
255 nam
.nam$b_ess
= sizeof esa
;
256 nam
.nam$b_nop
|= NAM$M_SYNCHK
;
258 /* We call SYS$PARSE to handle such things as [--] for us. */
259 if (SYS$
PARSE(&fab
, 0, 0) == RMS$_NORMAL
)
261 slen
= nam
.nam$b_esl
- 1;
262 if (esa
[slen
] == ';' && esa
[slen
- 1] == '.')
264 esa
[slen
+ 1] = '\0';
267 if (src
[slen
] != FN_C_AFTER_DIR
&& src
[slen
] != FN_C_AFTER_DIR_2
)
269 /* what about when we have logical_name:???? */
270 if (src
[slen
] == FN_DEVCHAR
)
271 { /* Xlate logical name and see what we get */
272 VOID(strmov(dst
,src
));
273 dst
[slen
] = 0; /* remove colon */
274 if (!(src
= getenv (dst
)))
275 return dst
; /* Can't translate */
277 /* should we jump to the beginning of this procedure?
278 Good points: allows us to use logical names that xlate
280 Bad points: can be a problem if we just translated to a device
282 For now, I'll punt and always expect VMS names, and hope for
285 slen
= strlen (src
) - 1;
286 if (src
[slen
] != FN_C_AFTER_DIR
&& src
[slen
] != FN_C_AFTER_DIR_2
)
287 { /* no recursion here! */
288 VOID(strmov(dst
, src
));
293 { /* not a directory spec */
294 VOID(strmov(dst
, src
));
299 bracket
= src
[slen
]; /* End char */
300 if (!(ptr
= strchr (src
, bracket
- 2)))
301 { /* no opening bracket */
302 VOID(strmov (dst
, src
));
305 if (!(rptr
= strrchr (src
, '.')))
308 VOID(strmake (dst
, src
, slen
));
311 { /* Put bracket and add */
312 dst
[slen
++] = bracket
; /* (rptr+1) after this */
316 /* If we have the top-level of a rooted directory (i.e. xx:[000000]),
317 then translate the device and recurse. */
319 if (dst
[slen
- 1] == ':'
320 && dst
[slen
- 2] != ':' /* skip decnet nodes */
321 && strcmp(src
+ slen
, "[000000]") == 0)
323 dst
[slen
- 1] = '\0';
324 if ((ptr
= getenv (dst
))
325 && (rlen
= strlen (ptr
) - 1) > 0
326 && (ptr
[rlen
] == FN_C_AFTER_DIR
|| ptr
[rlen
] == FN_C_AFTER_DIR_2
)
327 && ptr
[rlen
- 1] == '.')
329 VOID(strmov(esa
,ptr
));
330 esa
[rlen
- 1] = FN_C_AFTER_DIR
;
332 return (directory_file_name (dst
, esa
));
337 VOID(strmov(dst
+slen
,"[000000]"));
340 VOID(strmov(strmov(dst
+slen
,rptr
+1)-1,".DIR.1"));
343 VOID(strmov(dst
, src
));
344 if (dst
[slen
] == '/' && slen
> 1)
348 } /* directory_file_name */
353 *****************************************************************************
354 ** Read long filename using windows rutines
355 *****************************************************************************
358 MY_DIR
*my_dir(const char *path
, myf MyFlags
)
363 DYNAMIC_ARRAY
*dir_entries_storage
;
364 MEM_ROOT
*names_storage
;
368 struct _finddata_t find
;
371 char tmp_path
[FN_REFLEN
],*tmp_file
,attrib
;
377 DBUG_ENTER("my_dir");
378 DBUG_PRINT("my",("path: '%s' stat: %d MyFlags: %d",path
,MyFlags
));
380 /* Put LIB-CHAR as last path-character if not there */
383 *tmp_file
++ ='.'; /* From current dir */
384 tmp_file
= strnmov(tmp_file
, path
, FN_REFLEN
-5);
385 if (tmp_file
[-1] == FN_DEVCHAR
)
386 *tmp_file
++= '.'; /* From current dev-dir */
387 if (tmp_file
[-1] != FN_LIBCHAR
)
388 *tmp_file
++ =FN_LIBCHAR
;
389 tmp_file
[0]='*'; /* Windows needs this !??? */
394 if (!(buffer
= my_malloc(ALIGN_SIZE(sizeof(MY_DIR
)) +
395 ALIGN_SIZE(sizeof(DYNAMIC_ARRAY
)) +
396 sizeof(MEM_ROOT
), MyFlags
)))
399 dir_entries_storage
= (DYNAMIC_ARRAY
*)(buffer
+ ALIGN_SIZE(sizeof(MY_DIR
)));
400 names_storage
= (MEM_ROOT
*)(buffer
+ ALIGN_SIZE(sizeof(MY_DIR
)) +
401 ALIGN_SIZE(sizeof(DYNAMIC_ARRAY
)));
403 if (my_init_dynamic_array(dir_entries_storage
, sizeof(FILEINFO
),
404 ENTRIES_START_SIZE
, ENTRIES_INCREMENT
))
406 my_free((uchar
*) buffer
,MYF(0));
409 init_alloc_root(names_storage
, NAMES_START_SIZE
, NAMES_START_SIZE
);
411 /* MY_DIR structure is allocated and completly initialized at this point */
412 result
= (MY_DIR
*)buffer
;
415 if ((handle
= findfirst(tmp_path
,&find
,0)) == -1L)
417 if ((handle
=_findfirst(tmp_path
,&find
)) == -1L)
420 DBUG_PRINT("info", ("findfirst returned error, errno: %d", errno
));
424 Could not read the directory, no read access.
425 Probably because by "chmod -r".
426 continue and return zero files in dir
435 attrib
= find
.ff_attrib
;
439 Do not show hidden and system files which Windows sometimes create.
440 Note. Because Borland's findfirst() is called with the third
441 argument = 0 hidden/system files are excluded from the search.
443 if (attrib
& (_A_HIDDEN
| _A_SYSTEM
))
447 if (!(finfo
.name
= strdup_root(names_storage
, find
.ff_name
)))
450 if (!(finfo
.name
= strdup_root(names_storage
, find
.name
)))
453 if (MyFlags
& MY_WANT_STAT
)
455 if (!(finfo
.mystat
= (MY_STAT
*)alloc_root(names_storage
,
459 bzero(finfo
.mystat
, sizeof(MY_STAT
));
461 finfo
.mystat
->st_size
=find
.ff_fsize
;
463 finfo
.mystat
->st_size
=find
.size
;
466 if (!(attrib
& _A_RDONLY
))
468 if (attrib
& _A_SUBDIR
)
470 finfo
.mystat
->st_mode
= mode
;
472 finfo
.mystat
->st_mtime
= ((uint32
) find
.ff_ftime
);
474 finfo
.mystat
->st_mtime
= ((uint32
) find
.time_write
);
480 if (push_dynamic(dir_entries_storage
, (uchar
*)&finfo
))
484 while (findnext(&find
) == 0);
486 while (_findnext(handle
,&find
) == 0);
492 result
->dir_entry
= (FILEINFO
*)dir_entries_storage
->buffer
;
493 result
->number_off_files
= dir_entries_storage
->elements
;
495 if (!(MyFlags
& MY_DONT_SORT
))
496 my_qsort((void *) result
->dir_entry
, result
->number_off_files
,
497 sizeof(FILEINFO
), (qsort_cmp
) comp_names
);
498 DBUG_PRINT("exit", ("found %d files", result
->number_off_files
));
507 if (MyFlags
& MY_FAE
+MY_WME
)
508 my_error(EE_DIR
,MYF(ME_BELL
+ME_WAITTANG
),path
,errno
);
509 DBUG_RETURN((MY_DIR
*) NULL
);
514 /****************************************************************************
516 ** Note that MY_STAT is assumed to be same as struct stat
517 ****************************************************************************/
519 int my_fstat(int Filedes
, MY_STAT
*stat_area
,
520 myf MyFlags
__attribute__((unused
)))
522 DBUG_ENTER("my_fstat");
523 DBUG_PRINT("my",("fd: %d MyFlags: %d", Filedes
, MyFlags
));
524 DBUG_RETURN(fstat(Filedes
, (struct stat
*) stat_area
));
528 MY_STAT
*my_stat(const char *path
, MY_STAT
*stat_area
, myf my_flags
)
531 DBUG_ENTER("my_stat");
532 DBUG_PRINT("my", ("path: '%s' stat_area: 0x%lx MyFlags: %d", path
,
533 (long) stat_area
, my_flags
));
535 if ((m_used
= (stat_area
== NULL
)))
536 if (!(stat_area
= (MY_STAT
*) my_malloc(sizeof(MY_STAT
), my_flags
)))
538 if (! stat((char *) path
, (struct stat
*) stat_area
) )
539 DBUG_RETURN(stat_area
);
541 DBUG_PRINT("error",("Got errno: %d from stat", errno
));
543 if (m_used
) /* Free if new area */
544 my_free((uchar
*) stat_area
,MYF(0));
547 if (my_flags
& (MY_FAE
+MY_WME
))
549 my_error(EE_STAT
, MYF(ME_BELL
+ME_WAITTANG
),path
,my_errno
);
550 DBUG_RETURN((MY_STAT
*) NULL
);
552 DBUG_RETURN((MY_STAT
*) NULL
);