From patchwork Fri Apr 17 13:22:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 38821 Return-Path: X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qt1-x842.google.com (mail-qt1-x842.google.com [IPv6:2607:f8b0:4864:20::842]) by sourceware.org (Postfix) with ESMTPS id C84B2385DC04 for ; Fri, 17 Apr 2020 13:22:16 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org C84B2385DC04 Received: by mail-qt1-x842.google.com with SMTP id w24so1823981qts.11 for ; Fri, 17 Apr 2020 06:22:16 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id; bh=PwgVtkxs8UgyzzZbRtQJgw3ueIplr3M108e/vyCfDKE=; b=MBchke6s7VGJiOZxLakRLYKFy9IHE/m3V5NFg1X8qFgEbBdmeIHvEKeBZNoCKIqfUt IVxW1yGbFvDL1jj6i1XBvJVbyZGh4vX66odByzVmAt4co+XJPMBpMvK1RMuLfkiJqn++ jI4950sDRauQDWx1mtOU6nqf5EBFzl3MFRbws6k/LZKG+S0NvEg1ySBX6V2uQfgPnFX6 UqUm9w5TRQe0n3jhYMkVkNiSEooHlaFkqWM54/+hmfEVSfRzXAizKecoJzHav4N4POjV 4RGOr0thilDS/3h8U7+7vAm1JyP/52xd3wlhnv75MkhFPlIeWNSVCs4DZ9B3Gz+jCDGu OK2Q== X-Gm-Message-State: AGi0Pub4rdxuwVPQXImgQl2ikdmn81EoW4Lwt35DA7rgGIyouDTAiH0l GZI4d/YMUCsj/TvHkm85wyvk0hi8hVAujQ== X-Google-Smtp-Source: APiQypKaDwv/QTkhIN3ZrBTi0dS5rdRwOIqNRrff13IDSh6EdBff1zB4E42LGNPveT1MlHAcMe66LQ== X-Received: by 2002:ac8:6d23:: with SMTP id r3mr2799919qtu.84.1587129735079; Fri, 17 Apr 2020 06:22:15 -0700 (PDT) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id s14sm14737571qts.70.2020.04.17.06.22.13 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Apr 2020 06:22:14 -0700 (PDT) From: Adhemerval Zanella To: libc-alpha@sourceware.org Subject: [PATCH 01/10] linux: Move posix dir implementations to Linux Date: Fri, 17 Apr 2020 10:22:00 -0300 Message-Id: <20200417132209.22065-1-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.17.1 X-Spam-Status: No, score=-25.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 17 Apr 2020 13:22:19 -0000 This generic implementation already expects a getdents API which is Linux specific. It also allows simplify it by assuming _DIRENT_HAVE_D_RECLEN and _DIRENT_HAVE_D_OFF support. The readdir are also expanded on each required implementation, futher fixes and improvements will make parametrize the implementation more complex. Checked on x86_64-linux-gnu, i686-linux-gnu, and with a build for all affected ABIs. --- sysdeps/posix/readdir.c | 127 ------------ sysdeps/posix/readdir_r.c | 159 -------------- sysdeps/unix/sysv/linux/alpha/bits/dirent.h | 6 +- sysdeps/unix/sysv/linux/bits/dirent.h | 6 +- sysdeps/{posix => unix/sysv/linux}/closedir.c | 0 sysdeps/{posix => unix/sysv/linux}/dirfd.c | 0 .../{posix => unix/sysv/linux}/dirstream.h | 0 .../{posix => unix/sysv/linux}/fdopendir.c | 0 sysdeps/{posix => unix/sysv/linux}/opendir.c | 0 sysdeps/unix/sysv/linux/readdir.c | 65 +++++- sysdeps/unix/sysv/linux/readdir64.c | 131 +++++++++++- sysdeps/unix/sysv/linux/readdir64_r.c | 194 +++++++++++++++++- sysdeps/unix/sysv/linux/readdir_r.c | 95 ++++++++- .../{posix => unix/sysv/linux}/rewinddir.c | 0 sysdeps/{posix => unix/sysv/linux}/seekdir.c | 0 sysdeps/{posix => unix/sysv/linux}/telldir.c | 0 16 files changed, 468 insertions(+), 315 deletions(-) delete mode 100644 sysdeps/posix/readdir.c delete mode 100644 sysdeps/posix/readdir_r.c rename sysdeps/{posix => unix/sysv/linux}/closedir.c (100%) rename sysdeps/{posix => unix/sysv/linux}/dirfd.c (100%) rename sysdeps/{posix => unix/sysv/linux}/dirstream.h (100%) rename sysdeps/{posix => unix/sysv/linux}/fdopendir.c (100%) rename sysdeps/{posix => unix/sysv/linux}/opendir.c (100%) rename sysdeps/{posix => unix/sysv/linux}/rewinddir.c (100%) rename sysdeps/{posix => unix/sysv/linux}/seekdir.c (100%) rename sysdeps/{posix => unix/sysv/linux}/telldir.c (100%) diff --git a/sysdeps/posix/readdir.c b/sysdeps/posix/readdir.c deleted file mode 100644 index b36278b5f4..0000000000 --- a/sysdeps/posix/readdir.c +++ /dev/null @@ -1,127 +0,0 @@ -/* Copyright (C) 1991-2020 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 - -#ifndef __READDIR -# define __READDIR __readdir -# define __GETDENTS __getdents -# define DIRENT_TYPE struct dirent -# define __READDIR_ALIAS -#endif - -/* Read a directory entry from DIRP. */ -DIRENT_TYPE * -__READDIR (DIR *dirp) -{ - DIRENT_TYPE *dp; - int saved_errno = errno; - -#if IS_IN (libc) - __libc_lock_lock (dirp->lock); -#endif - - do - { - size_t reclen; - - if (dirp->offset >= dirp->size) - { - /* We've emptied out our buffer. Refill it. */ - - size_t maxread; - ssize_t bytes; - -#ifndef _DIRENT_HAVE_D_RECLEN - /* Fixed-size struct; must read one at a time (see below). */ - maxread = sizeof *dp; -#else - maxread = dirp->allocation; -#endif - - bytes = __GETDENTS (dirp->fd, dirp->data, maxread); - if (bytes <= 0) - { - /* On some systems getdents fails with ENOENT when the - open directory has been rmdir'd already. POSIX.1 - requires that we treat this condition like normal EOF. */ - if (bytes < 0 && errno == ENOENT) - bytes = 0; - - /* Don't modifiy errno when reaching EOF. */ - if (bytes == 0) - __set_errno (saved_errno); - dp = NULL; - break; - } - dirp->size = (size_t) bytes; - - /* Reset the offset into the buffer. */ - dirp->offset = 0; - } - - dp = (DIRENT_TYPE *) &dirp->data[dirp->offset]; - -#ifdef _DIRENT_HAVE_D_RECLEN - reclen = dp->d_reclen; -#else - /* The only version of `struct dirent*' that lacks `d_reclen' - is fixed-size. */ - assert (sizeof dp->d_name > 1); - reclen = sizeof *dp; - /* The name is not terminated if it is the largest possible size. - Clobber the following byte to ensure proper null termination. We - read jst one entry at a time above so we know that byte will not - be used later. */ - dp->d_name[sizeof dp->d_name] = '\0'; -#endif - - dirp->offset += reclen; - -#ifdef _DIRENT_HAVE_D_OFF - dirp->filepos = dp->d_off; -#else - dirp->filepos += reclen; -#endif - - /* Skip deleted files. */ - } while (dp->d_ino == 0); - -#if IS_IN (libc) - __libc_lock_unlock (dirp->lock); -#endif - - return dp; -} - -#ifdef __READDIR_ALIAS -weak_alias (__readdir, readdir) -#endif - -#undef __READDIR -#undef __GETDENTS -#undef DIRENT_TYPE -#undef __READDIR_ALIAS diff --git a/sysdeps/posix/readdir_r.c b/sysdeps/posix/readdir_r.c deleted file mode 100644 index 9079abc2ff..0000000000 --- a/sysdeps/posix/readdir_r.c +++ /dev/null @@ -1,159 +0,0 @@ -/* Copyright (C) 1991-2020 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 - -#ifndef __READDIR_R -# define __READDIR_R __readdir_r -# define __GETDENTS __getdents -# define DIRENT_TYPE struct dirent -# define __READDIR_R_ALIAS -#endif - -/* Read a directory entry from DIRP. */ -int -__READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result) -{ - DIRENT_TYPE *dp; - size_t reclen; - const int saved_errno = errno; - int ret; - - __libc_lock_lock (dirp->lock); - - do - { - if (dirp->offset >= dirp->size) - { - /* We've emptied out our buffer. Refill it. */ - - size_t maxread; - ssize_t bytes; - -#ifndef _DIRENT_HAVE_D_RECLEN - /* Fixed-size struct; must read one at a time (see below). */ - maxread = sizeof *dp; -#else - maxread = dirp->allocation; -#endif - - bytes = __GETDENTS (dirp->fd, dirp->data, maxread); - if (bytes <= 0) - { - /* On some systems getdents fails with ENOENT when the - open directory has been rmdir'd already. POSIX.1 - requires that we treat this condition like normal EOF. */ - if (bytes < 0 && errno == ENOENT) - { - bytes = 0; - __set_errno (saved_errno); - } - if (bytes < 0) - dirp->errcode = errno; - - dp = NULL; - break; - } - dirp->size = (size_t) bytes; - - /* Reset the offset into the buffer. */ - dirp->offset = 0; - } - - dp = (DIRENT_TYPE *) &dirp->data[dirp->offset]; - -#ifdef _DIRENT_HAVE_D_RECLEN - reclen = dp->d_reclen; -#else - /* The only version of `struct dirent*' that lacks `d_reclen' - is fixed-size. */ - assert (sizeof dp->d_name > 1); - reclen = sizeof *dp; - /* The name is not terminated if it is the largest possible size. - Clobber the following byte to ensure proper null termination. We - read just one entry at a time above so we know that byte will not - be used later. */ - dp->d_name[sizeof dp->d_name] = '\0'; -#endif - - dirp->offset += reclen; - -#ifdef _DIRENT_HAVE_D_OFF - dirp->filepos = dp->d_off; -#else - dirp->filepos += reclen; -#endif - -#ifdef NAME_MAX - if (reclen > offsetof (DIRENT_TYPE, d_name) + NAME_MAX + 1) - { - /* The record is very long. It could still fit into the - caller-supplied buffer if we can skip padding at the - end. */ - size_t namelen = _D_EXACT_NAMLEN (dp); - if (namelen <= NAME_MAX) - reclen = offsetof (DIRENT_TYPE, d_name) + namelen + 1; - else - { - /* The name is too long. Ignore this file. */ - dirp->errcode = ENAMETOOLONG; - dp->d_ino = 0; - continue; - } - } -#endif - - /* Skip deleted and ignored files. */ - } - while (dp->d_ino == 0); - - if (dp != NULL) - { - *result = memcpy (entry, dp, reclen); -#ifdef _DIRENT_HAVE_D_RECLEN - entry->d_reclen = reclen; -#endif - ret = 0; - } - else - { - *result = NULL; - ret = dirp->errcode; - } - - __libc_lock_unlock (dirp->lock); - - return ret; -} - -#ifdef __READDIR_R_ALIAS -weak_alias (__readdir_r, readdir_r) -#endif - -#undef __READDIR_R -#undef __GETDENTS -#undef DIRENT_TYPE -#undef __READDIR_R_ALIAS diff --git a/sysdeps/unix/sysv/linux/alpha/bits/dirent.h b/sysdeps/unix/sysv/linux/alpha/bits/dirent.h index 953d590cff..649b6bcb78 100644 --- a/sysdeps/unix/sysv/linux/alpha/bits/dirent.h +++ b/sysdeps/unix/sysv/linux/alpha/bits/dirent.h @@ -47,9 +47,9 @@ struct dirent64 #define d_fileno d_ino /* Backwards compatibility. */ #undef _DIRENT_HAVE_D_NAMLEN -#define _DIRENT_HAVE_D_RECLEN -#define _DIRENT_HAVE_D_OFF -#define _DIRENT_HAVE_D_TYPE +#define _DIRENT_HAVE_D_RECLEN 1 +#define _DIRENT_HAVE_D_OFF 1 +#define _DIRENT_HAVE_D_TYPE 1 /* Inform libc code that these two types are effectively identical. */ #define _DIRENT_MATCHES_DIRENT64 1 diff --git a/sysdeps/unix/sysv/linux/bits/dirent.h b/sysdeps/unix/sysv/linux/bits/dirent.h index 9e4df8a58b..82c38d9ef8 100644 --- a/sysdeps/unix/sysv/linux/bits/dirent.h +++ b/sysdeps/unix/sysv/linux/bits/dirent.h @@ -47,9 +47,9 @@ struct dirent64 #define d_fileno d_ino /* Backwards compatibility. */ #undef _DIRENT_HAVE_D_NAMLEN -#define _DIRENT_HAVE_D_RECLEN -#define _DIRENT_HAVE_D_OFF -#define _DIRENT_HAVE_D_TYPE +#define _DIRENT_HAVE_D_RECLEN 1 +#define _DIRENT_HAVE_D_OFF 1 +#define _DIRENT_HAVE_D_TYPE 1 #if defined __OFF_T_MATCHES_OFF64_T && defined __INO_T_MATCHES_INO64_T /* Inform libc code that these two types are effectively identical. */ diff --git a/sysdeps/posix/closedir.c b/sysdeps/unix/sysv/linux/closedir.c similarity index 100% rename from sysdeps/posix/closedir.c rename to sysdeps/unix/sysv/linux/closedir.c diff --git a/sysdeps/posix/dirfd.c b/sysdeps/unix/sysv/linux/dirfd.c similarity index 100% rename from sysdeps/posix/dirfd.c rename to sysdeps/unix/sysv/linux/dirfd.c diff --git a/sysdeps/posix/dirstream.h b/sysdeps/unix/sysv/linux/dirstream.h similarity index 100% rename from sysdeps/posix/dirstream.h rename to sysdeps/unix/sysv/linux/dirstream.h diff --git a/sysdeps/posix/fdopendir.c b/sysdeps/unix/sysv/linux/fdopendir.c similarity index 100% rename from sysdeps/posix/fdopendir.c rename to sysdeps/unix/sysv/linux/fdopendir.c diff --git a/sysdeps/posix/opendir.c b/sysdeps/unix/sysv/linux/opendir.c similarity index 100% rename from sysdeps/posix/opendir.c rename to sysdeps/unix/sysv/linux/opendir.c diff --git a/sysdeps/unix/sysv/linux/readdir.c b/sysdeps/unix/sysv/linux/readdir.c index df7a92aa78..2e03e66e69 100644 --- a/sysdeps/unix/sysv/linux/readdir.c +++ b/sysdeps/unix/sysv/linux/readdir.c @@ -19,5 +19,68 @@ #include #if !_DIRENT_MATCHES_DIRENT64 -# include +#include + +/* Read a directory entry from DIRP. */ +struct dirent * +__readdir (DIR *dirp) +{ + struct dirent *dp; + int saved_errno = errno; + +#if IS_IN (libc) + __libc_lock_lock (dirp->lock); +#endif + + do + { + size_t reclen; + + if (dirp->offset >= dirp->size) + { + /* We've emptied out our buffer. Refill it. */ + + size_t maxread = dirp->allocation; + ssize_t bytes; + + bytes = __getdents (dirp->fd, dirp->data, maxread); + if (bytes <= 0) + { + /* On some systems getdents fails with ENOENT when the + open directory has been rmdir'd already. POSIX.1 + requires that we treat this condition like normal EOF. */ + if (bytes < 0 && errno == ENOENT) + bytes = 0; + + /* Don't modifiy errno when reaching EOF. */ + if (bytes == 0) + __set_errno (saved_errno); + dp = NULL; + break; + } + dirp->size = (size_t) bytes; + + /* Reset the offset into the buffer. */ + dirp->offset = 0; + } + + dp = (struct dirent *) &dirp->data[dirp->offset]; + + reclen = dp->d_reclen; + + dirp->offset += reclen; + + dirp->filepos = dp->d_off; + + /* Skip deleted files. */ + } while (dp->d_ino == 0); + +#if IS_IN (libc) + __libc_lock_unlock (dirp->lock); +#endif + + return dp; +} +weak_alias (__readdir, readdir) + #endif diff --git a/sysdeps/unix/sysv/linux/readdir64.c b/sysdeps/unix/sysv/linux/readdir64.c index 7d4b0001b3..e4d56cb2ae 100644 --- a/sysdeps/unix/sysv/linux/readdir64.c +++ b/sysdeps/unix/sysv/linux/readdir64.c @@ -23,17 +23,71 @@ #define readdir __no_readdir_decl #define __readdir __no___readdir_decl #include +#undef __readdir +#undef readdir -#define __READDIR __readdir64 -#define __GETDENTS __getdents64 -#define DIRENT_TYPE struct dirent64 +/* Read a directory entry from DIRP. */ +struct dirent64 * +__readdir64 (DIR *dirp) +{ + struct dirent64 *dp; + int saved_errno = errno; -#include +#if IS_IN (libc) + __libc_lock_lock (dirp->lock); +#endif -#undef __readdir -#undef readdir + do + { + size_t reclen; + + if (dirp->offset >= dirp->size) + { + /* We've emptied out our buffer. Refill it. */ + + size_t maxread = dirp->allocation; + ssize_t bytes; + + bytes = __getdents64 (dirp->fd, dirp->data, maxread); + if (bytes <= 0) + { + /* On some systems getdents fails with ENOENT when the + open directory has been rmdir'd already. POSIX.1 + requires that we treat this condition like normal EOF. */ + if (bytes < 0 && errno == ENOENT) + bytes = 0; + + /* Don't modifiy errno when reaching EOF. */ + if (bytes == 0) + __set_errno (saved_errno); + dp = NULL; + break; + } + dirp->size = (size_t) bytes; + /* Reset the offset into the buffer. */ + dirp->offset = 0; + } + + dp = (struct dirent64 *) &dirp->data[dirp->offset]; + + reclen = dp->d_reclen; + + dirp->offset += reclen; + + dirp->filepos = dp->d_off; + + /* Skip deleted files. */ + } while (dp->d_ino == 0); + +#if IS_IN (libc) + __libc_lock_unlock (dirp->lock); +#endif + + return dp; +} libc_hidden_def (__readdir64) + #if _DIRENT_MATCHES_DIRENT64 strong_alias (__readdir64, __readdir) weak_alias (__readdir64, readdir64) @@ -45,10 +99,67 @@ weak_alias (__readdir64, readdir) versioned_symbol (libc, __readdir64, readdir64, GLIBC_2_2); # if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) # include -# define __READDIR attribute_compat_text_section __old_readdir64 -# define __GETDENTS __old_getdents64 -# define DIRENT_TYPE struct __old_dirent64 -# include + +attribute_compat_text_section +struct __old_dirent64 * +__old_readdir64 (DIR *dirp) +{ + struct __old_dirent64 *dp; + int saved_errno = errno; + +#if IS_IN (libc) + __libc_lock_lock (dirp->lock); +#endif + + do + { + size_t reclen; + + if (dirp->offset >= dirp->size) + { + /* We've emptied out our buffer. Refill it. */ + + size_t maxread = dirp->allocation; + ssize_t bytes; + + bytes = __old_getdents64 (dirp->fd, dirp->data, maxread); + if (bytes <= 0) + { + /* On some systems getdents fails with ENOENT when the + open directory has been rmdir'd already. POSIX.1 + requires that we treat this condition like normal EOF. */ + if (bytes < 0 && errno == ENOENT) + bytes = 0; + + /* Don't modifiy errno when reaching EOF. */ + if (bytes == 0) + __set_errno (saved_errno); + dp = NULL; + break; + } + dirp->size = (size_t) bytes; + + /* Reset the offset into the buffer. */ + dirp->offset = 0; + } + + dp = (struct __old_dirent64 *) &dirp->data[dirp->offset]; + + reclen = dp->d_reclen; + + dirp->offset += reclen; + + dirp->filepos = dp->d_off; + + /* Skip deleted files. */ + } while (dp->d_ino == 0); + +#if IS_IN (libc) + __libc_lock_unlock (dirp->lock); +#endif + + return dp; +} libc_hidden_def (__old_readdir64) compat_symbol (libc, __old_readdir64, readdir64, GLIBC_2_1); # endif /* SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) */ diff --git a/sysdeps/unix/sysv/linux/readdir64_r.c b/sysdeps/unix/sysv/linux/readdir64_r.c index 6d589f36f5..c587787417 100644 --- a/sysdeps/unix/sysv/linux/readdir64_r.c +++ b/sysdeps/unix/sysv/linux/readdir64_r.c @@ -23,15 +23,100 @@ #define readdir_r __no_readdir_r_decl #define __readdir_r __no___readdir_r_decl #include +#undef __readdir_r +#undef readdir_r -#define __READDIR_R __readdir64_r -#define __GETDENTS __getdents64 -#define DIRENT_TYPE struct dirent64 +/* Read a directory entry from DIRP. */ +int +__readdir64_r (DIR *dirp, struct dirent64 *entry, struct dirent64 **result) +{ + struct dirent64 *dp; + size_t reclen; + const int saved_errno = errno; + int ret; -#include + __libc_lock_lock (dirp->lock); + + do + { + if (dirp->offset >= dirp->size) + { + /* We've emptied out our buffer. Refill it. */ + + size_t maxread = dirp->allocation; + ssize_t bytes; + + maxread = dirp->allocation; + + bytes = __getdents64 (dirp->fd, dirp->data, maxread); + if (bytes <= 0) + { + /* On some systems getdents fails with ENOENT when the + open directory has been rmdir'd already. POSIX.1 + requires that we treat this condition like normal EOF. */ + if (bytes < 0 && errno == ENOENT) + { + bytes = 0; + __set_errno (saved_errno); + } + if (bytes < 0) + dirp->errcode = errno; + + dp = NULL; + break; + } + dirp->size = (size_t) bytes; + + /* Reset the offset into the buffer. */ + dirp->offset = 0; + } + + dp = (struct dirent64 *) &dirp->data[dirp->offset]; + + reclen = dp->d_reclen; + + dirp->offset += reclen; + + dirp->filepos = dp->d_off; + + if (reclen > offsetof (struct dirent64, d_name) + NAME_MAX + 1) + { + /* The record is very long. It could still fit into the + caller-supplied buffer if we can skip padding at the + end. */ + size_t namelen = _D_EXACT_NAMLEN (dp); + if (namelen <= NAME_MAX) + reclen = offsetof (struct dirent64, d_name) + namelen + 1; + else + { + /* The name is too long. Ignore this file. */ + dirp->errcode = ENAMETOOLONG; + dp->d_ino = 0; + continue; + } + } + + /* Skip deleted and ignored files. */ + } + while (dp->d_ino == 0); + + if (dp != NULL) + { + *result = memcpy (entry, dp, reclen); + entry->d_reclen = reclen; + ret = 0; + } + else + { + *result = NULL; + ret = dirp->errcode; + } + + __libc_lock_unlock (dirp->lock); + + return ret; +} -#undef __readdir_r -#undef readdir_r #if _DIRENT_MATCHES_DIRENT64 strong_alias (__readdir64_r, __readdir_r) @@ -44,10 +129,99 @@ weak_alias (__readdir64_r, readdir64_r) versioned_symbol (libc, __readdir64_r, readdir64_r, GLIBC_2_2); # if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) # include -# define __READDIR_R attribute_compat_text_section __old_readdir64_r -# define __GETDENTS __old_getdents64 -# define DIRENT_TYPE struct __old_dirent64 -# include + +int +attribute_compat_text_section +__old_readdir64_r (DIR *dirp, struct __old_dirent64 *entry, + struct __old_dirent64 **result) +{ + struct __old_dirent64 *dp; + size_t reclen; + const int saved_errno = errno; + int ret; + + __libc_lock_lock (dirp->lock); + + do + { + if (dirp->offset >= dirp->size) + { + /* We've emptied out our buffer. Refill it. */ + + size_t maxread = dirp->allocation; + ssize_t bytes; + + maxread = dirp->allocation; + + bytes = __old_getdents64 (dirp->fd, dirp->data, maxread); + if (bytes <= 0) + { + /* On some systems getdents fails with ENOENT when the + open directory has been rmdir'd already. POSIX.1 + requires that we treat this condition like normal EOF. */ + if (bytes < 0 && errno == ENOENT) + { + bytes = 0; + __set_errno (saved_errno); + } + if (bytes < 0) + dirp->errcode = errno; + + dp = NULL; + break; + } + dirp->size = (size_t) bytes; + + /* Reset the offset into the buffer. */ + dirp->offset = 0; + } + + dp = (struct __old_dirent64 *) &dirp->data[dirp->offset]; + + reclen = dp->d_reclen; + + dirp->offset += reclen; + + dirp->filepos = dp->d_off; + + if (reclen > offsetof (struct __old_dirent64, d_name) + NAME_MAX + 1) + { + /* The record is very long. It could still fit into the + caller-supplied buffer if we can skip padding at the + end. */ + size_t namelen = _D_EXACT_NAMLEN (dp); + if (namelen <= NAME_MAX) + reclen = offsetof (struct __old_dirent64, d_name) + namelen + 1; + else + { + /* The name is too long. Ignore this file. */ + dirp->errcode = ENAMETOOLONG; + dp->d_ino = 0; + continue; + } + } + + /* Skip deleted and ignored files. */ + } + while (dp->d_ino == 0); + + if (dp != NULL) + { + *result = memcpy (entry, dp, reclen); + entry->d_reclen = reclen; + ret = 0; + } + else + { + *result = NULL; + ret = dirp->errcode; + } + + __libc_lock_unlock (dirp->lock); + + return ret; +} + compat_symbol (libc, __old_readdir64_r, readdir64_r, GLIBC_2_1); # endif /* SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) */ #endif /* _DIRENT_MATCHES_DIRENT64 */ diff --git a/sysdeps/unix/sysv/linux/readdir_r.c b/sysdeps/unix/sysv/linux/readdir_r.c index 30f237dbcc..0069041394 100644 --- a/sysdeps/unix/sysv/linux/readdir_r.c +++ b/sysdeps/unix/sysv/linux/readdir_r.c @@ -19,5 +19,96 @@ #include #if !_DIRENT_MATCHES_DIRENT64 -# include -#endif +/* Read a directory entry from DIRP. */ +int +__readdir_r (DIR *dirp, struct dirent *entry, struct dirent **result) +{ + struct dirent *dp; + size_t reclen; + const int saved_errno = errno; + int ret; + + __libc_lock_lock (dirp->lock); + + do + { + if (dirp->offset >= dirp->size) + { + /* We've emptied out our buffer. Refill it. */ + + size_t maxread = dirp->allocation; + ssize_t bytes; + + maxread = dirp->allocation; + + bytes = __getdents (dirp->fd, dirp->data, maxread); + if (bytes <= 0) + { + /* On some systems getdents fails with ENOENT when the + open directory has been rmdir'd already. POSIX.1 + requires that we treat this condition like normal EOF. */ + if (bytes < 0 && errno == ENOENT) + { + bytes = 0; + __set_errno (saved_errno); + } + if (bytes < 0) + dirp->errcode = errno; + + dp = NULL; + break; + } + dirp->size = (size_t) bytes; + + /* Reset the offset into the buffer. */ + dirp->offset = 0; + } + + dp = (struct dirent *) &dirp->data[dirp->offset]; + + reclen = dp->d_reclen; + + dirp->offset += reclen; + + dirp->filepos = dp->d_off; + + if (reclen > offsetof (struct dirent, d_name) + NAME_MAX + 1) + { + /* The record is very long. It could still fit into the + caller-supplied buffer if we can skip padding at the + end. */ + size_t namelen = _D_EXACT_NAMLEN (dp); + if (namelen <= NAME_MAX) + reclen = offsetof (struct dirent, d_name) + namelen + 1; + else + { + /* The name is too long. Ignore this file. */ + dirp->errcode = ENAMETOOLONG; + dp->d_ino = 0; + continue; + } + } + + /* Skip deleted and ignored files. */ + } + while (dp->d_ino == 0); + + if (dp != NULL) + { + *result = memcpy (entry, dp, reclen); + entry->d_reclen = reclen; + ret = 0; + } + else + { + *result = NULL; + ret = dirp->errcode; + } + + __libc_lock_unlock (dirp->lock); + + return ret; +} + +weak_alias (__readdir_r, readdir_r) +#endif /* _DIRENT_MATCHES_DIRENT64 */ diff --git a/sysdeps/posix/rewinddir.c b/sysdeps/unix/sysv/linux/rewinddir.c similarity index 100% rename from sysdeps/posix/rewinddir.c rename to sysdeps/unix/sysv/linux/rewinddir.c diff --git a/sysdeps/posix/seekdir.c b/sysdeps/unix/sysv/linux/seekdir.c similarity index 100% rename from sysdeps/posix/seekdir.c rename to sysdeps/unix/sysv/linux/seekdir.c diff --git a/sysdeps/posix/telldir.c b/sysdeps/unix/sysv/linux/telldir.c similarity index 100% rename from sysdeps/posix/telldir.c rename to sysdeps/unix/sysv/linux/telldir.c From patchwork Fri Apr 17 13:22:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 38820 Return-Path: X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qk1-x743.google.com (mail-qk1-x743.google.com [IPv6:2607:f8b0:4864:20::743]) by sourceware.org (Postfix) with ESMTPS id 1C4D6385DC08 for ; Fri, 17 Apr 2020 13:22:17 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 1C4D6385DC08 Received: by mail-qk1-x743.google.com with SMTP id j4so2254395qkc.11 for ; Fri, 17 Apr 2020 06:22:17 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=lMxg4ody7Eg1+3MQYOdhzYeFkhv+HnTTF1yt9w+XU1Q=; b=bcRlj2bn8FBv8P0/MdjvMkU2krKiWlRE81Z1I+HVX0y3VD1TkPD/Iho1A1aFCBmc3r nln6pEUk3SAVKjWwy8jjP6br0OuvlTxbFyCP04kT4ZM3xNpuAJVgntTr9UUQ7n33iH7l kokh0UvlWmgxv3AiS9Z1ZdrleaWp18gOnI/LxT9AduJJqMO159eQkQoeefxkEJO+4d6i b39Ke/eW9LHESc2cioSh89bI+XRRfjGnzAzIjM749Yse4KkJOo69ndPoS1UYMzj/bgnE uRDfVQ+tO25GDrDvDLvoqwrOlJzmZOvy9GtcT1aMUoqAlQr9s4i50TfpcuTD77JcxmcF 0JSA== X-Gm-Message-State: AGi0PuYMhiw5xngZ51zmXluJaLzEuMq+lQskyvYP02YSddoCWE2qze6O tmPCbET5pzKUaJ74hADuMoDGw2ezxIN5xg== X-Google-Smtp-Source: APiQypJHwbh/EFG/57Fd/wtaX3KnQ1fm/Mxe9vkOB+RebwE3XROFPtpvhSqU9OCLlKQdUM6AEYQp7g== X-Received: by 2002:a37:b1c7:: with SMTP id a190mr3028927qkf.69.1587129736356; Fri, 17 Apr 2020 06:22:16 -0700 (PDT) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id s14sm14737571qts.70.2020.04.17.06.22.15 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Apr 2020 06:22:16 -0700 (PDT) From: Adhemerval Zanella To: libc-alpha@sourceware.org Subject: [PATCH 02/10] linux: Simplify opendir buffer allocation Date: Fri, 17 Apr 2020 10:22:01 -0300 Message-Id: <20200417132209.22065-2-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200417132209.22065-1-adhemerval.zanella@linaro.org> References: <20200417132209.22065-1-adhemerval.zanella@linaro.org> X-Spam-Status: No, score=-25.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 17 Apr 2020 13:22:18 -0000 THe fallback allocation is removed, so the possible size constraint should be analized just once; __alloc_dir assumes that 'statp' argument is non-null, and the max_buffer_size move to close its used. Checked on x86_64-linux-gnu and i686-linux-gnu. --- include/dirent.h | 3 +- sysdeps/unix/sysv/linux/opendir.c | 52 +++++++++++-------------------- 2 files changed, 21 insertions(+), 34 deletions(-) diff --git a/include/dirent.h b/include/dirent.h index 2b1cdcf8bd..fdf4c4a2f1 100644 --- a/include/dirent.h +++ b/include/dirent.h @@ -48,7 +48,8 @@ extern int __versionsort64 (const struct dirent64 **a, const struct dirent64 **b) __attribute_pure__; extern DIR *__alloc_dir (int fd, bool close_fd, int flags, - const struct stat64 *statp) attribute_hidden; + const struct stat64 *statp) + __nonnull (4) attribute_hidden; extern __typeof (rewinddir) __rewinddir; extern __typeof (seekdir) __seekdir; extern __typeof (dirfd) __dirfd; diff --git a/sysdeps/unix/sysv/linux/opendir.c b/sysdeps/unix/sysv/linux/opendir.c index c6ab79246c..765c8104b3 100644 --- a/sysdeps/unix/sysv/linux/opendir.c +++ b/sysdeps/unix/sysv/linux/opendir.c @@ -23,12 +23,6 @@ #include -/* The st_blksize value of the directory is used as a hint for the - size of the buffer which receives struct dirent values from the - kernel. st_blksize is limited to MAX_DIR_BUFFER_SIZE, in case the - file system provides a bogus value. */ -#define MAX_DIR_BUFFER_SIZE 1048576U - enum { opendir_oflags = O_RDONLY|O_NDELAY|O_DIRECTORY|O_LARGEFILE|O_CLOEXEC }; @@ -100,38 +94,30 @@ __alloc_dir (int fd, bool close_fd, int flags, const struct stat64 *statp) file descriptor. */ if (!close_fd && __glibc_unlikely (__fcntl64_nocancel (fd, F_SETFD, FD_CLOEXEC) < 0)) - goto lose; - - const size_t default_allocation = (4 * BUFSIZ < sizeof (struct dirent64) - ? sizeof (struct dirent64) : 4 * BUFSIZ); - const size_t small_allocation = (BUFSIZ < sizeof (struct dirent64) - ? sizeof (struct dirent64) : BUFSIZ); - size_t allocation = default_allocation; -#ifdef _STATBUF_ST_BLKSIZE + return NULL; + + /* The st_blksize value of the directory is used as a hint for the + size of the buffer which receives struct dirent values from the + kernel. st_blksize is limited to max_buffer_size, in case the + file system provides a bogus value. */ + enum { max_buffer_size = 1U << 20 }; + + const size_t allocation_size = 4 * BUFSIZ; + _Static_assert (allocation_size >= sizeof (struct dirent64), + "allocation_size < sizeof (struct dirent64)"); + /* Increase allocation if requested, but not if the value appears to - be bogus. */ - if (statp != NULL) - allocation = MIN (MAX ((size_t) statp->st_blksize, default_allocation), - MAX_DIR_BUFFER_SIZE); -#endif + be bogus. It will be between 32Kb (for blocksizes smaller than BUFSIZ) + up to 1Mb. */ + size_t allocation = MIN (MAX ((size_t) statp->st_blksize, allocation_size), + max_buffer_size); DIR *dirp = (DIR *) malloc (sizeof (DIR) + allocation); if (dirp == NULL) { - allocation = small_allocation; - dirp = (DIR *) malloc (sizeof (DIR) + allocation); - - if (dirp == NULL) - lose: - { - if (close_fd) - { - int save_errno = errno; - __close_nocancel_nostatus (fd); - __set_errno (save_errno); - } - return NULL; - } + if (close_fd) + __close_nocancel_nostatus (fd); + return NULL; } dirp->fd = fd; From patchwork Fri Apr 17 13:22:02 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 38822 Return-Path: X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qv1-xf41.google.com (mail-qv1-xf41.google.com [IPv6:2607:f8b0:4864:20::f41]) by sourceware.org (Postfix) with ESMTPS id 8F1B8385DC08 for ; Fri, 17 Apr 2020 13:22:18 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 8F1B8385DC08 Received: by mail-qv1-xf41.google.com with SMTP id v18so822971qvx.9 for ; Fri, 17 Apr 2020 06:22:18 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=jPydN9YIsNs5Fy6f5zR33KsrU9VH+ex2Ii1z+2Cva3k=; b=ui1km3dkVl/m8x8jB0UFu5wFL5cj2qzRcUm+WMe7RVCU1v5NbOTfdfhU6A/QfdRoIN Gea2uNB+0lAMTBRkLzY0PhHD5/0g5fHCuEG4jACisAkL8zzPHorSApfaBcVhbQg87+7S zIpErlb2eSYlLQ4/8mT1Qfeuxwy30cR1iF0q4klZca//ixAeQI4CkUgGrYTRbH9sTVIL KCxZpxJVm2pyLvGxcRL9EX2cS9dB66wKW0wnAB2FuI6+SOGlyV+UN+5oOEwn3Mq9dSOp aDf09E/aMjuAwkp/SCI1FThVstjDk4TWlpkagiGVhRkTA4OyAQIxTDHgpknqwlAoK7WE b1BQ== X-Gm-Message-State: AGi0Pubckb1qtzU+Lkrbgc7qhH3ChJwsYq9Tr18aBSHhZxpGHslyq5Ug 8PCML8BEvBQFk7hLkDm6/12/T0Ky7XkSsg== X-Google-Smtp-Source: APiQypLVOa4V7tlF7pfUBF58FrR/Sl2qubPAYYYFzCjd0uwI6EraKjScYRTjZStBvderiIuPOLopoQ== X-Received: by 2002:ad4:55c4:: with SMTP id bt4mr2568264qvb.225.1587129737683; Fri, 17 Apr 2020 06:22:17 -0700 (PDT) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id s14sm14737571qts.70.2020.04.17.06.22.16 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Apr 2020 06:22:17 -0700 (PDT) From: Adhemerval Zanella To: libc-alpha@sourceware.org Subject: [PATCH 03/10] linux: Add __readdir_unlocked Date: Fri, 17 Apr 2020 10:22:02 -0300 Message-Id: <20200417132209.22065-3-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200417132209.22065-1-adhemerval.zanella@linaro.org> References: <20200417132209.22065-1-adhemerval.zanella@linaro.org> X-Spam-Status: No, score=-25.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 17 Apr 2020 13:22:19 -0000 And use it on readdir_r implementation. Checked on i686-linux-gnu. --- include/dirent.h | 1 + sysdeps/unix/sysv/linux/readdir.c | 18 +++++-- sysdeps/unix/sysv/linux/readdir_r.c | 79 +++++++---------------------- 3 files changed, 31 insertions(+), 67 deletions(-) diff --git a/include/dirent.h b/include/dirent.h index fdf4c4a2f1..8325a19e5f 100644 --- a/include/dirent.h +++ b/include/dirent.h @@ -20,6 +20,7 @@ extern DIR *__opendirat (int dfd, const char *__name) attribute_hidden; extern DIR *__fdopendir (int __fd) attribute_hidden; extern int __closedir (DIR *__dirp) attribute_hidden; extern struct dirent *__readdir (DIR *__dirp) attribute_hidden; +extern struct dirent *__readdir_unlocked (DIR *__dirp) attribute_hidden; extern struct dirent64 *__readdir64 (DIR *__dirp); libc_hidden_proto (__readdir64) extern int __readdir_r (DIR *__dirp, struct dirent *__entry, diff --git a/sysdeps/unix/sysv/linux/readdir.c b/sysdeps/unix/sysv/linux/readdir.c index 2e03e66e69..ca2a8964e9 100644 --- a/sysdeps/unix/sysv/linux/readdir.c +++ b/sysdeps/unix/sysv/linux/readdir.c @@ -23,15 +23,11 @@ /* Read a directory entry from DIRP. */ struct dirent * -__readdir (DIR *dirp) +__readdir_unlocked (DIR *dirp) { struct dirent *dp; int saved_errno = errno; -#if IS_IN (libc) - __libc_lock_lock (dirp->lock); -#endif - do { size_t reclen; @@ -75,6 +71,18 @@ __readdir (DIR *dirp) /* Skip deleted files. */ } while (dp->d_ino == 0); + return dp; +} + +struct dirent * +__readdir (DIR *dirp) +{ + struct dirent *dp; + +#if IS_IN (libc) + __libc_lock_lock (dirp->lock); +#endif + dp = __readdir_unlocked (dirp); #if IS_IN (libc) __libc_lock_unlock (dirp->lock); #endif diff --git a/sysdeps/unix/sysv/linux/readdir_r.c b/sysdeps/unix/sysv/linux/readdir_r.c index 0069041394..a01d2845a6 100644 --- a/sysdeps/unix/sysv/linux/readdir_r.c +++ b/sysdeps/unix/sysv/linux/readdir_r.c @@ -25,89 +25,44 @@ __readdir_r (DIR *dirp, struct dirent *entry, struct dirent **result) { struct dirent *dp; size_t reclen; - const int saved_errno = errno; - int ret; __libc_lock_lock (dirp->lock); - do + while (1) { - if (dirp->offset >= dirp->size) - { - /* We've emptied out our buffer. Refill it. */ - - size_t maxread = dirp->allocation; - ssize_t bytes; - - maxread = dirp->allocation; - - bytes = __getdents (dirp->fd, dirp->data, maxread); - if (bytes <= 0) - { - /* On some systems getdents fails with ENOENT when the - open directory has been rmdir'd already. POSIX.1 - requires that we treat this condition like normal EOF. */ - if (bytes < 0 && errno == ENOENT) - { - bytes = 0; - __set_errno (saved_errno); - } - if (bytes < 0) - dirp->errcode = errno; - - dp = NULL; - break; - } - dirp->size = (size_t) bytes; - - /* Reset the offset into the buffer. */ - dirp->offset = 0; - } - - dp = (struct dirent *) &dirp->data[dirp->offset]; + dp = __readdir_unlocked (dirp); + if (dp == NULL) + break; reclen = dp->d_reclen; + if (reclen <= offsetof (struct dirent, d_name) + NAME_MAX + 1) + break; - dirp->offset += reclen; - - dirp->filepos = dp->d_off; - - if (reclen > offsetof (struct dirent, d_name) + NAME_MAX + 1) + /* The record is very long. It could still fit into the caller-supplied + buffer if we can skip padding at the end. */ + size_t namelen = _D_EXACT_NAMLEN (dp); + if (namelen <= NAME_MAX) { - /* The record is very long. It could still fit into the - caller-supplied buffer if we can skip padding at the - end. */ - size_t namelen = _D_EXACT_NAMLEN (dp); - if (namelen <= NAME_MAX) - reclen = offsetof (struct dirent, d_name) + namelen + 1; - else - { - /* The name is too long. Ignore this file. */ - dirp->errcode = ENAMETOOLONG; - dp->d_ino = 0; - continue; - } + reclen = offsetof (struct dirent, d_name) + namelen + 1; + break; } - /* Skip deleted and ignored files. */ + /* The name is too long. Ignore this file. */ + dirp->errcode = ENAMETOOLONG; + dp->d_ino = 0; } - while (dp->d_ino == 0); if (dp != NULL) { *result = memcpy (entry, dp, reclen); entry->d_reclen = reclen; - ret = 0; } else - { - *result = NULL; - ret = dirp->errcode; - } + *result = NULL; __libc_lock_unlock (dirp->lock); - return ret; + return dp != NULL ? 0 : dirp->errcode; } weak_alias (__readdir_r, readdir_r) From patchwork Fri Apr 17 13:22:03 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 38823 Return-Path: X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qt1-x843.google.com (mail-qt1-x843.google.com [IPv6:2607:f8b0:4864:20::843]) by sourceware.org (Postfix) with ESMTPS id 7E5CE385DC0B for ; Fri, 17 Apr 2020 13:22:19 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 7E5CE385DC0B Received: by mail-qt1-x843.google.com with SMTP id 71so1815677qtc.12 for ; Fri, 17 Apr 2020 06:22:19 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=PaVnCyQRIeb6GRBpshB3U/qkN5F+pOCW+UfkrwievVA=; b=OpALXjkGq6fsuxwiGhqCodneG7wPAR0umvjNIyR30kTT+A583Ucoo3b1RH/MIuxtWA eSBtqjEECi+SSGnmmSdzJebAdQOdEJ5/7MGVTIFpp5TRZZr5EUbHNi6WhAfBlxSqJSnY Pkb93btzRxWTHtV+KfNhVFRWQF0LBzQ+tZKaxqg0KwQDOUhRfdwEj2hH/2cRLY878qx3 KAFnZbDFBCq5EjFjQafBcpdT+e+LD8c0rthNLwyiIH3fAnZkU/AT5S6JgBf00uLzEQdM 3ByQPDDsBX5RnP9wilwyb6WHmBjcUaln/qIN56g8bk/xeV+cEPCDwkM7xsbIY3hHXTM6 KGTQ== X-Gm-Message-State: AGi0Puaah9Z4VMyPMowZ2mq3GGzs4IhenQ1mHviY4ap2SGsTBrh8NvGk faH+FYldzbe2eIYQ1nPynob13Fh1SifE4A== X-Google-Smtp-Source: APiQypJTjNZa2fNXUeLPW1028jxdQgntaBmvM5pEtwMBW/ICQbDZ3zBz41UvBQgv6lQ13i6Yz3kL6A== X-Received: by 2002:aed:3a86:: with SMTP id o6mr2926171qte.262.1587129738928; Fri, 17 Apr 2020 06:22:18 -0700 (PDT) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id s14sm14737571qts.70.2020.04.17.06.22.17 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Apr 2020 06:22:18 -0700 (PDT) From: Adhemerval Zanella To: libc-alpha@sourceware.org Subject: [PATCH 04/10] linux: Use internal DIR locks when accessing filepos on telldir Date: Fri, 17 Apr 2020 10:22:03 -0300 Message-Id: <20200417132209.22065-4-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200417132209.22065-1-adhemerval.zanella@linaro.org> References: <20200417132209.22065-1-adhemerval.zanella@linaro.org> X-Spam-Status: No, score=-25.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 17 Apr 2020 13:22:20 -0000 Since it might change during a readdir call. Checked on x86_64-linux-gnu and i686-linux-gnu. --- sysdeps/unix/sysv/linux/telldir.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sysdeps/unix/sysv/linux/telldir.c b/sysdeps/unix/sysv/linux/telldir.c index 1bb822c807..57d435ed21 100644 --- a/sysdeps/unix/sysv/linux/telldir.c +++ b/sysdeps/unix/sysv/linux/telldir.c @@ -23,5 +23,11 @@ long int telldir (DIR *dirp) { - return dirp->filepos; + long int ret; + + __libc_lock_lock (dirp->lock); + ret = dirp->filepos; + __libc_lock_unlock (dirp->lock); + + return ret; } From patchwork Fri Apr 17 13:22:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 38824 Return-Path: X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qt1-x842.google.com (mail-qt1-x842.google.com [IPv6:2607:f8b0:4864:20::842]) by sourceware.org (Postfix) with ESMTPS id 363D2385DC16 for ; Fri, 17 Apr 2020 13:22:21 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 363D2385DC16 Received: by mail-qt1-x842.google.com with SMTP id l60so1845098qtd.8 for ; Fri, 17 Apr 2020 06:22:21 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=wEELnn+C4utXGvlY7MMI+bZJY3oeY7BQhl7qTqpSejI=; b=T/XQ4vmkC1mANjIAkgOXJuMTj/xgDEOfGOlJHDQ8wOb/t6jRPeZEKwAg5mlbP/VZT/ zNO2aycB9bQUY9t7ZsRHFTwH9+NTFZdwTU8RS5h9gscBlkORcrgDUj+XXrYwB/7GgH76 dFbKVW8Pqg1TfXrdudlu6DW/eIQc7QttGOczRFTkynxJfAHlZxU+iiR4n6EASx0+txbD nJ1drxpa/ziOHy0tJ3ncGvB18XpUaIQDm/MiskQlcx21LMnrOgi4qfPKMprl4+qVj8sP tsfn5f96UJfPAp5WNpySSW5D1zJfK/sHXfdQQvmKaQWyruBVujDWKJ5kU/WfvLoA+0er onFQ== X-Gm-Message-State: AGi0PuackhfYQRV1lY4wrolbVp0gVaLadoBHDrZNtiviFbCHPmzbJ3yj g/D7PcPZwZIDwhom/Rl/bQtmhKUNhVcgUQ== X-Google-Smtp-Source: APiQypLxjPwQYPvUCjuq1xpWXToUID4HwGNKllIBhE6CHI2X1jBxGBGigSlp8GLW/balr0aRd5zmFQ== X-Received: by 2002:ac8:359d:: with SMTP id k29mr3034924qtb.106.1587129740227; Fri, 17 Apr 2020 06:22:20 -0700 (PDT) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id s14sm14737571qts.70.2020.04.17.06.22.19 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Apr 2020 06:22:19 -0700 (PDT) From: Adhemerval Zanella To: libc-alpha@sourceware.org Subject: [PATCH 05/10] linux: Use getdents64 on non-LFS readdir Date: Fri, 17 Apr 2020 10:22:04 -0300 Message-Id: <20200417132209.22065-5-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200417132209.22065-1-adhemerval.zanella@linaro.org> References: <20200417132209.22065-1-adhemerval.zanella@linaro.org> X-Spam-Status: No, score=-25.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 17 Apr 2020 13:22:22 -0000 It reserves some space on the allocated internal buffer to be used as a the returned dirent struct. The kernel obtained dirent64 struct are copied to the temporary buffer on each readdir call. The overflow test is moved once the dirent64 entry is copied to the temporary buffer, and a subsequent readdir will obtain the next entry. The idea is an overflow fails to return the entry on readdir, but a next readdir might still obtain the next entry. (for filesystem that does not have the concept of sequential d_off, such as ext4). Checked on x86_64-linux-gnu and i686-linux-gnu. --- sysdeps/unix/sysv/linux/opendir.c | 6 +- sysdeps/unix/sysv/linux/readdir.c | 25 +++---- sysdeps/unix/sysv/linux/readdir.h | 117 ++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+), 17 deletions(-) create mode 100644 sysdeps/unix/sysv/linux/readdir.h diff --git a/sysdeps/unix/sysv/linux/opendir.c b/sysdeps/unix/sysv/linux/opendir.c index 765c8104b3..d4a0885bd3 100644 --- a/sysdeps/unix/sysv/linux/opendir.c +++ b/sysdeps/unix/sysv/linux/opendir.c @@ -22,6 +22,7 @@ #include /* For MIN and MAX. */ #include +#include /* For return_buffer_size. */ enum { opendir_oflags = O_RDONLY|O_NDELAY|O_DIRECTORY|O_LARGEFILE|O_CLOEXEC @@ -103,8 +104,9 @@ __alloc_dir (int fd, bool close_fd, int flags, const struct stat64 *statp) enum { max_buffer_size = 1U << 20 }; const size_t allocation_size = 4 * BUFSIZ; - _Static_assert (allocation_size >= sizeof (struct dirent64), - "allocation_size < sizeof (struct dirent64)"); + _Static_assert (allocation_size >= sizeof (struct dirent64) + + return_buffer_size, + "opendir buffer size smaller than required"); /* Increase allocation if requested, but not if the value appears to be bogus. It will be between 32Kb (for blocksizes smaller than BUFSIZ) diff --git a/sysdeps/unix/sysv/linux/readdir.c b/sysdeps/unix/sysv/linux/readdir.c index ca2a8964e9..8eab0f4c9b 100644 --- a/sysdeps/unix/sysv/linux/readdir.c +++ b/sysdeps/unix/sysv/linux/readdir.c @@ -19,7 +19,7 @@ #include #if !_DIRENT_MATCHES_DIRENT64 -#include +#include /* Read a directory entry from DIRP. */ struct dirent * @@ -30,16 +30,12 @@ __readdir_unlocked (DIR *dirp) do { - size_t reclen; - if (dirp->offset >= dirp->size) { /* We've emptied out our buffer. Refill it. */ - size_t maxread = dirp->allocation; - ssize_t bytes; - - bytes = __getdents (dirp->fd, dirp->data, maxread); + ssize_t bytes = __getdents64 (dirp->fd, dirstream_data (dirp), + dirstream_alloc_size (dirp)); if (bytes <= 0) { /* On some systems getdents fails with ENOENT when the @@ -54,19 +50,18 @@ __readdir_unlocked (DIR *dirp) dp = NULL; break; } - dirp->size = (size_t) bytes; + dirp->size = bytes; /* Reset the offset into the buffer. */ dirp->offset = 0; } - dp = (struct dirent *) &dirp->data[dirp->offset]; - - reclen = dp->d_reclen; - - dirp->offset += reclen; - - dirp->filepos = dp->d_off; + dp = dirstream_ret_entry (dirp); + if (dp == NULL) + { + __set_errno (EOVERFLOW); + break; + } /* Skip deleted files. */ } while (dp->d_ino == 0); diff --git a/sysdeps/unix/sysv/linux/readdir.h b/sysdeps/unix/sysv/linux/readdir.h new file mode 100644 index 0000000000..4dc219e220 --- /dev/null +++ b/sysdeps/unix/sysv/linux/readdir.h @@ -0,0 +1,117 @@ +/* Linux readdir internal implementation details. + Copyright (C) 2020 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 _DIRSTREAM_NOLFS_H +#define _DIRSTREAM_NOLFS_H + +#if !_DIRENT_MATCHES_DIRENT64 +# include + +/* getdents64 is used internally for both LFS and non-LFS implementations. + The non-LFS interface reserves part of the allocated buffer to return the + non-LFS 'struct dirent' entry. */ + +/* This defines the reserved space size on DIR internal buffer to use as the + returned 'struct dirent' from a 'readdir' call. + + The largest possible practical length of the d_name member are 255 + Unicode characters in UTF-8 encoding, so d_name is 766 bytes long, plus + 10 bytes from header, for a total of 776 bytes total. + + Also it should take in cosideration the alignment requirement for + getdents64 call. */ +enum { return_buffer_size = 1024 + + sizeof (off64_t) + - _Alignof (((struct __dirstream) {0}).data) }; + +_Static_assert ((_Alignof (((struct __dirstream) {0}).data) + + return_buffer_size) % sizeof (off64_t) == 0, + "return_buffer_size does not align the buffer properly"); + +/* Return the avaliable buffer size to use with getdents64 calls. */ +static inline size_t +dirstream_alloc_size (struct __dirstream *ds) +{ + return ds->allocation - return_buffer_size; +} + +/* Return the start of the allocated buffer minus the reserved part to use on + non-LFS readdir call. */ +static inline void * +dirstream_data (struct __dirstream *ds) +{ + return (char *) ds->data + return_buffer_size; +} + +/* Return the allocated buffer used on non-LFS readdir call. */ +static inline struct dirent * +dirstream_ret (struct __dirstream *ds) +{ + return (struct dirent *) ds->data; +} + +/* Return the current dirent64 entry from the reserved buffer used on + getdent64. */ +static inline struct dirent64 * +dirstream_entry (struct __dirstream *ds) +{ + size_t offset = return_buffer_size + ds->offset; + return (struct dirent64 *) ((char *) ds->data + offset); +} + +/* Copy one obtained entry from 'getdents64' call to the reserved space + on DS allocated buffer and updated its internal state. */ +static inline struct dirent * +dirstream_ret_entry (struct __dirstream *ds) +{ + struct dirent64 *dp64 = dirstream_entry (ds); + struct dirent *dp = dirstream_ret (ds); + + dp->d_ino = dp64->d_ino; + + dp->d_off = dp64->d_off; + if (dp->d_off != dp64->d_off) + /* Overflow. */ + return NULL; + + const size_t size_diff = (offsetof (struct dirent64, d_name) + - offsetof (struct dirent, d_name)); + const size_t alignment = _Alignof (struct dirent); + size_t new_reclen = (dp64->d_reclen - size_diff + alignment - 1) + & ~(alignment - 1); + if (new_reclen > return_buffer_size) + /* Overflow. */ + return NULL; + dp->d_reclen = new_reclen; + + dp->d_type = dp64->d_type; + + memcpy (dp->d_name, dp64->d_name, + dp64->d_reclen - offsetof (struct dirent64, d_name)); + + ds->offset += dp64->d_reclen; + ds->filepos = dp64->d_off; + + return dp; +} +#else +/* No need to reserve an buffer space if dirent has already LFS support. */ +enum { return_buffer_size = 0 }; +#endif /* _DIRENT_MATCHES_DIRENT64 */ + +#endif From patchwork Fri Apr 17 13:22:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 38825 Return-Path: X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qk1-x744.google.com (mail-qk1-x744.google.com [IPv6:2607:f8b0:4864:20::744]) by sourceware.org (Postfix) with ESMTPS id 4F7EC385DC16 for ; Fri, 17 Apr 2020 13:22:23 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 4F7EC385DC16 Received: by mail-qk1-x744.google.com with SMTP id l25so2313995qkk.3 for ; Fri, 17 Apr 2020 06:22:23 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=CM8KKWsJBqzn80AZKoT87dRNu3uNWYEFnYCTIzV5sw0=; b=R9QZDZGjEoaF273mPiraUN100vYB9kBs5QqF077ryDjoSt6ANZf8erCrKvlD0VoyG3 OQwCuOoiJnfgmaCcXR8tCwPnpOYIoibGoH1N2uMzb6mMZNZM5yfUREwuI+IdgwK/zAVl 4M2sNLEFXytmH77tRNc3gDgtCpYah6F3vp/jNSSFJhKFX2xnT8vnoZUahHOpJ4GALwwr OVJ4hYjiqsEhLtPHbYLnPKxeBTK1c8vGZPAJcm8zd+QTNlze0eYiuCpvdF3mxd8cipK9 jx/gA5Md89ik3Yyl97m6+nelbL+jrxqxGSc6uHF4ErgrQRkDh5zsY1PUp4uirb8qK8uw 3BLA== X-Gm-Message-State: AGi0PuaX5PsJ2mQcOxt+E3mEO3hBDWf/eRGcDVq80qRiJDEtLTGKMuiI h5yea/s2yEat4GMfuCd0WexXrytwvdUf0g== X-Google-Smtp-Source: APiQypIwUPkdBlsjA39p8UskyilrT/7a38+kvkUxaQk+lmBSD1HO9bginbp+lVfNAqAI4DopaVfcdg== X-Received: by 2002:a37:5d02:: with SMTP id r2mr3130016qkb.57.1587129741969; Fri, 17 Apr 2020 06:22:21 -0700 (PDT) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id s14sm14737571qts.70.2020.04.17.06.22.20 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Apr 2020 06:22:21 -0700 (PDT) From: Adhemerval Zanella To: libc-alpha@sourceware.org Subject: [PATCH 06/10] linux: Set internal DIR filepos as off64_t [BZ #23960, BZ #24050] Date: Fri, 17 Apr 2020 10:22:05 -0300 Message-Id: <20200417132209.22065-6-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200417132209.22065-1-adhemerval.zanella@linaro.org> References: <20200417132209.22065-1-adhemerval.zanella@linaro.org> X-Spam-Status: No, score=-25.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 17 Apr 2020 13:22:25 -0000 It allows to obtain the expected entry offset on telldir and set it correctly on seekdir on platforms where long int is smaller than off64_t. On such cases telldir will mantain an internal list that maps the DIR object off64_t offsets to the returned long int (the function return value). The seekdir will then set the correct offset from the internal list using the telldir as the list key. It also removes the overflow check on readdir and the returned value will be truncated by the non-LFS off_t size. As Joseph has noted in BZ #23960 comment #22, d_off is an opaque value and since telldir/seekdir works regardless of the returned dirent d_off value. Finally it removed the requirement to check for overflow values on telldir (BZ #24050). Checked on x86_64-linux-gnu, i686-linux-gnu, powerpc-linux-gnu, and arm-linux-gnueabihf. --- dirent/Makefile | 2 +- dirent/tst-seekdir2.c | 156 ++++++++++++++++++++++++++++ support/temp_file.c | 12 ++- support/temp_file.h | 7 ++ sysdeps/unix/sysv/linux/closedir.c | 4 + sysdeps/unix/sysv/linux/dirstream.h | 7 +- sysdeps/unix/sysv/linux/opendir.c | 3 + sysdeps/unix/sysv/linux/readdir.c | 1 + sysdeps/unix/sysv/linux/readdir.h | 7 +- sysdeps/unix/sysv/linux/rewinddir.c | 5 + sysdeps/unix/sysv/linux/seekdir.c | 36 ++++++- sysdeps/unix/sysv/linux/telldir.c | 47 ++++++++- sysdeps/unix/sysv/linux/telldir.h | 64 ++++++++++++ 13 files changed, 333 insertions(+), 18 deletions(-) create mode 100644 dirent/tst-seekdir2.c create mode 100644 sysdeps/unix/sysv/linux/telldir.h diff --git a/dirent/Makefile b/dirent/Makefile index e917d5ceab..f100431845 100644 --- a/dirent/Makefile +++ b/dirent/Makefile @@ -31,7 +31,7 @@ routines := opendir closedir readdir readdir_r rewinddir \ scandir-cancel scandir-tail scandir64-tail tests := list tst-seekdir opendir-tst1 bug-readdir1 tst-fdopendir \ - tst-fdopendir2 tst-scandir tst-scandir64 + tst-fdopendir2 tst-scandir tst-scandir64 tst-seekdir2 \ CFLAGS-scandir.c += $(uses-callbacks) CFLAGS-scandir64.c += $(uses-callbacks) diff --git a/dirent/tst-seekdir2.c b/dirent/tst-seekdir2.c new file mode 100644 index 0000000000..4bd2509f72 --- /dev/null +++ b/dirent/tst-seekdir2.c @@ -0,0 +1,156 @@ +/* Check multiple telldir and seekdir. + Copyright (C) 2020 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 + +/* Some filesystems returns a arbitrary value for d_off direnty entry (ext4 + for instance, where the value is an internal hash key). The idea of + create a large number of file is to try trigger a overflow d_off value + in a entry to check if telldir/seekdir does work corretly in such + case. */ +static const char *dirname; +static const size_t nfiles = 10240; + +static void +do_prepare (int argc, char *argv[]) +{ + dirname = support_create_temp_directory ("tst-seekdir2-"); + + for (size_t i = 0; i < nfiles; i++) + { + int fd = create_temp_file_in_dir ("tempfile.", dirname, NULL); + TEST_VERIFY_EXIT (fd > 0); + close (fd); + } +} +#define PREPARE do_prepare + +/* Check for old non Large File Support (LFS). */ +static int +do_test_not_lfs (void) +{ + DIR *dirp; + struct dirent *dp; + size_t dirp_count; + + dirp = opendir (dirname); + TEST_VERIFY_EXIT (dirp != NULL); + + dirp_count = 0; + for (dp = readdir (dirp); + dp != NULL; + dp = readdir (dirp)) + dirp_count++; + + /* The 2 extra files are '.' and '..'. */ + TEST_COMPARE (dirp_count, nfiles + 2); + + rewinddir (dirp); + + long *tdirp = xmalloc (dirp_count * sizeof (long)); + struct dirent *ddirp = xmalloc (dirp_count * sizeof (struct dirent)); + + size_t i = 0; + do + { + tdirp[i] = telldir (dirp); + dp = readdir (dirp); + TEST_VERIFY_EXIT (dp != NULL); + memcpy (&ddirp[i], dp, sizeof (struct dirent)); + } while (++i < dirp_count); + + for (i = 0; i < dirp_count - 1; i++) + { + seekdir (dirp, tdirp[i]); + dp = readdir (dirp); + TEST_COMPARE (strcmp (dp->d_name, ddirp[i].d_name), 0); + TEST_COMPARE (dp->d_ino, ddirp[i].d_ino); + TEST_COMPARE (dp->d_off, ddirp[i].d_off); + } + + closedir (dirp); + + return 0; +} + +/* Same as before but with LFS support. */ +static int +do_test_lfs (void) +{ + DIR *dirp; + struct dirent64 *dp; + size_t dirp_count; + + dirp = opendir (dirname); + TEST_VERIFY_EXIT (dirp != NULL); + + dirp_count = 0; + for (dp = readdir64 (dirp); + dp != NULL; + dp = readdir64 (dirp)) + dirp_count++; + + /* The 2 extra files are '.' and '..'. */ + TEST_COMPARE (dirp_count, nfiles + 2); + + rewinddir (dirp); + + long *tdirp = xmalloc (dirp_count * sizeof (long)); + struct dirent64 *ddirp = xmalloc (dirp_count * sizeof (struct dirent64)); + + size_t i = 0; + do + { + tdirp[i] = telldir (dirp); + dp = readdir64 (dirp); + TEST_VERIFY_EXIT (dp != NULL); + memcpy (&ddirp[i], dp, sizeof (struct dirent64)); + } while (++i < dirp_count); + + for (i = 0; i < dirp_count - 1; i++) + { + seekdir (dirp, tdirp[i]); + dp = readdir64 (dirp); + TEST_COMPARE (strcmp (dp->d_name, ddirp[i].d_name), 0); + TEST_COMPARE (dp->d_ino, ddirp[i].d_ino); + TEST_COMPARE (dp->d_off, ddirp[i].d_off); + } + + closedir (dirp); + + return 0; +} + +static int +do_test (void) +{ + do_test_not_lfs (); + do_test_lfs (); + + return 0; +} + +#include diff --git a/support/temp_file.c b/support/temp_file.c index 277c5e0cf1..98bd235526 100644 --- a/support/temp_file.c +++ b/support/temp_file.c @@ -60,14 +60,12 @@ add_temp_file (const char *name) } int -create_temp_file (const char *base, char **filename) +create_temp_file_in_dir (const char *base, const char *dir, char **filename) { char *fname; int fd; - fname = (char *) xmalloc (strlen (test_dir) + 1 + strlen (base) - + sizeof ("XXXXXX")); - strcpy (stpcpy (stpcpy (stpcpy (fname, test_dir), "/"), base), "XXXXXX"); + fname = xasprintf ("%s/%sXXXXXX", dir, base); fd = mkstemp (fname); if (fd == -1) @@ -86,6 +84,12 @@ create_temp_file (const char *base, char **filename) return fd; } +int +create_temp_file (const char *base, char **filename) +{ + return create_temp_file_in_dir (base, test_dir, filename); +} + char * support_create_temp_directory (const char *base) { diff --git a/support/temp_file.h b/support/temp_file.h index 8b6303a6e4..ac61105428 100644 --- a/support/temp_file.h +++ b/support/temp_file.h @@ -32,6 +32,13 @@ void add_temp_file (const char *name); *FILENAME. */ int create_temp_file (const char *base, char **filename); +/* Create a temporary file in directory DIR. Return the opened file + descriptor on success, or -1 on failure. Write the file name to + *FILENAME if FILENAME is not NULL. In this case, the caller is + expected to free *FILENAME. */ +int create_temp_file_in_dir (const char *base, const char *dir, + char **filename); + /* Create a temporary directory and schedule it for deletion. BASE is used as a prefix for the unique directory name, which the function returns. The caller should free this string. */ diff --git a/sysdeps/unix/sysv/linux/closedir.c b/sysdeps/unix/sysv/linux/closedir.c index ccc19eefcd..c39f58aba5 100644 --- a/sysdeps/unix/sysv/linux/closedir.c +++ b/sysdeps/unix/sysv/linux/closedir.c @@ -43,6 +43,10 @@ __closedir (DIR *dirp) fd = dirp->fd; +#ifndef __LP64__ + dirstream_loc_clear (&dirp->locs); +#endif + #if IS_IN (libc) __libc_lock_fini (dirp->lock); #endif diff --git a/sysdeps/unix/sysv/linux/dirstream.h b/sysdeps/unix/sysv/linux/dirstream.h index a3ea2b7197..664d73cd40 100644 --- a/sysdeps/unix/sysv/linux/dirstream.h +++ b/sysdeps/unix/sysv/linux/dirstream.h @@ -21,6 +21,7 @@ #include #include +#include /* Directory stream type. @@ -37,10 +38,14 @@ struct __dirstream size_t size; /* Total valid data in the block. */ size_t offset; /* Current offset into the block. */ - off_t filepos; /* Position of next entry to read. */ + off64_t filepos; /* Position of next entry to read. */ int errcode; /* Delayed error code. */ +#ifndef __LP64__ + struct dirstream_loc_t locs; +#endif + /* Directory block. We must make sure that this block starts at an address that is aligned adequately enough to store dirent entries. Using the alignment of "void *" is not diff --git a/sysdeps/unix/sysv/linux/opendir.c b/sysdeps/unix/sysv/linux/opendir.c index d4a0885bd3..a987af0e89 100644 --- a/sysdeps/unix/sysv/linux/opendir.c +++ b/sysdeps/unix/sysv/linux/opendir.c @@ -131,6 +131,9 @@ __alloc_dir (int fd, bool close_fd, int flags, const struct stat64 *statp) dirp->offset = 0; dirp->filepos = 0; dirp->errcode = 0; +#ifndef __LP64__ + dirstream_loc_init (&dirp->locs); +#endif return dirp; } diff --git a/sysdeps/unix/sysv/linux/readdir.c b/sysdeps/unix/sysv/linux/readdir.c index 8eab0f4c9b..010ccf0a00 100644 --- a/sysdeps/unix/sysv/linux/readdir.c +++ b/sysdeps/unix/sysv/linux/readdir.c @@ -17,6 +17,7 @@ . */ #include +#include #if !_DIRENT_MATCHES_DIRENT64 #include diff --git a/sysdeps/unix/sysv/linux/readdir.h b/sysdeps/unix/sysv/linux/readdir.h index 4dc219e220..7f6cf3783d 100644 --- a/sysdeps/unix/sysv/linux/readdir.h +++ b/sysdeps/unix/sysv/linux/readdir.h @@ -85,15 +85,12 @@ dirstream_ret_entry (struct __dirstream *ds) dp->d_ino = dp64->d_ino; dp->d_off = dp64->d_off; - if (dp->d_off != dp64->d_off) - /* Overflow. */ - return NULL; const size_t size_diff = (offsetof (struct dirent64, d_name) - offsetof (struct dirent, d_name)); const size_t alignment = _Alignof (struct dirent); - size_t new_reclen = (dp64->d_reclen - size_diff + alignment - 1) - & ~(alignment - 1); + size_t new_reclen = (dp64->d_reclen - size_diff + alignment - 1) + & ~(alignment - 1); if (new_reclen > return_buffer_size) /* Overflow. */ return NULL; diff --git a/sysdeps/unix/sysv/linux/rewinddir.c b/sysdeps/unix/sysv/linux/rewinddir.c index 860bfda004..8db0d0be4a 100644 --- a/sysdeps/unix/sysv/linux/rewinddir.c +++ b/sysdeps/unix/sysv/linux/rewinddir.c @@ -33,6 +33,11 @@ __rewinddir (DIR *dirp) dirp->offset = 0; dirp->size = 0; dirp->errcode = 0; + +#ifndef __LP64__ + dirstream_loc_clear (&dirp->locs); +#endif + #if IS_IN (libc) __libc_lock_unlock (dirp->lock); #endif diff --git a/sysdeps/unix/sysv/linux/seekdir.c b/sysdeps/unix/sysv/linux/seekdir.c index 3c30520928..5f39ef9eef 100644 --- a/sysdeps/unix/sysv/linux/seekdir.c +++ b/sysdeps/unix/sysv/linux/seekdir.c @@ -22,14 +22,40 @@ #include /* Seek to position POS in DIRP. */ -/* XXX should be __seekdir ? */ void seekdir (DIR *dirp, long int pos) { + off64_t filepos; + __libc_lock_lock (dirp->lock); - (void) __lseek (dirp->fd, pos, SEEK_SET); - dirp->size = 0; - dirp->offset = 0; - dirp->filepos = pos; + +#ifndef __LP64__ + union dirstream_packed dsp; + + dsp.l = pos; + + if (dsp.p.is_packed == 1) + filepos = dsp.p.info; + else + { + size_t index = dsp.p.info; + + if (index >= dirstream_loc_size (&dirp->locs)) + return; + struct dirstream_loc *loc = dirstream_loc_at (&dirp->locs, index); + filepos = loc->filepos; + } +#else + filepos = pos; +#endif + + if (dirp->filepos != filepos) + { + __lseek64 (dirp->fd, filepos, SEEK_SET); + dirp->filepos = filepos; + dirp->offset = 0; + dirp->size = 0; + } + __libc_lock_unlock (dirp->lock); } diff --git a/sysdeps/unix/sysv/linux/telldir.c b/sysdeps/unix/sysv/linux/telldir.c index 57d435ed21..bb33626fa4 100644 --- a/sysdeps/unix/sysv/linux/telldir.c +++ b/sysdeps/unix/sysv/linux/telldir.c @@ -18,16 +18,59 @@ #include #include +#include /* Return the current position of DIRP. */ long int telldir (DIR *dirp) { - long int ret; +#ifndef __LP64__ + /* If the directory position fits in the packet structure returns it. + Otherwise, check if the position is already been recorded in the + dynamic array. If not, add the new record. */ + + union dirstream_packed dsp; + size_t i; __libc_lock_lock (dirp->lock); - ret = dirp->filepos; + + if (dirp->filepos < (1U << 31)) + { + dsp.p.is_packed = 1; + dsp.p.info = dirp->filepos; + goto out; + } + + dsp.l = -1; + + for (i = 0; i < dirstream_loc_size (&dirp->locs); i++) + { + struct dirstream_loc *loc = dirstream_loc_at (&dirp->locs, i); + if (loc->filepos == dirp->filepos) + break; + } + if (i == dirstream_loc_size (&dirp->locs)) + { + dirstream_loc_add (&dirp->locs, + (struct dirstream_loc) { dirp->filepos }); + if (dirstream_loc_has_failed (&dirp->locs)) + goto out; + } + + dsp.p.is_packed = 0; + /* This assignment might overflow, however most likely ENOMEM would happen + long before. */ + dsp.p.info = i; + +out: __libc_lock_unlock (dirp->lock); + return dsp.l; +#else + long int ret; + __libc_lock_lock (dirp->lock); + ret = dirp->filepos; + __libc_lock_unlock (dirp->lock); return ret; +#endif } diff --git a/sysdeps/unix/sysv/linux/telldir.h b/sysdeps/unix/sysv/linux/telldir.h new file mode 100644 index 0000000000..7c45886341 --- /dev/null +++ b/sysdeps/unix/sysv/linux/telldir.h @@ -0,0 +1,64 @@ +/* Linux internal telldir definitions. + Copyright (C) 2020 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 _TELLDIR_H +#define _TELLDIR_H 1 + +#ifndef __LP64__ + +/* On platforms where long int is smaller than off64_t this is how the + returned value is encoded and returned by 'telldir'. If the directory + offset can be enconded in 31 bits it is returned in the 'info' member + with 'is_packed' set to 1. + + Otherwise, the 'info' member describes an index in a dynamic array at + 'DIR' structure. */ + +union dirstream_packed +{ + long int l; + struct + { + unsigned long is_packed:1; + unsigned long info:31; + } p; +}; + +_Static_assert (sizeof (long int) == sizeof (union dirstream_packed), + "sizeof (long int) != sizeof (union dirstream_packed)"); + +/* telldir will mantain a list of offsets that describe the obtained diretory + position if it can fit this information in the returned 'dirstream_packed' + struct. */ + +struct dirstream_loc +{ + off64_t filepos; +}; + +# define DYNARRAY_STRUCT dirstream_loc_t +# define DYNARRAY_ELEMENT struct dirstream_loc +# define DYNARRAY_PREFIX dirstream_loc_ +# include +#else + +_Static_assert (sizeof (long int) == sizeof (off64_t), + "sizeof (long int) != sizeof (off64_t)"); +#endif /* __LP64__ */ + +#endif /* _TELLDIR_H */ From patchwork Fri Apr 17 13:22:06 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 38826 Return-Path: X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qk1-x743.google.com (mail-qk1-x743.google.com [IPv6:2607:f8b0:4864:20::743]) by sourceware.org (Postfix) with ESMTPS id 5CB6A384BC03 for ; Fri, 17 Apr 2020 13:22:24 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 5CB6A384BC03 Received: by mail-qk1-x743.google.com with SMTP id v7so2335509qkc.0 for ; Fri, 17 Apr 2020 06:22:24 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=s+xn5WhiO2IG567uXR21knVQL3vR44VceeoWFZb3u+k=; b=ATuyCgrMxJjD5rqIWBFh2BMBOHrCBIqVqfR1/ARfpV8fVZSEpMDIHuCVMe7kH0BqNE t0w8rL7rL/djPmYl7fqu048a2w0Nle11mYEvdO06As7rls7RpYEd7o+ABT1ckjxvPtXQ NgBDGHIKtqvebgyfCW/zJi8ZTBugE644ywnlZYpc6F8oO4UyOj0cK43t119ui0dF7i4Y IueKmDnydagcFKwHhofMuTemtKnt6K8inBzcBxHE7eAWQOF+HwReCy/ajR8Vd6vzd3Bn kSkgPHtOEKJU25PzCS8Fl0b0duAMH1vkvICGX5ONOxP1EUe6cXaZ7htNlspVJnd0raoe S2jQ== X-Gm-Message-State: AGi0PuZabnyBSfq0Hj5fwLUgjm/AHLad38q6PTZQcVYdudHp39D860Cf VcoBLV1ymAeozl/OZ5b3We6nyT6IaHRQ5A== X-Google-Smtp-Source: APiQypLkKNb2dXT3rponJKyYsS5si8C6PC0S21+DyjKPe7lH9Bn7jMZoQZgXr8kiUF2bMzZIQ5ySPg== X-Received: by 2002:a37:a841:: with SMTP id r62mr1471530qke.426.1587129743557; Fri, 17 Apr 2020 06:22:23 -0700 (PDT) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id s14sm14737571qts.70.2020.04.17.06.22.22 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Apr 2020 06:22:22 -0700 (PDT) From: Adhemerval Zanella To: libc-alpha@sourceware.org Subject: [PATCH 07/10] linux: Add __readdir64_unlocked Date: Fri, 17 Apr 2020 10:22:06 -0300 Message-Id: <20200417132209.22065-7-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200417132209.22065-1-adhemerval.zanella@linaro.org> References: <20200417132209.22065-1-adhemerval.zanella@linaro.org> X-Spam-Status: No, score=-25.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 17 Apr 2020 13:22:25 -0000 And use it on readdir_r implementation. Checked on i686-linux-gnu. --- include/dirent.h | 1 + sysdeps/unix/sysv/linux/readdir64.c | 20 +++++-- sysdeps/unix/sysv/linux/readdir64_r.c | 80 ++++++--------------------- 3 files changed, 33 insertions(+), 68 deletions(-) diff --git a/include/dirent.h b/include/dirent.h index 8325a19e5f..79c8fce969 100644 --- a/include/dirent.h +++ b/include/dirent.h @@ -21,6 +21,7 @@ extern DIR *__fdopendir (int __fd) attribute_hidden; extern int __closedir (DIR *__dirp) attribute_hidden; extern struct dirent *__readdir (DIR *__dirp) attribute_hidden; extern struct dirent *__readdir_unlocked (DIR *__dirp) attribute_hidden; +extern struct dirent64 *__readdir64_unlocked (DIR *__dirp) attribute_hidden; extern struct dirent64 *__readdir64 (DIR *__dirp); libc_hidden_proto (__readdir64) extern int __readdir_r (DIR *__dirp, struct dirent *__entry, diff --git a/sysdeps/unix/sysv/linux/readdir64.c b/sysdeps/unix/sysv/linux/readdir64.c index e4d56cb2ae..26e656acf7 100644 --- a/sysdeps/unix/sysv/linux/readdir64.c +++ b/sysdeps/unix/sysv/linux/readdir64.c @@ -28,15 +28,11 @@ /* Read a directory entry from DIRP. */ struct dirent64 * -__readdir64 (DIR *dirp) +__readdir64_unlocked (DIR *dirp) { struct dirent64 *dp; int saved_errno = errno; -#if IS_IN (libc) - __libc_lock_lock (dirp->lock); -#endif - do { size_t reclen; @@ -80,6 +76,20 @@ __readdir64 (DIR *dirp) /* Skip deleted files. */ } while (dp->d_ino == 0); + return dp; +} + +struct dirent64 * +__readdir64 (DIR *dirp) +{ + struct dirent64 *dp; + +#if IS_IN (libc) + __libc_lock_lock (dirp->lock); +#endif + + dp = __readdir64_unlocked (dirp); + #if IS_IN (libc) __libc_lock_unlock (dirp->lock); #endif diff --git a/sysdeps/unix/sysv/linux/readdir64_r.c b/sysdeps/unix/sysv/linux/readdir64_r.c index c587787417..e5ef7be4c2 100644 --- a/sysdeps/unix/sysv/linux/readdir64_r.c +++ b/sysdeps/unix/sysv/linux/readdir64_r.c @@ -32,89 +32,43 @@ __readdir64_r (DIR *dirp, struct dirent64 *entry, struct dirent64 **result) { struct dirent64 *dp; size_t reclen; - const int saved_errno = errno; - int ret; __libc_lock_lock (dirp->lock); - - do + while (1) { - if (dirp->offset >= dirp->size) - { - /* We've emptied out our buffer. Refill it. */ - - size_t maxread = dirp->allocation; - ssize_t bytes; - - maxread = dirp->allocation; - - bytes = __getdents64 (dirp->fd, dirp->data, maxread); - if (bytes <= 0) - { - /* On some systems getdents fails with ENOENT when the - open directory has been rmdir'd already. POSIX.1 - requires that we treat this condition like normal EOF. */ - if (bytes < 0 && errno == ENOENT) - { - bytes = 0; - __set_errno (saved_errno); - } - if (bytes < 0) - dirp->errcode = errno; - - dp = NULL; - break; - } - dirp->size = (size_t) bytes; - - /* Reset the offset into the buffer. */ - dirp->offset = 0; - } - - dp = (struct dirent64 *) &dirp->data[dirp->offset]; + dp = __readdir64_unlocked (dirp); + if (dp == NULL) + break; reclen = dp->d_reclen; + if (reclen <= offsetof (struct dirent64, d_name) + NAME_MAX + 1) + break; - dirp->offset += reclen; - - dirp->filepos = dp->d_off; - - if (reclen > offsetof (struct dirent64, d_name) + NAME_MAX + 1) + /* The record is very long. It could still fit into the caller-supplied + buffer if we can skip padding at the end. */ + size_t namelen = _D_EXACT_NAMLEN (dp); + if (namelen <= NAME_MAX) { - /* The record is very long. It could still fit into the - caller-supplied buffer if we can skip padding at the - end. */ - size_t namelen = _D_EXACT_NAMLEN (dp); - if (namelen <= NAME_MAX) - reclen = offsetof (struct dirent64, d_name) + namelen + 1; - else - { - /* The name is too long. Ignore this file. */ - dirp->errcode = ENAMETOOLONG; - dp->d_ino = 0; - continue; - } + reclen = offsetof (struct dirent64, d_name) + namelen + 1; + break; } - /* Skip deleted and ignored files. */ + /* The name is too long. Ignore this file. */ + dirp->errcode = ENAMETOOLONG; + dp->d_ino = 0; } - while (dp->d_ino == 0); if (dp != NULL) { *result = memcpy (entry, dp, reclen); entry->d_reclen = reclen; - ret = 0; } else - { - *result = NULL; - ret = dirp->errcode; - } + *result = NULL; __libc_lock_unlock (dirp->lock); - return ret; + return dp != NULL ? 0 : dirp->errcode; } From patchwork Fri Apr 17 13:22:07 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 38827 Return-Path: X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qk1-x744.google.com (mail-qk1-x744.google.com [IPv6:2607:f8b0:4864:20::744]) by sourceware.org (Postfix) with ESMTPS id ACAFD385DC16 for ; Fri, 17 Apr 2020 13:22:25 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org ACAFD385DC16 Received: by mail-qk1-x744.google.com with SMTP id c63so2324524qke.2 for ; Fri, 17 Apr 2020 06:22:25 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=OWeqXn6TXUqpNXP8UinO2ZK/9RtyAiGbkjhnp6v9Dgk=; b=TGs+Yw1+hL6t9gQI96VkieZaBldcYROvz2InimbJzSjdVJ4lGTPRmCEmQ/+Jqgbllq lLJP2j+CJPiCR5dRJOcnlX2JCbF1FFUMUzXHkCK0WJDdvWqtMN1IYrKufLahLbLljNuk 8MuHlBo1lXWY6bIueONRbH0aQPLu3H/hH7bpp8gyXoDoNDsQ8fWzGVK4f99wtqCifqIk 6oN30tL8A99O21nnuuEzIQJZMLcTxdtzabBLGdxKSt1c388pWZgWsbhpoDInG0809OVU Sby7iCJ7nAdyi/HsEDl3FVzCjunEeM86kbFlMGgbsDcHS7KyM0L5PapF1+E3X+UEDApu D09g== X-Gm-Message-State: AGi0PuZVAx2nWqqhwwickLWuDYYEUyXI6DIx4Me6NRdpUiJvhlxtafPW clDyvT1zvXtqKnNc1LzS3bcS6vUCqdBFEQ== X-Google-Smtp-Source: APiQypKthGE+T+8gJoB18rnxT8+qfl6MN7GjOmQ+9SLY0yVGsxnxt5zDd/gNxDJuPvlfJ4pRD7mQzA== X-Received: by 2002:a37:a45:: with SMTP id 66mr3074325qkk.395.1587129744939; Fri, 17 Apr 2020 06:22:24 -0700 (PDT) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id s14sm14737571qts.70.2020.04.17.06.22.23 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Apr 2020 06:22:24 -0700 (PDT) From: Adhemerval Zanella To: libc-alpha@sourceware.org Subject: [PATCH 08/10] linux: Add __old_readdir64_unlocked Date: Fri, 17 Apr 2020 10:22:07 -0300 Message-Id: <20200417132209.22065-8-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200417132209.22065-1-adhemerval.zanella@linaro.org> References: <20200417132209.22065-1-adhemerval.zanella@linaro.org> X-Spam-Status: No, score=-25.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 17 Apr 2020 13:22:27 -0000 And use it __old_readdir64_r. Checked on i686-linux-gnu. --- sysdeps/unix/sysv/linux/olddirent.h | 2 + sysdeps/unix/sysv/linux/readdir64.c | 21 +++++-- sysdeps/unix/sysv/linux/readdir64_r.c | 79 ++++++--------------------- 3 files changed, 35 insertions(+), 67 deletions(-) diff --git a/sysdeps/unix/sysv/linux/olddirent.h b/sysdeps/unix/sysv/linux/olddirent.h index 2d2559c1e9..b118b0ef96 100644 --- a/sysdeps/unix/sysv/linux/olddirent.h +++ b/sysdeps/unix/sysv/linux/olddirent.h @@ -32,6 +32,8 @@ struct __old_dirent64 /* Now define the internal interfaces. */ extern struct __old_dirent64 *__old_readdir64 (DIR *__dirp); libc_hidden_proto (__old_readdir64); +extern struct __old_dirent64 *__old_readdir64_unlocked (DIR *__dirp) + attribute_hidden; extern int __old_readdir64_r (DIR *__dirp, struct __old_dirent64 *__entry, struct __old_dirent64 **__result); extern __ssize_t __old_getdents64 (int __fd, char *__buf, size_t __nbytes) diff --git a/sysdeps/unix/sysv/linux/readdir64.c b/sysdeps/unix/sysv/linux/readdir64.c index 26e656acf7..4ce6024b38 100644 --- a/sysdeps/unix/sysv/linux/readdir64.c +++ b/sysdeps/unix/sysv/linux/readdir64.c @@ -112,15 +112,11 @@ versioned_symbol (libc, __readdir64, readdir64, GLIBC_2_2); attribute_compat_text_section struct __old_dirent64 * -__old_readdir64 (DIR *dirp) +__old_readdir64_unlocked (DIR *dirp) { struct __old_dirent64 *dp; int saved_errno = errno; -#if IS_IN (libc) - __libc_lock_lock (dirp->lock); -#endif - do { size_t reclen; @@ -164,6 +160,21 @@ __old_readdir64 (DIR *dirp) /* Skip deleted files. */ } while (dp->d_ino == 0); + return dp; +} + +attribute_compat_text_section +struct __old_dirent64 * +__old_readdir64 (DIR *dirp) +{ + struct __old_dirent64 *dp; + +#if IS_IN (libc) + __libc_lock_lock (dirp->lock); +#endif + + dp = __old_readdir64_unlocked (dirp); + #if IS_IN (libc) __libc_lock_unlock (dirp->lock); #endif diff --git a/sysdeps/unix/sysv/linux/readdir64_r.c b/sysdeps/unix/sysv/linux/readdir64_r.c index e5ef7be4c2..133c534a69 100644 --- a/sysdeps/unix/sysv/linux/readdir64_r.c +++ b/sysdeps/unix/sysv/linux/readdir64_r.c @@ -91,89 +91,44 @@ __old_readdir64_r (DIR *dirp, struct __old_dirent64 *entry, { struct __old_dirent64 *dp; size_t reclen; - const int saved_errno = errno; - int ret; __libc_lock_lock (dirp->lock); - do + while (1) { - if (dirp->offset >= dirp->size) - { - /* We've emptied out our buffer. Refill it. */ - - size_t maxread = dirp->allocation; - ssize_t bytes; - - maxread = dirp->allocation; - - bytes = __old_getdents64 (dirp->fd, dirp->data, maxread); - if (bytes <= 0) - { - /* On some systems getdents fails with ENOENT when the - open directory has been rmdir'd already. POSIX.1 - requires that we treat this condition like normal EOF. */ - if (bytes < 0 && errno == ENOENT) - { - bytes = 0; - __set_errno (saved_errno); - } - if (bytes < 0) - dirp->errcode = errno; - - dp = NULL; - break; - } - dirp->size = (size_t) bytes; - - /* Reset the offset into the buffer. */ - dirp->offset = 0; - } - - dp = (struct __old_dirent64 *) &dirp->data[dirp->offset]; + dp = __old_readdir64_unlocked (dirp); + if (dp == NULL) + break; reclen = dp->d_reclen; + if (reclen <= offsetof (struct __old_dirent64, d_name) + NAME_MAX + 1) + break; - dirp->offset += reclen; - - dirp->filepos = dp->d_off; - - if (reclen > offsetof (struct __old_dirent64, d_name) + NAME_MAX + 1) + /* The record is very long. It could still fit into the caller-supplied + buffer if we can skip padding at the end. */ + size_t namelen = _D_EXACT_NAMLEN (dp); + if (namelen <= NAME_MAX) { - /* The record is very long. It could still fit into the - caller-supplied buffer if we can skip padding at the - end. */ - size_t namelen = _D_EXACT_NAMLEN (dp); - if (namelen <= NAME_MAX) - reclen = offsetof (struct __old_dirent64, d_name) + namelen + 1; - else - { - /* The name is too long. Ignore this file. */ - dirp->errcode = ENAMETOOLONG; - dp->d_ino = 0; - continue; - } + reclen = offsetof (struct dirent64, d_name) + namelen + 1; + break; } - /* Skip deleted and ignored files. */ + /* The name is too long. Ignore this file. */ + dirp->errcode = ENAMETOOLONG; + dp->d_ino = 0; } - while (dp->d_ino == 0); if (dp != NULL) { *result = memcpy (entry, dp, reclen); entry->d_reclen = reclen; - ret = 0; } else - { - *result = NULL; - ret = dirp->errcode; - } + *result = NULL; __libc_lock_unlock (dirp->lock); - return ret; + return dp != NULL ? 0 : dirp->errcode; } compat_symbol (libc, __old_readdir64_r, readdir64_r, GLIBC_2_1); From patchwork Fri Apr 17 13:22:08 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 38828 Return-Path: X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qk1-x744.google.com (mail-qk1-x744.google.com [IPv6:2607:f8b0:4864:20::744]) by sourceware.org (Postfix) with ESMTPS id 216E6385DC16 for ; Fri, 17 Apr 2020 13:22:27 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 216E6385DC16 Received: by mail-qk1-x744.google.com with SMTP id l78so2284300qke.7 for ; Fri, 17 Apr 2020 06:22:27 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=xvAWt/InoH4fPbVUh1NI/5rTttNNw4Q9wSYf93qAjdc=; b=hXFp4/v+OJru14gpaqp1CRUeDW/CT/tFUyYmFj+Hemy1IYAcG90BsfN8sET55LWdYO Rw7TeNVq16cdgDl9c2brG+HjA+M0Sfuw/neX8Uq46WexkWltAlIbtUpClFLutM2Jjbc5 IP+SLG0KbB731rRD8lNZF2BP7cosNaoE7FvaD45lgaWTUiHZd/LvoFtqz0RPvVVLqwfI xygI7HWhCJVRZjdPh63zg72TjigomTg2aGxjffdnLxr8d00PS8au+4/cYBy3ajrBLHbe cHlqZV5bqWcQ4XLuXKClwLnCGAdnmEAqspxpV+xXqhRzQVRUtT7td/KJbZvnir8uMJrG +NhQ== X-Gm-Message-State: AGi0PubV+/G3KMQfkAYTtK6TXS/2IBO8UjuC+Erc/YSCf1U0uxzyBcDQ Cl/DAkL4INfbFsBD2bJmYrk7YTiDGgV+QQ== X-Google-Smtp-Source: APiQypLzku3JewWKB4Xjxw9u0l3lnqoFgoh/VZSuy4sLFPbmuPQnvalt7a2b2+6W9ICG0k/Pk2q/Pg== X-Received: by 2002:a37:4708:: with SMTP id u8mr3192282qka.400.1587129746214; Fri, 17 Apr 2020 06:22:26 -0700 (PDT) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id s14sm14737571qts.70.2020.04.17.06.22.25 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Apr 2020 06:22:25 -0700 (PDT) From: Adhemerval Zanella To: libc-alpha@sourceware.org Subject: [PATCH 09/10] linux: Use getdents64 on readdir64 compat implementation Date: Fri, 17 Apr 2020 10:22:08 -0300 Message-Id: <20200417132209.22065-9-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200417132209.22065-1-adhemerval.zanella@linaro.org> References: <20200417132209.22065-1-adhemerval.zanella@linaro.org> X-Spam-Status: No, score=-25.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 17 Apr 2020 13:22:28 -0000 It uses a similar strategy from the non-LFS readdir that also uses getdents64 internally and reserves some space on the allocated internal DIR buffer to be used as a temporary buffer. The kernel obtained dirent64 data are copied to the temporary buffer for each readdir compat call. It allows to remove __old_getdents64. Checked on i686-linux-gnu. --- sysdeps/unix/sysv/linux/getdents64.c | 95 +--------------------------- sysdeps/unix/sysv/linux/olddirent.h | 2 - sysdeps/unix/sysv/linux/readdir.h | 47 +++++++++++++- sysdeps/unix/sysv/linux/readdir64.c | 27 ++++---- 4 files changed, 58 insertions(+), 113 deletions(-) diff --git a/sysdeps/unix/sysv/linux/getdents64.c b/sysdeps/unix/sysv/linux/getdents64.c index 75892c2823..f40dfacbfe 100644 --- a/sysdeps/unix/sysv/linux/getdents64.c +++ b/sysdeps/unix/sysv/linux/getdents64.c @@ -36,97 +36,4 @@ weak_alias (__getdents64, getdents64) #if _DIRENT_MATCHES_DIRENT64 strong_alias (__getdents64, __getdents) -#else -# include - -# if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) -# include -# include - -static ssize_t -handle_overflow (int fd, __off64_t offset, ssize_t count) -{ - /* If this is the first entry in the buffer, we can report the - error. */ - if (offset == 0) - { - __set_errno (EOVERFLOW); - return -1; - } - - /* Otherwise, seek to the overflowing entry, so that the next call - will report the error, and return the data read so far. */ - if (__lseek64 (fd, offset, SEEK_SET) != 0) - return -1; - return count; -} - -ssize_t -__old_getdents64 (int fd, char *buf, size_t nbytes) -{ - /* We do not move the individual directory entries. This is only - possible if the target type (struct __old_dirent64) is smaller - than the source type. */ - _Static_assert (offsetof (struct __old_dirent64, d_name) - <= offsetof (struct dirent64, d_name), - "__old_dirent64 is larger than dirent64"); - _Static_assert (__alignof__ (struct __old_dirent64) - <= __alignof__ (struct dirent64), - "alignment of __old_dirent64 is larger than dirent64"); - - ssize_t retval = INLINE_SYSCALL_CALL (getdents64, fd, buf, nbytes); - if (retval > 0) - { - /* This is the marker for the first entry. Offset 0 is reserved - for the first entry (see rewinddir). Here, we use it as a - marker for the first entry in the buffer. We never actually - seek to offset 0 because handle_overflow reports the error - directly, so it does not matter that the offset is incorrect - if entries have been read from the descriptor before (so that - the descriptor is not actually at offset 0). */ - __off64_t previous_offset = 0; - - char *p = buf; - char *end = buf + retval; - while (p < end) - { - struct dirent64 *source = (struct dirent64 *) p; - - /* Copy out the fixed-size data. */ - __ino_t ino = source->d_ino; - __off64_t offset = source->d_off; - unsigned int reclen = source->d_reclen; - unsigned char type = source->d_type; - - /* Check for ino_t overflow. */ - if (__glibc_unlikely (ino != source->d_ino)) - return handle_overflow (fd, previous_offset, p - buf); - - /* Convert to the target layout. Use a separate struct and - memcpy to side-step aliasing issues. */ - struct __old_dirent64 result; - result.d_ino = ino; - result.d_off = offset; - result.d_reclen = reclen; - result.d_type = type; - - /* Write the fixed-sized part of the result to the - buffer. */ - size_t result_name_offset = offsetof (struct __old_dirent64, d_name); - memcpy (p, &result, result_name_offset); - - /* Adjust the position of the name if necessary. Copy - everything until the end of the record, including the - terminating NUL byte. */ - if (result_name_offset != offsetof (struct dirent64, d_name)) - memmove (p + result_name_offset, source->d_name, - reclen - offsetof (struct dirent64, d_name)); - - p += reclen; - previous_offset = offset; - } - } - return retval; -} -# endif /* SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) */ -#endif /* _DIRENT_MATCHES_DIRENT64 */ +#endif diff --git a/sysdeps/unix/sysv/linux/olddirent.h b/sysdeps/unix/sysv/linux/olddirent.h index b118b0ef96..63d8e97868 100644 --- a/sysdeps/unix/sysv/linux/olddirent.h +++ b/sysdeps/unix/sysv/linux/olddirent.h @@ -36,8 +36,6 @@ extern struct __old_dirent64 *__old_readdir64_unlocked (DIR *__dirp) attribute_hidden; extern int __old_readdir64_r (DIR *__dirp, struct __old_dirent64 *__entry, struct __old_dirent64 **__result); -extern __ssize_t __old_getdents64 (int __fd, char *__buf, size_t __nbytes) - attribute_hidden; int __old_scandir64 (const char * __dir, struct __old_dirent64 *** __namelist, int (*__selector) (const struct __old_dirent64 *), diff --git a/sysdeps/unix/sysv/linux/readdir.h b/sysdeps/unix/sysv/linux/readdir.h index 7f6cf3783d..234a7f26e6 100644 --- a/sysdeps/unix/sysv/linux/readdir.h +++ b/sysdeps/unix/sysv/linux/readdir.h @@ -21,6 +21,7 @@ #if !_DIRENT_MATCHES_DIRENT64 # include +# include /* getdents64 is used internally for both LFS and non-LFS implementations. The non-LFS interface reserves part of the allocated buffer to return the @@ -106,9 +107,53 @@ dirstream_ret_entry (struct __dirstream *ds) return dp; } + +/* Return the allocated buffer used on LFS compat readdir call. */ +static inline struct __old_dirent64 * +dirstream_ret64_compat (struct __dirstream *ds) +{ + return (struct __old_dirent64 *) ds->data; +} + +static inline struct __old_dirent64 * +dirstream_ret_entry64_compat (struct __dirstream *ds) +{ + struct dirent64 *dp64 = dirstream_entry (ds); + struct __old_dirent64 *dp64_compat = dirstream_ret64_compat (ds); + + dp64_compat->d_ino = dp64->d_ino; + if (dp64_compat->d_ino != dp64->d_ino) + /* Overflow. */ + return NULL; + + dp64_compat->d_off = dp64->d_off; + + const size_t size_diff = (offsetof (struct dirent64, d_name) + - offsetof (struct __old_dirent64, d_name)); + const size_t alignment = _Alignof (struct __old_dirent64); + size_t new_reclen = (dp64->d_reclen - size_diff + alignment - 1) + & ~(alignment - 1); + if (new_reclen > return_buffer_size) + /* Overflow. */ + return NULL; + + /* The compat symbol report the kernel obtained d_reclen, even though + it has an incompatible dirent layout. */ + dp64_compat->d_reclen = dp64->d_reclen; + + dp64_compat->d_type = dp64->d_type; + + memcpy (dp64_compat->d_name, dp64->d_name, + dp64->d_reclen - offsetof (struct dirent64, d_name)); + + ds->offset += dp64->d_reclen; + ds->filepos = dp64->d_off; + + return dp64_compat; +} + #else /* No need to reserve an buffer space if dirent has already LFS support. */ enum { return_buffer_size = 0 }; #endif /* _DIRENT_MATCHES_DIRENT64 */ - #endif diff --git a/sysdeps/unix/sysv/linux/readdir64.c b/sysdeps/unix/sysv/linux/readdir64.c index 4ce6024b38..4095b94a0f 100644 --- a/sysdeps/unix/sysv/linux/readdir64.c +++ b/sysdeps/unix/sysv/linux/readdir64.c @@ -108,27 +108,23 @@ weak_alias (__readdir64, readdir) # include versioned_symbol (libc, __readdir64, readdir64, GLIBC_2_2); # if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) -# include +# include +# include attribute_compat_text_section struct __old_dirent64 * __old_readdir64_unlocked (DIR *dirp) { struct __old_dirent64 *dp; - int saved_errno = errno; + const int saved_errno = errno; do { - size_t reclen; - if (dirp->offset >= dirp->size) { /* We've emptied out our buffer. Refill it. */ - - size_t maxread = dirp->allocation; - ssize_t bytes; - - bytes = __old_getdents64 (dirp->fd, dirp->data, maxread); + ssize_t bytes = __getdents64 (dirp->fd, dirstream_data (dirp), + dirstream_alloc_size (dirp)); if (bytes <= 0) { /* On some systems getdents fails with ENOENT when the @@ -149,13 +145,12 @@ __old_readdir64_unlocked (DIR *dirp) dirp->offset = 0; } - dp = (struct __old_dirent64 *) &dirp->data[dirp->offset]; - - reclen = dp->d_reclen; - - dirp->offset += reclen; - - dirp->filepos = dp->d_off; + dp = dirstream_ret_entry64_compat (dirp); + if (dp == NULL) + { + __set_errno (EOVERFLOW); + break; + } /* Skip deleted files. */ } while (dp->d_ino == 0); From patchwork Fri Apr 17 13:22:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 38829 Return-Path: X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qk1-x742.google.com (mail-qk1-x742.google.com [IPv6:2607:f8b0:4864:20::742]) by sourceware.org (Postfix) with ESMTPS id 3CE67384A040 for ; Fri, 17 Apr 2020 13:22:28 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 3CE67384A040 Received: by mail-qk1-x742.google.com with SMTP id j4so2255035qkc.11 for ; Fri, 17 Apr 2020 06:22:28 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=9QEcMFZzHkQd57gAOKmxBGPpo2ohwB1UCXxWhjrDmOA=; b=nQAXuGD5y9uQ/sDxAH3rsMaJC1yu1yrMR9+I0al492Wo6Xd8qTwoJPYNfXAjWgN4CT BZhdQ6FP0N+BQMkb8dyPFzq6Nc00BfMmVHiCOkoGy4nnVOobu5Zl79xVtOFXnG2EkcOV 46egAvkr1mvfvF0Cnoy2TzHF5RQXMstZq9UiWd7rIkJUw6n8CvBt0os674KgQ7dFKyU7 SxTdBEV8TmFMamp5ZU7OYTWOJBzmhyl7663AWPOoalfJVbcYzUu+bap3CrVkICQicAQO Y1bKTFJkwwtNP51PtMQMgozrSA+n2ri+ffPKo5phuBKrqKL9EYzzdrFxIZ/eRv+NQiq1 rKZw== X-Gm-Message-State: AGi0PuZ9/5UzO/6XT1PKezgW3GDosksQxBPs1fKJMc31bBdodYo6bp+o oJY+vDmIEPWwBwqj1Fo8iChmFk+6DaoC0w== X-Google-Smtp-Source: APiQypIJLmr8vhuu3pj1jG62vGy4fnGjnF+Jt/AUW3ZSmfoReDw3fJGybKCEjMgsobnWxWbnlIW/jw== X-Received: by 2002:a37:a486:: with SMTP id n128mr3235785qke.140.1587129747594; Fri, 17 Apr 2020 06:22:27 -0700 (PDT) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id s14sm14737571qts.70.2020.04.17.06.22.26 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Apr 2020 06:22:27 -0700 (PDT) From: Adhemerval Zanella To: libc-alpha@sourceware.org Subject: [PATCH 10/10] dirent: Deprecate getdirentries Date: Fri, 17 Apr 2020 10:22:09 -0300 Message-Id: <20200417132209.22065-10-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200417132209.22065-1-adhemerval.zanella@linaro.org> References: <20200417132209.22065-1-adhemerval.zanella@linaro.org> X-Spam-Status: No, score=-25.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 17 Apr 2020 13:22:29 -0000 The interface has some issues: 1. It is build on top getdents on Linux and requires handling non-LFS call using LFS getdents. 2. It is not wildly used and the non-LFS support is as problematic as non-LFS readdir. glibc only exports the LFS getdents. 3. It is not a direct replacement over BSD since on some plataform its signature has changed (FreeBSD 11, for instance, used to set the offset as a 'long' and changed to 'off_t' on version 12). The idea is to eventually move the symbols to compat ones. --- NEWS | 3 +++ dirent/dirent.h | 7 ++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index 2424fecdc0..58d9db6d00 100644 --- a/NEWS +++ b/NEWS @@ -22,6 +22,9 @@ Deprecated and removed features, and other changes affecting compatibility: but always fails with ENOSYS. This reflects the removal of the system call from all architectures, starting with Linux 5.5. +* The function getdirentries is now deprecated, applications should use + either getdents or POSIX readdir instead. + Changes to build and runtime requirements: [Add changes to build and runtime requirements here] diff --git a/dirent/dirent.h b/dirent/dirent.h index 92d0925047..4ee60471f7 100644 --- a/dirent/dirent.h +++ b/dirent/dirent.h @@ -353,14 +353,15 @@ extern int alphasort64 (const struct dirent64 **__e1, extern __ssize_t getdirentries (int __fd, char *__restrict __buf, size_t __nbytes, __off_t *__restrict __basep) - __THROW __nonnull ((2, 4)); + __THROW __nonnull ((2, 4)) __attribute_deprecated__; # else # ifdef __REDIRECT extern __ssize_t __REDIRECT_NTH (getdirentries, (int __fd, char *__restrict __buf, size_t __nbytes, __off64_t *__restrict __basep), - getdirentries64) __nonnull ((2, 4)); + getdirentries64) + __THROW __nonnull ((2, 4)) __attribute_deprecated__; # else # define getdirentries getdirentries64 # endif @@ -370,7 +371,7 @@ extern __ssize_t __REDIRECT_NTH (getdirentries, extern __ssize_t getdirentries64 (int __fd, char *__restrict __buf, size_t __nbytes, __off64_t *__restrict __basep) - __THROW __nonnull ((2, 4)); + __THROW __nonnull ((2, 4)) __attribute_deprecated__; # endif #endif /* Use misc. */