From patchwork Fri Jan 27 17:28:30 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 63808 X-Patchwork-Delegate: fweimer@redhat.com Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id BF67D38493DB for ; Fri, 27 Jan 2023 17:29:10 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org BF67D38493DB DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1674840550; bh=iBL92Gp1K9pw+NViykFNtdBYfQuuNoAUnUiova+laCU=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=MgJO2i8D2LCpe/dyuaV2b9CcpdtG49qW9JpKM87OOp8DW12DC0UZaK0fBxlE2/edh 4Atea/+zJslSv0INqmjELayjM7uCfJ47wcnw7nEhQ60E+q7CHuV3FNoYsmK9vK+3zX msVy8jid63NXVLcl3CBPvJp7q8vRYPFojFK6PbQ4= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-oi1-x22b.google.com (mail-oi1-x22b.google.com [IPv6:2607:f8b0:4864:20::22b]) by sourceware.org (Postfix) with ESMTPS id 20CA2385AC39 for ; Fri, 27 Jan 2023 17:28:45 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 20CA2385AC39 Received: by mail-oi1-x22b.google.com with SMTP id s66so4734717oib.7 for ; Fri, 27 Jan 2023 09:28:45 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=iBL92Gp1K9pw+NViykFNtdBYfQuuNoAUnUiova+laCU=; b=I1udlWCeI4zz2g3EzpMvK+qzH1DQXBiMobsVX2KX4rCDVnlX8lIpv7x/LhsTc7D1v5 syAMSHN1CzYs+7VdH7wTObsyLWYq1ZJ9hoFSrfGGnJ36NNeT/2H4Qt+0fQlFYOWfYIyp NXTPuRQ3f73HS1oOCkxUN1aTxFTH4YessXee1lzyuA0Eazg6SQfrUA3Nn6rNlb8SDUbr QJc8VrsPRGoFhLwiIjRSpN3bBoZwXZpdzljyivPYfzvgWcvXTXmDfHFFqUyBoRcQYnWd Oy//krq1Aa2TCPtyYGfZKjP+H56tugAqDymjob2PInZhAq8GmpCn+5Eq+0Zjk2sLoMI4 N0mg== X-Gm-Message-State: AFqh2kqodVHVr/bQMTYLIW9mDrJLbJfERMU3l2l91nKTshcsBuprZx7z zOSpbfuv6vnpZkqLuqTTSwMMHixTOjlAy28P0hU= X-Google-Smtp-Source: AMrXdXs+TrZnCd0Ps/v1BZqTxOQjF7pBA2kYHxxpWleLDKGbBgRu5FH/VNVS8CL5I1qwJ7GAd8TWxQ== X-Received: by 2002:a05:6808:8f6:b0:360:c4f3:ec79 with SMTP id d22-20020a05680808f600b00360c4f3ec79mr17490902oic.33.1674840522148; Fri, 27 Jan 2023 09:28:42 -0800 (PST) Received: from mandiga.. ([2804:1b3:a7c1:7e99:a00f:8f3d:7ba5:11f1]) by smtp.gmail.com with ESMTPSA id r131-20020acada89000000b0035aa617156bsm1803940oig.17.2023.01.27.09.28.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 27 Jan 2023 09:28:40 -0800 (PST) To: libc-alpha@sourceware.org, "Andreas K . Huettel" , Paul Eggert , Florian Weimer Subject: [PATCH v5 1/5] linux: Use getdents64 on non-LFS readdir Date: Fri, 27 Jan 2023 14:28:30 -0300 Message-Id: <20230127172834.391311-2-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230127172834.391311-1-adhemerval.zanella@linaro.org> References: <20230127172834.391311-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-12.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) 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-Patchwork-Original-From: Adhemerval Zanella via Libc-alpha From: Adhemerval Zanella Reply-To: Adhemerval Zanella Errors-To: libc-alpha-bounces+patchwork=sourceware.org@sourceware.org Sender: "Libc-alpha" The non-LFS opendir reserves a translation entry to be used to return the entry and the dirent64 struct is translated to the temporary buffer on each readdir call. Entries that overflow d_off/d_ino and the buffer reallocation failure (in case of large d_name) are ignored. Checked on x86_64-linux-gnu and i686-linux-gnu. --- dirent/tst-scandir.c | 6 ++- include/dirent.h | 2 +- sysdeps/unix/sysv/linux/dirstream.h | 5 ++ sysdeps/unix/sysv/linux/readdir.c | 83 +++++++++++++++++++---------- 4 files changed, 67 insertions(+), 29 deletions(-) diff --git a/dirent/tst-scandir.c b/dirent/tst-scandir.c index 8d87d4dd74..7bc666449e 100644 --- a/dirent/tst-scandir.c +++ b/dirent/tst-scandir.c @@ -155,8 +155,12 @@ do_test (void) } if (n != 6) { + /* Non-lfs opendir skips entries that can not be represented (for + instance if d_off is not an offset but rather an internal filesystem + representation. For this case there is no point in continue the + testcase. */ printf ("scandir returned %d entries instead of 6\n", n); - return 1; + return EXIT_UNSUPPORTED; } struct diff --git a/include/dirent.h b/include/dirent.h index d7567f5e86..17827176ba 100644 --- a/include/dirent.h +++ b/include/dirent.h @@ -1,8 +1,8 @@ #ifndef _DIRENT_H +# include # ifndef _ISOMAC # include # endif -# include # ifndef _ISOMAC # include # include diff --git a/sysdeps/unix/sysv/linux/dirstream.h b/sysdeps/unix/sysv/linux/dirstream.h index 3cb313b410..adcf8234f1 100644 --- a/sysdeps/unix/sysv/linux/dirstream.h +++ b/sysdeps/unix/sysv/linux/dirstream.h @@ -18,6 +18,7 @@ #ifndef _DIRSTREAM_H #define _DIRSTREAM_H 1 +#include #include #include @@ -41,6 +42,10 @@ struct __dirstream int errcode; /* Delayed error code. */ +#if !defined __OFF_T_MATCHES_OFF64_T || !defined __INO_T_MATCHES_INO64_T + struct dirent tdp; +#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/readdir.c b/sysdeps/unix/sysv/linux/readdir.c index 4a4c00ea07..cd0ccaf33a 100644 --- a/sysdeps/unix/sysv/linux/readdir.c +++ b/sysdeps/unix/sysv/linux/readdir.c @@ -21,42 +21,71 @@ #if !_DIRENT_MATCHES_DIRENT64 #include +/* Translate the DP64 entry to the non-LFS one in the translation entry + at dirstream DS. Return true is the translation was possible or + false if either an internal field can not be represented in the non-LFS + entry or if the name is too long. */ +static bool +dirstream_entry (struct __dirstream *ds, const struct dirent64 *dp64) +{ + /* Check for overflow. */ + if (!in_off_t_range (dp64->d_off) || !in_ino_t_range (dp64->d_ino)) + return false; + + /* And if name is too large. */ + if (dp64->d_reclen - offsetof (struct dirent64, d_name) > NAME_MAX) + return false; + + ds->filepos = dp64->d_off; + + ds->tdp.d_off = dp64->d_off; + ds->tdp.d_ino = dp64->d_ino; + ds->tdp.d_reclen = sizeof (struct dirent) + + dp64->d_reclen - offsetof (struct dirent64, d_name); + ds->tdp.d_type = dp64->d_type; + memcpy (ds->tdp.d_name, dp64->d_name, + dp64->d_reclen - offsetof (struct dirent64, d_name)); + + return true; +} + /* Read a directory entry from DIRP. */ struct dirent * __readdir_unlocked (DIR *dirp) { - struct dirent *dp; int saved_errno = errno; - if (dirp->offset >= dirp->size) + while (1) { - /* 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) + if (dirp->offset >= dirp->size) { - /* Linux may fail with ENOENT on some file systems if the - directory inode is marked as dead (deleted). POSIX - treats this as a regular end-of-directory condition, so - do not set errno in that case, to indicate success. */ - if (bytes == 0 || errno == ENOENT) - __set_errno (saved_errno); - return NULL; - } - dirp->size = (size_t) bytes; - - /* Reset the offset into the buffer. */ - dirp->offset = 0; + /* We've emptied out our buffer. Refill it. */ + ssize_t bytes = __getdents64 (dirp->fd, dirp->data, + dirp->allocation); + if (bytes <= 0) + { + /* Linux may fail with ENOENT on some file systems if the + directory inode is marked as dead (deleted). POSIX + treats this as a regular end-of-directory condition, so + do not set errno in that case, to indicate success. */ + if (bytes < 0 && errno == ENOENT) + __set_errno (saved_errno); + return NULL; + } + dirp->size = bytes; + + /* Reset the offset into the buffer. */ + dirp->offset = 0; + } + + struct dirent64 *dp64 = (struct dirent64 *) &dirp->data[dirp->offset]; + dirp->offset += dp64->d_reclen; + + /* Skip entries which might overflow d_off/d_ino or if the translation + buffer can not be resized. */ + if (dirstream_entry (dirp, dp64)) + return &dirp->tdp; } - - dp = (struct dirent *) &dirp->data[dirp->offset]; - dirp->offset += dp->d_reclen; - dirp->filepos = dp->d_off; - - return dp; } struct dirent *