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