bug-glob2.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. /* Test glob memory management.
  2. for the filesystem access functions.
  3. Copyright (C) 2001, 2002, 2004 Free Software Foundation, Inc.
  4. This file is part of the GNU C Library.
  5. The GNU C Library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Lesser General Public
  7. License as published by the Free Software Foundation; either
  8. version 2.1 of the License, or (at your option) any later version.
  9. The GNU C Library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public
  14. License along with the GNU C Library; if not, write to the Free
  15. Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  16. 02111-1307 USA. */
  17. #include <errno.h>
  18. #include <error.h>
  19. #include <dirent.h>
  20. #include <glob.h>
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <string.h>
  24. #include <sys/stat.h>
  25. // #define DEBUG
  26. #ifdef DEBUG
  27. # define PRINTF(fmt, args...) \
  28. do \
  29. { \
  30. int save_errno = errno; \
  31. printf (fmt, ##args); \
  32. errno = save_errno; \
  33. } while (0)
  34. #else
  35. # define PRINTF(fmt, args...)
  36. #endif
  37. #ifdef GLOB_ALTDIRFUNC
  38. static struct
  39. {
  40. const char *name;
  41. int level;
  42. int type;
  43. mode_t mode;
  44. } filesystem[] =
  45. {
  46. { ".", 1, DT_DIR, 0755 },
  47. { "..", 1, DT_DIR, 0755 },
  48. { "dir", 1, DT_DIR, 0755 },
  49. { ".", 2, DT_DIR, 0755 },
  50. { "..", 2, DT_DIR, 0755 },
  51. { "readable", 2, DT_DIR, 0755 },
  52. { ".", 3, DT_DIR, 0755 },
  53. { "..", 3, DT_DIR, 0755 },
  54. { "a", 3, DT_REG, 0644 },
  55. { "unreadable", 2, DT_DIR, 0111 },
  56. { ".", 3, DT_DIR, 0111 },
  57. { "..", 3, DT_DIR, 0755 },
  58. { "a", 3, DT_REG, 0644 },
  59. { "zz-readable", 2, DT_DIR, 0755 },
  60. { ".", 3, DT_DIR, 0755 },
  61. { "..", 3, DT_DIR, 0755 },
  62. { "a", 3, DT_REG, 0644 }
  63. };
  64. #define nfiles (sizeof (filesystem) / sizeof (filesystem[0]))
  65. typedef struct
  66. {
  67. int level;
  68. int idx;
  69. struct dirent d;
  70. char room_for_dirent[NAME_MAX];
  71. } my_DIR;
  72. static long int
  73. find_file (const char *s)
  74. {
  75. int level = 1;
  76. long int idx = 0;
  77. if (strcmp (s, ".") == 0)
  78. return 0;
  79. if (s[0] == '.' && s[1] == '/')
  80. s += 2;
  81. while (*s != '\0')
  82. {
  83. char *endp = strchrnul (s, '/');
  84. PRINTF ("looking for %.*s, level %d\n", (int) (endp - s), s, level);
  85. while (idx < nfiles && filesystem[idx].level >= level)
  86. {
  87. if (filesystem[idx].level == level
  88. && memcmp (s, filesystem[idx].name, endp - s) == 0
  89. && filesystem[idx].name[endp - s] == '\0')
  90. break;
  91. ++idx;
  92. }
  93. if (idx == nfiles || filesystem[idx].level < level)
  94. {
  95. errno = ENOENT;
  96. return -1;
  97. }
  98. if (*endp == '\0')
  99. return idx + 1;
  100. if (filesystem[idx].type != DT_DIR
  101. && (idx + 1 >= nfiles
  102. || filesystem[idx].level >= filesystem[idx + 1].level))
  103. {
  104. errno = ENOTDIR;
  105. return -1;
  106. }
  107. ++idx;
  108. s = endp + 1;
  109. ++level;
  110. }
  111. errno = ENOENT;
  112. return -1;
  113. }
  114. static void *
  115. my_opendir (const char *s)
  116. {
  117. long int idx = find_file (s);
  118. my_DIR *dir;
  119. if (idx == -1)
  120. {
  121. PRINTF ("my_opendir(\"%s\") == NULL (%m)\n", s);
  122. return NULL;
  123. }
  124. if ((filesystem[idx].mode & 0400) == 0)
  125. {
  126. errno = EACCES;
  127. PRINTF ("my_opendir(\"%s\") == NULL (%m)\n", s);
  128. return NULL;
  129. }
  130. dir = (my_DIR *) malloc (sizeof (my_DIR));
  131. if (dir == NULL)
  132. {
  133. printf ("cannot allocate directory handle: %m\n");
  134. exit (EXIT_FAILURE);
  135. }
  136. dir->level = filesystem[idx].level;
  137. dir->idx = idx;
  138. PRINTF ("my_opendir(\"%s\") == { level: %d, idx: %ld }\n",
  139. s, filesystem[idx].level, idx);
  140. return dir;
  141. }
  142. static struct dirent *
  143. my_readdir (void *gdir)
  144. {
  145. my_DIR *dir = gdir;
  146. if (dir->idx == -1)
  147. {
  148. PRINTF ("my_readdir ({ level: %d, idx: %ld }) = NULL\n",
  149. dir->level, (long int) dir->idx);
  150. return NULL;
  151. }
  152. while (dir->idx < nfiles && filesystem[dir->idx].level > dir->level)
  153. ++dir->idx;
  154. if (dir->idx == nfiles || filesystem[dir->idx].level < dir->level)
  155. {
  156. dir->idx = -1;
  157. PRINTF ("my_readdir ({ level: %d, idx: %ld }) = NULL\n",
  158. dir->level, (long int) dir->idx);
  159. return NULL;
  160. }
  161. dir->d.d_ino = dir->idx;
  162. #ifdef _DIRENT_HAVE_D_TYPE
  163. dir->d.d_type = filesystem[dir->idx].type;
  164. #endif
  165. strcpy (dir->d.d_name, filesystem[dir->idx].name);
  166. #ifdef _DIRENT_HAVE_D_TYPE
  167. PRINTF ("my_readdir ({ level: %d, idx: %ld }) = { d_ino: %ld, d_type: %d, d_name: \"%s\" }\n",
  168. dir->level, (long int) dir->idx, dir->d.d_ino, dir->d.d_type,
  169. dir->d.d_name);
  170. #else
  171. PRINTF ("my_readdir ({ level: %d, idx: %ld }) = { d_ino: %ld, d_name: \"%s\" }\n",
  172. dir->level, (long int) dir->idx, dir->d.d_ino,
  173. dir->d.d_name);
  174. #endif
  175. ++dir->idx;
  176. return &dir->d;
  177. }
  178. static void
  179. my_closedir (void *dir)
  180. {
  181. PRINTF ("my_closedir ()\n");
  182. free (dir);
  183. }
  184. /* We use this function for lstat as well since we don't have any. */
  185. static int
  186. my_stat (const char *name, struct stat *st)
  187. {
  188. long int idx = find_file (name);
  189. if (idx == -1)
  190. {
  191. PRINTF ("my_stat (\"%s\", ...) = -1 (%m)\n", name);
  192. return -1;
  193. }
  194. memset (st, '\0', sizeof (*st));
  195. if (filesystem[idx].type == DT_UNKNOWN)
  196. st->st_mode = DTTOIF (idx + 1 < nfiles
  197. && filesystem[idx].level < filesystem[idx + 1].level
  198. ? DT_DIR : DT_REG) | filesystem[idx].mode;
  199. else
  200. st->st_mode = DTTOIF (filesystem[idx].type) | filesystem[idx].mode;
  201. PRINTF ("my_stat (\"%s\", { st_mode: %o }) = 0\n", name, st->st_mode);
  202. return 0;
  203. }
  204. static void
  205. init_glob_altdirfuncs (glob_t *pglob)
  206. {
  207. pglob->gl_closedir = my_closedir;
  208. pglob->gl_readdir = my_readdir;
  209. pglob->gl_opendir = my_opendir;
  210. pglob->gl_lstat = my_stat;
  211. pglob->gl_stat = my_stat;
  212. }
  213. int
  214. do_test (void)
  215. {
  216. glob_t gl;
  217. memset (&gl, 0, sizeof (gl));
  218. init_glob_altdirfuncs (&gl);
  219. if (glob ("dir/*able/*", GLOB_ERR | GLOB_ALTDIRFUNC, NULL, &gl)
  220. != GLOB_ABORTED)
  221. {
  222. puts ("glob did not fail with GLOB_ABORTED");
  223. exit (EXIT_FAILURE);
  224. }
  225. globfree (&gl);
  226. memset (&gl, 0, sizeof (gl));
  227. init_glob_altdirfuncs (&gl);
  228. gl.gl_offs = 3;
  229. if (glob ("dir2/*", GLOB_DOOFFS, NULL, &gl) != GLOB_NOMATCH)
  230. {
  231. puts ("glob did not fail with GLOB_NOMATCH");
  232. exit (EXIT_FAILURE);
  233. }
  234. globfree (&gl);
  235. return 0;
  236. }
  237. #else
  238. int do_test (void) { return 0; }
  239. #endif
  240. #define TEST_FUNCTION do_test ()
  241. #include "../test-skeleton.c"