From patchwork Tue Oct 27 14:35:31 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: 40889 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 993C43953CF8; Tue, 27 Oct 2020 14:35:44 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 993C43953CF8 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1603809344; bh=3VeEU4rCB4/YGoH/ml51HOd+0isTZLG+rDLOD2RfEoU=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=OWAInEwLQ3I2iU4ofCaN3av36LzAwwW/fgtklZcwC5f1ABxd+L7Q0bFrPkQJqQqhA oB9vjODN60nRPBLNs5SzU4xi3IHppeeLR29pjjLlPZbGYhK994vcFvB8G28zvLigku y1bQBy11s7jJbSn68tEyoKdv/8UFpJ3Q2m9taJzw= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-qv1-xf42.google.com (mail-qv1-xf42.google.com [IPv6:2607:f8b0:4864:20::f42]) by sourceware.org (Postfix) with ESMTPS id D59A83953C09 for ; Tue, 27 Oct 2020 14:35:42 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org D59A83953C09 Received: by mail-qv1-xf42.google.com with SMTP id w5so726888qvn.12 for ; Tue, 27 Oct 2020 07:35:42 -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:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=3VeEU4rCB4/YGoH/ml51HOd+0isTZLG+rDLOD2RfEoU=; b=tcpfMIHBM0QY9BJ/kzyvnD3CPtI220hMLr/Q7fe7qRRTO1OzmiWl3MHYXe/+PkLelM PS6c1Xh177m/k5ReSN0+lfjofne5kmd/V2mBWQlpYsr6WgM9AS79hN/pgPHepEYcvmzQ Um1aU9O1I36HkqZrVY9lyVOCYJ65QwMORJ8jS4Gw25FVlubL2eMFI6784xILgtg8DXde QfnVqqcMEinoXKoTYDmCCKkp6i36Q6L33n4i1rbE4JetR1kITpGFgUiETa40eZSVWJ+j l3lhj2jD9Mj1GpEYuJZDsXzh0z+p3eymd+9r6h8H4Z2jqgF0jTg/Fu9bNms2NYKMQoZq /SsA== X-Gm-Message-State: AOAM533aE7sDAKpUW8MoGafHzMub1b2i1Iti6ttJzTl+/48pP+CvtxTQ D9Dwyt0GDcG088IXVzEbsBQxCnEyT6RDmA== X-Google-Smtp-Source: ABdhPJzaO/47+UZJw7Q+LaPQKbXS6ij52t+6WN/UvNVwlxja00Sw4oWc9A9MUYvt4fIoPN92f9KsTw== X-Received: by 2002:a05:6214:9a7:: with SMTP id du7mr2389956qvb.21.1603809342215; Tue, 27 Oct 2020 07:35:42 -0700 (PDT) Received: from localhost.localdomain ([177.194.48.209]) by smtp.googlemail.com with ESMTPSA id 19sm780704qki.33.2020.10.27.07.35.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 27 Oct 2020 07:35:41 -0700 (PDT) To: libc-alpha@sourceware.org Subject: [PATCH v2 4/4] stdlib: Remove lstat usage from realpath [BZ #24970] Date: Tue, 27 Oct 2020 11:35:31 -0300 Message-Id: <20201027143531.2448132-4-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20201027143531.2448132-1-adhemerval.zanella@linaro.org> References: <20201027143531.2448132-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-14.0 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.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-Patchwork-Original-From: Adhemerval Zanella via Libc-alpha From: Adhemerval Zanella Netto Reply-To: Adhemerval Zanella Cc: Andreas Schwab Errors-To: libc-alpha-bounces@sourceware.org Sender: "Libc-alpha" The readlink already tells whether the file is a symlink, so there is no need to call lstat to check it. However for '..' it requires an extra readlink check if the previous component can be really accessed, otherwise the next iteration will check a possible valid path and end early. It should performance-wise acceptable and a gain over lstat, afaik symlink should not update any inode information. Checked on x86_64-linux-gnu and i686-linux-gnu. --- stdlib/canonicalize.c | 52 ++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/stdlib/canonicalize.c b/stdlib/canonicalize.c index 9aa69676e4..952f4dca41 100644 --- a/stdlib/canonicalize.c +++ b/stdlib/canonicalize.c @@ -55,6 +55,7 @@ __realpath (const char *name, char *resolved) const char *start, *end, *rpath_limit; const size_t path_max = PATH_MAX; int num_links = 0; + char buf[PATH_MAX]; char extra_buf[PATH_MAX]; if (name == NULL) @@ -104,12 +105,6 @@ __realpath (const char *name, char *resolved) for (end = start; *start; start = end) { -#ifdef _LIBC - struct stat64 st; -#else - struct stat st; -#endif - /* Skip sequence of multiple path-separators. */ while (*start == '/') ++start; @@ -118,12 +113,25 @@ __realpath (const char *name, char *resolved) for (end = start; *end && *end != '/'; ++end) /* Nothing. */; - if (end - start == 0) - break; - else if (end - start == 1 && start[0] == '.') + if (end - start == 1 && start[0] == '.') /* nothing */; else if (end - start == 2 && start[0] == '.' && start[1] == '.') { + ssize_t n; + + if (dest[-1] != '/') + *dest++ = '/'; + *dest = '\0'; + + n = __readlink (rpath, buf, path_max - 1); + if (n == -1) + { + if (errno == ENOTDIR && dest[-1] == '/') + dest[-1] = '\0'; + if (errno != EINVAL) + goto error; + } + /* Back up to previous component, ignore if at root already. */ if (dest > rpath + 1) for (--dest; dest > rpath && dest[-1] != '/'; --dest) @@ -132,6 +140,7 @@ __realpath (const char *name, char *resolved) else { size_t new_size; + ssize_t n; if (dest[-1] != '/') *dest++ = '/'; @@ -166,25 +175,23 @@ __realpath (const char *name, char *resolved) dest = __mempcpy (dest, start, end - start); *dest = '\0'; - if (__lstat64 (rpath, &st) < 0) - goto error; - - if (S_ISLNK (st.st_mode)) + n = __readlink (rpath, buf, path_max - 1); + if (n < 0) + { + if (errno == ENOTDIR && dest[-1] == '/') + dest[-1] = '\0'; + if (errno != EINVAL) + goto error; + } + else { - char buf[PATH_MAX]; size_t len; - ssize_t n; if (++num_links > __eloop_threshold ()) { __set_errno (ELOOP); goto error; } - n = __readlink (rpath, buf, path_max - 1); - if (n < 0) - goto error; - buf[n] = '\0'; - len = strlen (end); /* Check that n + len + 1 doesn't overflow and is <= path_max. */ if (n >= SIZE_MAX - len || n + len >= path_max) @@ -211,11 +218,6 @@ __realpath (const char *name, char *resolved) continue; } } - else if (!S_ISDIR (st.st_mode) && *end != '\0') - { - __set_errno (ENOTDIR); - goto error; - } } } if (dest > rpath + 1 && dest[-1] == '/')