getfilelist.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. /***********************************************************************
  39. ** NAME
  40. ** getfilelist.c
  41. **
  42. ** DESCRIPTION
  43. **
  44. **
  45. ** AUTHOR
  46. ** Rich Megginson <[email protected]>
  47. **
  48. ***********************************************************************/
  49. /***********************************************************************
  50. ** Includes
  51. ***********************************************************************/
  52. #include "prio.h"
  53. #include "slap.h"
  54. #include "avl.h"
  55. struct data_wrapper {
  56. char **list;
  57. int n;
  58. int max;
  59. const char *dirname;
  60. };
  61. static int
  62. add_file_to_list(caddr_t data, caddr_t arg)
  63. {
  64. struct data_wrapper *dw = (struct data_wrapper *)arg;
  65. if (dw) {
  66. /* max is number of entries; the range of n is 0 - max-1 */
  67. PR_ASSERT(dw->n <= dw->max);
  68. PR_ASSERT(dw->list);
  69. PR_ASSERT(data);
  70. /* this strdup is free'd by free_filelist */
  71. dw->list[dw->n++] = slapi_ch_smprintf("%s/%s", dw->dirname, data);
  72. return 0;
  73. }
  74. return -1;
  75. }
  76. static void
  77. free_string(caddr_t data)
  78. {
  79. slapi_ch_free((void **)&data);
  80. }
  81. static int
  82. file_is_type_x(const char *dirname, const char *filename, PRFileType x)
  83. {
  84. struct PRFileInfo inf;
  85. int status = 0;
  86. char *fullpath = slapi_ch_smprintf("%s/%s", dirname, filename);
  87. if (PR_SUCCESS == PR_GetFileInfo(fullpath, &inf) &&
  88. inf.type == x)
  89. status = 1;
  90. slapi_ch_free((void **)&fullpath);
  91. return status;
  92. }
  93. /* return true if the given path and file corresponds to a directory */
  94. static int
  95. is_a_dir(const char *dirname, const char *filename)
  96. {
  97. return file_is_type_x(dirname, filename, PR_FILE_DIRECTORY);
  98. }
  99. /* return true if the given path and file corresponds to a regular file */
  100. static int
  101. is_a_file(const char *dirname, const char *filename)
  102. {
  103. return file_is_type_x(dirname, filename, PR_FILE_FILE);
  104. }
  105. static int
  106. matches(const char *filename, const char *pattern)
  107. {
  108. int match = 0;
  109. char *s = 0;
  110. if (!pattern)
  111. return 1; /* null pattern matches everything */
  112. slapd_re_lock();
  113. s = slapd_re_comp((char *)pattern);
  114. if (!s)
  115. match = slapd_re_exec((char *)filename);
  116. slapd_re_unlock();
  117. return match;
  118. }
  119. /**
  120. * getfilelist will return a list of all files and directories in the
  121. * given directory matching the given pattern. If dirname is NULL, the
  122. * current directory "." will be used. If the pattern is NULL, all files
  123. * and directories will be returned. The additional integer arguments
  124. * control which files and directories are selected. The default value
  125. * for all of them is 0, which will not return hidden files (e.g. files
  126. * beginning with . on unix), but will return both files and directories
  127. * If nofiles is non-zero, only directory names will be returned. If
  128. * nodirs is non-zero, only filenames will be returned.
  129. * The pattern is a grep style regular expression, not a shell or command
  130. * interpreter style regular expression. For example, to get all files ending
  131. * in .ldif, use ".*\\.ldif" instead of "*.ldif"
  132. * The return value is a NULL terminated array of names.
  133. */
  134. char **
  135. get_filelist(
  136. const char *dirname, /* directory path; if NULL, uses "." */
  137. const char *pattern, /* grep (not shell!) file pattern regex */
  138. int hiddenfiles, /* if true, return hidden files and directories too */
  139. int nofiles, /* if true, do not return files */
  140. int nodirs /* if true, do not return directories */
  141. )
  142. {
  143. Avlnode *filetree = 0;
  144. PRDir *dirptr = 0;
  145. PRDirEntry *dirent = 0;
  146. PRDirFlags dirflags = PR_SKIP_BOTH & PR_SKIP_HIDDEN;
  147. char **retval = 0;
  148. int num = 0;
  149. struct data_wrapper dw;
  150. if (!dirname)
  151. dirname = ".";
  152. if (hiddenfiles)
  153. dirflags = PR_SKIP_BOTH;
  154. if (!(dirptr = PR_OpenDir(dirname))) {
  155. return NULL;
  156. }
  157. /* read the directory entries into an ascii sorted avl tree */
  158. for (dirent = PR_ReadDir(dirptr, dirflags); dirent ;
  159. dirent = PR_ReadDir(dirptr, dirflags)) {
  160. if (nofiles && is_a_file(dirname, dirent->name))
  161. continue;
  162. if (nodirs && is_a_dir(dirname, dirent->name))
  163. continue;
  164. if (matches(dirent->name, pattern)) {
  165. /* this strdup is free'd by free_string */
  166. char *newone = slapi_ch_strdup(dirent->name);
  167. avl_insert(&filetree, newone, strcmp, 0);
  168. num++;
  169. }
  170. }
  171. PR_CloseDir(dirptr);
  172. /* allocate space for the list */
  173. retval = (char **)slapi_ch_calloc(num+1, sizeof(char *));
  174. /* traverse the avl tree and copy the filenames into the list */
  175. dw.list = retval;
  176. dw.n = 0;
  177. dw.max = num;
  178. dw.dirname = dirname;
  179. (void)avl_apply(filetree, add_file_to_list, &dw, -1, AVL_INORDER);
  180. retval[num] = 0; /* set last entry to null */
  181. /* delete the avl tree and all its data */
  182. avl_free(filetree, free_string);
  183. return retval;
  184. }
  185. void
  186. free_filelist(char **filelist)
  187. {
  188. int ii;
  189. for (ii = 0; filelist && filelist[ii]; ++ii)
  190. slapi_ch_free((void **)&filelist[ii]);
  191. slapi_ch_free((void **)&filelist);
  192. }
  193. /**
  194. * Returns a list of files in order of "priority" where priority is defined
  195. * as:
  196. * The first two characters in the filename are digits representing a
  197. * number from 00 to 99. The lower the number the higher the
  198. * priority. For example, 00 is in the list before 01, and 99 is the
  199. * last item in the list. The ordering of files with the same
  200. * priority cannot be guaranteed. The pattern is the grep style
  201. * regular expression of filenames to match which is applied to the
  202. * end of the string. If you are a Solaris person, you may recognize
  203. * this as the rules for init level initialization using shell scripts
  204. * under /etc/rcX.d/
  205. */
  206. char **
  207. get_priority_filelist(const char *directory, const char *pattern)
  208. {
  209. char *basepattern = "^[0-9][0-9]";
  210. char *genericpattern = ".*"; /* used if pattern is null */
  211. char *bigpattern = 0;
  212. char **retval = 0;
  213. if (!pattern)
  214. pattern = genericpattern;
  215. bigpattern = slapi_ch_smprintf("%s%s", basepattern, pattern);
  216. retval = get_filelist(directory, bigpattern, 0, 0, 1);
  217. slapi_ch_free((void **)&bigpattern);
  218. return retval;
  219. }