From patchwork Tue Jun 18 14:24:58 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 33182 Received: (qmail 24899 invoked by alias); 18 Jun 2019 14:25:07 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 24885 invoked by uid 89); 18 Jun 2019 14:25:06 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-18.9 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_HELO_PASS autolearn=ham version=3.3.1 spammy=Cheap, republic, Republic, 1766 X-HELO: mx1.redhat.com From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH] Linux: Add Date: Tue, 18 Jun 2019 16:24:58 +0200 Message-ID: <87o92v7yyt.fsf@oldenburg2.str.redhat.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.2 (gnu/linux) MIME-Version: 1.0 This header file provides the types struct direntry and struct direntries, and the functions direntries_init, direntries_read, and direntries_next. Using a separate header file (instead of augmenting ) allows more straightforward type names because identifier collisions are less of a problem (new code can work around them). The d_off member is not exposed via struct direntry because it is difficult to use correctly (it refers to the *next* entry), and it is also difficult to emulate with other interfaces. 2019-06-18 Florian Weimer Linux: Add a directory stream iterator. * manual/filesys.texi (Low-level Directory Access): Document struct direntries, struct direntry, direntries_init, direntries_read, and direntries_next. * manual/examples/direntries.c: New file. * include/sys/direntries.h: Likewise. * sysdeps/unix/sysv/linux/Makefile [$(subdir) == dirent] (sysdep_headers): Add sys/direntries.h. [$(subdir) == dirent] (sysdep_routines): Add direntries_init, direntries_read, direntries_next. [$(subdir) == dirent] (tests): Add tst-direntries. * sysdeps/unix/sysv/linux/direntries_init.c: New file. * sysdeps/unix/sysv/linux/direntries_next.c: Likewise. * sysdeps/unix/sysv/linux/direntries_read.c: Likewise. * sysdeps/unix/sysv/linux/sys/direntries.h: Likewise. * sysdeps/unix/sysv/linux/tst-direntries.c: Likewise. * sysdeps/unix/sysv/linux/Versions (GLIBC_2.30): Export direntries_init, direntries_read, direntries_next. * sysdeps/unix/sysv/linux/aarch64/libc.abilist (GLIBC_2.30): Add direntries_init, direntries_read, direntries_next. * sysdeps/unix/sysv/linux/alpha/libc.abilist (GLIBC_2.30): Likewise. * sysdeps/unix/sysv/linux/arm/libc.abilist (GLIBC_2.30): Likewise. * sysdeps/unix/sysv/linux/csky/libc.abilist (GLIBC_2.30): Likewise. * sysdeps/unix/sysv/linux/hppa/libc.abilist (GLIBC_2.30): Likewise. * sysdeps/unix/sysv/linux/i386/libc.abilist (GLIBC_2.30): Likewise. * sysdeps/unix/sysv/linux/ia64/libc.abilist (GLIBC_2.30): Likewise. * sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist (GLIBC_2.30): Likewise. * sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist (GLIBC_2.30): Likewise. * sysdeps/unix/sysv/linux/microblaze/libc.abilist (GLIBC_2.30): Likewise. * sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist (GLIBC_2.30): Likewise. * sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist (GLIBC_2.30): Likewise. * sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist (GLIBC_2.30): Likewise. * sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist (GLIBC_2.30): Likewise. * sysdeps/unix/sysv/linux/nios2/libc.abilist (GLIBC_2.30): Likewise. * sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist (GLIBC_2.30): Likewise. * sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist (GLIBC_2.30): Likewise. * sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist (GLIBC_2.30): Likewise. * sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist (GLIBC_2.30): Likewise. * sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist (GLIBC_2.30): Likewise. * sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist (GLIBC_2.30): Likewise. * sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist (GLIBC_2.30): Likewise. * sysdeps/unix/sysv/linux/sh/libc.abilist (GLIBC_2.30): Likewise. * sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist (GLIBC_2.30): Likewise. * sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist (GLIBC_2.30): Likewise. * sysdeps/unix/sysv/linux/x86_64/64/libc.abilist (GLIBC_2.30): Likewise. * sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist (GLIBC_2.30): Likewise. diff --git a/NEWS b/NEWS index 8a2fecef47..6b3958cd34 100644 --- a/NEWS +++ b/NEWS @@ -20,7 +20,8 @@ Major new features: twalk function, but it passes an additional caller-supplied argument to the callback function. -* On Linux, the getdents64, gettid, and tgkill functions have been added. +* On Linux, the getdents64, direntries_init, direntries_read, + direntries_next, gettid, and tgkill functions have been added. * Minguo (Republic of China) calendar support has been added as an alternative calendar for the following locales: zh_TW, cmn_TW, hak_TW, diff --git a/include/sys/direntries.h b/include/sys/direntries.h new file mode 100644 index 0000000000..33675fcb79 --- /dev/null +++ b/include/sys/direntries.h @@ -0,0 +1,38 @@ +/* Wrapper for . + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* The direntries parser is available on Linux only for now. */ + +#ifndef _LIBC_DIRENTRIES_H +#define _LIBC_DIRENTRIES_H + +#include_next + +#ifndef _ISOMAC +extern __typeof__ (direntries_init) __direntries_init; +libc_hidden_proto (__direntries_init) +extern __typeof__ (direntries_read) __direntries_read; +libc_hidden_proto (__direntries_read) +extern __typeof__ (direntries_next) __direntries_next; +libc_hidden_proto (__direntries_next) + +/* Members of struct direntries. */ +# define direntries_buffer_begin __glibc_internal_1 +# define direntries_buffer_end __glibc_internal_2 +#endif /* !_ISOMAC */ +#endif /* _LIBC_DIRENTRIES_H */ diff --git a/manual/examples/direntries.c b/manual/examples/direntries.c new file mode 100644 index 0000000000..8aaabfa6d0 --- /dev/null +++ b/manual/examples/direntries.c @@ -0,0 +1,42 @@ +/* Implement directory iteration using . + Copyright (C) 2019 Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . +*/ + +#include +#include + +int +foreach_directory_entry (int fd, + int (*callback) (const struct direntry *, void *), + void *closure) +{ + while (true) + { + char buffer[4096]; + struct direntries entries; + ssize_t ret = direntries_read (fd, &entries, buffer, sizeof (buffer)); + if (ret <= 0) + return ret; + + struct direntry entry; + while (direntries_next (&entries, &entry) == 0) + { + int callback_result = callback (&entry, closure); + if (callback_result != 0) + return callback_result; + } + } +} diff --git a/manual/filesys.texi b/manual/filesys.texi index 513319418a..908bc44cc6 100644 --- a/manual/filesys.texi +++ b/manual/filesys.texi @@ -864,6 +864,88 @@ characters), so a buffer size of at least 1024 is recommended. This function is specific to Linux. @end deftypefun +@deftp {Data Type} {struct direntries} +@standards {GNU, sys/direntries.h} + +This type is used to store an iterator which is used to traverse a +buffer filled by the @code{getdents64} function. +@end deftp + +@deftp {Data Type} {struct direntry} +@standards {GNU, sys/direntries.h} + +This type provides access to one directory entry. It is similar to +@code{struct dirent} defined in @file{dirent.h}. The +@code{direntries_next} function described below uses this type to +provide information to its caller. + +The following members are available to applications. + +@table @code +@item d_name +The name of the directory entry. Note that unlike +@code{struct dirent}, this is a pointer to a null-terminated string. + +@item d_ino +The inode number of the directory entry. + +@item d_type +The file type. This is one of the @code{DT_} constants described for +@code{struct direntry}. It is @code{DT_UNKNOWN} if the information is +not available. @xref{Directory Entries}. + +@item d_flags +Flags indicating extensions. Currently always zero. +@end table +@end deftp + +@deftypefun void direntries_init (struct direntries *@var{iterator}, void *@var{buffer}, size_t @var{length}) +@standards{Linux, sys/direntries.h} +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} +This function initializes @code{*@var{iterator}} for traversing +@var{length} bytes of directory data at @var{buffer}. The buffer must +have been filled with the @code{getdents64} function, and @var{length} +should correspond to the return value of a successful call to +@code{getdents64} for that buffer. + +This function is specific to Linux. +@end deftypefun + +@deftypefun int direntries_read (int @var{fd}, struct direntries *@var{iterator}, void *@var{buffer}, size_t @var{length}) +@standards{Linux, sys/direntries.h} +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} +This function combines reading directory data from the file descriptor +@var{fd} using the @code{getdents64} function and initialization of the +iterator using the @code{direntries_init} function. On success, the +@code{direntries_read} function returns either zero (if there are no +more directory entries available in @var{fd}), or a positive value (if +more entries are availabe). On failure, it returns @code{-1} and sets +@code{errno} accordingly, and @code{*@var{iterator}} is not +initialized. + +The buffer size considerations for @code{getdents64} also apply to +this function. + +This function is specific to Linux. +@end deftypefun + +@deftypefun int direntries_next (struct direntries *@var{iterator}, struct direntry *@var{entry}) +@standards{Linux, sys/direntries.h} +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} +This function copies the next directory entry (if available) from the +iterator to @code{*@var{entry}}, and updates @code{*@var{iterator}} +accordingly. On success, it returns zero, and on failure, it returns +@code{-1} and sets @code{errno} to @code{ENOENT}. + +This function is specific to Linux. +@end deftypefun + +The example below shows how implement callback-based traversal of one +directory using @code{direntries_read} and @code{direntries_next}. + +@smallexample +@include direntries.c.texi +@end smallexample @node Working with Directory Trees @section Working with Directory Trees diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index afcdc658b5..498e60c223 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -187,8 +187,10 @@ endif inhibit-glue = yes ifeq ($(subdir),dirent) -sysdep_routines += getdirentries getdirentries64 -tests += tst-getdents64 +sysdep_headers += sys/direntries.h +sysdep_routines += getdirentries getdirentries64 \ + direntries_init direntries_read direntries_next +tests += tst-getdents64 tst-direntries tests-internal += tst-readdir64-compat endif diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions index 1ca102a9e2..e478c6bf39 100644 --- a/sysdeps/unix/sysv/linux/Versions +++ b/sysdeps/unix/sysv/linux/Versions @@ -176,6 +176,7 @@ libc { } GLIBC_2.30 { getdents64; gettid; tgkill; + direntries_init; direntries_read; direntries_next; } GLIBC_PRIVATE { # functions used in other libraries diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist index a4c31932cb..cf2c128a2d 100644 --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist @@ -2141,6 +2141,9 @@ GLIBC_2.28 thrd_yield F GLIBC_2.29 getcpu F GLIBC_2.29 posix_spawn_file_actions_addchdir_np F GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist index fe85a35620..80daa9383f 100644 --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist @@ -2216,6 +2216,9 @@ GLIBC_2.30 __nldbl_vwarn F GLIBC_2.30 __nldbl_vwarnx F GLIBC_2.30 __nldbl_warn F GLIBC_2.30 __nldbl_warnx F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist index bc3df8dcea..3ba50a2618 100644 --- a/sysdeps/unix/sysv/linux/arm/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/libc.abilist @@ -126,6 +126,9 @@ GLIBC_2.28 thrd_yield F GLIBC_2.29 getcpu F GLIBC_2.29 posix_spawn_file_actions_addchdir_np F GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist index 9b3cee65bb..3cf2aaa6ed 100644 --- a/sysdeps/unix/sysv/linux/csky/libc.abilist +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist @@ -2085,6 +2085,9 @@ GLIBC_2.29 xdrstdio_create F GLIBC_2.29 xencrypt F GLIBC_2.29 xprt_register F GLIBC_2.29 xprt_unregister F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F diff --git a/sysdeps/unix/sysv/linux/direntries_init.c b/sysdeps/unix/sysv/linux/direntries_init.c new file mode 100644 index 0000000000..812bcc4cdd --- /dev/null +++ b/sysdeps/unix/sysv/linux/direntries_init.c @@ -0,0 +1,34 @@ +/* Initialization of directory iterators. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include + +void +__direntries_init (struct direntries *iterator, void *buffer, size_t length) +{ + /* Cheap security check if the caller accidentally passed an error + result from getdirentries to this function. */ + if ((ssize_t) length < 0) + __fortify_fail ("invalid direntries_init call"); + + iterator->direntries_buffer_begin = buffer; + iterator->direntries_buffer_end = (char *) buffer + length; +} +libc_hidden_def (__direntries_init) +strong_alias (__direntries_init, direntries_init) diff --git a/sysdeps/unix/sysv/linux/direntries_next.c b/sysdeps/unix/sysv/linux/direntries_next.c new file mode 100644 index 0000000000..8624c679f4 --- /dev/null +++ b/sysdeps/unix/sysv/linux/direntries_next.c @@ -0,0 +1,51 @@ +/* Advancing directory iterators. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include + +int +__direntries_next (struct direntries *iterator, struct direntry *result) +{ + if (iterator->direntries_buffer_begin == iterator->direntries_buffer_end) + { + __set_errno (ENOENT); + return -1; + } + + char *begin = iterator->direntries_buffer_begin; + + /* The caller may have supplied an unaligned buffer. Make an + aligned copy of the entry, excluding its name. */ + struct dirent64 entry; + memcpy (&entry, begin, offsetof (struct dirent64, d_name)); + + /* The name is not copied. It points into the existing buffer. */ + result->d_name = begin + offsetof (struct dirent64, d_name); + result->d_ino = entry.d_ino; + result->d_type = entry.d_type; + result->d_flags = 0; + + iterator->direntries_buffer_begin = begin + entry.d_reclen; + return 0; +} +libc_hidden_def (__direntries_next) +strong_alias (__direntries_next, direntries_next) diff --git a/sysdeps/unix/sysv/linux/direntries_read.c b/sysdeps/unix/sysv/linux/direntries_read.c new file mode 100644 index 0000000000..493a0aaaaf --- /dev/null +++ b/sysdeps/unix/sysv/linux/direntries_read.c @@ -0,0 +1,34 @@ +/* Buffer reading for directory iterators. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include + +ssize_t +__direntries_read (int fd, struct direntries *iterator, + void *buffer, size_t length) +{ + ssize_t ret = __getdents64 (fd, buffer, length); + if (ret < 0) + return ret; + __direntries_init (iterator, buffer, ret); + return ret; +} +libc_hidden_def (__direntries_read) +strong_alias (__direntries_read, direntries_read) diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist index 75edece94a..333986e6ed 100644 --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist @@ -2037,6 +2037,9 @@ GLIBC_2.3.4 setipv4sourcefilter F GLIBC_2.3.4 setsourcefilter F GLIBC_2.3.4 xdr_quad_t F GLIBC_2.3.4 xdr_u_quad_t F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist index edeaf8e722..99cef29872 100644 --- a/sysdeps/unix/sysv/linux/i386/libc.abilist +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist @@ -2203,6 +2203,9 @@ GLIBC_2.3.4 setsourcefilter F GLIBC_2.3.4 vm86 F GLIBC_2.3.4 xdr_quad_t F GLIBC_2.3.4 xdr_u_quad_t F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist index b5d460eeb2..4bcd0d284b 100644 --- a/sysdeps/unix/sysv/linux/ia64/libc.abilist +++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist @@ -2069,6 +2069,9 @@ GLIBC_2.3.4 setipv4sourcefilter F GLIBC_2.3.4 setsourcefilter F GLIBC_2.3.4 xdr_quad_t F GLIBC_2.3.4 xdr_u_quad_t F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist index 05633b3cb8..e070c1f604 100644 --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist @@ -127,6 +127,9 @@ GLIBC_2.28 thrd_yield F GLIBC_2.29 getcpu F GLIBC_2.29 posix_spawn_file_actions_addchdir_np F GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist index 47eb7b4608..2135ca7f75 100644 --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist @@ -2146,6 +2146,9 @@ GLIBC_2.3.4 setipv4sourcefilter F GLIBC_2.3.4 setsourcefilter F GLIBC_2.3.4 xdr_quad_t F GLIBC_2.3.4 xdr_u_quad_t F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist index f7ced487f7..9b7ade8fe9 100644 --- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist @@ -2133,6 +2133,9 @@ GLIBC_2.28 thrd_yield F GLIBC_2.29 getcpu F GLIBC_2.29 posix_spawn_file_actions_addchdir_np F GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist index e49dc4272e..2beeb2521d 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist @@ -2120,6 +2120,9 @@ GLIBC_2.3.4 setipv4sourcefilter F GLIBC_2.3.4 setsourcefilter F GLIBC_2.3.4 xdr_quad_t F GLIBC_2.3.4 xdr_u_quad_t F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist index daa3b60c5b..2ccf091945 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist @@ -2118,6 +2118,9 @@ GLIBC_2.3.4 setipv4sourcefilter F GLIBC_2.3.4 setsourcefilter F GLIBC_2.3.4 xdr_quad_t F GLIBC_2.3.4 xdr_u_quad_t F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist index 457ce0b6f2..ff555e9fa1 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist @@ -2126,6 +2126,9 @@ GLIBC_2.3.4 setipv4sourcefilter F GLIBC_2.3.4 setsourcefilter F GLIBC_2.3.4 xdr_quad_t F GLIBC_2.3.4 xdr_u_quad_t F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist index 63d5c03bfb..964d4f6070 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist @@ -2120,6 +2120,9 @@ GLIBC_2.3.4 setipv4sourcefilter F GLIBC_2.3.4 setsourcefilter F GLIBC_2.3.4 xdr_quad_t F GLIBC_2.3.4 xdr_u_quad_t F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist index 7fec0c9670..9600c65a74 100644 --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist @@ -2174,6 +2174,9 @@ GLIBC_2.28 thrd_yield F GLIBC_2.29 getcpu F GLIBC_2.29 posix_spawn_file_actions_addchdir_np F GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist index 9200a54309..610b9ba711 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist @@ -2176,6 +2176,9 @@ GLIBC_2.30 __nldbl_vwarn F GLIBC_2.30 __nldbl_vwarnx F GLIBC_2.30 __nldbl_warn F GLIBC_2.30 __nldbl_warnx F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist index ef7779905f..11313a15cb 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist @@ -2209,6 +2209,9 @@ GLIBC_2.30 __nldbl_vwarn F GLIBC_2.30 __nldbl_vwarnx F GLIBC_2.30 __nldbl_warn F GLIBC_2.30 __nldbl_warnx F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist index 2860df8ebc..aad19fe59a 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist @@ -2039,6 +2039,9 @@ GLIBC_2.30 __nldbl_vwarn F GLIBC_2.30 __nldbl_vwarnx F GLIBC_2.30 __nldbl_warn F GLIBC_2.30 __nldbl_warnx F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist index 2229a1dcc0..756caf69e5 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist @@ -2243,6 +2243,9 @@ GLIBC_2.30 __nldbl_vwarn F GLIBC_2.30 __nldbl_vwarnx F GLIBC_2.30 __nldbl_warn F GLIBC_2.30 __nldbl_warnx F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist index 31010e6cf7..d0b175117e 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist @@ -2103,6 +2103,9 @@ GLIBC_2.28 thrd_yield F GLIBC_2.29 getcpu F GLIBC_2.29 posix_spawn_file_actions_addchdir_np F GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist index 576295deff..61d15d4b0c 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist @@ -2171,6 +2171,9 @@ GLIBC_2.30 __nldbl_vwarn F GLIBC_2.30 __nldbl_vwarnx F GLIBC_2.30 __nldbl_warn F GLIBC_2.30 __nldbl_warnx F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist index abf0473683..a43049c313 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist @@ -2075,6 +2075,9 @@ GLIBC_2.30 __nldbl_vwarn F GLIBC_2.30 __nldbl_vwarnx F GLIBC_2.30 __nldbl_warn F GLIBC_2.30 __nldbl_warnx F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist index 41977f6e9c..69000da3d7 100644 --- a/sysdeps/unix/sysv/linux/sh/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/libc.abilist @@ -2041,6 +2041,9 @@ GLIBC_2.3.4 setipv4sourcefilter F GLIBC_2.3.4 setsourcefilter F GLIBC_2.3.4 xdr_quad_t F GLIBC_2.3.4 xdr_u_quad_t F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist index 3d2f00ca52..367b1af9b1 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist @@ -2165,6 +2165,9 @@ GLIBC_2.30 __nldbl_vwarn F GLIBC_2.30 __nldbl_vwarnx F GLIBC_2.30 __nldbl_warn F GLIBC_2.30 __nldbl_warnx F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist index 2f20643e8e..e961fcc386 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist @@ -2092,6 +2092,9 @@ GLIBC_2.3.4 setipv4sourcefilter F GLIBC_2.3.4 setsourcefilter F GLIBC_2.3.4 xdr_quad_t F GLIBC_2.3.4 xdr_u_quad_t F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F diff --git a/sysdeps/unix/sysv/linux/sys/direntries.h b/sysdeps/unix/sysv/linux/sys/direntries.h new file mode 100644 index 0000000000..f2bd2667f5 --- /dev/null +++ b/sysdeps/unix/sysv/linux/sys/direntries.h @@ -0,0 +1,93 @@ +/* Parsing directory streams. Linux version. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _SYS_DIRENTRIES_H +#define _SYS_DIRENTRIES_H + +#include +#include + +/* One directory entry. See struct dirent in . The main + difference is that d_name is a pointer here, and not an array, as + in struct dirent. */ +struct direntry +{ + /* Name of the directory entry. The string is part of the buffer + passed to direntries_init or direntries_read below. */ + const char *d_name; + + /* Inode number of this directory entry. */ + __ino64_t d_ino; + + /* Type of the entry. Can be DT_UNKNOWN if unknown. */ + unsigned char d_type; + + /* Currently always zero. */ + unsigned char d_flags; + + /* Room for further extension. Do not use. */ + union + { + __int64_t __glibc__reserved_1[3]; + void *__glibc__reserved_2[3]; + } __glibc__reserved_3; +}; + +/* Initialized by direntries_init or direntires_read below and used by + direntry_next. */ +struct direntries +{ + /* Internal information. Do not use. */ + void *__glibc_internal_1; + void *__glibc_internal_2; + + /* Room for further extension. Do not use. */ + union + { + __int64_t __glibc__reserved_1[4]; + void *__glibc__reserved_2[4]; + } __glibc__reserved_3; +}; + +__BEGIN_DECLS + +/* Initialize *ITERATOR based on BUFFER and LENGTH. BUFFER must have + been filled by getdents, and length must be a non-negative return + value from this function. Afterwards, individual entries can be + retrieved using direntries_next. */ +void direntries_init (struct direntries *__iterator, + void *__buffer, size_t __length) + __THROW __nonnull ((1, 2)); + +/* Read directory entries from FD and write them to LENGTH bytes at + BUFFER and initialize *ITERATOR so that individual entries can be + retrieved using direntries_next. Returns -1 on error, 0 on end of + stream, and a positive value in case of more data. */ +__ssize_t direntries_read (int __fd, struct direntries *__iterator, + void *__buffer, size_t __length) + __THROW __nonnull ((2, 3)) __wur; + +/* If there is a next entry, copy the next directory entry in ITERATOR + to *ENTRY, update *ITERATOR, and returns 0. If there is no next + entry, return -1 and set errno to ENOENT. */ +int direntries_next (struct direntries *__iterator, struct direntry *__entry) + __THROW __nonnull ((1, 2)) __wur; + +__END_DECLS + +#endif /* _SYS_DIRENTRIES_H */ diff --git a/sysdeps/unix/sysv/linux/tst-direntries.c b/sysdeps/unix/sysv/linux/tst-direntries.c new file mode 100644 index 0000000000..1636dbd9e7 --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-direntries.c @@ -0,0 +1,120 @@ +/* Test for directory iterators. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void +test_one (bool do_read) +{ + /* The test compares the iteration order with readdir64. */ + DIR *reference = opendir ("."); + TEST_VERIFY_EXIT (reference != NULL); + + int fd = xopen (".", O_RDONLY | O_DIRECTORY, 0); + TEST_VERIFY (fd >= 0); + + /* Check that we need to fill the buffer multiple times. */ + int read_count = 0; + + while (true) + { + char buffer[1024]; + struct direntries entries; + ssize_t ret; + if (do_read) + { + ret = direntries_read (fd, &entries, buffer, sizeof (buffer)); + if (ret < 0) + FAIL_EXIT1 ("direntries_read: %m"); + } + else + { + ret = getdents64 (fd, buffer, sizeof (buffer)); + if (ret < 0) + FAIL_EXIT1 ("getdents64: %m"); + if (ret > 0) + direntries_init (&entries, buffer, ret); + } + if (ret == 0) + break; + ++read_count; + if (test_verbose > 0) + { + char *s = support_quote_blob (buffer, ret); + printf ("info: data: \"%s\"\n", s); + free (s); + } + + struct direntry entry; + errno = 0; + while (direntries_next (&entries, &entry) == 0) + { + errno = 0; + struct dirent64 *refentry = readdir64 (reference); + if (refentry == NULL && errno == 0) + FAIL_EXIT1 ("readdir64 failed too early, at: %s", + entry.d_name); + else if (refentry == NULL) + FAIL_EXIT1 ("readdir64: %m"); + + TEST_COMPARE_STRING (entry.d_name, refentry->d_name); + TEST_COMPARE (entry.d_ino, refentry->d_ino); + TEST_COMPARE (entry.d_type, refentry->d_type); + TEST_COMPARE (entry.d_flags, 0); + + errno = 0; + } + TEST_COMPARE (errno, ENOENT); + } + + /* We expect to have reached the end of the stream. */ + errno = 0; + TEST_VERIFY (readdir64 (reference) == NULL); + TEST_COMPARE (errno, 0); + + /* We should have read more than one block. */ + TEST_VERIFY (read_count > 0); + + xclose (fd); + closedir (reference); +} + +static int +do_test (void) +{ + puts ("info: test using getdents64"); + test_one (false); + + puts ("info: test using direntries_read"); + test_one (true); + + return 0; +} + +#include diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist index 59f85d9373..b4456c0928 100644 --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist @@ -2050,6 +2050,9 @@ GLIBC_2.3.4 setipv4sourcefilter F GLIBC_2.3.4 setsourcefilter F GLIBC_2.3.4 xdr_quad_t F GLIBC_2.3.4 xdr_u_quad_t F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist index 67a4e238d6..4c5937e609 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist @@ -2149,6 +2149,9 @@ GLIBC_2.28 thrd_yield F GLIBC_2.29 getcpu F GLIBC_2.29 posix_spawn_file_actions_addchdir_np F GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F +GLIBC_2.30 direntries_init F +GLIBC_2.30 direntries_next F +GLIBC_2.30 direntries_read F GLIBC_2.30 getdents64 F GLIBC_2.30 gettid F GLIBC_2.30 tgkill F