getfilelist.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * All rights reserved.
  5. *
  6. * License: GPL (version 3 or any later version).
  7. * See LICENSE for details.
  8. * END COPYRIGHT BLOCK **/
  9. #ifdef HAVE_CONFIG_H
  10. # include <config.h>
  11. #endif
  12. /***********************************************************************
  13. ** NAME
  14. ** getfilelist.c
  15. **
  16. ** DESCRIPTION
  17. **
  18. **
  19. ** AUTHOR
  20. ** Rich Megginson <[email protected]>
  21. **
  22. ***********************************************************************/
  23. /***********************************************************************
  24. ** Includes
  25. ***********************************************************************/
  26. #include "prio.h"
  27. #include "slap.h"
  28. #include "avl.h"
  29. struct data_wrapper {
  30. char **list;
  31. int n;
  32. int max;
  33. const char *dirname;
  34. };
  35. static int
  36. add_file_to_list(caddr_t data, caddr_t arg)
  37. {
  38. struct data_wrapper *dw = (struct data_wrapper *)arg;
  39. if (dw) {
  40. /* max is number of entries; the range of n is 0 - max-1 */
  41. PR_ASSERT(dw->n <= dw->max);
  42. PR_ASSERT(dw->list);
  43. PR_ASSERT(data);
  44. /* this strdup is free'd by free_filelist */
  45. dw->list[dw->n++] = slapi_ch_smprintf("%s/%s", dw->dirname, data);
  46. return 0;
  47. }
  48. return -1;
  49. }
  50. static void
  51. free_string(caddr_t data)
  52. {
  53. slapi_ch_free((void **)&data);
  54. }
  55. static int
  56. file_is_type_x(const char *dirname, const char *filename, PRFileType x)
  57. {
  58. struct PRFileInfo64 inf;
  59. int status = 0;
  60. char *fullpath = slapi_ch_smprintf("%s/%s", dirname, filename);
  61. if (PR_SUCCESS == PR_GetFileInfo64(fullpath, &inf) &&
  62. inf.type == x)
  63. status = 1;
  64. slapi_ch_free((void **)&fullpath);
  65. return status;
  66. }
  67. /* return true if the given path and file corresponds to a directory */
  68. static int
  69. is_a_dir(const char *dirname, const char *filename)
  70. {
  71. return file_is_type_x(dirname, filename, PR_FILE_DIRECTORY);
  72. }
  73. /* return true if the given path and file corresponds to a regular file */
  74. static int
  75. is_a_file(const char *dirname, const char *filename)
  76. {
  77. return file_is_type_x(dirname, filename, PR_FILE_FILE);
  78. }
  79. static int
  80. matches(const char *filename, const char *pattern)
  81. {
  82. Slapi_Regex *re = NULL;
  83. int match = 0;
  84. const char *error = NULL;
  85. if (!pattern)
  86. return 1; /* null pattern matches everything */
  87. /* Compile the pattern */
  88. re = slapi_re_comp( pattern, &error );
  89. if (re) {
  90. /* Matches the compiled pattern against the filename */
  91. match = slapi_re_exec( re, filename, -1 /* no time limit */ );
  92. slapi_re_free( re );
  93. }
  94. return match;
  95. }
  96. /**
  97. * getfilelist will return a list of all files and directories in the
  98. * given directory matching the given pattern. If dirname is NULL, the
  99. * current directory "." will be used. If the pattern is NULL, all files
  100. * and directories will be returned. The additional integer arguments
  101. * control which files and directories are selected. The default value
  102. * for all of them is 0, which will not return hidden files (e.g. files
  103. * beginning with . on unix), but will return both files and directories
  104. * If nofiles is non-zero, only directory names will be returned. If
  105. * nodirs is non-zero, only filenames will be returned.
  106. * The pattern is a grep style regular expression, not a shell or command
  107. * interpreter style regular expression. For example, to get all files ending
  108. * in .ldif, use ".*\\.ldif" instead of "*.ldif"
  109. * The return value is a NULL terminated array of names.
  110. */
  111. char **
  112. get_filelist(
  113. const char *dirname, /* directory path; if NULL, uses "." */
  114. const char *pattern, /* grep (not shell!) file pattern regex */
  115. int hiddenfiles, /* if true, return hidden files and directories too */
  116. int nofiles, /* if true, do not return files */
  117. int nodirs /* if true, do not return directories */
  118. )
  119. {
  120. Avlnode *filetree = 0;
  121. PRDir *dirptr = 0;
  122. PRDirEntry *dirent = 0;
  123. PRDirFlags dirflags = PR_SKIP_BOTH & PR_SKIP_HIDDEN;
  124. char **retval = 0;
  125. int num = 0;
  126. struct data_wrapper dw;
  127. if (!dirname)
  128. dirname = ".";
  129. if (hiddenfiles)
  130. dirflags = PR_SKIP_BOTH;
  131. if (!(dirptr = PR_OpenDir(dirname))) {
  132. return NULL;
  133. }
  134. /* read the directory entries into an ascii sorted avl tree */
  135. for (dirent = PR_ReadDir(dirptr, dirflags); dirent ;
  136. dirent = PR_ReadDir(dirptr, dirflags)) {
  137. if (nofiles && is_a_file(dirname, dirent->name))
  138. continue;
  139. if (nodirs && is_a_dir(dirname, dirent->name))
  140. continue;
  141. if (1 == matches(dirent->name, pattern)) {
  142. /* this strdup is free'd by free_string */
  143. char *newone = slapi_ch_strdup(dirent->name);
  144. avl_insert(&filetree, newone, strcmp, 0);
  145. num++;
  146. }
  147. }
  148. PR_CloseDir(dirptr);
  149. /* allocate space for the list */
  150. retval = (char **)slapi_ch_calloc(num+1, sizeof(char *));
  151. /* traverse the avl tree and copy the filenames into the list */
  152. dw.list = retval;
  153. dw.n = 0;
  154. dw.max = num;
  155. dw.dirname = dirname;
  156. (void)avl_apply(filetree, add_file_to_list, &dw, -1, AVL_INORDER);
  157. retval[num] = 0; /* set last entry to null */
  158. /* delete the avl tree and all its data */
  159. avl_free(filetree, free_string);
  160. return retval;
  161. }
  162. void
  163. free_filelist(char **filelist)
  164. {
  165. int ii;
  166. for (ii = 0; filelist && filelist[ii]; ++ii)
  167. slapi_ch_free((void **)&filelist[ii]);
  168. slapi_ch_free((void **)&filelist);
  169. }
  170. /**
  171. * Returns a list of files in order of "priority" where priority is defined
  172. * as:
  173. * The first two characters in the filename are digits representing a
  174. * number from 00 to 99. The lower the number the higher the
  175. * priority. For example, 00 is in the list before 01, and 99 is the
  176. * last item in the list. The ordering of files with the same
  177. * priority cannot be guaranteed. The pattern is the grep style
  178. * regular expression of filenames to match which is applied to the
  179. * end of the string. If you are a Solaris person, you may recognize
  180. * this as the rules for init level initialization using shell scripts
  181. * under /etc/rcX.d/
  182. */
  183. char **
  184. get_priority_filelist(const char *directory, const char *pattern)
  185. {
  186. char *basepattern = "^[0-9][0-9]";
  187. char *genericpattern = ".*"; /* used if pattern is null */
  188. char *bigpattern = 0;
  189. char **retval = 0;
  190. if (!pattern)
  191. pattern = genericpattern;
  192. bigpattern = slapi_ch_smprintf("%s%s", basepattern, pattern);
  193. retval = get_filelist(directory, bigpattern, 0, 0, 1);
  194. slapi_ch_free((void **)&bigpattern);
  195. return retval;
  196. }