bug-glob2.c 6.4 KB

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