00001 /* Copyright (C) 2000 MySQL AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 00016 00017 /* TODO: check for overun of memory for names. */ 00018 /* Convert MSDOS-TIME to standar time_t (still needed?) */ 00019 00020 #include "mysys_priv.h" 00021 #include <m_string.h> 00022 #include <my_dir.h> /* Structs used by my_dir,includes sys/types */ 00023 #include "mysys_err.h" 00024 #if defined(HAVE_DIRENT_H) 00025 # include <dirent.h> 00026 # define NAMLEN(dirent) strlen((dirent)->d_name) 00027 #else 00028 # define dirent direct 00029 # define NAMLEN(dirent) (dirent)->d_namlen 00030 # if defined(HAVE_SYS_NDIR_H) 00031 # include <sys/ndir.h> 00032 # endif 00033 # if defined(HAVE_SYS_DIR_H) 00034 # include <sys/dir.h> 00035 # endif 00036 # if defined(HAVE_NDIR_H) 00037 # include <ndir.h> 00038 # endif 00039 # if defined(__WIN__) 00040 # include <dos.h> 00041 # ifdef __BORLANDC__ 00042 # include <dir.h> 00043 # endif 00044 # endif 00045 #endif 00046 #ifdef VMS 00047 #include <rms.h> 00048 #include <iodef.h> 00049 #include <descrip.h> 00050 #endif 00051 00052 #if defined(THREAD) && defined(HAVE_READDIR_R) 00053 #define READDIR(A,B,C) ((errno=readdir_r(A,B,&C)) != 0 || !C) 00054 #else 00055 #define READDIR(A,B,C) (!(C=readdir(A))) 00056 #endif 00057 00058 /* 00059 We are assuming that directory we are reading is either has less than 00060 100 files and so can be read in one initial chunk or has more than 1000 00061 files and so big increment are suitable. 00062 */ 00063 #define ENTRIES_START_SIZE (8192/sizeof(FILEINFO)) 00064 #define ENTRIES_INCREMENT (65536/sizeof(FILEINFO)) 00065 #define NAMES_START_SIZE 32768 00066 00067 00068 static int comp_names(struct fileinfo *a,struct fileinfo *b); 00069 00070 00071 /* We need this because program don't know with malloc we used */ 00072 00073 void my_dirend(MY_DIR *buffer) 00074 { 00075 DBUG_ENTER("my_dirend"); 00076 if (buffer) 00077 { 00078 delete_dynamic((DYNAMIC_ARRAY*)((char*)buffer + 00079 ALIGN_SIZE(sizeof(MY_DIR)))); 00080 free_root((MEM_ROOT*)((char*)buffer + ALIGN_SIZE(sizeof(MY_DIR)) + 00081 ALIGN_SIZE(sizeof(DYNAMIC_ARRAY))), MYF(0)); 00082 my_free((gptr) buffer,MYF(0)); 00083 } 00084 DBUG_VOID_RETURN; 00085 } /* my_dirend */ 00086 00087 00088 /* Compare in sort of filenames */ 00089 00090 static int comp_names(struct fileinfo *a, struct fileinfo *b) 00091 { 00092 return (strcmp(a->name,b->name)); 00093 } /* comp_names */ 00094 00095 00096 #if !defined(__WIN__) 00097 00098 MY_DIR *my_dir(const char *path, myf MyFlags) 00099 { 00100 char *buffer; 00101 MY_DIR *result= 0; 00102 FILEINFO finfo; 00103 DYNAMIC_ARRAY *dir_entries_storage; 00104 MEM_ROOT *names_storage; 00105 DIR *dirp; 00106 struct dirent *dp; 00107 char tmp_path[FN_REFLEN+1],*tmp_file; 00108 #ifdef THREAD 00109 char dirent_tmp[sizeof(struct dirent)+_POSIX_PATH_MAX+1]; 00110 #endif 00111 DBUG_ENTER("my_dir"); 00112 DBUG_PRINT("my",("path: '%s' MyFlags: %d",path,MyFlags)); 00113 00114 #if defined(THREAD) && !defined(HAVE_READDIR_R) 00115 pthread_mutex_lock(&THR_LOCK_open); 00116 #endif 00117 00118 dirp = opendir(directory_file_name(tmp_path,(my_string) path)); 00119 #if defined(__amiga__) 00120 if ((dirp->dd_fd) < 0) /* Directory doesn't exists */ 00121 goto error; 00122 #endif 00123 if (dirp == NULL || 00124 ! (buffer= my_malloc(ALIGN_SIZE(sizeof(MY_DIR)) + 00125 ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)) + 00126 sizeof(MEM_ROOT), MyFlags))) 00127 goto error; 00128 00129 dir_entries_storage= (DYNAMIC_ARRAY*)(buffer + ALIGN_SIZE(sizeof(MY_DIR))); 00130 names_storage= (MEM_ROOT*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)) + 00131 ALIGN_SIZE(sizeof(DYNAMIC_ARRAY))); 00132 00133 if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO), 00134 ENTRIES_START_SIZE, ENTRIES_INCREMENT)) 00135 { 00136 my_free((gptr) buffer,MYF(0)); 00137 goto error; 00138 } 00139 init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE); 00140 00141 /* MY_DIR structure is allocated and completly initialized at this point */ 00142 result= (MY_DIR*)buffer; 00143 00144 tmp_file=strend(tmp_path); 00145 00146 #ifdef THREAD 00147 dp= (struct dirent*) dirent_tmp; 00148 #else 00149 dp=0; 00150 #endif 00151 00152 while (!(READDIR(dirp,(struct dirent*) dirent_tmp,dp))) 00153 { 00154 if (!(finfo.name= strdup_root(names_storage, dp->d_name))) 00155 goto error; 00156 00157 if (MyFlags & MY_WANT_STAT) 00158 { 00159 if (!(finfo.mystat= (MY_STAT*)alloc_root(names_storage, 00160 sizeof(MY_STAT)))) 00161 goto error; 00162 00163 bzero(finfo.mystat, sizeof(MY_STAT)); 00164 VOID(strmov(tmp_file,dp->d_name)); 00165 VOID(my_stat(tmp_path, finfo.mystat, MyFlags)); 00166 if (!(finfo.mystat->st_mode & MY_S_IREAD)) 00167 continue; 00168 } 00169 else 00170 finfo.mystat= NULL; 00171 00172 if (push_dynamic(dir_entries_storage, (gptr)&finfo)) 00173 goto error; 00174 } 00175 00176 (void) closedir(dirp); 00177 #if defined(THREAD) && !defined(HAVE_READDIR_R) 00178 pthread_mutex_unlock(&THR_LOCK_open); 00179 #endif 00180 result->dir_entry= (FILEINFO *)dir_entries_storage->buffer; 00181 result->number_off_files= dir_entries_storage->elements; 00182 00183 if (!(MyFlags & MY_DONT_SORT)) 00184 qsort((void *) result->dir_entry, result->number_off_files, 00185 sizeof(FILEINFO), (qsort_cmp) comp_names); 00186 DBUG_RETURN(result); 00187 00188 error: 00189 #if defined(THREAD) && !defined(HAVE_READDIR_R) 00190 pthread_mutex_unlock(&THR_LOCK_open); 00191 #endif 00192 my_errno=errno; 00193 if (dirp) 00194 (void) closedir(dirp); 00195 my_dirend(result); 00196 if (MyFlags & (MY_FAE | MY_WME)) 00197 my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,my_errno); 00198 DBUG_RETURN((MY_DIR *) NULL); 00199 } /* my_dir */ 00200 00201 00202 /* 00203 * Convert from directory name to filename. 00204 * On VMS: 00205 * xyzzy:[mukesh.emacs] => xyzzy:[mukesh]emacs.dir.1 00206 * xyzzy:[mukesh] => xyzzy:[000000]mukesh.dir.1 00207 * On UNIX, it's simple: just make sure there is a terminating / 00208 00209 * Returns pointer to dst; 00210 */ 00211 00212 my_string directory_file_name (my_string dst, const char *src) 00213 { 00214 #ifndef VMS 00215 00216 /* Process as Unix format: just remove test the final slash. */ 00217 00218 my_string end; 00219 00220 if (src[0] == 0) 00221 src= (char*) "."; /* Use empty as current */ 00222 end=strmov(dst, src); 00223 if (end[-1] != FN_LIBCHAR) 00224 { 00225 end[0]=FN_LIBCHAR; /* Add last '/' */ 00226 end[1]='\0'; 00227 } 00228 return dst; 00229 00230 #else /* VMS */ 00231 00232 long slen; 00233 long rlen; 00234 my_string ptr, rptr; 00235 char bracket; 00236 struct FAB fab = cc$rms_fab; 00237 struct NAM nam = cc$rms_nam; 00238 char esa[NAM$C_MAXRSS]; 00239 00240 if (! src[0]) 00241 src="[.]"; /* Empty is == current dir */ 00242 00243 slen = strlen (src) - 1; 00244 if (src[slen] == FN_C_AFTER_DIR || src[slen] == FN_C_AFTER_DIR_2 || 00245 src[slen] == FN_DEVCHAR) 00246 { 00247 /* VMS style - convert [x.y.z] to [x.y]z, [x] to [000000]x */ 00248 fab.fab$l_fna = src; 00249 fab.fab$b_fns = slen + 1; 00250 fab.fab$l_nam = &nam; 00251 fab.fab$l_fop = FAB$M_NAM; 00252 00253 nam.nam$l_esa = esa; 00254 nam.nam$b_ess = sizeof esa; 00255 nam.nam$b_nop |= NAM$M_SYNCHK; 00256 00257 /* We call SYS$PARSE to handle such things as [--] for us. */ 00258 if (SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL) 00259 { 00260 slen = nam.nam$b_esl - 1; 00261 if (esa[slen] == ';' && esa[slen - 1] == '.') 00262 slen -= 2; 00263 esa[slen + 1] = '\0'; 00264 src = esa; 00265 } 00266 if (src[slen] != FN_C_AFTER_DIR && src[slen] != FN_C_AFTER_DIR_2) 00267 { 00268 /* what about when we have logical_name:???? */ 00269 if (src[slen] == FN_DEVCHAR) 00270 { /* Xlate logical name and see what we get */ 00271 VOID(strmov(dst,src)); 00272 dst[slen] = 0; /* remove colon */ 00273 if (!(src = getenv (dst))) 00274 return dst; /* Can't translate */ 00275 00276 /* should we jump to the beginning of this procedure? 00277 Good points: allows us to use logical names that xlate 00278 to Unix names, 00279 Bad points: can be a problem if we just translated to a device 00280 name... 00281 For now, I'll punt and always expect VMS names, and hope for 00282 the best! */ 00283 00284 slen = strlen (src) - 1; 00285 if (src[slen] != FN_C_AFTER_DIR && src[slen] != FN_C_AFTER_DIR_2) 00286 { /* no recursion here! */ 00287 VOID(strmov(dst, src)); 00288 return(dst); 00289 } 00290 } 00291 else 00292 { /* not a directory spec */ 00293 VOID(strmov(dst, src)); 00294 return(dst); 00295 } 00296 } 00297 00298 bracket = src[slen]; /* End char */ 00299 if (!(ptr = strchr (src, bracket - 2))) 00300 { /* no opening bracket */ 00301 VOID(strmov (dst, src)); 00302 return dst; 00303 } 00304 if (!(rptr = strrchr (src, '.'))) 00305 rptr = ptr; 00306 slen = rptr - src; 00307 VOID(strmake (dst, src, slen)); 00308 00309 if (*rptr == '.') 00310 { /* Put bracket and add */ 00311 dst[slen++] = bracket; /* (rptr+1) after this */ 00312 } 00313 else 00314 { 00315 /* If we have the top-level of a rooted directory (i.e. xx:[000000]), 00316 then translate the device and recurse. */ 00317 00318 if (dst[slen - 1] == ':' 00319 && dst[slen - 2] != ':' /* skip decnet nodes */ 00320 && strcmp(src + slen, "[000000]") == 0) 00321 { 00322 dst[slen - 1] = '\0'; 00323 if ((ptr = getenv (dst)) 00324 && (rlen = strlen (ptr) - 1) > 0 00325 && (ptr[rlen] == FN_C_AFTER_DIR || ptr[rlen] == FN_C_AFTER_DIR_2) 00326 && ptr[rlen - 1] == '.') 00327 { 00328 VOID(strmov(esa,ptr)); 00329 esa[rlen - 1] = FN_C_AFTER_DIR; 00330 esa[rlen] = '\0'; 00331 return (directory_file_name (dst, esa)); 00332 } 00333 else 00334 dst[slen - 1] = ':'; 00335 } 00336 VOID(strmov(dst+slen,"[000000]")); 00337 slen += 8; 00338 } 00339 VOID(strmov(strmov(dst+slen,rptr+1)-1,".DIR.1")); 00340 return dst; 00341 } 00342 VOID(strmov(dst, src)); 00343 if (dst[slen] == '/' && slen > 1) 00344 dst[slen] = 0; 00345 return dst; 00346 #endif /* VMS */ 00347 } /* directory_file_name */ 00348 00349 #else 00350 00351 /* 00352 ***************************************************************************** 00353 ** Read long filename using windows rutines 00354 ***************************************************************************** 00355 */ 00356 00357 MY_DIR *my_dir(const char *path, myf MyFlags) 00358 { 00359 char *buffer; 00360 MY_DIR *result= 0; 00361 FILEINFO finfo; 00362 DYNAMIC_ARRAY *dir_entries_storage; 00363 MEM_ROOT *names_storage; 00364 #ifdef __BORLANDC__ 00365 struct ffblk find; 00366 #else 00367 struct _finddata_t find; 00368 #endif 00369 ushort mode; 00370 char tmp_path[FN_REFLEN],*tmp_file,attrib; 00371 #ifdef _WIN64 00372 __int64 handle; 00373 #else 00374 long handle; 00375 #endif 00376 DBUG_ENTER("my_dir"); 00377 DBUG_PRINT("my",("path: '%s' stat: %d MyFlags: %d",path,MyFlags)); 00378 00379 /* Put LIB-CHAR as last path-character if not there */ 00380 tmp_file=tmp_path; 00381 if (!*path) 00382 *tmp_file++ ='.'; /* From current dir */ 00383 tmp_file= strnmov(tmp_file, path, FN_REFLEN-5); 00384 if (tmp_file[-1] == FN_DEVCHAR) 00385 *tmp_file++= '.'; /* From current dev-dir */ 00386 if (tmp_file[-1] != FN_LIBCHAR) 00387 *tmp_file++ =FN_LIBCHAR; 00388 tmp_file[0]='*'; /* Windows needs this !??? */ 00389 tmp_file[1]='.'; 00390 tmp_file[2]='*'; 00391 tmp_file[3]='\0'; 00392 00393 if (!(buffer= my_malloc(ALIGN_SIZE(sizeof(MY_DIR)) + 00394 ALIGN_SIZE(sizeof(DYNAMIC_ARRAY)) + 00395 sizeof(MEM_ROOT), MyFlags))) 00396 goto error; 00397 00398 dir_entries_storage= (DYNAMIC_ARRAY*)(buffer + ALIGN_SIZE(sizeof(MY_DIR))); 00399 names_storage= (MEM_ROOT*)(buffer + ALIGN_SIZE(sizeof(MY_DIR)) + 00400 ALIGN_SIZE(sizeof(DYNAMIC_ARRAY))); 00401 00402 if (my_init_dynamic_array(dir_entries_storage, sizeof(FILEINFO), 00403 ENTRIES_START_SIZE, ENTRIES_INCREMENT)) 00404 { 00405 my_free((gptr) buffer,MYF(0)); 00406 goto error; 00407 } 00408 init_alloc_root(names_storage, NAMES_START_SIZE, NAMES_START_SIZE); 00409 00410 /* MY_DIR structure is allocated and completly initialized at this point */ 00411 result= (MY_DIR*)buffer; 00412 00413 #ifdef __BORLANDC__ 00414 if ((handle= findfirst(tmp_path,&find,0)) == -1L) 00415 #else 00416 if ((handle=_findfirst(tmp_path,&find)) == -1L) 00417 #endif 00418 { 00419 DBUG_PRINT("info", ("findfirst returned error, errno: %d", errno)); 00420 if (errno != EINVAL) 00421 goto error; 00422 /* 00423 Could not read the directory, no read access. 00424 Probably because by "chmod -r". 00425 continue and return zero files in dir 00426 */ 00427 } 00428 else 00429 { 00430 00431 do 00432 { 00433 #ifdef __BORLANDC__ 00434 attrib= find.ff_attrib; 00435 #else 00436 attrib= find.attrib; 00437 /* 00438 Do not show hidden and system files which Windows sometimes create. 00439 Note. Because Borland's findfirst() is called with the third 00440 argument = 0 hidden/system files are excluded from the search. 00441 */ 00442 if (attrib & (_A_HIDDEN | _A_SYSTEM)) 00443 continue; 00444 #endif 00445 #ifdef __BORLANDC__ 00446 if (!(finfo.name= strdup_root(names_storage, find.ff_name))) 00447 goto error; 00448 #else 00449 if (!(finfo.name= strdup_root(names_storage, find.name))) 00450 goto error; 00451 #endif 00452 if (MyFlags & MY_WANT_STAT) 00453 { 00454 if (!(finfo.mystat= (MY_STAT*)alloc_root(names_storage, 00455 sizeof(MY_STAT)))) 00456 goto error; 00457 00458 bzero(finfo.mystat, sizeof(MY_STAT)); 00459 #ifdef __BORLANDC__ 00460 finfo.mystat->st_size=find.ff_fsize; 00461 #else 00462 finfo.mystat->st_size=find.size; 00463 #endif 00464 mode= MY_S_IREAD; 00465 if (!(attrib & _A_RDONLY)) 00466 mode|= MY_S_IWRITE; 00467 if (attrib & _A_SUBDIR) 00468 mode|= MY_S_IFDIR; 00469 finfo.mystat->st_mode= mode; 00470 #ifdef __BORLANDC__ 00471 finfo.mystat->st_mtime= ((uint32) find.ff_ftime); 00472 #else 00473 finfo.mystat->st_mtime= ((uint32) find.time_write); 00474 #endif 00475 } 00476 else 00477 finfo.mystat= NULL; 00478 00479 if (push_dynamic(dir_entries_storage, (gptr)&finfo)) 00480 goto error; 00481 } 00482 #ifdef __BORLANDC__ 00483 while (findnext(&find) == 0); 00484 #else 00485 while (_findnext(handle,&find) == 0); 00486 00487 _findclose(handle); 00488 #endif 00489 } 00490 00491 result->dir_entry= (FILEINFO *)dir_entries_storage->buffer; 00492 result->number_off_files= dir_entries_storage->elements; 00493 00494 if (!(MyFlags & MY_DONT_SORT)) 00495 qsort((void *) result->dir_entry, result->number_off_files, 00496 sizeof(FILEINFO), (qsort_cmp) comp_names); 00497 DBUG_PRINT("exit", ("found %d files", result->number_off_files)); 00498 DBUG_RETURN(result); 00499 error: 00500 my_errno=errno; 00501 #ifndef __BORLANDC__ 00502 if (handle != -1) 00503 _findclose(handle); 00504 #endif 00505 my_dirend(result); 00506 if (MyFlags & MY_FAE+MY_WME) 00507 my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,errno); 00508 DBUG_RETURN((MY_DIR *) NULL); 00509 } /* my_dir */ 00510 00511 #endif /* __WIN__ */ 00512 00513 /**************************************************************************** 00514 ** File status 00515 ** Note that MY_STAT is assumed to be same as struct stat 00516 ****************************************************************************/ 00517 00518 int my_fstat(int Filedes, MY_STAT *stat_area, 00519 myf MyFlags __attribute__((unused))) 00520 { 00521 DBUG_ENTER("my_fstat"); 00522 DBUG_PRINT("my",("fd: %d MyFlags: %d",Filedes,MyFlags)); 00523 DBUG_RETURN(fstat(Filedes, (struct stat *) stat_area)); 00524 } 00525 00526 00527 MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags) 00528 { 00529 int m_used; 00530 DBUG_ENTER("my_stat"); 00531 DBUG_PRINT("my", ("path: '%s', stat_area: 0x%lx, MyFlags: %d", path, 00532 (byte *) stat_area, my_flags)); 00533 00534 if ((m_used= (stat_area == NULL))) 00535 if (!(stat_area = (MY_STAT *) my_malloc(sizeof(MY_STAT), my_flags))) 00536 goto error; 00537 if (! stat((my_string) path, (struct stat *) stat_area) ) 00538 DBUG_RETURN(stat_area); 00539 00540 DBUG_PRINT("error",("Got errno: %d from stat", errno)); 00541 my_errno= errno; 00542 if (m_used) /* Free if new area */ 00543 my_free((gptr) stat_area,MYF(0)); 00544 00545 error: 00546 if (my_flags & (MY_FAE+MY_WME)) 00547 { 00548 my_error(EE_STAT, MYF(ME_BELL+ME_WAITTANG),path,my_errno); 00549 DBUG_RETURN((MY_STAT *) NULL); 00550 } 00551 DBUG_RETURN((MY_STAT *) NULL); 00552 } /* my_stat */
1.4.7

