1 |
commit: fb003cf688e133a0fe792bee345b400735b7c333 |
2 |
Author: Andreas K. Hüttel <dilfridge <AT> gentoo <DOT> org> |
3 |
AuthorDate: Tue Jan 4 10:58:39 2022 +0000 |
4 |
Commit: Andreas K. Hüttel <dilfridge <AT> gentoo <DOT> org> |
5 |
CommitDate: Tue Jan 4 10:58:39 2022 +0000 |
6 |
URL: https://gitweb.gentoo.org/proj/toolchain/glibc-patches.git/commit/?id=fb003cf6 |
7 |
|
8 |
Add patch series from azanella to fix 32bit qemu on 64bit filesystem regression |
9 |
|
10 |
Signed-off-by: Andreas K. Hüttel <dilfridge <AT> gentoo.org> |
11 |
|
12 |
...t-skip-entries-with-zero-d_ino-values-BZ-.patch | 182 ++++++++ |
13 |
...2-linux-Use-getdents64-on-non-LFS-readdir.patch | 204 +++++++++ |
14 |
...nternal-DIR-filepos-as-off64_t-BZ-23960-B.patch | 494 +++++++++++++++++++++ |
15 |
9999/0204-linux-Add-__readdir64_unlocked.patch | 181 ++++++++ |
16 |
9999/0205-linux-Add-__old_readdir64_unlocked.patch | 184 ++++++++ |
17 |
...etdents64-on-readdir64-compat-implementat.patch | 297 +++++++++++++ |
18 |
9999/0207-dirent-Deprecate-getdirentries.patch | 101 +++++ |
19 |
7 files changed, 1643 insertions(+) |
20 |
|
21 |
diff --git a/9999/0201-linux-Do-not-skip-entries-with-zero-d_ino-values-BZ-.patch b/9999/0201-linux-Do-not-skip-entries-with-zero-d_ino-values-BZ-.patch |
22 |
new file mode 100644 |
23 |
index 0000000..5325a91 |
24 |
--- /dev/null |
25 |
+++ b/9999/0201-linux-Do-not-skip-entries-with-zero-d_ino-values-BZ-.patch |
26 |
@@ -0,0 +1,182 @@ |
27 |
+From 7856a2b7ae88602bc9ee65e08fe652b6a6ad5f7e Mon Sep 17 00:00:00 2001 |
28 |
+From: Adhemerval Zanella <adhemerval.zanella@××××××.org> |
29 |
+Date: Tue, 20 Oct 2020 12:18:56 -0300 |
30 |
+Subject: [PATCH 1/7] linux: Do not skip entries with zero d_ino values [BZ |
31 |
+ #12165] |
32 |
+ |
33 |
+According to Linux commit 2adc376c55194 (vfs: avoid creation of inode |
34 |
+number 0 in get_next_ino) Linux did not treat d_ino == 0 as a special |
35 |
+case (it is a valid inode number). |
36 |
+ |
37 |
+This patch fixes readdir{64} by not ignoring entried with d_ino being |
38 |
+0. |
39 |
+ |
40 |
+Checked on x86_64-linux-gnu and i686-linux-gnu. |
41 |
+--- |
42 |
+ sysdeps/unix/sysv/linux/readdir.c | 59 +++++++++++------------------ |
43 |
+ sysdeps/unix/sysv/linux/readdir64.c | 59 +++++++++++------------------ |
44 |
+ 2 files changed, 44 insertions(+), 74 deletions(-) |
45 |
+ |
46 |
+diff --git a/sysdeps/unix/sysv/linux/readdir.c b/sysdeps/unix/sysv/linux/readdir.c |
47 |
+index b480135164..c0619ce06f 100644 |
48 |
+--- a/sysdeps/unix/sysv/linux/readdir.c |
49 |
++++ b/sysdeps/unix/sysv/linux/readdir.c |
50 |
+@@ -25,51 +25,36 @@ |
51 |
+ struct dirent * |
52 |
+ __readdir_unlocked (DIR *dirp) |
53 |
+ { |
54 |
+- struct dirent *dp; |
55 |
+- int saved_errno = errno; |
56 |
++ const int saved_errno = errno; |
57 |
+ |
58 |
+- do |
59 |
++ if (dirp->offset >= dirp->size) |
60 |
+ { |
61 |
+- size_t reclen; |
62 |
+- |
63 |
+- if (dirp->offset >= dirp->size) |
64 |
++ /* We've emptied out our buffer. Refill it. */ |
65 |
++ ssize_t bytes = __getdents (dirp->fd, dirp->data, dirp->allocation); |
66 |
++ if (bytes <= 0) |
67 |
+ { |
68 |
+- /* We've emptied out our buffer. Refill it. */ |
69 |
+- |
70 |
+- size_t maxread = dirp->allocation; |
71 |
+- ssize_t bytes; |
72 |
+- |
73 |
+- bytes = __getdents (dirp->fd, dirp->data, maxread); |
74 |
+- if (bytes <= 0) |
75 |
+- { |
76 |
+- /* On some systems getdents fails with ENOENT when the |
77 |
+- open directory has been rmdir'd already. POSIX.1 |
78 |
+- requires that we treat this condition like normal EOF. */ |
79 |
+- if (bytes < 0 && errno == ENOENT) |
80 |
+- bytes = 0; |
81 |
+- |
82 |
+- /* Don't modifiy errno when reaching EOF. */ |
83 |
+- if (bytes == 0) |
84 |
+- __set_errno (saved_errno); |
85 |
+- dp = NULL; |
86 |
+- break; |
87 |
+- } |
88 |
+- dirp->size = (size_t) bytes; |
89 |
+- |
90 |
+- /* Reset the offset into the buffer. */ |
91 |
+- dirp->offset = 0; |
92 |
++ /* On some systems getdents fails with ENOENT when the |
93 |
++ open directory has been rmdir'd already. POSIX.1 |
94 |
++ requires that we treat this condition like normal EOF. */ |
95 |
++ if (bytes < 0 && errno == ENOENT) |
96 |
++ bytes = 0; |
97 |
++ |
98 |
++ /* Don't modifiy errno when reaching EOF. */ |
99 |
++ if (bytes == 0) |
100 |
++ __set_errno (saved_errno); |
101 |
++ return NULL; |
102 |
+ } |
103 |
++ dirp->size = bytes; |
104 |
+ |
105 |
+- dp = (struct dirent *) &dirp->data[dirp->offset]; |
106 |
+- |
107 |
+- reclen = dp->d_reclen; |
108 |
++ /* Reset the offset into the buffer. */ |
109 |
++ dirp->offset = 0; |
110 |
++ } |
111 |
+ |
112 |
+- dirp->offset += reclen; |
113 |
++ struct dirent *dp = (struct dirent *) &dirp->data[dirp->offset]; |
114 |
+ |
115 |
+- dirp->filepos = dp->d_off; |
116 |
++ dirp->offset += dp->d_reclen; |
117 |
+ |
118 |
+- /* Skip deleted files. */ |
119 |
+- } while (dp->d_ino == 0); |
120 |
++ dirp->filepos = dp->d_off; |
121 |
+ |
122 |
+ return dp; |
123 |
+ } |
124 |
+diff --git a/sysdeps/unix/sysv/linux/readdir64.c b/sysdeps/unix/sysv/linux/readdir64.c |
125 |
+index 52b11eb9d9..3aea0b1df1 100644 |
126 |
+--- a/sysdeps/unix/sysv/linux/readdir64.c |
127 |
++++ b/sysdeps/unix/sysv/linux/readdir64.c |
128 |
+@@ -30,55 +30,40 @@ |
129 |
+ struct dirent64 * |
130 |
+ __readdir64 (DIR *dirp) |
131 |
+ { |
132 |
+- struct dirent64 *dp; |
133 |
+- int saved_errno = errno; |
134 |
++ const int saved_errno = errno; |
135 |
+ |
136 |
+ #if IS_IN (libc) |
137 |
+ __libc_lock_lock (dirp->lock); |
138 |
+ #endif |
139 |
+ |
140 |
+- do |
141 |
++ if (dirp->offset >= dirp->size) |
142 |
+ { |
143 |
+- size_t reclen; |
144 |
+- |
145 |
+- if (dirp->offset >= dirp->size) |
146 |
++ /* We've emptied out our buffer. Refill it. */ |
147 |
++ ssize_t bytes = __getdents64 (dirp->fd, dirp->data, dirp->allocation); |
148 |
++ if (bytes <= 0) |
149 |
+ { |
150 |
+- /* We've emptied out our buffer. Refill it. */ |
151 |
+- |
152 |
+- size_t maxread = dirp->allocation; |
153 |
+- ssize_t bytes; |
154 |
+- |
155 |
+- bytes = __getdents64 (dirp->fd, dirp->data, maxread); |
156 |
+- if (bytes <= 0) |
157 |
+- { |
158 |
+- /* On some systems getdents fails with ENOENT when the |
159 |
+- open directory has been rmdir'd already. POSIX.1 |
160 |
+- requires that we treat this condition like normal EOF. */ |
161 |
+- if (bytes < 0 && errno == ENOENT) |
162 |
+- bytes = 0; |
163 |
+- |
164 |
+- /* Don't modifiy errno when reaching EOF. */ |
165 |
+- if (bytes == 0) |
166 |
+- __set_errno (saved_errno); |
167 |
+- dp = NULL; |
168 |
+- break; |
169 |
+- } |
170 |
+- dirp->size = (size_t) bytes; |
171 |
+- |
172 |
+- /* Reset the offset into the buffer. */ |
173 |
+- dirp->offset = 0; |
174 |
++ /* On some systems getdents fails with ENOENT when the |
175 |
++ open directory has been rmdir'd already. POSIX.1 |
176 |
++ requires that we treat this condition like normal EOF. */ |
177 |
++ if (bytes < 0 && errno == ENOENT) |
178 |
++ bytes = 0; |
179 |
++ |
180 |
++ /* Don't modifiy errno when reaching EOF. */ |
181 |
++ if (bytes == 0) |
182 |
++ __set_errno (saved_errno); |
183 |
++ return NULL; |
184 |
+ } |
185 |
++ dirp->size = bytes; |
186 |
+ |
187 |
+- dp = (struct dirent64 *) &dirp->data[dirp->offset]; |
188 |
+- |
189 |
+- reclen = dp->d_reclen; |
190 |
++ /* Reset the offset into the buffer. */ |
191 |
++ dirp->offset = 0; |
192 |
++ } |
193 |
+ |
194 |
+- dirp->offset += reclen; |
195 |
++ struct dirent64 *dp = (struct dirent64 *) &dirp->data[dirp->offset]; |
196 |
+ |
197 |
+- dirp->filepos = dp->d_off; |
198 |
++ dirp->offset += dp->d_reclen; |
199 |
+ |
200 |
+- /* Skip deleted files. */ |
201 |
+- } while (dp->d_ino == 0); |
202 |
++ dirp->filepos = dp->d_off; |
203 |
+ |
204 |
+ #if IS_IN (libc) |
205 |
+ __libc_lock_unlock (dirp->lock); |
206 |
+-- |
207 |
+2.32.0 |
208 |
+ |
209 |
|
210 |
diff --git a/9999/0202-linux-Use-getdents64-on-non-LFS-readdir.patch b/9999/0202-linux-Use-getdents64-on-non-LFS-readdir.patch |
211 |
new file mode 100644 |
212 |
index 0000000..90910a6 |
213 |
--- /dev/null |
214 |
+++ b/9999/0202-linux-Use-getdents64-on-non-LFS-readdir.patch |
215 |
@@ -0,0 +1,204 @@ |
216 |
+From 5180512e6c81b1b0423572594983c74c499b7e1e Mon Sep 17 00:00:00 2001 |
217 |
+From: Adhemerval Zanella <adhemerval.zanella@××××××.org> |
218 |
+Date: Tue, 20 Oct 2020 13:37:15 -0300 |
219 |
+Subject: [PATCH 2/7] linux: Use getdents64 on non-LFS readdir |
220 |
+ |
221 |
+The opendir allocates a translation buffer to be used to return the |
222 |
+non-LFS readdir entry. The obtained dirent64 struct is translated |
223 |
+to the temporary buffer on each readdir call. |
224 |
+ |
225 |
+Entries that overflow d_off/d_ino and the buffer reallocation failure |
226 |
+(in case of large d_name) are ignored. |
227 |
+ |
228 |
+Checked on x86_64-linux-gnu and i686-linux-gnu. |
229 |
+--- |
230 |
+ sysdeps/unix/sysv/linux/closedir.c | 4 ++ |
231 |
+ sysdeps/unix/sysv/linux/dirstream.h | 5 ++ |
232 |
+ sysdeps/unix/sysv/linux/opendir.c | 21 +++++++ |
233 |
+ sysdeps/unix/sysv/linux/readdir.c | 97 +++++++++++++++++++++-------- |
234 |
+ 4 files changed, 101 insertions(+), 26 deletions(-) |
235 |
+ |
236 |
+diff --git a/sysdeps/unix/sysv/linux/closedir.c b/sysdeps/unix/sysv/linux/closedir.c |
237 |
+index 4bb5274b00..1f71445ad9 100644 |
238 |
+--- a/sysdeps/unix/sysv/linux/closedir.c |
239 |
++++ b/sysdeps/unix/sysv/linux/closedir.c |
240 |
+@@ -47,6 +47,10 @@ __closedir (DIR *dirp) |
241 |
+ __libc_lock_fini (dirp->lock); |
242 |
+ #endif |
243 |
+ |
244 |
++#if !_DIRENT_MATCHES_DIRENT64 |
245 |
++ free (dirp->tbuffer); |
246 |
++#endif |
247 |
++ |
248 |
+ free ((void *) dirp); |
249 |
+ |
250 |
+ return __close_nocancel (fd); |
251 |
+diff --git a/sysdeps/unix/sysv/linux/dirstream.h b/sysdeps/unix/sysv/linux/dirstream.h |
252 |
+index b5e1db8db0..64b1495ba0 100644 |
253 |
+--- a/sysdeps/unix/sysv/linux/dirstream.h |
254 |
++++ b/sysdeps/unix/sysv/linux/dirstream.h |
255 |
+@@ -41,6 +41,11 @@ struct __dirstream |
256 |
+ |
257 |
+ int errcode; /* Delayed error code. */ |
258 |
+ |
259 |
++#if !defined __OFF_T_MATCHES_OFF64_T || !defined __INO_T_MATCHES_INO64_T |
260 |
++ char *tbuffer; /* Translation buffer for non-LFS calls. */ |
261 |
++ size_t tbuffer_size; /* Size of translation buffer. */ |
262 |
++#endif |
263 |
++ |
264 |
+ /* Directory block. We must make sure that this block starts |
265 |
+ at an address that is aligned adequately enough to store |
266 |
+ dirent entries. Using the alignment of "void *" is not |
267 |
+diff --git a/sysdeps/unix/sysv/linux/opendir.c b/sysdeps/unix/sysv/linux/opendir.c |
268 |
+index 48f254d169..d7df13575e 100644 |
269 |
+--- a/sysdeps/unix/sysv/linux/opendir.c |
270 |
++++ b/sysdeps/unix/sysv/linux/opendir.c |
271 |
+@@ -120,6 +120,27 @@ __alloc_dir (int fd, bool close_fd, int flags, |
272 |
+ return NULL; |
273 |
+ } |
274 |
+ |
275 |
++#if !_DIRENT_MATCHES_DIRENT64 |
276 |
++ /* Allocates a translation buffer to use as the returned 'struct direct' |
277 |
++ for non-LFS 'readdir' calls. |
278 |
++ |
279 |
++ The initial NAME_MAX size should handle most cases, while readdir might |
280 |
++ expand the buffer if required. */ |
281 |
++ enum |
282 |
++ { |
283 |
++ tbuffer_size = sizeof (struct dirent) + NAME_MAX + 1 |
284 |
++ }; |
285 |
++ dirp->tbuffer = malloc (tbuffer_size); |
286 |
++ if (dirp->tbuffer == NULL) |
287 |
++ { |
288 |
++ free (dirp); |
289 |
++ if (close_fd) |
290 |
++ __close_nocancel_nostatus (fd); |
291 |
++ return NULL; |
292 |
++ } |
293 |
++ dirp->tbuffer_size = tbuffer_size; |
294 |
++#endif |
295 |
++ |
296 |
+ dirp->fd = fd; |
297 |
+ #if IS_IN (libc) |
298 |
+ __libc_lock_init (dirp->lock); |
299 |
+diff --git a/sysdeps/unix/sysv/linux/readdir.c b/sysdeps/unix/sysv/linux/readdir.c |
300 |
+index c0619ce06f..8647bb0aef 100644 |
301 |
+--- a/sysdeps/unix/sysv/linux/readdir.c |
302 |
++++ b/sysdeps/unix/sysv/linux/readdir.c |
303 |
+@@ -21,42 +21,87 @@ |
304 |
+ #if !_DIRENT_MATCHES_DIRENT64 |
305 |
+ #include <dirstream.h> |
306 |
+ |
307 |
++/* Translate the DP64 entry to the non-LFS one in the translation buffer |
308 |
++ at dirstream DS. Return true is the translation was possible or |
309 |
++ false if either an internal fields can be represented in the non-LFS |
310 |
++ entry or if the translation can not be resized. */ |
311 |
++static bool |
312 |
++dirstream_entry (struct __dirstream *ds, const struct dirent64 *dp64) |
313 |
++{ |
314 |
++ off_t d_off = dp64->d_off; |
315 |
++ if (d_off != dp64->d_off) |
316 |
++ return false; |
317 |
++ ino_t d_ino = dp64->d_ino; |
318 |
++ if (d_ino != dp64->d_ino) |
319 |
++ return false; |
320 |
++ |
321 |
++ /* Expand the translation buffer to hold the new name size. */ |
322 |
++ size_t new_reclen = sizeof (struct dirent) |
323 |
++ + dp64->d_reclen - offsetof (struct dirent64, d_name); |
324 |
++ if (new_reclen > ds->tbuffer_size) |
325 |
++ { |
326 |
++ char *newbuffer = realloc (ds->tbuffer, new_reclen); |
327 |
++ if (newbuffer == NULL) |
328 |
++ return false; |
329 |
++ ds->tbuffer = newbuffer; |
330 |
++ ds->tbuffer_size = new_reclen; |
331 |
++ } |
332 |
++ |
333 |
++ struct dirent *dp = (struct dirent *) ds->tbuffer; |
334 |
++ |
335 |
++ dp->d_off = d_off; |
336 |
++ dp->d_ino = d_ino; |
337 |
++ dp->d_reclen = new_reclen; |
338 |
++ dp->d_type = dp64->d_type; |
339 |
++ memcpy (dp->d_name, dp64->d_name, |
340 |
++ dp64->d_reclen - offsetof (struct dirent64, d_name)); |
341 |
++ |
342 |
++ return true; |
343 |
++} |
344 |
++ |
345 |
+ /* Read a directory entry from DIRP. */ |
346 |
+ struct dirent * |
347 |
+ __readdir_unlocked (DIR *dirp) |
348 |
+ { |
349 |
+ const int saved_errno = errno; |
350 |
+ |
351 |
+- if (dirp->offset >= dirp->size) |
352 |
++ while (1) |
353 |
+ { |
354 |
+- /* We've emptied out our buffer. Refill it. */ |
355 |
+- ssize_t bytes = __getdents (dirp->fd, dirp->data, dirp->allocation); |
356 |
+- if (bytes <= 0) |
357 |
++ if (dirp->offset >= dirp->size) |
358 |
+ { |
359 |
+- /* On some systems getdents fails with ENOENT when the |
360 |
+- open directory has been rmdir'd already. POSIX.1 |
361 |
+- requires that we treat this condition like normal EOF. */ |
362 |
+- if (bytes < 0 && errno == ENOENT) |
363 |
+- bytes = 0; |
364 |
+- |
365 |
+- /* Don't modifiy errno when reaching EOF. */ |
366 |
+- if (bytes == 0) |
367 |
+- __set_errno (saved_errno); |
368 |
+- return NULL; |
369 |
++ /* We've emptied out our buffer. Refill it. */ |
370 |
++ ssize_t bytes = __getdents64 (dirp->fd, dirp->data, |
371 |
++ dirp->allocation); |
372 |
++ if (bytes <= 0) |
373 |
++ { |
374 |
++ /* On some systems getdents fails with ENOENT when the |
375 |
++ open directory has been rmdir'd already. POSIX.1 |
376 |
++ requires that we treat this condition like normal EOF. */ |
377 |
++ if (bytes < 0 && errno == ENOENT) |
378 |
++ bytes = 0; |
379 |
++ |
380 |
++ /* Don't modifiy errno when reaching EOF. */ |
381 |
++ if (bytes == 0) |
382 |
++ __set_errno (saved_errno); |
383 |
++ return NULL; |
384 |
++ } |
385 |
++ dirp->size = bytes; |
386 |
++ |
387 |
++ /* Reset the offset into the buffer. */ |
388 |
++ dirp->offset = 0; |
389 |
++ } |
390 |
++ |
391 |
++ struct dirent64 *dp64 = (struct dirent64 *) &dirp->data[dirp->offset]; |
392 |
++ dirp->offset += dp64->d_reclen; |
393 |
++ |
394 |
++ /* Skip entries which might overflow d_off/d_ino or if the translation |
395 |
++ buffer can't be resized. */ |
396 |
++ if (dirstream_entry (dirp, dp64)) |
397 |
++ { |
398 |
++ dirp->filepos = dp64->d_off; |
399 |
++ return (struct dirent *) dirp->tbuffer; |
400 |
+ } |
401 |
+- dirp->size = bytes; |
402 |
+- |
403 |
+- /* Reset the offset into the buffer. */ |
404 |
+- dirp->offset = 0; |
405 |
+ } |
406 |
+- |
407 |
+- struct dirent *dp = (struct dirent *) &dirp->data[dirp->offset]; |
408 |
+- |
409 |
+- dirp->offset += dp->d_reclen; |
410 |
+- |
411 |
+- dirp->filepos = dp->d_off; |
412 |
+- |
413 |
+- return dp; |
414 |
+ } |
415 |
+ |
416 |
+ struct dirent * |
417 |
+-- |
418 |
+2.32.0 |
419 |
+ |
420 |
|
421 |
diff --git a/9999/0203-linux-Set-internal-DIR-filepos-as-off64_t-BZ-23960-B.patch b/9999/0203-linux-Set-internal-DIR-filepos-as-off64_t-BZ-23960-B.patch |
422 |
new file mode 100644 |
423 |
index 0000000..06e8d14 |
424 |
--- /dev/null |
425 |
+++ b/9999/0203-linux-Set-internal-DIR-filepos-as-off64_t-BZ-23960-B.patch |
426 |
@@ -0,0 +1,494 @@ |
427 |
+From 7d2845e6ed10f2109d2e0f6432932b6693f0037d Mon Sep 17 00:00:00 2001 |
428 |
+From: Adhemerval Zanella <adhemerval.zanella@××××××.org> |
429 |
+Date: Mon, 13 Apr 2020 18:09:20 -0300 |
430 |
+Subject: [PATCH 3/7] linux: Set internal DIR filepos as off64_t [BZ #23960, BZ |
431 |
+ #24050] |
432 |
+ |
433 |
+It allows to obtain the expected entry offset on telldir and set |
434 |
+it correctly on seekdir on platforms where long int is smaller |
435 |
+than off64_t. |
436 |
+ |
437 |
+On such cases telldir will mantain an internal list that maps the |
438 |
+DIR object off64_t offsets to the returned long int (the function |
439 |
+return value). The seekdir will then set the correct offset from |
440 |
+the internal list using the telldir as the list key. |
441 |
+ |
442 |
+It also removes the overflow check on readdir and the returned value |
443 |
+will be truncated by the non-LFS off_t size. As Joseph has noted |
444 |
+in BZ #23960 comment #22, d_off is an opaque value and since |
445 |
+telldir/seekdir works regardless of the returned dirent d_off value. |
446 |
+ |
447 |
+Finally it removed the requirement to check for overflow values on |
448 |
+telldir (BZ #24050). |
449 |
+ |
450 |
+Checked on x86_64-linux-gnu, i686-linux-gnu, powerpc-linux-gnu, |
451 |
+and arm-linux-gnueabihf. |
452 |
+--- |
453 |
+ dirent/Makefile | 2 +- |
454 |
+ dirent/tst-seekdir2.c | 158 ++++++++++++++++++++++++++++ |
455 |
+ sysdeps/unix/sysv/linux/closedir.c | 4 + |
456 |
+ sysdeps/unix/sysv/linux/dirstream.h | 6 +- |
457 |
+ sysdeps/unix/sysv/linux/opendir.c | 3 + |
458 |
+ sysdeps/unix/sysv/linux/readdir.c | 1 + |
459 |
+ sysdeps/unix/sysv/linux/rewinddir.c | 5 + |
460 |
+ sysdeps/unix/sysv/linux/seekdir.c | 36 ++++++- |
461 |
+ sysdeps/unix/sysv/linux/telldir.c | 47 ++++++++- |
462 |
+ sysdeps/unix/sysv/linux/telldir.h | 64 +++++++++++ |
463 |
+ 10 files changed, 317 insertions(+), 9 deletions(-) |
464 |
+ create mode 100644 dirent/tst-seekdir2.c |
465 |
+ create mode 100644 sysdeps/unix/sysv/linux/telldir.h |
466 |
+ |
467 |
+diff --git a/dirent/Makefile b/dirent/Makefile |
468 |
+index afc7226a5b..c7f046b3f7 100644 |
469 |
+--- a/dirent/Makefile |
470 |
++++ b/dirent/Makefile |
471 |
+@@ -31,7 +31,7 @@ routines := opendir closedir readdir readdir_r rewinddir \ |
472 |
+ scandir-cancel scandir-tail scandir64-tail |
473 |
+ |
474 |
+ tests := list tst-seekdir opendir-tst1 bug-readdir1 tst-fdopendir \ |
475 |
+- tst-fdopendir2 tst-scandir tst-scandir64 |
476 |
++ tst-fdopendir2 tst-scandir tst-scandir64 tst-seekdir2 |
477 |
+ |
478 |
+ CFLAGS-scandir.c += $(uses-callbacks) |
479 |
+ CFLAGS-scandir64.c += $(uses-callbacks) |
480 |
+diff --git a/dirent/tst-seekdir2.c b/dirent/tst-seekdir2.c |
481 |
+new file mode 100644 |
482 |
+index 0000000000..3e01b361e5 |
483 |
+--- /dev/null |
484 |
++++ b/dirent/tst-seekdir2.c |
485 |
+@@ -0,0 +1,158 @@ |
486 |
++/* Check multiple telldir and seekdir. |
487 |
++ Copyright (C) 2020 Free Software Foundation, Inc. |
488 |
++ This file is part of the GNU C Library. |
489 |
++ |
490 |
++ The GNU C Library is free software; you can redistribute it and/or |
491 |
++ modify it under the terms of the GNU Lesser General Public |
492 |
++ License as published by the Free Software Foundation; either |
493 |
++ version 2.1 of the License, or (at your option) any later version. |
494 |
++ |
495 |
++ The GNU C Library is distributed in the hope that it will be useful, |
496 |
++ but WITHOUT ANY WARRANTY; without even the implied warranty of |
497 |
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
498 |
++ Lesser General Public License for more details. |
499 |
++ |
500 |
++ You should have received a copy of the GNU Lesser General Public |
501 |
++ License along with the GNU C Library; if not, see |
502 |
++ <https://www.gnu.org/licenses/>. */ |
503 |
++ |
504 |
++#include <dirent.h> |
505 |
++#include <stdlib.h> |
506 |
++#include <unistd.h> |
507 |
++#include <stdio.h> |
508 |
++#include <string.h> |
509 |
++ |
510 |
++#include <support/temp_file.h> |
511 |
++#include <support/support.h> |
512 |
++#include <support/check.h> |
513 |
++ |
514 |
++/* Some filesystems returns a arbitrary value for d_off direnty entry (ext4 |
515 |
++ for instance, where the value is an internal hash key). The idea of |
516 |
++ create a large number of file is to try trigger a overflow d_off value |
517 |
++ in a entry to check if telldir/seekdir does work corretly in such |
518 |
++ case. */ |
519 |
++static const char *dirname; |
520 |
++static const size_t nfiles = 10240; |
521 |
++ |
522 |
++static void |
523 |
++do_prepare (int argc, char *argv[]) |
524 |
++{ |
525 |
++ dirname = support_create_temp_directory ("tst-seekdir2-"); |
526 |
++ |
527 |
++ for (size_t i = 0; i < nfiles; i++) |
528 |
++ { |
529 |
++ int fd = create_temp_file_in_dir ("tempfile.", dirname, NULL); |
530 |
++ TEST_VERIFY_EXIT (fd > 0); |
531 |
++ close (fd); |
532 |
++ } |
533 |
++} |
534 |
++#define PREPARE do_prepare |
535 |
++ |
536 |
++/* Check for old non Large File Support (LFS). */ |
537 |
++static int |
538 |
++do_test_not_lfs (void) |
539 |
++{ |
540 |
++ DIR *dirp = opendir (dirname); |
541 |
++ TEST_VERIFY_EXIT (dirp != NULL); |
542 |
++ |
543 |
++ size_t dirp_count = 0; |
544 |
++ for (struct dirent *dp = readdir (dirp); |
545 |
++ dp != NULL; |
546 |
++ dp = readdir (dirp)) |
547 |
++ dirp_count++; |
548 |
++ |
549 |
++ /* The 2 extra files are '.' and '..'. */ |
550 |
++ TEST_COMPARE (dirp_count, nfiles + 2); |
551 |
++ |
552 |
++ rewinddir (dirp); |
553 |
++ |
554 |
++ long *tdirp = xmalloc (dirp_count * sizeof (long)); |
555 |
++ struct dirent **ddirp = xmalloc (dirp_count * sizeof (struct dirent *)); |
556 |
++ |
557 |
++ size_t i = 0; |
558 |
++ do |
559 |
++ { |
560 |
++ tdirp[i] = telldir (dirp); |
561 |
++ struct dirent *dp = readdir (dirp); |
562 |
++ TEST_VERIFY_EXIT (dp != NULL); |
563 |
++ ddirp[i] = xmalloc (dp->d_reclen); |
564 |
++ memcpy (ddirp[i], dp, dp->d_reclen); |
565 |
++ } while (++i < dirp_count); |
566 |
++ |
567 |
++ for (i = 0; i < dirp_count - 1; i++) |
568 |
++ { |
569 |
++ seekdir (dirp, tdirp[i]); |
570 |
++ struct dirent *dp = readdir (dirp); |
571 |
++ TEST_COMPARE (strcmp (dp->d_name, ddirp[i]->d_name), 0); |
572 |
++ TEST_COMPARE (dp->d_ino, ddirp[i]->d_ino); |
573 |
++ TEST_COMPARE (dp->d_off, ddirp[i]->d_off); |
574 |
++ } |
575 |
++ |
576 |
++ closedir (dirp); |
577 |
++ free (tdirp); |
578 |
++ for (i = 0; i < dirp_count; i++) |
579 |
++ free (ddirp[i]); |
580 |
++ free (ddirp); |
581 |
++ |
582 |
++ return 0; |
583 |
++} |
584 |
++ |
585 |
++/* Same as before but with LFS support. */ |
586 |
++static int |
587 |
++do_test_lfs (void) |
588 |
++{ |
589 |
++ DIR *dirp = opendir (dirname); |
590 |
++ TEST_VERIFY_EXIT (dirp != NULL); |
591 |
++ |
592 |
++ size_t dirp_count = 0; |
593 |
++ for (struct dirent64 * dp = readdir64 (dirp); |
594 |
++ dp != NULL; |
595 |
++ dp = readdir64 (dirp)) |
596 |
++ dirp_count++; |
597 |
++ |
598 |
++ /* The 2 extra files are '.' and '..'. */ |
599 |
++ TEST_COMPARE (dirp_count, nfiles + 2); |
600 |
++ |
601 |
++ rewinddir (dirp); |
602 |
++ |
603 |
++ long *tdirp = xmalloc (dirp_count * sizeof (long)); |
604 |
++ struct dirent64 **ddirp = xmalloc (dirp_count * sizeof (struct dirent64 *)); |
605 |
++ |
606 |
++ size_t i = 0; |
607 |
++ do |
608 |
++ { |
609 |
++ tdirp[i] = telldir (dirp); |
610 |
++ struct dirent64 *dp = readdir64 (dirp); |
611 |
++ TEST_VERIFY_EXIT (dp != NULL); |
612 |
++ ddirp[i] = xmalloc (dp->d_reclen); |
613 |
++ memcpy (ddirp[i], dp, dp->d_reclen); |
614 |
++ } while (++i < dirp_count); |
615 |
++ |
616 |
++ for (i = 0; i < dirp_count - 1; i++) |
617 |
++ { |
618 |
++ seekdir (dirp, tdirp[i]); |
619 |
++ struct dirent64 *dp = readdir64 (dirp); |
620 |
++ TEST_COMPARE (strcmp (dp->d_name, ddirp[i]->d_name), 0); |
621 |
++ TEST_COMPARE (dp->d_ino, ddirp[i]->d_ino); |
622 |
++ TEST_COMPARE (dp->d_off, ddirp[i]->d_off); |
623 |
++ } |
624 |
++ |
625 |
++ closedir (dirp); |
626 |
++ free (tdirp); |
627 |
++ for (i = 0; i < dirp_count; i++) |
628 |
++ free (ddirp[i]); |
629 |
++ free (ddirp); |
630 |
++ |
631 |
++ return 0; |
632 |
++} |
633 |
++ |
634 |
++static int |
635 |
++do_test (void) |
636 |
++{ |
637 |
++ do_test_not_lfs (); |
638 |
++ do_test_lfs (); |
639 |
++ |
640 |
++ return 0; |
641 |
++} |
642 |
++ |
643 |
++#include <support/test-driver.c> |
644 |
+diff --git a/sysdeps/unix/sysv/linux/closedir.c b/sysdeps/unix/sysv/linux/closedir.c |
645 |
+index 1f71445ad9..1845c48be0 100644 |
646 |
+--- a/sysdeps/unix/sysv/linux/closedir.c |
647 |
++++ b/sysdeps/unix/sysv/linux/closedir.c |
648 |
+@@ -43,6 +43,10 @@ __closedir (DIR *dirp) |
649 |
+ |
650 |
+ fd = dirp->fd; |
651 |
+ |
652 |
++#ifndef __LP64__ |
653 |
++ dirstream_loc_clear (&dirp->locs); |
654 |
++#endif |
655 |
++ |
656 |
+ #if IS_IN (libc) |
657 |
+ __libc_lock_fini (dirp->lock); |
658 |
+ #endif |
659 |
+diff --git a/sysdeps/unix/sysv/linux/dirstream.h b/sysdeps/unix/sysv/linux/dirstream.h |
660 |
+index 64b1495ba0..1a3362fda6 100644 |
661 |
+--- a/sysdeps/unix/sysv/linux/dirstream.h |
662 |
++++ b/sysdeps/unix/sysv/linux/dirstream.h |
663 |
+@@ -21,6 +21,7 @@ |
664 |
+ #include <sys/types.h> |
665 |
+ |
666 |
+ #include <libc-lock.h> |
667 |
++#include <telldir.h> |
668 |
+ |
669 |
+ /* Directory stream type. |
670 |
+ |
671 |
+@@ -37,7 +38,7 @@ struct __dirstream |
672 |
+ size_t size; /* Total valid data in the block. */ |
673 |
+ size_t offset; /* Current offset into the block. */ |
674 |
+ |
675 |
+- off_t filepos; /* Position of next entry to read. */ |
676 |
++ off64_t filepos; /* Position of next entry to read. */ |
677 |
+ |
678 |
+ int errcode; /* Delayed error code. */ |
679 |
+ |
680 |
+@@ -45,6 +46,9 @@ struct __dirstream |
681 |
+ char *tbuffer; /* Translation buffer for non-LFS calls. */ |
682 |
+ size_t tbuffer_size; /* Size of translation buffer. */ |
683 |
+ #endif |
684 |
++#ifndef __LP64__ |
685 |
++ struct dirstream_loc_t locs; /* off64_t to long int map for telldir. */ |
686 |
++#endif |
687 |
+ |
688 |
+ /* Directory block. We must make sure that this block starts |
689 |
+ at an address that is aligned adequately enough to store |
690 |
+diff --git a/sysdeps/unix/sysv/linux/opendir.c b/sysdeps/unix/sysv/linux/opendir.c |
691 |
+index d7df13575e..56365f9da5 100644 |
692 |
+--- a/sysdeps/unix/sysv/linux/opendir.c |
693 |
++++ b/sysdeps/unix/sysv/linux/opendir.c |
694 |
+@@ -150,6 +150,9 @@ __alloc_dir (int fd, bool close_fd, int flags, |
695 |
+ dirp->offset = 0; |
696 |
+ dirp->filepos = 0; |
697 |
+ dirp->errcode = 0; |
698 |
++#ifndef __LP64__ |
699 |
++ dirstream_loc_init (&dirp->locs); |
700 |
++#endif |
701 |
+ |
702 |
+ return dirp; |
703 |
+ } |
704 |
+diff --git a/sysdeps/unix/sysv/linux/readdir.c b/sysdeps/unix/sysv/linux/readdir.c |
705 |
+index 8647bb0aef..b26d2756b9 100644 |
706 |
+--- a/sysdeps/unix/sysv/linux/readdir.c |
707 |
++++ b/sysdeps/unix/sysv/linux/readdir.c |
708 |
+@@ -17,6 +17,7 @@ |
709 |
+ <https://www.gnu.org/licenses/>. */ |
710 |
+ |
711 |
+ #include <dirent.h> |
712 |
++#include <unistd.h> |
713 |
+ |
714 |
+ #if !_DIRENT_MATCHES_DIRENT64 |
715 |
+ #include <dirstream.h> |
716 |
+diff --git a/sysdeps/unix/sysv/linux/rewinddir.c b/sysdeps/unix/sysv/linux/rewinddir.c |
717 |
+index 5b68db7167..74b336bfd8 100644 |
718 |
+--- a/sysdeps/unix/sysv/linux/rewinddir.c |
719 |
++++ b/sysdeps/unix/sysv/linux/rewinddir.c |
720 |
+@@ -33,6 +33,11 @@ __rewinddir (DIR *dirp) |
721 |
+ dirp->offset = 0; |
722 |
+ dirp->size = 0; |
723 |
+ dirp->errcode = 0; |
724 |
++ |
725 |
++#ifndef __LP64__ |
726 |
++ dirstream_loc_clear (&dirp->locs); |
727 |
++#endif |
728 |
++ |
729 |
+ #if IS_IN (libc) |
730 |
+ __libc_lock_unlock (dirp->lock); |
731 |
+ #endif |
732 |
+diff --git a/sysdeps/unix/sysv/linux/seekdir.c b/sysdeps/unix/sysv/linux/seekdir.c |
733 |
+index b128ae8e76..2fcf689dc0 100644 |
734 |
+--- a/sysdeps/unix/sysv/linux/seekdir.c |
735 |
++++ b/sysdeps/unix/sysv/linux/seekdir.c |
736 |
+@@ -22,14 +22,40 @@ |
737 |
+ #include <dirstream.h> |
738 |
+ |
739 |
+ /* Seek to position POS in DIRP. */ |
740 |
+-/* XXX should be __seekdir ? */ |
741 |
+ void |
742 |
+ seekdir (DIR *dirp, long int pos) |
743 |
+ { |
744 |
++ off64_t filepos; |
745 |
++ |
746 |
+ __libc_lock_lock (dirp->lock); |
747 |
+- (void) __lseek (dirp->fd, pos, SEEK_SET); |
748 |
+- dirp->size = 0; |
749 |
+- dirp->offset = 0; |
750 |
+- dirp->filepos = pos; |
751 |
++ |
752 |
++#ifndef __LP64__ |
753 |
++ union dirstream_packed dsp; |
754 |
++ |
755 |
++ dsp.l = pos; |
756 |
++ |
757 |
++ if (dsp.p.is_packed == 1) |
758 |
++ filepos = dsp.p.info; |
759 |
++ else |
760 |
++ { |
761 |
++ size_t index = dsp.p.info; |
762 |
++ |
763 |
++ if (index >= dirstream_loc_size (&dirp->locs)) |
764 |
++ return; |
765 |
++ struct dirstream_loc *loc = dirstream_loc_at (&dirp->locs, index); |
766 |
++ filepos = loc->filepos; |
767 |
++ } |
768 |
++#else |
769 |
++ filepos = pos; |
770 |
++#endif |
771 |
++ |
772 |
++ if (dirp->filepos != filepos) |
773 |
++ { |
774 |
++ __lseek64 (dirp->fd, filepos, SEEK_SET); |
775 |
++ dirp->filepos = filepos; |
776 |
++ dirp->offset = 0; |
777 |
++ dirp->size = 0; |
778 |
++ } |
779 |
++ |
780 |
+ __libc_lock_unlock (dirp->lock); |
781 |
+ } |
782 |
+diff --git a/sysdeps/unix/sysv/linux/telldir.c b/sysdeps/unix/sysv/linux/telldir.c |
783 |
+index b184db8d2c..a0eb1efeff 100644 |
784 |
+--- a/sysdeps/unix/sysv/linux/telldir.c |
785 |
++++ b/sysdeps/unix/sysv/linux/telldir.c |
786 |
+@@ -18,16 +18,59 @@ |
787 |
+ #include <dirent.h> |
788 |
+ |
789 |
+ #include <dirstream.h> |
790 |
++#include <telldir.h> |
791 |
+ |
792 |
+ /* Return the current position of DIRP. */ |
793 |
+ long int |
794 |
+ telldir (DIR *dirp) |
795 |
+ { |
796 |
+- long int ret; |
797 |
++#ifndef __LP64__ |
798 |
++ /* If the directory position fits in the packet structure returns it. |
799 |
++ Otherwise, check if the position is already been recorded in the |
800 |
++ dynamic array. If not, add the new record. */ |
801 |
++ |
802 |
++ union dirstream_packed dsp; |
803 |
++ size_t i; |
804 |
+ |
805 |
+ __libc_lock_lock (dirp->lock); |
806 |
+- ret = dirp->filepos; |
807 |
++ |
808 |
++ if (dirp->filepos < (1U << 31)) |
809 |
++ { |
810 |
++ dsp.p.is_packed = 1; |
811 |
++ dsp.p.info = dirp->filepos; |
812 |
++ goto out; |
813 |
++ } |
814 |
++ |
815 |
++ dsp.l = -1; |
816 |
++ |
817 |
++ for (i = 0; i < dirstream_loc_size (&dirp->locs); i++) |
818 |
++ { |
819 |
++ struct dirstream_loc *loc = dirstream_loc_at (&dirp->locs, i); |
820 |
++ if (loc->filepos == dirp->filepos) |
821 |
++ break; |
822 |
++ } |
823 |
++ if (i == dirstream_loc_size (&dirp->locs)) |
824 |
++ { |
825 |
++ dirstream_loc_add (&dirp->locs, |
826 |
++ (struct dirstream_loc) { dirp->filepos }); |
827 |
++ if (dirstream_loc_has_failed (&dirp->locs)) |
828 |
++ goto out; |
829 |
++ } |
830 |
++ |
831 |
++ dsp.p.is_packed = 0; |
832 |
++ /* This assignment might overflow, however most likely ENOMEM would happen |
833 |
++ long before. */ |
834 |
++ dsp.p.info = i; |
835 |
++ |
836 |
++out: |
837 |
+ __libc_lock_unlock (dirp->lock); |
838 |
+ |
839 |
++ return dsp.l; |
840 |
++#else |
841 |
++ long int ret; |
842 |
++ __libc_lock_lock (dirp->lock); |
843 |
++ ret = dirp->filepos; |
844 |
++ __libc_lock_unlock (dirp->lock); |
845 |
+ return ret; |
846 |
++#endif |
847 |
+ } |
848 |
+diff --git a/sysdeps/unix/sysv/linux/telldir.h b/sysdeps/unix/sysv/linux/telldir.h |
849 |
+new file mode 100644 |
850 |
+index 0000000000..7c45886341 |
851 |
+--- /dev/null |
852 |
++++ b/sysdeps/unix/sysv/linux/telldir.h |
853 |
+@@ -0,0 +1,64 @@ |
854 |
++/* Linux internal telldir definitions. |
855 |
++ Copyright (C) 2020 Free Software Foundation, Inc. |
856 |
++ This file is part of the GNU C Library. |
857 |
++ |
858 |
++ The GNU C Library is free software; you can redistribute it and/or |
859 |
++ modify it under the terms of the GNU Lesser General Public |
860 |
++ License as published by the Free Software Foundation; either |
861 |
++ version 2.1 of the License, or (at your option) any later version. |
862 |
++ |
863 |
++ The GNU C Library is distributed in the hope that it will be useful, |
864 |
++ but WITHOUT ANY WARRANTY; without even the implied warranty of |
865 |
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
866 |
++ Lesser General Public License for more details. |
867 |
++ |
868 |
++ You should have received a copy of the GNU Lesser General Public |
869 |
++ License along with the GNU C Library; if not, see |
870 |
++ <https://www.gnu.org/licenses/>. */ |
871 |
++ |
872 |
++#ifndef _TELLDIR_H |
873 |
++#define _TELLDIR_H 1 |
874 |
++ |
875 |
++#ifndef __LP64__ |
876 |
++ |
877 |
++/* On platforms where long int is smaller than off64_t this is how the |
878 |
++ returned value is encoded and returned by 'telldir'. If the directory |
879 |
++ offset can be enconded in 31 bits it is returned in the 'info' member |
880 |
++ with 'is_packed' set to 1. |
881 |
++ |
882 |
++ Otherwise, the 'info' member describes an index in a dynamic array at |
883 |
++ 'DIR' structure. */ |
884 |
++ |
885 |
++union dirstream_packed |
886 |
++{ |
887 |
++ long int l; |
888 |
++ struct |
889 |
++ { |
890 |
++ unsigned long is_packed:1; |
891 |
++ unsigned long info:31; |
892 |
++ } p; |
893 |
++}; |
894 |
++ |
895 |
++_Static_assert (sizeof (long int) == sizeof (union dirstream_packed), |
896 |
++ "sizeof (long int) != sizeof (union dirstream_packed)"); |
897 |
++ |
898 |
++/* telldir will mantain a list of offsets that describe the obtained diretory |
899 |
++ position if it can fit this information in the returned 'dirstream_packed' |
900 |
++ struct. */ |
901 |
++ |
902 |
++struct dirstream_loc |
903 |
++{ |
904 |
++ off64_t filepos; |
905 |
++}; |
906 |
++ |
907 |
++# define DYNARRAY_STRUCT dirstream_loc_t |
908 |
++# define DYNARRAY_ELEMENT struct dirstream_loc |
909 |
++# define DYNARRAY_PREFIX dirstream_loc_ |
910 |
++# include <malloc/dynarray-skeleton.c> |
911 |
++#else |
912 |
++ |
913 |
++_Static_assert (sizeof (long int) == sizeof (off64_t), |
914 |
++ "sizeof (long int) != sizeof (off64_t)"); |
915 |
++#endif /* __LP64__ */ |
916 |
++ |
917 |
++#endif /* _TELLDIR_H */ |
918 |
+-- |
919 |
+2.32.0 |
920 |
+ |
921 |
|
922 |
diff --git a/9999/0204-linux-Add-__readdir64_unlocked.patch b/9999/0204-linux-Add-__readdir64_unlocked.patch |
923 |
new file mode 100644 |
924 |
index 0000000..29609dd |
925 |
--- /dev/null |
926 |
+++ b/9999/0204-linux-Add-__readdir64_unlocked.patch |
927 |
@@ -0,0 +1,181 @@ |
928 |
+From 1524804c8133564c204340a0d618f04c585d7706 Mon Sep 17 00:00:00 2001 |
929 |
+From: Adhemerval Zanella <adhemerval.zanella@××××××.org> |
930 |
+Date: Mon, 13 Apr 2020 08:35:40 -0300 |
931 |
+Subject: [PATCH 4/7] linux: Add __readdir64_unlocked |
932 |
+ |
933 |
+And use it on readdir_r implementation. |
934 |
+ |
935 |
+Checked on i686-linux-gnu. |
936 |
+--- |
937 |
+ include/dirent.h | 1 + |
938 |
+ sysdeps/unix/sysv/linux/readdir64.c | 20 +++++-- |
939 |
+ sysdeps/unix/sysv/linux/readdir64_r.c | 80 ++++++--------------------- |
940 |
+ 3 files changed, 33 insertions(+), 68 deletions(-) |
941 |
+ |
942 |
+diff --git a/include/dirent.h b/include/dirent.h |
943 |
+index d7567f5e86..0c6715d0e4 100644 |
944 |
+--- a/include/dirent.h |
945 |
++++ b/include/dirent.h |
946 |
+@@ -21,6 +21,7 @@ extern DIR *__fdopendir (int __fd) attribute_hidden; |
947 |
+ extern int __closedir (DIR *__dirp) attribute_hidden; |
948 |
+ extern struct dirent *__readdir (DIR *__dirp) attribute_hidden; |
949 |
+ extern struct dirent *__readdir_unlocked (DIR *__dirp) attribute_hidden; |
950 |
++extern struct dirent64 *__readdir64_unlocked (DIR *__dirp) attribute_hidden; |
951 |
+ extern struct dirent64 *__readdir64 (DIR *__dirp); |
952 |
+ libc_hidden_proto (__readdir64) |
953 |
+ extern int __readdir_r (DIR *__dirp, struct dirent *__entry, |
954 |
+diff --git a/sysdeps/unix/sysv/linux/readdir64.c b/sysdeps/unix/sysv/linux/readdir64.c |
955 |
+index 3aea0b1df1..5519487ede 100644 |
956 |
+--- a/sysdeps/unix/sysv/linux/readdir64.c |
957 |
++++ b/sysdeps/unix/sysv/linux/readdir64.c |
958 |
+@@ -28,14 +28,10 @@ |
959 |
+ |
960 |
+ /* Read a directory entry from DIRP. */ |
961 |
+ struct dirent64 * |
962 |
+-__readdir64 (DIR *dirp) |
963 |
++__readdir64_unlocked (DIR *dirp) |
964 |
+ { |
965 |
+ const int saved_errno = errno; |
966 |
+ |
967 |
+-#if IS_IN (libc) |
968 |
+- __libc_lock_lock (dirp->lock); |
969 |
+-#endif |
970 |
+- |
971 |
+ if (dirp->offset >= dirp->size) |
972 |
+ { |
973 |
+ /* We've emptied out our buffer. Refill it. */ |
974 |
+@@ -65,6 +61,20 @@ __readdir64 (DIR *dirp) |
975 |
+ |
976 |
+ dirp->filepos = dp->d_off; |
977 |
+ |
978 |
++ return dp; |
979 |
++} |
980 |
++ |
981 |
++struct dirent64 * |
982 |
++__readdir64 (DIR *dirp) |
983 |
++{ |
984 |
++ struct dirent64 *dp; |
985 |
++ |
986 |
++#if IS_IN (libc) |
987 |
++ __libc_lock_lock (dirp->lock); |
988 |
++#endif |
989 |
++ |
990 |
++ dp = __readdir64_unlocked (dirp); |
991 |
++ |
992 |
+ #if IS_IN (libc) |
993 |
+ __libc_lock_unlock (dirp->lock); |
994 |
+ #endif |
995 |
+diff --git a/sysdeps/unix/sysv/linux/readdir64_r.c b/sysdeps/unix/sysv/linux/readdir64_r.c |
996 |
+index 073a6453d1..058d401279 100644 |
997 |
+--- a/sysdeps/unix/sysv/linux/readdir64_r.c |
998 |
++++ b/sysdeps/unix/sysv/linux/readdir64_r.c |
999 |
+@@ -32,89 +32,43 @@ __readdir64_r (DIR *dirp, struct dirent64 *entry, struct dirent64 **result) |
1000 |
+ { |
1001 |
+ struct dirent64 *dp; |
1002 |
+ size_t reclen; |
1003 |
+- const int saved_errno = errno; |
1004 |
+- int ret; |
1005 |
+ |
1006 |
+ __libc_lock_lock (dirp->lock); |
1007 |
+- |
1008 |
+- do |
1009 |
++ while (1) |
1010 |
+ { |
1011 |
+- if (dirp->offset >= dirp->size) |
1012 |
+- { |
1013 |
+- /* We've emptied out our buffer. Refill it. */ |
1014 |
+- |
1015 |
+- size_t maxread = dirp->allocation; |
1016 |
+- ssize_t bytes; |
1017 |
+- |
1018 |
+- maxread = dirp->allocation; |
1019 |
+- |
1020 |
+- bytes = __getdents64 (dirp->fd, dirp->data, maxread); |
1021 |
+- if (bytes <= 0) |
1022 |
+- { |
1023 |
+- /* On some systems getdents fails with ENOENT when the |
1024 |
+- open directory has been rmdir'd already. POSIX.1 |
1025 |
+- requires that we treat this condition like normal EOF. */ |
1026 |
+- if (bytes < 0 && errno == ENOENT) |
1027 |
+- { |
1028 |
+- bytes = 0; |
1029 |
+- __set_errno (saved_errno); |
1030 |
+- } |
1031 |
+- if (bytes < 0) |
1032 |
+- dirp->errcode = errno; |
1033 |
+- |
1034 |
+- dp = NULL; |
1035 |
+- break; |
1036 |
+- } |
1037 |
+- dirp->size = (size_t) bytes; |
1038 |
+- |
1039 |
+- /* Reset the offset into the buffer. */ |
1040 |
+- dirp->offset = 0; |
1041 |
+- } |
1042 |
+- |
1043 |
+- dp = (struct dirent64 *) &dirp->data[dirp->offset]; |
1044 |
++ dp = __readdir64_unlocked (dirp); |
1045 |
++ if (dp == NULL) |
1046 |
++ break; |
1047 |
+ |
1048 |
+ reclen = dp->d_reclen; |
1049 |
++ if (reclen <= offsetof (struct dirent64, d_name) + NAME_MAX + 1) |
1050 |
++ break; |
1051 |
+ |
1052 |
+- dirp->offset += reclen; |
1053 |
+- |
1054 |
+- dirp->filepos = dp->d_off; |
1055 |
+- |
1056 |
+- if (reclen > offsetof (struct dirent64, d_name) + NAME_MAX + 1) |
1057 |
++ /* The record is very long. It could still fit into the caller-supplied |
1058 |
++ buffer if we can skip padding at the end. */ |
1059 |
++ size_t namelen = _D_EXACT_NAMLEN (dp); |
1060 |
++ if (namelen <= NAME_MAX) |
1061 |
+ { |
1062 |
+- /* The record is very long. It could still fit into the |
1063 |
+- caller-supplied buffer if we can skip padding at the |
1064 |
+- end. */ |
1065 |
+- size_t namelen = _D_EXACT_NAMLEN (dp); |
1066 |
+- if (namelen <= NAME_MAX) |
1067 |
+- reclen = offsetof (struct dirent64, d_name) + namelen + 1; |
1068 |
+- else |
1069 |
+- { |
1070 |
+- /* The name is too long. Ignore this file. */ |
1071 |
+- dirp->errcode = ENAMETOOLONG; |
1072 |
+- dp->d_ino = 0; |
1073 |
+- continue; |
1074 |
+- } |
1075 |
++ reclen = offsetof (struct dirent64, d_name) + namelen + 1; |
1076 |
++ break; |
1077 |
+ } |
1078 |
+ |
1079 |
+- /* Skip deleted and ignored files. */ |
1080 |
++ /* The name is too long. Ignore this file. */ |
1081 |
++ dirp->errcode = ENAMETOOLONG; |
1082 |
++ dp->d_ino = 0; |
1083 |
+ } |
1084 |
+- while (dp->d_ino == 0); |
1085 |
+ |
1086 |
+ if (dp != NULL) |
1087 |
+ { |
1088 |
+ *result = memcpy (entry, dp, reclen); |
1089 |
+ entry->d_reclen = reclen; |
1090 |
+- ret = 0; |
1091 |
+ } |
1092 |
+ else |
1093 |
+- { |
1094 |
+- *result = NULL; |
1095 |
+- ret = dirp->errcode; |
1096 |
+- } |
1097 |
++ *result = NULL; |
1098 |
+ |
1099 |
+ __libc_lock_unlock (dirp->lock); |
1100 |
+ |
1101 |
+- return ret; |
1102 |
++ return dp != NULL ? 0 : dirp->errcode; |
1103 |
+ } |
1104 |
+ |
1105 |
+ |
1106 |
+-- |
1107 |
+2.32.0 |
1108 |
+ |
1109 |
|
1110 |
diff --git a/9999/0205-linux-Add-__old_readdir64_unlocked.patch b/9999/0205-linux-Add-__old_readdir64_unlocked.patch |
1111 |
new file mode 100644 |
1112 |
index 0000000..c1ccb61 |
1113 |
--- /dev/null |
1114 |
+++ b/9999/0205-linux-Add-__old_readdir64_unlocked.patch |
1115 |
@@ -0,0 +1,184 @@ |
1116 |
+From f16c3815c6ad46450d6e58e179ddf494c52a98a4 Mon Sep 17 00:00:00 2001 |
1117 |
+From: Adhemerval Zanella <adhemerval.zanella@××××××.org> |
1118 |
+Date: Tue, 14 Apr 2020 11:14:22 -0300 |
1119 |
+Subject: [PATCH 5/7] linux: Add __old_readdir64_unlocked |
1120 |
+ |
1121 |
+And use it __old_readdir64_r. |
1122 |
+ |
1123 |
+Checked on i686-linux-gnu. |
1124 |
+--- |
1125 |
+ sysdeps/unix/sysv/linux/olddirent.h | 2 + |
1126 |
+ sysdeps/unix/sysv/linux/readdir64.c | 21 +++++-- |
1127 |
+ sysdeps/unix/sysv/linux/readdir64_r.c | 79 ++++++--------------------- |
1128 |
+ 3 files changed, 35 insertions(+), 67 deletions(-) |
1129 |
+ |
1130 |
+diff --git a/sysdeps/unix/sysv/linux/olddirent.h b/sysdeps/unix/sysv/linux/olddirent.h |
1131 |
+index 3e672d47f5..42ab593c4d 100644 |
1132 |
+--- a/sysdeps/unix/sysv/linux/olddirent.h |
1133 |
++++ b/sysdeps/unix/sysv/linux/olddirent.h |
1134 |
+@@ -32,6 +32,8 @@ struct __old_dirent64 |
1135 |
+ /* Now define the internal interfaces. */ |
1136 |
+ extern struct __old_dirent64 *__old_readdir64 (DIR *__dirp); |
1137 |
+ libc_hidden_proto (__old_readdir64); |
1138 |
++extern struct __old_dirent64 *__old_readdir64_unlocked (DIR *__dirp) |
1139 |
++ attribute_hidden; |
1140 |
+ extern int __old_readdir64_r (DIR *__dirp, struct __old_dirent64 *__entry, |
1141 |
+ struct __old_dirent64 **__result); |
1142 |
+ extern __ssize_t __old_getdents64 (int __fd, char *__buf, size_t __nbytes) |
1143 |
+diff --git a/sysdeps/unix/sysv/linux/readdir64.c b/sysdeps/unix/sysv/linux/readdir64.c |
1144 |
+index 5519487ede..8869e49150 100644 |
1145 |
+--- a/sysdeps/unix/sysv/linux/readdir64.c |
1146 |
++++ b/sysdeps/unix/sysv/linux/readdir64.c |
1147 |
+@@ -101,15 +101,11 @@ versioned_symbol (libc, __readdir64, readdir64, GLIBC_2_2); |
1148 |
+ |
1149 |
+ attribute_compat_text_section |
1150 |
+ struct __old_dirent64 * |
1151 |
+-__old_readdir64 (DIR *dirp) |
1152 |
++__old_readdir64_unlocked (DIR *dirp) |
1153 |
+ { |
1154 |
+ struct __old_dirent64 *dp; |
1155 |
+ int saved_errno = errno; |
1156 |
+ |
1157 |
+-#if IS_IN (libc) |
1158 |
+- __libc_lock_lock (dirp->lock); |
1159 |
+-#endif |
1160 |
+- |
1161 |
+ do |
1162 |
+ { |
1163 |
+ size_t reclen; |
1164 |
+@@ -153,6 +149,21 @@ __old_readdir64 (DIR *dirp) |
1165 |
+ /* Skip deleted files. */ |
1166 |
+ } while (dp->d_ino == 0); |
1167 |
+ |
1168 |
++ return dp; |
1169 |
++} |
1170 |
++ |
1171 |
++attribute_compat_text_section |
1172 |
++struct __old_dirent64 * |
1173 |
++__old_readdir64 (DIR *dirp) |
1174 |
++{ |
1175 |
++ struct __old_dirent64 *dp; |
1176 |
++ |
1177 |
++#if IS_IN (libc) |
1178 |
++ __libc_lock_lock (dirp->lock); |
1179 |
++#endif |
1180 |
++ |
1181 |
++ dp = __old_readdir64_unlocked (dirp); |
1182 |
++ |
1183 |
+ #if IS_IN (libc) |
1184 |
+ __libc_lock_unlock (dirp->lock); |
1185 |
+ #endif |
1186 |
+diff --git a/sysdeps/unix/sysv/linux/readdir64_r.c b/sysdeps/unix/sysv/linux/readdir64_r.c |
1187 |
+index 058d401279..e4a0baeaf7 100644 |
1188 |
+--- a/sysdeps/unix/sysv/linux/readdir64_r.c |
1189 |
++++ b/sysdeps/unix/sysv/linux/readdir64_r.c |
1190 |
+@@ -91,89 +91,44 @@ __old_readdir64_r (DIR *dirp, struct __old_dirent64 *entry, |
1191 |
+ { |
1192 |
+ struct __old_dirent64 *dp; |
1193 |
+ size_t reclen; |
1194 |
+- const int saved_errno = errno; |
1195 |
+- int ret; |
1196 |
+ |
1197 |
+ __libc_lock_lock (dirp->lock); |
1198 |
+ |
1199 |
+- do |
1200 |
++ while (1) |
1201 |
+ { |
1202 |
+- if (dirp->offset >= dirp->size) |
1203 |
+- { |
1204 |
+- /* We've emptied out our buffer. Refill it. */ |
1205 |
+- |
1206 |
+- size_t maxread = dirp->allocation; |
1207 |
+- ssize_t bytes; |
1208 |
+- |
1209 |
+- maxread = dirp->allocation; |
1210 |
+- |
1211 |
+- bytes = __old_getdents64 (dirp->fd, dirp->data, maxread); |
1212 |
+- if (bytes <= 0) |
1213 |
+- { |
1214 |
+- /* On some systems getdents fails with ENOENT when the |
1215 |
+- open directory has been rmdir'd already. POSIX.1 |
1216 |
+- requires that we treat this condition like normal EOF. */ |
1217 |
+- if (bytes < 0 && errno == ENOENT) |
1218 |
+- { |
1219 |
+- bytes = 0; |
1220 |
+- __set_errno (saved_errno); |
1221 |
+- } |
1222 |
+- if (bytes < 0) |
1223 |
+- dirp->errcode = errno; |
1224 |
+- |
1225 |
+- dp = NULL; |
1226 |
+- break; |
1227 |
+- } |
1228 |
+- dirp->size = (size_t) bytes; |
1229 |
+- |
1230 |
+- /* Reset the offset into the buffer. */ |
1231 |
+- dirp->offset = 0; |
1232 |
+- } |
1233 |
+- |
1234 |
+- dp = (struct __old_dirent64 *) &dirp->data[dirp->offset]; |
1235 |
++ dp = __old_readdir64_unlocked (dirp); |
1236 |
++ if (dp == NULL) |
1237 |
++ break; |
1238 |
+ |
1239 |
+ reclen = dp->d_reclen; |
1240 |
++ if (reclen <= offsetof (struct __old_dirent64, d_name) + NAME_MAX + 1) |
1241 |
++ break; |
1242 |
+ |
1243 |
+- dirp->offset += reclen; |
1244 |
+- |
1245 |
+- dirp->filepos = dp->d_off; |
1246 |
+- |
1247 |
+- if (reclen > offsetof (struct __old_dirent64, d_name) + NAME_MAX + 1) |
1248 |
++ /* The record is very long. It could still fit into the caller-supplied |
1249 |
++ buffer if we can skip padding at the end. */ |
1250 |
++ size_t namelen = _D_EXACT_NAMLEN (dp); |
1251 |
++ if (namelen <= NAME_MAX) |
1252 |
+ { |
1253 |
+- /* The record is very long. It could still fit into the |
1254 |
+- caller-supplied buffer if we can skip padding at the |
1255 |
+- end. */ |
1256 |
+- size_t namelen = _D_EXACT_NAMLEN (dp); |
1257 |
+- if (namelen <= NAME_MAX) |
1258 |
+- reclen = offsetof (struct __old_dirent64, d_name) + namelen + 1; |
1259 |
+- else |
1260 |
+- { |
1261 |
+- /* The name is too long. Ignore this file. */ |
1262 |
+- dirp->errcode = ENAMETOOLONG; |
1263 |
+- dp->d_ino = 0; |
1264 |
+- continue; |
1265 |
+- } |
1266 |
++ reclen = offsetof (struct dirent64, d_name) + namelen + 1; |
1267 |
++ break; |
1268 |
+ } |
1269 |
+ |
1270 |
+- /* Skip deleted and ignored files. */ |
1271 |
++ /* The name is too long. Ignore this file. */ |
1272 |
++ dirp->errcode = ENAMETOOLONG; |
1273 |
++ dp->d_ino = 0; |
1274 |
+ } |
1275 |
+- while (dp->d_ino == 0); |
1276 |
+ |
1277 |
+ if (dp != NULL) |
1278 |
+ { |
1279 |
+ *result = memcpy (entry, dp, reclen); |
1280 |
+ entry->d_reclen = reclen; |
1281 |
+- ret = 0; |
1282 |
+ } |
1283 |
+ else |
1284 |
+- { |
1285 |
+- *result = NULL; |
1286 |
+- ret = dirp->errcode; |
1287 |
+- } |
1288 |
++ *result = NULL; |
1289 |
+ |
1290 |
+ __libc_lock_unlock (dirp->lock); |
1291 |
+ |
1292 |
+- return ret; |
1293 |
++ return dp != NULL ? 0 : dirp->errcode; |
1294 |
+ } |
1295 |
+ |
1296 |
+ compat_symbol (libc, __old_readdir64_r, readdir64_r, GLIBC_2_1); |
1297 |
+-- |
1298 |
+2.32.0 |
1299 |
+ |
1300 |
|
1301 |
diff --git a/9999/0206-linux-Use-getdents64-on-readdir64-compat-implementat.patch b/9999/0206-linux-Use-getdents64-on-readdir64-compat-implementat.patch |
1302 |
new file mode 100644 |
1303 |
index 0000000..90f5d89 |
1304 |
--- /dev/null |
1305 |
+++ b/9999/0206-linux-Use-getdents64-on-readdir64-compat-implementat.patch |
1306 |
@@ -0,0 +1,297 @@ |
1307 |
+From 46b9383118182cb2ac2e81637e00fde6c21097bb Mon Sep 17 00:00:00 2001 |
1308 |
+From: Adhemerval Zanella <adhemerval.zanella@××××××.org> |
1309 |
+Date: Tue, 20 Oct 2020 16:00:43 -0300 |
1310 |
+Subject: [PATCH 6/7] linux: Use getdents64 on readdir64 compat implementation |
1311 |
+ |
1312 |
+It uses a similar strategy from the non-LFS readdir that also |
1313 |
+uses getdents64 internally and uses a translation buffer to return |
1314 |
+the compat readdir64 entry. |
1315 |
+ |
1316 |
+It allows to remove __old_getdents64. |
1317 |
+ |
1318 |
+Checked on i686-linux-gnu. |
1319 |
+--- |
1320 |
+ sysdeps/unix/sysv/linux/getdents64.c | 93 ------------------------ |
1321 |
+ sysdeps/unix/sysv/linux/olddirent.h | 2 - |
1322 |
+ sysdeps/unix/sysv/linux/opendir.c | 15 +++- |
1323 |
+ sysdeps/unix/sysv/linux/readdir64.c | 104 +++++++++++++++++---------- |
1324 |
+ 4 files changed, 79 insertions(+), 135 deletions(-) |
1325 |
+ |
1326 |
+diff --git a/sysdeps/unix/sysv/linux/getdents64.c b/sysdeps/unix/sysv/linux/getdents64.c |
1327 |
+index 6323e003b3..38285e9f4b 100644 |
1328 |
+--- a/sysdeps/unix/sysv/linux/getdents64.c |
1329 |
++++ b/sysdeps/unix/sysv/linux/getdents64.c |
1330 |
+@@ -36,97 +36,4 @@ weak_alias (__getdents64, getdents64) |
1331 |
+ |
1332 |
+ #if _DIRENT_MATCHES_DIRENT64 |
1333 |
+ strong_alias (__getdents64, __getdents) |
1334 |
+-#else |
1335 |
+-# include <shlib-compat.h> |
1336 |
+- |
1337 |
+-# if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) |
1338 |
+-# include <olddirent.h> |
1339 |
+-# include <unistd.h> |
1340 |
+- |
1341 |
+-static ssize_t |
1342 |
+-handle_overflow (int fd, __off64_t offset, ssize_t count) |
1343 |
+-{ |
1344 |
+- /* If this is the first entry in the buffer, we can report the |
1345 |
+- error. */ |
1346 |
+- if (offset == 0) |
1347 |
+- { |
1348 |
+- __set_errno (EOVERFLOW); |
1349 |
+- return -1; |
1350 |
+- } |
1351 |
+- |
1352 |
+- /* Otherwise, seek to the overflowing entry, so that the next call |
1353 |
+- will report the error, and return the data read so far. */ |
1354 |
+- if (__lseek64 (fd, offset, SEEK_SET) != 0) |
1355 |
+- return -1; |
1356 |
+- return count; |
1357 |
+-} |
1358 |
+- |
1359 |
+-ssize_t |
1360 |
+-__old_getdents64 (int fd, char *buf, size_t nbytes) |
1361 |
+-{ |
1362 |
+- /* We do not move the individual directory entries. This is only |
1363 |
+- possible if the target type (struct __old_dirent64) is smaller |
1364 |
+- than the source type. */ |
1365 |
+- _Static_assert (offsetof (struct __old_dirent64, d_name) |
1366 |
+- <= offsetof (struct dirent64, d_name), |
1367 |
+- "__old_dirent64 is larger than dirent64"); |
1368 |
+- _Static_assert (__alignof__ (struct __old_dirent64) |
1369 |
+- <= __alignof__ (struct dirent64), |
1370 |
+- "alignment of __old_dirent64 is larger than dirent64"); |
1371 |
+- |
1372 |
+- ssize_t retval = INLINE_SYSCALL_CALL (getdents64, fd, buf, nbytes); |
1373 |
+- if (retval > 0) |
1374 |
+- { |
1375 |
+- /* This is the marker for the first entry. Offset 0 is reserved |
1376 |
+- for the first entry (see rewinddir). Here, we use it as a |
1377 |
+- marker for the first entry in the buffer. We never actually |
1378 |
+- seek to offset 0 because handle_overflow reports the error |
1379 |
+- directly, so it does not matter that the offset is incorrect |
1380 |
+- if entries have been read from the descriptor before (so that |
1381 |
+- the descriptor is not actually at offset 0). */ |
1382 |
+- __off64_t previous_offset = 0; |
1383 |
+- |
1384 |
+- char *p = buf; |
1385 |
+- char *end = buf + retval; |
1386 |
+- while (p < end) |
1387 |
+- { |
1388 |
+- struct dirent64 *source = (struct dirent64 *) p; |
1389 |
+- |
1390 |
+- /* Copy out the fixed-size data. */ |
1391 |
+- __ino_t ino = source->d_ino; |
1392 |
+- __off64_t offset = source->d_off; |
1393 |
+- unsigned int reclen = source->d_reclen; |
1394 |
+- unsigned char type = source->d_type; |
1395 |
+- |
1396 |
+- /* Check for ino_t overflow. */ |
1397 |
+- if (__glibc_unlikely (ino != source->d_ino)) |
1398 |
+- return handle_overflow (fd, previous_offset, p - buf); |
1399 |
+- |
1400 |
+- /* Convert to the target layout. Use a separate struct and |
1401 |
+- memcpy to side-step aliasing issues. */ |
1402 |
+- struct __old_dirent64 result; |
1403 |
+- result.d_ino = ino; |
1404 |
+- result.d_off = offset; |
1405 |
+- result.d_reclen = reclen; |
1406 |
+- result.d_type = type; |
1407 |
+- |
1408 |
+- /* Write the fixed-sized part of the result to the |
1409 |
+- buffer. */ |
1410 |
+- size_t result_name_offset = offsetof (struct __old_dirent64, d_name); |
1411 |
+- memcpy (p, &result, result_name_offset); |
1412 |
+- |
1413 |
+- /* Adjust the position of the name if necessary. Copy |
1414 |
+- everything until the end of the record, including the |
1415 |
+- terminating NUL byte. */ |
1416 |
+- if (result_name_offset != offsetof (struct dirent64, d_name)) |
1417 |
+- memmove (p + result_name_offset, source->d_name, |
1418 |
+- reclen - offsetof (struct dirent64, d_name)); |
1419 |
+- |
1420 |
+- p += reclen; |
1421 |
+- previous_offset = offset; |
1422 |
+- } |
1423 |
+- } |
1424 |
+- return retval; |
1425 |
+-} |
1426 |
+-# endif /* SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) */ |
1427 |
+ #endif /* _DIRENT_MATCHES_DIRENT64 */ |
1428 |
+diff --git a/sysdeps/unix/sysv/linux/olddirent.h b/sysdeps/unix/sysv/linux/olddirent.h |
1429 |
+index 42ab593c4d..b7c51d5ccc 100644 |
1430 |
+--- a/sysdeps/unix/sysv/linux/olddirent.h |
1431 |
++++ b/sysdeps/unix/sysv/linux/olddirent.h |
1432 |
+@@ -36,8 +36,6 @@ extern struct __old_dirent64 *__old_readdir64_unlocked (DIR *__dirp) |
1433 |
+ attribute_hidden; |
1434 |
+ extern int __old_readdir64_r (DIR *__dirp, struct __old_dirent64 *__entry, |
1435 |
+ struct __old_dirent64 **__result); |
1436 |
+-extern __ssize_t __old_getdents64 (int __fd, char *__buf, size_t __nbytes) |
1437 |
+- attribute_hidden; |
1438 |
+ int __old_scandir64 (const char * __dir, |
1439 |
+ struct __old_dirent64 *** __namelist, |
1440 |
+ int (*__selector) (const struct __old_dirent64 *), |
1441 |
+diff --git a/sysdeps/unix/sysv/linux/opendir.c b/sysdeps/unix/sysv/linux/opendir.c |
1442 |
+index 56365f9da5..de722c98e1 100644 |
1443 |
+--- a/sysdeps/unix/sysv/linux/opendir.c |
1444 |
++++ b/sysdeps/unix/sysv/linux/opendir.c |
1445 |
+@@ -23,6 +23,11 @@ |
1446 |
+ |
1447 |
+ #include <not-cancel.h> |
1448 |
+ |
1449 |
++#include <shlib-compat.h> |
1450 |
++#if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) |
1451 |
++# include <olddirent.h> |
1452 |
++#endif |
1453 |
++ |
1454 |
+ enum { |
1455 |
+ opendir_oflags = O_RDONLY|O_NDELAY|O_DIRECTORY|O_LARGEFILE|O_CLOEXEC |
1456 |
+ }; |
1457 |
+@@ -128,7 +133,15 @@ __alloc_dir (int fd, bool close_fd, int flags, |
1458 |
+ expand the buffer if required. */ |
1459 |
+ enum |
1460 |
+ { |
1461 |
+- tbuffer_size = sizeof (struct dirent) + NAME_MAX + 1 |
1462 |
++ tbuffer_size = |
1463 |
++# if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) |
1464 |
++ /* This is used on compat readdir64. */ |
1465 |
++ MAX (sizeof (struct dirent), |
1466 |
++ sizeof (struct __old_dirent64)) |
1467 |
++# else |
1468 |
++ sizeof (struct dirent) |
1469 |
++# endif |
1470 |
++ + NAME_MAX + 1 |
1471 |
+ }; |
1472 |
+ dirp->tbuffer = malloc (tbuffer_size); |
1473 |
+ if (dirp->tbuffer == NULL) |
1474 |
+diff --git a/sysdeps/unix/sysv/linux/readdir64.c b/sysdeps/unix/sysv/linux/readdir64.c |
1475 |
+index 8869e49150..7ecc8c1b16 100644 |
1476 |
+--- a/sysdeps/unix/sysv/linux/readdir64.c |
1477 |
++++ b/sysdeps/unix/sysv/linux/readdir64.c |
1478 |
+@@ -99,57 +99,83 @@ versioned_symbol (libc, __readdir64, readdir64, GLIBC_2_2); |
1479 |
+ # if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) |
1480 |
+ # include <olddirent.h> |
1481 |
+ |
1482 |
++/* Translate the DP64 entry to the old LFS one in the translation buffer |
1483 |
++ at dirstream DS. Return true is the translation was possible or |
1484 |
++ false if either an internal fields can be represented in the non-LFS |
1485 |
++ entry or if the translation can not be resized. */ |
1486 |
++static bool |
1487 |
++dirstream_old_entry (struct __dirstream *ds, const struct dirent64 *dp64) |
1488 |
++{ |
1489 |
++ /* Check for overflow. */ |
1490 |
++ ino_t d_ino = dp64->d_ino; |
1491 |
++ if (d_ino != dp64->d_ino) |
1492 |
++ return false; |
1493 |
++ |
1494 |
++ /* Expand the translation buffer to hold the new namesize. */ |
1495 |
++ size_t d_reclen = sizeof (struct __old_dirent64) |
1496 |
++ + dp64->d_reclen - offsetof (struct dirent64, d_name); |
1497 |
++ if (d_reclen > ds->tbuffer_size) |
1498 |
++ { |
1499 |
++ char *newbuffer = realloc (ds->tbuffer, d_reclen); |
1500 |
++ if (newbuffer == NULL) |
1501 |
++ return false; |
1502 |
++ ds->tbuffer = newbuffer; |
1503 |
++ ds->tbuffer_size = d_reclen; |
1504 |
++ } |
1505 |
++ |
1506 |
++ struct __old_dirent64 *olddp64 = (struct __old_dirent64 *) ds->tbuffer; |
1507 |
++ |
1508 |
++ olddp64->d_off = dp64->d_off; |
1509 |
++ olddp64->d_ino = dp64->d_ino; |
1510 |
++ olddp64->d_reclen = dp64->d_reclen; |
1511 |
++ olddp64->d_type = dp64->d_type; |
1512 |
++ memcpy (olddp64->d_name, dp64->d_name, |
1513 |
++ dp64->d_reclen - offsetof (struct dirent64, d_name)); |
1514 |
++ |
1515 |
++ return true; |
1516 |
++} |
1517 |
++ |
1518 |
+ attribute_compat_text_section |
1519 |
+ struct __old_dirent64 * |
1520 |
+ __old_readdir64_unlocked (DIR *dirp) |
1521 |
+ { |
1522 |
+- struct __old_dirent64 *dp; |
1523 |
+- int saved_errno = errno; |
1524 |
++ const int saved_errno = errno; |
1525 |
+ |
1526 |
+- do |
1527 |
++ if (dirp->offset >= dirp->size) |
1528 |
+ { |
1529 |
+- size_t reclen; |
1530 |
+- |
1531 |
+- if (dirp->offset >= dirp->size) |
1532 |
++ /* We've emptied out our buffer. Refill it. */ |
1533 |
++ ssize_t bytes = __getdents64 (dirp->fd, dirp->data, dirp->allocation); |
1534 |
++ if (bytes <= 0) |
1535 |
+ { |
1536 |
+- /* We've emptied out our buffer. Refill it. */ |
1537 |
+- |
1538 |
+- size_t maxread = dirp->allocation; |
1539 |
+- ssize_t bytes; |
1540 |
+- |
1541 |
+- bytes = __old_getdents64 (dirp->fd, dirp->data, maxread); |
1542 |
+- if (bytes <= 0) |
1543 |
+- { |
1544 |
+- /* On some systems getdents fails with ENOENT when the |
1545 |
+- open directory has been rmdir'd already. POSIX.1 |
1546 |
+- requires that we treat this condition like normal EOF. */ |
1547 |
+- if (bytes < 0 && errno == ENOENT) |
1548 |
+- bytes = 0; |
1549 |
+- |
1550 |
+- /* Don't modifiy errno when reaching EOF. */ |
1551 |
+- if (bytes == 0) |
1552 |
+- __set_errno (saved_errno); |
1553 |
+- dp = NULL; |
1554 |
+- break; |
1555 |
+- } |
1556 |
+- dirp->size = (size_t) bytes; |
1557 |
+- |
1558 |
+- /* Reset the offset into the buffer. */ |
1559 |
+- dirp->offset = 0; |
1560 |
+- } |
1561 |
+- |
1562 |
+- dp = (struct __old_dirent64 *) &dirp->data[dirp->offset]; |
1563 |
++ /* On some systems getdents fails with ENOENT when the |
1564 |
++ open directory has been rmdir'd already. POSIX.1 |
1565 |
++ requires that we treat this condition like normal EOF. */ |
1566 |
++ if (bytes < 0 && errno == ENOENT) |
1567 |
++ bytes = 0; |
1568 |
+ |
1569 |
+- reclen = dp->d_reclen; |
1570 |
++ /* Don't modifiy errno when reaching EOF. */ |
1571 |
++ if (bytes == 0) |
1572 |
++ __set_errno (saved_errno); |
1573 |
++ return NULL; |
1574 |
++ } |
1575 |
++ dirp->size = bytes; |
1576 |
+ |
1577 |
+- dirp->offset += reclen; |
1578 |
++ /* Reset the offset into the buffer. */ |
1579 |
++ dirp->offset = 0; |
1580 |
++ } |
1581 |
+ |
1582 |
+- dirp->filepos = dp->d_off; |
1583 |
++ struct dirent64 *dp64 = (struct dirent64 *) &dirp->data[dirp->offset]; |
1584 |
++ dirp->offset += dp64->d_reclen; |
1585 |
+ |
1586 |
+- /* Skip deleted files. */ |
1587 |
+- } while (dp->d_ino == 0); |
1588 |
++ /* Skip entries which might overflow d_ino or for memory allocation failure |
1589 |
++ in case of large file names. */ |
1590 |
++ if (dirstream_old_entry (dirp, dp64)) |
1591 |
++ { |
1592 |
++ dirp->filepos = dp64->d_off; |
1593 |
++ return (struct __old_dirent64 *) dirp->tbuffer; |
1594 |
++ } |
1595 |
+ |
1596 |
+- return dp; |
1597 |
++ return NULL; |
1598 |
+ } |
1599 |
+ |
1600 |
+ attribute_compat_text_section |
1601 |
+-- |
1602 |
+2.32.0 |
1603 |
+ |
1604 |
|
1605 |
diff --git a/9999/0207-dirent-Deprecate-getdirentries.patch b/9999/0207-dirent-Deprecate-getdirentries.patch |
1606 |
new file mode 100644 |
1607 |
index 0000000..7b00018 |
1608 |
--- /dev/null |
1609 |
+++ b/9999/0207-dirent-Deprecate-getdirentries.patch |
1610 |
@@ -0,0 +1,101 @@ |
1611 |
+From 8180167096d51c9767888a695e60a542b64813f0 Mon Sep 17 00:00:00 2001 |
1612 |
+From: Adhemerval Zanella <adhemerval.zanella@××××××.org> |
1613 |
+Date: Fri, 17 Apr 2020 09:59:51 -0300 |
1614 |
+Subject: [PATCH 7/7] dirent: Deprecate getdirentries |
1615 |
+ |
1616 |
+The interface has some issues: |
1617 |
+ |
1618 |
+ 1. It is build on top getdents on Linux and requires handling |
1619 |
+ non-LFS call using LFS getdents. |
1620 |
+ |
1621 |
+ 2. It is not wildly used and the non-LFS support is as problematic |
1622 |
+ as non-LFS readdir. glibc only exports the LFS getdents. |
1623 |
+ |
1624 |
+ 3. It is not a direct replacement over BSD since on some plataform |
1625 |
+ its signature has changed (FreeBSD 11, for instance, used to |
1626 |
+ set the offset as a 'long' and changed to 'off_t' on version 12). |
1627 |
+ |
1628 |
+The idea is to eventually move the symbols to compat ones. |
1629 |
+--- |
1630 |
+ NEWS | 5 +++++ |
1631 |
+ dirent/dirent.h | 14 ++++++++++---- |
1632 |
+ sysdeps/unix/sysv/linux/Makefile | 3 +++ |
1633 |
+ 3 files changed, 18 insertions(+), 4 deletions(-) |
1634 |
+ |
1635 |
+diff --git a/NEWS b/NEWS |
1636 |
+index d9b344027b..a18a1d7a8c 100644 |
1637 |
+--- a/NEWS |
1638 |
++++ b/NEWS |
1639 |
+@@ -7,6 +7,11 @@ using `glibc' in the "product" field. |
1640 |
+ |
1641 |
+ Version 2.34.1 |
1642 |
+ |
1643 |
++Deprecated and removed features, and other changes affecting compatibility: |
1644 |
++ |
1645 |
++* The function getdirentries is now deprecated, applications should use |
1646 |
++ either getdents64, readdir64 or readdir. |
1647 |
++ |
1648 |
+ The following bugs are resolved with this release: |
1649 |
+ |
1650 |
+ [12889] nptl: Fix race between pthread_kill and thread exit |
1651 |
+diff --git a/dirent/dirent.h b/dirent/dirent.h |
1652 |
+index 1d1fab7e55..8ad5fbf430 100644 |
1653 |
+--- a/dirent/dirent.h |
1654 |
++++ b/dirent/dirent.h |
1655 |
+@@ -348,29 +348,35 @@ extern int alphasort64 (const struct dirent64 **__e1, |
1656 |
+ /* Read directory entries from FD into BUF, reading at most NBYTES. |
1657 |
+ Reading starts at offset *BASEP, and *BASEP is updated with the new |
1658 |
+ position after reading. Returns the number of bytes read; zero when at |
1659 |
+- end of directory; or -1 for errors. */ |
1660 |
++ end of directory; or -1 for errors. |
1661 |
++ This is deprecated and getdents64 or readdir should be used instead. */ |
1662 |
+ # ifndef __USE_FILE_OFFSET64 |
1663 |
+ extern __ssize_t getdirentries (int __fd, char *__restrict __buf, |
1664 |
+ size_t __nbytes, |
1665 |
+ __off_t *__restrict __basep) |
1666 |
+- __THROW __nonnull ((2, 4)); |
1667 |
++ __THROW __nonnull ((2, 4)) |
1668 |
++ __attribute_deprecated_msg__ ("Use getdents64 instead"); |
1669 |
+ # else |
1670 |
+ # ifdef __REDIRECT |
1671 |
+ extern __ssize_t __REDIRECT_NTH (getdirentries, |
1672 |
+ (int __fd, char *__restrict __buf, |
1673 |
+ size_t __nbytes, |
1674 |
+ __off64_t *__restrict __basep), |
1675 |
+- getdirentries64) __nonnull ((2, 4)); |
1676 |
++ getdirentries64) |
1677 |
++ __THROW __nonnull ((2, 4)) |
1678 |
++ __attribute_deprecated_msg__ ("Use getdents64 instead"); |
1679 |
+ # else |
1680 |
+ # define getdirentries getdirentries64 |
1681 |
+ # endif |
1682 |
+ # endif |
1683 |
+ |
1684 |
+ # ifdef __USE_LARGEFILE64 |
1685 |
++/* This is deprecated and getdents64 or readdir64 should be used instead. */ |
1686 |
+ extern __ssize_t getdirentries64 (int __fd, char *__restrict __buf, |
1687 |
+ size_t __nbytes, |
1688 |
+ __off64_t *__restrict __basep) |
1689 |
+- __THROW __nonnull ((2, 4)); |
1690 |
++ __THROW __nonnull ((2, 4)) |
1691 |
++ __attribute_deprecated_msg__ ("Use getdents64 instead"); |
1692 |
+ # endif |
1693 |
+ #endif /* Use misc. */ |
1694 |
+ |
1695 |
+diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile |
1696 |
+index 76ad06361c..65ec7529f6 100644 |
1697 |
+--- a/sysdeps/unix/sysv/linux/Makefile |
1698 |
++++ b/sysdeps/unix/sysv/linux/Makefile |
1699 |
+@@ -313,6 +313,9 @@ tests += tst-getdents64 |
1700 |
+ # The tested readdir64 symbol was replaced in glibc 2.2. |
1701 |
+ ifeq ($(have-GLIBC_2.1.3)$(build-shared),yesyes) |
1702 |
+ tests += tst-readdir64-compat |
1703 |
++ |
1704 |
++# Avoid the warning for the weak_alias for _DIRENT_MATCHES_DIRENT64 |
1705 |
++CFLAGS-getdirentries64.c = -Wno-deprecated-declarations |
1706 |
+ endif |
1707 |
+ endif # $(subdir) == dirent |
1708 |
+ |
1709 |
+-- |
1710 |
+2.32.0 |
1711 |
+ |