Back to index

glibc  2.9
bug-glob2.c
Go to the documentation of this file.
00001 /* Test glob memory management.
00002    for the filesystem access functions.
00003    Copyright (C) 2001, 2002, 2004 Free Software Foundation, Inc.
00004    This file is part of the GNU C Library.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <errno.h>
00022 #include <error.h>
00023 #include <dirent.h>
00024 #include <glob.h>
00025 #include <mcheck.h>
00026 #include <stdlib.h>
00027 #include <stdio.h>
00028 #include <string.h>
00029 #include <sys/stat.h>
00030 
00031 // #define DEBUG
00032 #ifdef DEBUG
00033 # define PRINTF(fmt, args...) \
00034   do                               \
00035     {                              \
00036       int save_errno = errno;             \
00037       printf (fmt, ##args);        \
00038       errno = save_errno;          \
00039     } while (0)
00040 #else
00041 # define PRINTF(fmt, args...)
00042 #endif
00043 
00044 
00045 static struct
00046 {
00047   const char *name;
00048   int level;
00049   int type;
00050   mode_t mode;
00051 } filesystem[] =
00052 {
00053   { ".", 1, DT_DIR, 0755 },
00054   { "..", 1, DT_DIR, 0755 },
00055   { "dir", 1, DT_DIR, 0755 },
00056     { ".", 2, DT_DIR, 0755 },
00057     { "..", 2, DT_DIR, 0755 },
00058     { "readable", 2, DT_DIR, 0755 },
00059       { ".", 3, DT_DIR, 0755 },
00060       { "..", 3, DT_DIR, 0755 },
00061       { "a", 3, DT_REG, 0644 },
00062     { "unreadable", 2, DT_DIR, 0111 },
00063       { ".", 3, DT_DIR, 0111 },
00064       { "..", 3, DT_DIR, 0755 },
00065       { "a", 3, DT_REG, 0644 },
00066     { "zz-readable", 2, DT_DIR, 0755 },
00067       { ".", 3, DT_DIR, 0755 },
00068       { "..", 3, DT_DIR, 0755 },
00069       { "a", 3, DT_REG, 0644 }
00070 };
00071 #define nfiles (sizeof (filesystem) / sizeof (filesystem[0]))
00072 
00073 
00074 typedef struct
00075 {
00076   int level;
00077   int idx;
00078   struct dirent d;
00079   char room_for_dirent[NAME_MAX];
00080 } my_DIR;
00081 
00082 
00083 static long int
00084 find_file (const char *s)
00085 {
00086   int level = 1;
00087   long int idx = 0;
00088 
00089   if (strcmp (s, ".") == 0)
00090     return 0;
00091 
00092   if (s[0] == '.' && s[1] == '/')
00093     s += 2;
00094 
00095   while (*s != '\0')
00096     {
00097       char *endp = strchrnul (s, '/');
00098 
00099       PRINTF ("looking for %.*s, level %d\n", (int) (endp - s), s, level);
00100 
00101       while (idx < nfiles && filesystem[idx].level >= level)
00102        {
00103          if (filesystem[idx].level == level
00104              && memcmp (s, filesystem[idx].name, endp - s) == 0
00105              && filesystem[idx].name[endp - s] == '\0')
00106            break;
00107          ++idx;
00108        }
00109 
00110       if (idx == nfiles || filesystem[idx].level < level)
00111        {
00112          errno = ENOENT;
00113          return -1;
00114        }
00115 
00116       if (*endp == '\0')
00117        return idx + 1;
00118 
00119       if (filesystem[idx].type != DT_DIR
00120          && (idx + 1 >= nfiles
00121              || filesystem[idx].level >= filesystem[idx + 1].level))
00122        {
00123          errno = ENOTDIR;
00124          return -1;
00125        }
00126 
00127       ++idx;
00128 
00129       s = endp + 1;
00130       ++level;
00131     }
00132 
00133   errno = ENOENT;
00134   return -1;
00135 }
00136 
00137 
00138 static void *
00139 my_opendir (const char *s)
00140 {
00141   long int idx = find_file (s);
00142   my_DIR *dir;
00143 
00144   if (idx == -1)
00145     {
00146       PRINTF ("my_opendir(\"%s\") == NULL (%m)\n", s);
00147       return NULL;
00148     }
00149 
00150   if ((filesystem[idx].mode & 0400) == 0)
00151     {
00152       errno = EACCES;
00153       PRINTF ("my_opendir(\"%s\") == NULL (%m)\n", s);
00154       return NULL;
00155     }
00156 
00157   dir = (my_DIR *) malloc (sizeof (my_DIR));
00158   if (dir == NULL)
00159     {
00160       printf ("cannot allocate directory handle: %m\n");
00161       exit (EXIT_FAILURE);
00162     }
00163 
00164   dir->level = filesystem[idx].level;
00165   dir->idx = idx;
00166 
00167   PRINTF ("my_opendir(\"%s\") == { level: %d, idx: %ld }\n",
00168          s, filesystem[idx].level, idx);
00169 
00170   return dir;
00171 }
00172 
00173 
00174 static struct dirent *
00175 my_readdir (void *gdir)
00176 {
00177   my_DIR *dir = gdir;
00178 
00179   if (dir->idx == -1)
00180     {
00181       PRINTF ("my_readdir ({ level: %d, idx: %ld }) = NULL\n",
00182              dir->level, (long int) dir->idx);
00183       return NULL;
00184     }
00185 
00186   while (dir->idx < nfiles && filesystem[dir->idx].level > dir->level)
00187     ++dir->idx;
00188 
00189   if (dir->idx == nfiles || filesystem[dir->idx].level < dir->level)
00190     {
00191       dir->idx = -1;
00192       PRINTF ("my_readdir ({ level: %d, idx: %ld }) = NULL\n",
00193              dir->level, (long int) dir->idx);
00194       return NULL;
00195     }
00196 
00197   dir->d.d_ino = dir->idx;
00198 
00199 #ifdef _DIRENT_HAVE_D_TYPE
00200   dir->d.d_type = filesystem[dir->idx].type;
00201 #endif
00202 
00203   strcpy (dir->d.d_name, filesystem[dir->idx].name);
00204 
00205 #ifdef _DIRENT_HAVE_D_TYPE
00206   PRINTF ("my_readdir ({ level: %d, idx: %ld }) = { d_ino: %ld, d_type: %d, d_name: \"%s\" }\n",
00207          dir->level, (long int) dir->idx, dir->d.d_ino, dir->d.d_type,
00208          dir->d.d_name);
00209 #else
00210   PRINTF ("my_readdir ({ level: %d, idx: %ld }) = { d_ino: %ld, d_name: \"%s\" }\n",
00211          dir->level, (long int) dir->idx, dir->d.d_ino,
00212          dir->d.d_name);
00213 #endif
00214 
00215   ++dir->idx;
00216 
00217   return &dir->d;
00218 }
00219 
00220 
00221 static void
00222 my_closedir (void *dir)
00223 {
00224   PRINTF ("my_closedir ()\n");
00225   free (dir);
00226 }
00227 
00228 
00229 /* We use this function for lstat as well since we don't have any.  */
00230 static int
00231 my_stat (const char *name, struct stat *st)
00232 {
00233   long int idx = find_file (name);
00234 
00235   if (idx == -1)
00236     {
00237       PRINTF ("my_stat (\"%s\", ...) = -1 (%m)\n", name);
00238       return -1;
00239     }
00240 
00241   memset (st, '\0', sizeof (*st));
00242 
00243   if (filesystem[idx].type == DT_UNKNOWN)
00244     st->st_mode = DTTOIF (idx + 1 < nfiles
00245                        && filesystem[idx].level < filesystem[idx + 1].level
00246                        ? DT_DIR : DT_REG) | filesystem[idx].mode;
00247   else
00248     st->st_mode = DTTOIF (filesystem[idx].type) | filesystem[idx].mode;
00249 
00250   PRINTF ("my_stat (\"%s\", { st_mode: %o }) = 0\n", name, st->st_mode);
00251 
00252   return 0;
00253 }
00254 
00255 
00256 static void
00257 init_glob_altdirfuncs (glob_t *pglob)
00258 {
00259   pglob->gl_closedir = my_closedir;
00260   pglob->gl_readdir = my_readdir;
00261   pglob->gl_opendir = my_opendir;
00262   pglob->gl_lstat = my_stat;
00263   pglob->gl_stat = my_stat;
00264 }
00265 
00266 
00267 int
00268 do_test (void)
00269 {
00270   mtrace ();
00271 
00272   glob_t gl;
00273   memset (&gl, 0, sizeof (gl));
00274   init_glob_altdirfuncs (&gl);
00275 
00276   if (glob ("dir/*able/*", GLOB_ERR | GLOB_ALTDIRFUNC, NULL, &gl)
00277       != GLOB_ABORTED)
00278     {
00279       puts ("glob did not fail with GLOB_ABORTED");
00280       exit (EXIT_FAILURE); 
00281     }
00282 
00283   globfree (&gl);
00284 
00285   memset (&gl, 0, sizeof (gl));
00286   init_glob_altdirfuncs (&gl);
00287 
00288   gl.gl_offs = 3;
00289   if (glob ("dir2/*", GLOB_DOOFFS, NULL, &gl) != GLOB_NOMATCH)
00290     {
00291       puts ("glob did not fail with GLOB_NOMATCH");
00292       exit (EXIT_FAILURE); 
00293     }
00294 
00295   globfree (&gl);
00296 
00297   muntrace ();
00298 
00299   return 0;
00300 }
00301 
00302 #define TEST_FUNCTION do_test ()
00303 #include "../test-skeleton.c"