1commit 68302147ee061c69eb447e243ad9a18ef4cfbc4c
2Author: Florian Weimer <fweimer@redhat.com>
3Date: Fri Apr 29 09:33:07 2016 +0200
4
5 glob: Simplify the interface for the GLOB_ALTDIRFUNC callback gl_readdir
6
7 Previously, application code had to set up the d_namlen member if
8 the target supported it, involving conditional compilation. After
9 this change, glob will use the length of the string in d_name instead
10 of d_namlen to determine the file name length. All glibc targets
11 provide the d_type and d_ino members, and setting them as needed for
12 gl_readdir is straightforward.
13
14 Changing the behavior with regards to d_ino is left to a future
15 cleanup.
16
17 (cherry picked from commit 137fe72eca6923a00381a3ca9f0e7672c1f85e3f)
18
19diff --git a/manual/examples/mkdirent.c b/manual/examples/mkdirent.c
20new file mode 100644
21index 0000000..f8400f4
22--- /dev/null
23+++ b/manual/examples/mkdirent.c
24@@ -0,0 +1,42 @@
25+/* Example for creating a struct dirent object for use with glob.
26+ Copyright (C) 2016 Free Software Foundation, Inc.
27+
28+ This program is free software; you can redistribute it and/or
29+ modify it under the terms of the GNU General Public License
30+ as published by the Free Software Foundation; either version 2
31+ of the License, or (at your option) any later version.
32+
33+ This program is distributed in the hope that it will be useful,
34+ but WITHOUT ANY WARRANTY; without even the implied warranty of
35+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36+ GNU General Public License for more details.
37+
38+ You should have received a copy of the GNU General Public License
39+ along with this program; if not, if not, see <http://www.gnu.org/licenses/>.
40+*/
41+
42+#include <dirent.h>
43+#include <errno.h>
44+#include <stddef.h>
45+#include <stdlib.h>
46+#include <string.h>
47+
48+struct dirent *
49+mkdirent (const char *name)
50+{
51+ size_t dirent_size = offsetof (struct dirent, d_name) + 1;
52+ size_t name_length = strlen (name);
53+ size_t total_size = dirent_size + name_length;
54+ if (total_size < dirent_size)
55+ {
56+ errno = ENOMEM;
57+ return NULL;
58+ }
59+ struct dirent *result = malloc (total_size);
60+ if (result == NULL)
61+ return NULL;
62+ result->d_type = DT_UNKNOWN;
63+ result->d_ino = 1; /* Do not skip this entry. */
64+ memcpy (result->d_name, name, name_length + 1);
65+ return result;
66+}
67diff --git a/manual/pattern.texi b/manual/pattern.texi
68index d1b9275..565e7eb 100644
69--- a/manual/pattern.texi
70+++ b/manual/pattern.texi
71@@ -237,7 +237,44 @@ function used to read the contents of a directory. It is used if the
72 @code{GLOB_ALTDIRFUNC} bit is set in the flag parameter. The type of
73 this field is @w{@code{struct dirent *(*) (void *)}}.
74
75-This is a GNU extension.
76+An implementation of @code{gl_readdir} needs to initialize the following
77+members of the @code{struct dirent} object:
78+
79+@table @code
80+@item d_type
81+This member should be set to the file type of the entry if it is known.
82+Otherwise, the value @code{DT_UNKNOWN} can be used. The @code{glob}
83+function may use the specified file type to avoid callbacks in cases
84+where the file type indicates that the data is not required.
85+
86+@item d_ino
87+This member needs to be non-zero, otherwise @code{glob} may skip the
88+current entry and call the @code{gl_readdir} callback function again to
89+retrieve another entry.
90+
91+@item d_name
92+This member must be set to the name of the entry. It must be
93+null-terminated.
94+@end table
95+
96+The example below shows how to allocate a @code{struct dirent} object
97+containing a given name.
98+
99+@smallexample
100+@include mkdirent.c.texi
101+@end smallexample
102+
103+The @code{glob} function reads the @code{struct dirent} members listed
104+above and makes a copy of the file name in the @code{d_name} member
105+immediately after the @code{gl_readdir} callback function returns.
106+Future invocations of any of the callback functions may dealloacte or
107+reuse the buffer. It is the responsibility of the caller of the
108+@code{glob} function to allocate and deallocate the buffer, around the
109+call to @code{glob} or using the callback functions. For example, an
110+application could allocate the buffer in the @code{gl_readdir} callback
111+function, and deallocate it in the @code{gl_closedir} callback function.
112+
113+The @code{gl_readdir} member is a GNU extension.
114
115 @item gl_opendir
116 The address of an alternative implementation of the @code{opendir}
117diff --git a/posix/bug-glob2.c b/posix/bug-glob2.c
118index ddf5ec9..0fdc5d0 100644
119--- a/posix/bug-glob2.c
120+++ b/posix/bug-glob2.c
121@@ -193,7 +193,7 @@ my_readdir (void *gdir)
122 return NULL;
123 }
124
125- dir->d.d_ino = dir->idx;
126+ dir->d.d_ino = 1; /* glob should not skip this entry. */
127
128 #ifdef _DIRENT_HAVE_D_TYPE
129 dir->d.d_type = filesystem[dir->idx].type;
130diff --git a/posix/glob.c b/posix/glob.c
131index 0c04c3c..9ae76ac 100644
132--- a/posix/glob.c
133+++ b/posix/glob.c
134@@ -57,10 +57,8 @@
135
136 #if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__
137 # include <dirent.h>
138-# define NAMLEN(dirent) strlen((dirent)->d_name)
139 #else
140 # define dirent direct
141-# define NAMLEN(dirent) (dirent)->d_namlen
142 # ifdef HAVE_SYS_NDIR_H
143 # include <sys/ndir.h>
144 # endif
145@@ -76,12 +74,6 @@
146 #endif
147
148
149-/* In GNU systems, <dirent.h> defines this macro for us. */
150-#ifdef _D_NAMLEN
151-# undef NAMLEN
152-# define NAMLEN(d) _D_NAMLEN(d)
153-#endif
154-
155 /* When used in the GNU libc the symbol _DIRENT_HAVE_D_TYPE is available
156 if the `d_type' member for `struct dirent' is available.
157 HAVE_STRUCT_DIRENT_D_TYPE plays the same role in GNULIB. */
158@@ -105,12 +97,6 @@
159
160 /* If the system has the `struct dirent64' type we use it internally. */
161 #if defined _LIBC && !defined COMPILE_GLOB64
162-# if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__
163-# define CONVERT_D_NAMLEN(d64, d32)
164-# else
165-# define CONVERT_D_NAMLEN(d64, d32) \
166- (d64)->d_namlen = (d32)->d_namlen;
167-# endif
168
169 # if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
170 # define CONVERT_D_INO(d64, d32)
171@@ -127,8 +113,7 @@
172 # endif
173
174 # define CONVERT_DIRENT_DIRENT64(d64, d32) \
175- memcpy ((d64)->d_name, (d32)->d_name, NAMLEN (d32) + 1); \
176- CONVERT_D_NAMLEN (d64, d32) \
177+ strcpy ((d64)->d_name, (d32)->d_name); \
178 CONVERT_D_INO (d64, d32) \
179 CONVERT_D_TYPE (d64, d32)
180 #endif
181@@ -1554,7 +1539,6 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
182 while (1)
183 {
184 const char *name;
185- size_t len;
186 #if defined _LIBC && !defined COMPILE_GLOB64
187 struct dirent64 *d;
188 union
189@@ -1622,12 +1606,10 @@ glob_in_dir (const char *pattern, const char *directory, int flags,
190 names = newnames;
191 cur = 0;
192 }
193- len = NAMLEN (d);
194- names->name[cur] = (char *) malloc (len + 1);
195+ names->name[cur] = strdup (d->d_name);
196 if (names->name[cur] == NULL)
197 goto memory_error;
198- *((char *) mempcpy (names->name[cur++], name, len))
199- = '\0';
200+ ++cur;
201 ++nfound;
202 }
203 }
204diff --git a/posix/tst-gnuglob.c b/posix/tst-gnuglob.c
205index 992b997..b7b859b 100644
206--- a/posix/tst-gnuglob.c
207+++ b/posix/tst-gnuglob.c
208@@ -211,7 +211,7 @@ my_readdir (void *gdir)
209 return NULL;
210 }
211
212- dir->d.d_ino = dir->idx;
213+ dir->d.d_ino = 1; /* glob should not skip this entry. */
214
215 #ifdef _DIRENT_HAVE_D_TYPE
216 dir->d.d_type = filesystem[dir->idx].type;