From patchwork Mon Sep 19 06:54:52 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 1679163 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=sourceware.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=libc-alpha-bounces+incoming=patchwork.ozlabs.org@sourceware.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.a=rsa-sha256 header.s=default header.b=PMeA1GbQ; dkim-atps=neutral Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4MWFmg1ppRz1ypM for ; Mon, 19 Sep 2022 16:55:15 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 812F638582A4 for ; Mon, 19 Sep 2022 06:55:12 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 812F638582A4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1663570512; bh=EP9lFMJRGCCq0CyjEEnYCYIGhnkHQdOhw9WY9ezUxhw=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=PMeA1GbQijBJj30fbOzYezgPQt1LhbaBuiRWmPw30LnWxWA+kmb2eq6BEIzf/2K27 kS86/ejSnRwa62I3pWeRFoFh1Pxb2PrWUcSp5bVcAGzk+fJsLygwytnEypB7f2RYxU N8Ikt5vFTLrZ5K5AU2gH0tmYhf/5XhZFJBM/VsVo= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id EECAA3858CDA for ; Mon, 19 Sep 2022 06:54:56 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org EECAA3858CDA Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-215-BW9lWVSRO--UiNW9IJBmqA-1; Mon, 19 Sep 2022 02:54:55 -0400 X-MC-Unique: BW9lWVSRO--UiNW9IJBmqA-1 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id E31B380029D for ; Mon, 19 Sep 2022 06:54:54 +0000 (UTC) Received: from oldenburg.str.redhat.com (unknown [10.39.192.137]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 2216D40C6EC2 for ; Mon, 19 Sep 2022 06:54:54 +0000 (UTC) To: libc-alpha@sourceware.org Subject: [PATCH] Linux: Do not skip d_ino == 0 entries in readdir, readdir64 (bug 12165) Date: Mon, 19 Sep 2022 08:54:52 +0200 Message-ID: <87o7vbj1kz.fsf@oldenburg.str.redhat.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.2 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.0 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_NONE, 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: Florian Weimer via Libc-alpha From: Florian Weimer Reply-To: Florian Weimer Errors-To: libc-alpha-bounces+incoming=patchwork.ozlabs.org@sourceware.org Sender: "Libc-alpha" POSIX does not say this value is special. For example, old XFS file systems may still use inode number zero. Also update the comment regarding ENOENT. Linux may return ENOENT for some file systems. Tested on i686-linux-gnu and x86_64-linux-gnu. --- sysdeps/unix/sysv/linux/readdir.c | 57 +++++++---------- sysdeps/unix/sysv/linux/readdir64.c | 120 +++++++++++++++--------------------- 2 files changed, 69 insertions(+), 108 deletions(-) base-commit: 2ff6775ad341b10a08e3b27d6e1df1da637747c7 diff --git a/sysdeps/unix/sysv/linux/readdir.c b/sysdeps/unix/sysv/linux/readdir.c index b480135164..15f0033f36 100644 --- a/sysdeps/unix/sysv/linux/readdir.c +++ b/sysdeps/unix/sysv/linux/readdir.c @@ -28,48 +28,33 @@ __readdir_unlocked (DIR *dirp) struct dirent *dp; int saved_errno = errno; - do + if (dirp->offset >= dirp->size) { - size_t reclen; + /* We've emptied out our buffer. Refill it. */ - if (dirp->offset >= dirp->size) + size_t maxread = dirp->allocation; + ssize_t bytes; + + bytes = __getdents (dirp->fd, dirp->data, maxread); + if (bytes <= 0) { - /* 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; + /* Linux fails with ENOENT if IS_DEADDIR is true for the + directory inode. 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; - dp = (struct dirent *) &dirp->data[dirp->offset]; + /* Reset the offset into the buffer. */ + dirp->offset = 0; + } - reclen = dp->d_reclen; - - dirp->offset += reclen; - - dirp->filepos = dp->d_off; - - /* Skip deleted files. */ - } while (dp->d_ino == 0); + dp = (struct dirent *) &dirp->data[dirp->offset]; + dirp->offset += dp->d_reclen; + dirp->filepos = dp->d_off; return dp; } diff --git a/sysdeps/unix/sysv/linux/readdir64.c b/sysdeps/unix/sysv/linux/readdir64.c index 52b11eb9d9..f56c3c0d8e 100644 --- a/sysdeps/unix/sysv/linux/readdir64.c +++ b/sysdeps/unix/sysv/linux/readdir64.c @@ -37,48 +37,36 @@ __readdir64 (DIR *dirp) __libc_lock_lock (dirp->lock); #endif - do + if (dirp->offset >= dirp->size) { - size_t reclen; + /* We've emptied out our buffer. Refill it. */ - if (dirp->offset >= dirp->size) + size_t maxread = dirp->allocation; + ssize_t bytes; + + bytes = __getdents64 (dirp->fd, dirp->data, maxread); + if (bytes <= 0) { - /* 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; + /* Linux fails with ENOENT if IS_DEADDIR is true for the + directory inode. 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); +#if IS_IN (libc) + __libc_lock_unlock (dirp->lock); +#endif + return NULL; } + dirp->size = (size_t) bytes; - dp = (struct dirent64 *) &dirp->data[dirp->offset]; + /* Reset the offset into the buffer. */ + dirp->offset = 0; + } - reclen = dp->d_reclen; - - dirp->offset += reclen; - - dirp->filepos = dp->d_off; - - /* Skip deleted files. */ - } while (dp->d_ino == 0); + dp = (struct dirent64 *) &dirp->data[dirp->offset]; + dirp->offset += dp->d_reclen; + dirp->filepos = dp->d_off; #if IS_IN (libc) __libc_lock_unlock (dirp->lock); @@ -115,48 +103,36 @@ __old_readdir64 (DIR *dirp) __libc_lock_lock (dirp->lock); #endif - do + if (dirp->offset >= dirp->size) { - size_t reclen; + /* We've emptied out our buffer. Refill it. */ - if (dirp->offset >= dirp->size) + size_t maxread = dirp->allocation; + ssize_t bytes; + + bytes = __old_getdents64 (dirp->fd, dirp->data, maxread); + if (bytes <= 0) { - /* 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; + /* Linux fails with ENOENT if IS_DEADDIR is true for the + directory inode. 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); +#if IS_IN (libc) + __libc_lock_unlock (dirp->lock); +#endif + return NULL; } + dirp->size = (size_t) bytes; - dp = (struct __old_dirent64 *) &dirp->data[dirp->offset]; + /* Reset the offset into the buffer. */ + dirp->offset = 0; + } - reclen = dp->d_reclen; - - dirp->offset += reclen; - - dirp->filepos = dp->d_off; - - /* Skip deleted files. */ - } while (dp->d_ino == 0); + dp = (struct __old_dirent64 *) &dirp->data[dirp->offset]; + dirp->offset += dp->d_reclen; + dirp->filepos = dp->d_off; #if IS_IN (libc) __libc_lock_unlock (dirp->lock);