bug-glob2.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  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, see
  15. <http://www.gnu.org/licenses/>. */
  16. #include <errno.h>
  17. #include <error.h>
  18. #include <dirent.h>
  19. #include <glob.h>
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <sys/stat.h>
  24. // #define DEBUG
  25. #ifdef DEBUG
  26. # define PRINTF(fmt, args...) \
  27. do \
  28. { \
  29. int save_errno = errno; \
  30. printf (fmt, ##args); \
  31. errno = save_errno; \
  32. } while (0)
  33. #else
  34. # define PRINTF(fmt, args...)
  35. #endif
  36. #ifdef GLOB_ALTDIRFUNC
  37. static struct
  38. {
  39. const char *name;
  40. int level;
  41. int type;
  42. mode_t mode;
  43. } filesystem[] =
  44. {
  45. { ".", 1, DT_DIR, 0755 },
  46. { "..", 1, DT_DIR, 0755 },
  47. { "dir", 1, DT_DIR, 0755 },
  48. { ".", 2, DT_DIR, 0755 },
  49. { "..", 2, DT_DIR, 0755 },
  50. { "readable", 2, DT_DIR, 0755 },
  51. { ".", 3, DT_DIR, 0755 },
  52. { "..", 3, DT_DIR, 0755 },
  53. { "a", 3, DT_REG, 0644 },
  54. { "unreadable", 2, DT_DIR, 0111 },
  55. { ".", 3, DT_DIR, 0111 },
  56. { "..", 3, DT_DIR, 0755 },
  57. { "a", 3, DT_REG, 0644 },
  58. { "zz-readable", 2, DT_DIR, 0755 },
  59. { ".", 3, DT_DIR, 0755 },
  60. { "..", 3, DT_DIR, 0755 },
  61. { "a", 3, DT_REG, 0644 }
  62. };
  63. #define nfiles (sizeof (filesystem) / sizeof (filesystem[0]))
  64. typedef struct
  65. {
  66. int level;
  67. int idx;
  68. struct dirent d;
  69. char room_for_dirent[NAME_MAX];
  70. } my_DIR;
  71. static long int
  72. find_file (const char *s)
  73. {
  74. int level = 1;
  75. long int idx = 0;
  76. if (strcmp (s, ".") == 0)
  77. return 0;
  78. if (s[0] == '.' && s[1] == '/')
  79. s += 2;
  80. while (*s != '\0')
  81. {
  82. char *endp = strchrnul (s, '/');
  83. PRINTF ("looking for %.*s, level %d\n", (int) (endp - s), s, level);
  84. while (idx < nfiles && filesystem[idx].level >= level)
  85. {
  86. if (filesystem[idx].level == level
  87. && memcmp (s, filesystem[idx].name, endp - s) == 0
  88. && filesystem[idx].name[endp - s] == '\0')
  89. break;
  90. ++idx;
  91. }
  92. if (idx == nfiles || filesystem[idx].level < level)
  93. {
  94. errno = ENOENT;
  95. return -1;
  96. }
  97. if (*endp == '\0')
  98. return idx + 1;
  99. if (filesystem[idx].type != DT_DIR
  100. && (idx + 1 >= nfiles
  101. || filesystem[idx].level >= filesystem[idx + 1].level))
  102. {
  103. errno = ENOTDIR;
  104. return -1;
  105. }
  106. ++idx;
  107. s = endp + 1;
  108. ++level;
  109. }
  110. errno = ENOENT;
  111. return -1;
  112. }
  113. static void *
  114. my_opendir (const char *s)
  115. {
  116. long int idx = find_file (s);
  117. my_DIR *dir;
  118. if (idx == -1)
  119. {
  120. PRINTF ("my_opendir(\"%s\") == NULL (%m)\n", s);
  121. return NULL;
  122. }
  123. if ((filesystem[idx].mode & 0400) == 0)
  124. {
  125. errno = EACCES;
  126. PRINTF ("my_opendir(\"%s\") == NULL (%m)\n", s);
  127. return NULL;
  128. }
  129. dir = (my_DIR *) malloc (sizeof (my_DIR));
  130. if (dir == NULL)
  131. {
  132. printf ("cannot allocate directory handle: %m\n");
  133. exit (EXIT_FAILURE);
  134. }
  135. dir->level = filesystem[idx].level;
  136. dir->idx = idx;
  137. PRINTF ("my_opendir(\"%s\") == { level: %d, idx: %ld }\n",
  138. s, filesystem[idx].level, idx);
  139. return dir;
  140. }
  141. static struct dirent *
  142. my_readdir (void *gdir)
  143. {
  144. my_DIR *dir = gdir;
  145. if (dir->idx == -1)
  146. {
  147. PRINTF ("my_readdir ({ level: %d, idx: %ld }) = NULL\n",
  148. dir->level, (long int) dir->idx);
  149. return NULL;
  150. }
  151. while (dir->idx < nfiles && filesystem[dir->idx].level > dir->level)
  152. ++dir->idx;
  153. if (dir->idx == nfiles || filesystem[dir->idx].level < dir->level)
  154. {
  155. dir->idx = -1;
  156. PRINTF ("my_readdir ({ level: %d, idx: %ld }) = NULL\n",
  157. dir->level, (long int) dir->idx);
  158. return NULL;
  159. }
  160. dir->d.d_ino = dir->idx;
  161. #ifdef _DIRENT_HAVE_D_TYPE
  162. dir->d.d_type = filesystem[dir->idx].type;
  163. #endif
  164. strcpy (dir->d.d_name, filesystem[dir->idx].name);
  165. #ifdef _DIRENT_HAVE_D_TYPE
  166. PRINTF ("my_readdir ({ level: %d, idx: %ld }) = { d_ino: %ld, d_type: %d, d_name: \"%s\" }\n",
  167. dir->level, (long int) dir->idx, dir->d.d_ino, dir->d.d_type,
  168. dir->d.d_name);
  169. #else
  170. PRINTF ("my_readdir ({ level: %d, idx: %ld }) = { d_ino: %ld, d_name: \"%s\" }\n",
  171. dir->level, (long int) dir->idx, dir->d.d_ino,
  172. dir->d.d_name);
  173. #endif
  174. ++dir->idx;
  175. return &dir->d;
  176. }
  177. static void
  178. my_closedir (void *dir)
  179. {
  180. PRINTF ("my_closedir ()\n");
  181. free (dir);
  182. }
  183. /* We use this function for lstat as well since we don't have any. */
  184. static int
  185. my_stat (const char *name, struct stat *st)
  186. {
  187. long int idx = find_file (name);
  188. if (idx == -1)
  189. {
  190. PRINTF ("my_stat (\"%s\", ...) = -1 (%m)\n", name);
  191. return -1;
  192. }
  193. memset (st, '\0', sizeof (*st));
  194. if (filesystem[idx].type == DT_UNKNOWN)
  195. st->st_mode = DTTOIF (idx + 1 < nfiles
  196. && filesystem[idx].level < filesystem[idx + 1].level
  197. ? DT_DIR : DT_REG) | filesystem[idx].mode;
  198. else
  199. st->st_mode = DTTOIF (filesystem[idx].type) | filesystem[idx].mode;
  200. PRINTF ("my_stat (\"%s\", { st_mode: %o }) = 0\n", name, st->st_mode);
  201. return 0;
  202. }
  203. static void
  204. init_glob_altdirfuncs (glob_t *pglob)
  205. {
  206. pglob->gl_closedir = my_closedir;
  207. pglob->gl_readdir = my_readdir;
  208. pglob->gl_opendir = my_opendir;
  209. pglob->gl_lstat = my_stat;
  210. pglob->gl_stat = my_stat;
  211. }
  212. static int
  213. do_test (void)
  214. {
  215. glob_t gl;
  216. memset (&gl, 0, sizeof (gl));
  217. init_glob_altdirfuncs (&gl);
  218. if (glob ("dir/*able/*", GLOB_ERR | GLOB_ALTDIRFUNC, NULL, &gl)
  219. != GLOB_ABORTED)
  220. {
  221. puts ("glob did not fail with GLOB_ABORTED");
  222. exit (EXIT_FAILURE);
  223. }
  224. globfree (&gl);
  225. memset (&gl, 0, sizeof (gl));
  226. init_glob_altdirfuncs (&gl);
  227. gl.gl_offs = 3;
  228. if (glob ("dir2/*", GLOB_DOOFFS, NULL, &gl) != GLOB_NOMATCH)
  229. {
  230. puts ("glob did not fail with GLOB_NOMATCH");
  231. exit (EXIT_FAILURE);
  232. }
  233. globfree (&gl);
  234. return 0;
  235. }
  236. #else
  237. static int do_test (void) { return 0; }
  238. #endif
  239. #define TEST_FUNCTION do_test ()
  240. #include "../test-skeleton.c"