From patchwork Mon Aug 23 11:52:37 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBCamFybWFzb24=?= X-Patchwork-Id: 12452533 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D9CF7C4320A for ; Mon, 23 Aug 2021 11:52:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id BEC0061378 for ; Mon, 23 Aug 2021 11:52:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232280AbhHWLxi (ORCPT ); Mon, 23 Aug 2021 07:53:38 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50462 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236558AbhHWLxh (ORCPT ); Mon, 23 Aug 2021 07:53:37 -0400 Received: from mail-wm1-x334.google.com (mail-wm1-x334.google.com [IPv6:2a00:1450:4864:20::334]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C433BC061757 for ; Mon, 23 Aug 2021 04:52:54 -0700 (PDT) Received: by mail-wm1-x334.google.com with SMTP id j14-20020a1c230e000000b002e748b9a48bso1920296wmj.0 for ; Mon, 23 Aug 2021 04:52:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Lg304+so4q4O+2bFgjcPrYdrF0bESWwBCMQteVc+TQc=; b=lAzuCV+P1L883gWPcfgHMJxF0NrZ1ftItzynmkbmJ3BLPB5ZaL/APQafwY26wnGXup jAg8eh1CZ3InoBMFx8L145rsCTRPnUc4W8Fq8Ug1RbkBtSgM0CObp7lKq8ICxyxjnsU1 Tygz4prMN94apM2aX9GnOVCddPMESytMeauI1KSeQOoKKNDhJ0O7LdPNrUug0TruSlOV Lxi81oQStpwDfSWhfCUjOlIJ9QPBoQ1SpJTa5OUnDckKcXxkY7Mop4iRt4TKiOgG2JCZ jYRV16bm1nrorkzAKao+2NcIkjM8r9stNRreJcd7VI64mubGig0lnoZrTBAY64ZXh9uo 7vKA== 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=Lg304+so4q4O+2bFgjcPrYdrF0bESWwBCMQteVc+TQc=; b=lIGgFQmGqvru+kCFg4IB6cpn8yuIKL6UnqJN6B55i4tW4eGoFthi8dF6YAc1HcZcmV 6AM8ImALFPyKx15AHQEgbLj0cMC6aY7nTvYwDhpbv0YfWCykObBtvW+RIrTOxdUnFL6c IgaMGDxvcbUlM8at6DxAsCWSPvZeLU6u1cgio0CeMlJjmzth9SIUNjSIIXpwlcdtAn0R mlBSKk03l9cHkmvpttZCku+P5RNhatlT0WTXcm7yC2h8meUWUD0KX4AAQEIbT34n4z10 d6W8H2sA/FZCJbTvbGGfiph745QOa1SxE9QqK6gwh+i7SOGC+0FcnvD3VLKZY/sdY2WH h2UQ== X-Gm-Message-State: AOAM531FzRtr72sA8nnH8qfK+gnpqtq8j/x0NbTOwUaKYC0oCNSqubJv 8wXzdR7GTjyvLB8prEsTIx4Ysu11tKotG8kq X-Google-Smtp-Source: ABdhPJxuCab5h5BaoSYxfpYWoedvtlE0/kp0frwq4Zp2TpMC+/fKuS9bdC/wR1jXxglcSCdVMnD6kQ== X-Received: by 2002:a05:600c:4105:: with SMTP id j5mr16135049wmi.86.1629719573112; Mon, 23 Aug 2021 04:52:53 -0700 (PDT) Received: from vm.nix.is (vm.nix.is. [2a01:4f8:120:2468::2]) by smtp.gmail.com with ESMTPSA id l2sm12350713wmi.1.2021.08.23.04.52.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Aug 2021 04:52:52 -0700 (PDT) From: =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBCamFybWFzb24=?= To: git@vger.kernel.org Cc: Junio C Hamano , Jeff King , Han-Wen Nienhuys , Michael Haggerty , Jonathan Tan , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBC?= =?utf-8?b?amFybWFzb24=?= Subject: [PATCH v10 1/8] refs file backend: move raceproof_create_file() here Date: Mon, 23 Aug 2021 13:52:37 +0200 Message-Id: X-Mailer: git-send-email 2.33.0.662.g438caf9576d In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org Move the raceproof_create_file() API added to cache.h and object-file.c in 177978f56ad (raceproof_create_file(): new function, 2017-01-06) to its only user, refs/files-backend.c. Signed-off-by: Ævar Arnfjörð Bjarmason --- cache.h | 43 ----------------- object-file.c | 68 --------------------------- refs/files-backend.c | 109 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 111 deletions(-) diff --git a/cache.h b/cache.h index bd4869beee4..1e838303654 100644 --- a/cache.h +++ b/cache.h @@ -1211,49 +1211,6 @@ enum scld_error safe_create_leading_directories(char *path); enum scld_error safe_create_leading_directories_const(const char *path); enum scld_error safe_create_leading_directories_no_share(char *path); -/* - * Callback function for raceproof_create_file(). This function is - * expected to do something that makes dirname(path) permanent despite - * the fact that other processes might be cleaning up empty - * directories at the same time. Usually it will create a file named - * path, but alternatively it could create another file in that - * directory, or even chdir() into that directory. The function should - * return 0 if the action was completed successfully. On error, it - * should return a nonzero result and set errno. - * raceproof_create_file() treats two errno values specially: - * - * - ENOENT -- dirname(path) does not exist. In this case, - * raceproof_create_file() tries creating dirname(path) - * (and any parent directories, if necessary) and calls - * the function again. - * - * - EISDIR -- the file already exists and is a directory. In this - * case, raceproof_create_file() removes the directory if - * it is empty (and recursively any empty directories that - * it contains) and calls the function again. - * - * Any other errno causes raceproof_create_file() to fail with the - * callback's return value and errno. - * - * Obviously, this function should be OK with being called again if it - * fails with ENOENT or EISDIR. In other scenarios it will not be - * called again. - */ -typedef int create_file_fn(const char *path, void *cb); - -/* - * Create a file in dirname(path) by calling fn, creating leading - * directories if necessary. Retry a few times in case we are racing - * with another process that is trying to clean up the directory that - * contains path. See the documentation for create_file_fn for more - * details. - * - * Return the value and set the errno that resulted from the most - * recent call of fn. fn is always called at least once, and will be - * called more than once if it returns ENOENT or EISDIR. - */ -int raceproof_create_file(const char *path, create_file_fn fn, void *cb); - int mkdir_in_gitdir(const char *path); char *expand_user_path(const char *path, int real_home); const char *enter_repo(const char *path, int strict); diff --git a/object-file.c b/object-file.c index a8be8994814..9b318eecb19 100644 --- a/object-file.c +++ b/object-file.c @@ -414,74 +414,6 @@ enum scld_error safe_create_leading_directories_const(const char *path) return result; } -int raceproof_create_file(const char *path, create_file_fn fn, void *cb) -{ - /* - * The number of times we will try to remove empty directories - * in the way of path. This is only 1 because if another - * process is racily creating directories that conflict with - * us, we don't want to fight against them. - */ - int remove_directories_remaining = 1; - - /* - * The number of times that we will try to create the - * directories containing path. We are willing to attempt this - * more than once, because another process could be trying to - * clean up empty directories at the same time as we are - * trying to create them. - */ - int create_directories_remaining = 3; - - /* A scratch copy of path, filled lazily if we need it: */ - struct strbuf path_copy = STRBUF_INIT; - - int ret, save_errno; - - /* Sanity check: */ - assert(*path); - -retry_fn: - ret = fn(path, cb); - save_errno = errno; - if (!ret) - goto out; - - if (errno == EISDIR && remove_directories_remaining-- > 0) { - /* - * A directory is in the way. Maybe it is empty; try - * to remove it: - */ - if (!path_copy.len) - strbuf_addstr(&path_copy, path); - - if (!remove_dir_recursively(&path_copy, REMOVE_DIR_EMPTY_ONLY)) - goto retry_fn; - } else if (errno == ENOENT && create_directories_remaining-- > 0) { - /* - * Maybe the containing directory didn't exist, or - * maybe it was just deleted by a process that is - * racing with us to clean up empty directories. Try - * to create it: - */ - enum scld_error scld_result; - - if (!path_copy.len) - strbuf_addstr(&path_copy, path); - - do { - scld_result = safe_create_leading_directories(path_copy.buf); - if (scld_result == SCLD_OK) - goto retry_fn; - } while (scld_result == SCLD_VANISHED && create_directories_remaining-- > 0); - } - -out: - strbuf_release(&path_copy); - errno = save_errno; - return ret; -} - static void fill_loose_path(struct strbuf *buf, const struct object_id *oid) { int i; diff --git a/refs/files-backend.c b/refs/files-backend.c index ab666af4b75..950f9738ae0 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -852,6 +852,115 @@ static struct ref_iterator *files_ref_iterator_begin( return ref_iterator; } +/* + * Callback function for raceproof_create_file(). This function is + * expected to do something that makes dirname(path) permanent despite + * the fact that other processes might be cleaning up empty + * directories at the same time. Usually it will create a file named + * path, but alternatively it could create another file in that + * directory, or even chdir() into that directory. The function should + * return 0 if the action was completed successfully. On error, it + * should return a nonzero result and set errno. + * raceproof_create_file() treats two errno values specially: + * + * - ENOENT -- dirname(path) does not exist. In this case, + * raceproof_create_file() tries creating dirname(path) + * (and any parent directories, if necessary) and calls + * the function again. + * + * - EISDIR -- the file already exists and is a directory. In this + * case, raceproof_create_file() removes the directory if + * it is empty (and recursively any empty directories that + * it contains) and calls the function again. + * + * Any other errno causes raceproof_create_file() to fail with the + * callback's return value and errno. + * + * Obviously, this function should be OK with being called again if it + * fails with ENOENT or EISDIR. In other scenarios it will not be + * called again. + */ +typedef int create_file_fn(const char *path, void *cb); + +/* + * Create a file in dirname(path) by calling fn, creating leading + * directories if necessary. Retry a few times in case we are racing + * with another process that is trying to clean up the directory that + * contains path. See the documentation for create_file_fn for more + * details. + * + * Return the value and set the errno that resulted from the most + * recent call of fn. fn is always called at least once, and will be + * called more than once if it returns ENOENT or EISDIR. + */ +static int raceproof_create_file(const char *path, create_file_fn fn, void *cb) +{ + /* + * The number of times we will try to remove empty directories + * in the way of path. This is only 1 because if another + * process is racily creating directories that conflict with + * us, we don't want to fight against them. + */ + int remove_directories_remaining = 1; + + /* + * The number of times that we will try to create the + * directories containing path. We are willing to attempt this + * more than once, because another process could be trying to + * clean up empty directories at the same time as we are + * trying to create them. + */ + int create_directories_remaining = 3; + + /* A scratch copy of path, filled lazily if we need it: */ + struct strbuf path_copy = STRBUF_INIT; + + int ret, save_errno; + + /* Sanity check: */ + assert(*path); + +retry_fn: + ret = fn(path, cb); + save_errno = errno; + if (!ret) + goto out; + + if (errno == EISDIR && remove_directories_remaining-- > 0) { + /* + * A directory is in the way. Maybe it is empty; try + * to remove it: + */ + if (!path_copy.len) + strbuf_addstr(&path_copy, path); + + if (!remove_dir_recursively(&path_copy, REMOVE_DIR_EMPTY_ONLY)) + goto retry_fn; + } else if (errno == ENOENT && create_directories_remaining-- > 0) { + /* + * Maybe the containing directory didn't exist, or + * maybe it was just deleted by a process that is + * racing with us to clean up empty directories. Try + * to create it: + */ + enum scld_error scld_result; + + if (!path_copy.len) + strbuf_addstr(&path_copy, path); + + do { + scld_result = safe_create_leading_directories(path_copy.buf); + if (scld_result == SCLD_OK) + goto retry_fn; + } while (scld_result == SCLD_VANISHED && create_directories_remaining-- > 0); + } + +out: + strbuf_release(&path_copy); + errno = save_errno; + return ret; +} + static int remove_empty_directories(struct strbuf *path) { /* From patchwork Mon Aug 23 11:52:38 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBCamFybWFzb24=?= X-Patchwork-Id: 12452535 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 93C97C432BE for ; Mon, 23 Aug 2021 11:52:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7E1756138E for ; Mon, 23 Aug 2021 11:52:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236722AbhHWLxj (ORCPT ); Mon, 23 Aug 2021 07:53:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50468 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235953AbhHWLxi (ORCPT ); Mon, 23 Aug 2021 07:53:38 -0400 Received: from mail-wr1-x430.google.com (mail-wr1-x430.google.com [IPv6:2a00:1450:4864:20::430]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 91299C061575 for ; Mon, 23 Aug 2021 04:52:55 -0700 (PDT) Received: by mail-wr1-x430.google.com with SMTP id k8so25870988wrn.3 for ; Mon, 23 Aug 2021 04:52:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Use2JGkvk4kFUYGomJpJTzQpUhppHR9ErwMc67NdoP4=; b=Xtvb73rQvEs/Hy/SvR4F10JTvRp4q3BgXLvqNBqeYHNuawpk3JUYH9SPgYFwXla/9+ CD+TJuKRa0bBNhBv5xqBkPVsGjURd4gWBoUcjpsZl1+z6ZKwbp04kdwfXWJbOR7xHydj 3aKnisN8wT28gjvnsqAgLD4SZH4DKfUjRw5JKqwnkpUh8wQkwnQUh6Ig1psiv2K22y0L 5Ilwjl4HlCqKNgD8I9MbP/sa9KA2VFCe6Q4Wju44xjPWSQ8NJqJlIz0SNCUfug1OmW4E 5UYYBAZdNUHAPAiNQY6gJE64Lyg5n9QQAADQH2Foe0y9Tt+/8mbzvCERysMEX6v1JnDW Ovdg== 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=Use2JGkvk4kFUYGomJpJTzQpUhppHR9ErwMc67NdoP4=; b=lLMaxv2/Y1d+WiQJYZ0UX7+YHmqypODaik48ZpODeYSSFUnv1hKfrTdulkUEURo/Na TYe0rPYzfVVox42fvEldN1DtbWwNllEyzH4f022W0moRptnPunbdWrS/AOMpWqAKAzYw r3OhjCVRxQl3EAbNdzRPBISSXs+2etShhpfw3WFMZs6GGeKXs3HUIaRM0J/DI7vlcile kKH1nqVLX3iecaX1B4xrHgskHoJ498udPxEsctLhxDRvGI6/dhzsa4WyROHgDxeC0EY2 x+OjcmjNQV1VEiRxLRBRbEe0cxtfeIUJsSzb9IeG+pFq0FjGB7oiJgjfU77jqqSxiXHs qFiA== X-Gm-Message-State: AOAM531QDIGXyoSsuwnWVWKEx3N+iceIMIvPCNzK3cHf9+BGUl9Uj+5k Mdp0O4d7tCp1/IMyH3tPq8k/Y7CJ7BTSCjNe X-Google-Smtp-Source: ABdhPJzDgsNqaF+/thd4dt9jlCcZhIZnwosNqMCr34hEpLqy+38DZfk1m+vF6Rdgdh6e7A3ZzkDEfA== X-Received: by 2002:adf:f0c2:: with SMTP id x2mr12874579wro.107.1629719574005; Mon, 23 Aug 2021 04:52:54 -0700 (PDT) Received: from vm.nix.is (vm.nix.is. [2a01:4f8:120:2468::2]) by smtp.gmail.com with ESMTPSA id l2sm12350713wmi.1.2021.08.23.04.52.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Aug 2021 04:52:53 -0700 (PDT) From: =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBCamFybWFzb24=?= To: git@vger.kernel.org Cc: Junio C Hamano , Jeff King , Han-Wen Nienhuys , Michael Haggerty , Jonathan Tan , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBC?= =?utf-8?b?amFybWFzb24=?= Subject: [PATCH v10 2/8] refs: remove EINVAL errno output from specification of read_raw_ref_fn Date: Mon, 23 Aug 2021 13:52:38 +0200 Message-Id: X-Mailer: git-send-email 2.33.0.662.g438caf9576d In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Han-Wen Nienhuys This commit does not change code; it documents the fact that an alternate ref backend does not need to return EINVAL from read_raw_ref_fn to function properly. This is correct, because refs_read_raw_ref is only called from; * resolve_ref_unsafe(), which does not care for the EINVAL errno result. * refs_verify_refname_available(), which does not inspect errno. * files-backend.c, where errno is overwritten on failure. * packed-backend.c (is_packed_transaction_needed), which calls it for the packed ref backend, which never emits EINVAL. A grep for EINVAL */*c reveals that no code checks errno against EINVAL after reading references. In addition, the refs.h file does not mention errno at all. A grep over resolve_ref_unsafe() turned up the following callers that inspect errno: * sequencer.c::print_commit_summary, which uses it for die_errno * lock_ref_oid_basic(), which only treats EISDIR and ENOTDIR specially. The files ref backend does use EINVAL. The files backend does not call into the generic API (refs_read_raw), but into the files-specific function (files_read_raw_ref), which we are not changing in this commit. As the errno sideband is unintuitive and error-prone, remove EINVAL value, as a step towards getting rid of the errno sideband altogether. Spotted by Ævar Arnfjörð Bjarmason . Signed-off-by: Han-Wen Nienhuys Signed-off-by: Ævar Arnfjörð Bjarmason --- refs/refs-internal.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/refs/refs-internal.h b/refs/refs-internal.h index d496c5ed52d..1c6e5ab51d7 100644 --- a/refs/refs-internal.h +++ b/refs/refs-internal.h @@ -622,9 +622,9 @@ typedef int reflog_expire_fn(struct ref_store *ref_store, * * Return 0 on success. If the ref doesn't exist, set errno to ENOENT * and return -1. If the ref exists but is neither a symbolic ref nor - * an object ID, it is broken; set REF_ISBROKEN in type, set errno to - * EINVAL, and return -1. If there is another error reading the ref, - * set errno appropriately and return -1. + * an object ID, it is broken; set REF_ISBROKEN in type, and return -1 + * (errno should not be ENOENT) If there is another error reading the + * ref, set errno appropriately and return -1. * * Backend-specific flags might be set in type as well, regardless of * outcome. From patchwork Mon Aug 23 11:52:39 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBCamFybWFzb24=?= X-Patchwork-Id: 12452537 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 13952C4338F for ; Mon, 23 Aug 2021 11:53:06 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E849661357 for ; Mon, 23 Aug 2021 11:53:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236723AbhHWLxr (ORCPT ); Mon, 23 Aug 2021 07:53:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50476 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236719AbhHWLxi (ORCPT ); Mon, 23 Aug 2021 07:53:38 -0400 Received: from mail-wr1-x431.google.com (mail-wr1-x431.google.com [IPv6:2a00:1450:4864:20::431]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 54F8AC061764 for ; Mon, 23 Aug 2021 04:52:56 -0700 (PDT) Received: by mail-wr1-x431.google.com with SMTP id k8so25871050wrn.3 for ; Mon, 23 Aug 2021 04:52:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=AZY23QlS7LS9bzKtlJLI+hejPzLCrRa8/I1X5G/vTR0=; b=E56p82gTam7vEQYu46EkS6m+5M2toFZh0Tt4x8WSoMln5WQUQu8HclI4c9MNZpnvWT HSUA312aSaWLqpUoCsIvVmdV7jPI3U4z4v0SJofEQItHGg2L/8SL/URr8xBpDYI7tvNS 52f1OSRt2dOkKxjoRDg5lNjr8XNO4Os4s70Xt3wAwf1drlzEcrhJKLMHUNyNhYzxEuqF AVhTJibiQNv8JdZhtqdclnd9qps9repomaWMs6JV7fk7q3JKJAcw5JrJCsAURWXoUVQJ QS549gVaU0ECob69sBkbB764xOraH+wrDzfUZD2ixvfm1XRKMNuYtYx2C0up9d62Yhm+ aCxg== 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=AZY23QlS7LS9bzKtlJLI+hejPzLCrRa8/I1X5G/vTR0=; b=klwKV098uf+Rt0pi6UzZmAbEVccT8US5EqTRPkGzZDbi1zpb5ZTz/hudt5epXS5O5H nud0xSGdDTA4igVC9huwDtuphjNHQQAMVdKOilLgLUtwUGnIQ74irrUX73p1teS1EFM8 buHO1CftpXkN2tPgzKSfLNvd56mTuRuoNNuiQo08MbF0588prO750m8o2wiUUzTcUj5K ZrrdGNBzyG2Ua/OHSuftMf9ATnzlbonXx0vNnM2iZUuiRqFkhwNboS6yFjq9EbRfLOEA pk/7rcnvLWuzaGMSiAcs9H2UWjtgLqFEOtGa46kY+tlYZEFy+lkQDpDL5Co/uaxotN/o kDeQ== X-Gm-Message-State: AOAM5312/VyyUauVK38h77Cim1jGadbJIg6Zx8ZFJ0L3BoMGvJpNW7Ab FF23KNLMBi1dazZA0NoCE1q131fOYT801nh5 X-Google-Smtp-Source: ABdhPJwDP/fvSjb/ZpuAt3jAEpaqPEwesRVLhfG0z40q4/m5WsYWo/KvIkz5auCyN7dGLcssblZIMQ== X-Received: by 2002:a05:6000:1091:: with SMTP id y17mr12834725wrw.202.1629719574705; Mon, 23 Aug 2021 04:52:54 -0700 (PDT) Received: from vm.nix.is (vm.nix.is. [2a01:4f8:120:2468::2]) by smtp.gmail.com with ESMTPSA id l2sm12350713wmi.1.2021.08.23.04.52.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Aug 2021 04:52:54 -0700 (PDT) From: =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBCamFybWFzb24=?= To: git@vger.kernel.org Cc: Junio C Hamano , Jeff King , Han-Wen Nienhuys , Michael Haggerty , Jonathan Tan , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBC?= =?utf-8?b?amFybWFzb24=?= Subject: [PATCH v10 3/8] refs/files-backend: stop setting errno from lock_ref_oid_basic Date: Mon, 23 Aug 2021 13:52:39 +0200 Message-Id: X-Mailer: git-send-email 2.33.0.662.g438caf9576d In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Han-Wen Nienhuys refs/files-backend.c::lock_ref_oid_basic() tries to signal how it failed to its callers using errno. It is safe to stop setting errno here, because the callers of this file-scope static function are * files_copy_or_rename_ref() * files_create_symref() * files_reflog_expire() None of them looks at errno after seeing a negative return from lock_ref_oid_basic() to make any decision, and no caller of these three functions looks at errno after they signal a failure by returning a negative value. In particular, * files_copy_or_rename_ref() - here, calls are followed by error() (which performs I/O) or write_ref_to_lockfile() (which calls parse_object() which may perform I/O) * files_create_symref() - here, calls are followed by error() or create_symref_locked() (which performs I/O and does not inspect errno) * files_reflog_expire() - here, calls are followed by error() or refs_reflog_exists() (which calls a function in a vtable that is not documented to use and/or preserve errno) Signed-off-by: Han-Wen Nienhuys Signed-off-by: Ævar Arnfjörð Bjarmason --- refs/files-backend.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/refs/files-backend.c b/refs/files-backend.c index 950f9738ae0..c1794dcd295 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -982,7 +982,6 @@ static int create_reflock(const char *path, void *cb) /* * Locks a ref returning the lock on success and NULL on failure. - * On failure errno is set to something meaningful. */ static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs, const char *refname, int *type, @@ -990,7 +989,6 @@ static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs, { struct strbuf ref_file = STRBUF_INIT; struct ref_lock *lock; - int last_errno = 0; files_assert_main_repository(refs, "lock_ref_oid_basic"); assert(err); @@ -1001,11 +999,10 @@ static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs, if (!refs_resolve_ref_unsafe(&refs->base, refname, RESOLVE_REF_NO_RECURSE, &lock->old_oid, type)) { - last_errno = errno; if (!refs_verify_refname_available(&refs->base, refname, NULL, NULL, err)) strbuf_addf(err, "unable to resolve reference '%s': %s", - refname, strerror(last_errno)); + refname, strerror(errno)); goto error_return; } @@ -1018,15 +1015,12 @@ static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs, */ if (is_null_oid(&lock->old_oid) && refs_verify_refname_available(refs->packed_ref_store, refname, - NULL, NULL, err)) { - last_errno = ENOTDIR; + NULL, NULL, err)) goto error_return; - } lock->ref_name = xstrdup(refname); if (raceproof_create_file(ref_file.buf, create_reflock, &lock->lk)) { - last_errno = errno; unable_to_lock_message(ref_file.buf, errno, err); goto error_return; } @@ -1043,7 +1037,6 @@ static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs, out: strbuf_release(&ref_file); - errno = last_errno; return lock; } From patchwork Mon Aug 23 11:52:40 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBCamFybWFzb24=?= X-Patchwork-Id: 12452539 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7BE40C4320A for ; Mon, 23 Aug 2021 11:53:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 57B836138B for ; Mon, 23 Aug 2021 11:53:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236753AbhHWLxs (ORCPT ); Mon, 23 Aug 2021 07:53:48 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50482 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236721AbhHWLxj (ORCPT ); Mon, 23 Aug 2021 07:53:39 -0400 Received: from mail-wm1-x333.google.com (mail-wm1-x333.google.com [IPv6:2a00:1450:4864:20::333]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1E7B3C061575 for ; Mon, 23 Aug 2021 04:52:57 -0700 (PDT) Received: by mail-wm1-x333.google.com with SMTP id c8-20020a7bc008000000b002e6e462e95fso13878901wmb.2 for ; Mon, 23 Aug 2021 04:52:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=3KGv/CZA0aM+NRA2r4BkZ1AEGk8QGHQAt1yd6kQ5Ha0=; b=nNvksbJLgtDsIKctRGYazUOc8wQjllF6MIaKvOsXPunLI8RGcN0oH+hqd1Z+RGtRCP Af8E//z3h/LKeij/iHJ5NwSLBmq6aDbzLnW6CPHhf9e2LNiZbbLyqztVvT9bLVeWKb3z wLw4WoiFjZspWQsfeVlO7QBOYe0f8ZqYS6Cc9h2fzcVWNthMZJChI5Ixn8JMZWVUPE0D 43Nb3mZPyPwj9Wojfsz3xvQLhp8qMo6I2EFX175BRf6Fd2Oi13dziFOJ1VyYqIcDWGwx B/G1vfUcK++QXD+MjJuEoSXp3bfaxQyDqYlNhJhm/9A0Gaj5CcnTlxBsPlaAapclsNVW 3Guw== 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=3KGv/CZA0aM+NRA2r4BkZ1AEGk8QGHQAt1yd6kQ5Ha0=; b=NMFA95UBrE1W9T/VRVsiurzOuyy93UlG5Mlr1S/2L+0gP4O/W50VhvV2otccOavhsm Kt9QiO/B0hHdet2BBt1WLgurczmaph72A7gW1iSWlUo1LzSnT6JnNuDblWxaZTDuDOyh Nw6zrLvBc0fZzGUC+njztBKi4U7ovpdA/Ng7lkW57/PHA86BAq4b7ZN3+DSk9jfjs+L2 P1fOphWMkPWTyw9M35uWFyw15Pp3PV6XLCoKJ7a3E1VztuwMhFkLTgLvy6GSiENUU/Ty RqW4UcVAPMhVJ6Hg6jCx1TfbBJNb3+fxsdqC4fhamXrOLTh9FS00jAGwceuTMlJvzb/E 3viw== X-Gm-Message-State: AOAM533RWMO9dSHFNm1kAmM7qJNDTcjY4EW08u0siryLhlGiEk6l28GR TVWEKKhC/bqLy0XErMJddtIjwKlItahrn/bH X-Google-Smtp-Source: ABdhPJwDmI/mxSV4iwAi7lPsM/qXKPJ1z60VLDsB2E8u3m2dx37fuWRk9NIKKjErk2nal7N2Fa+J/A== X-Received: by 2002:a05:600c:6c5:: with SMTP id b5mr5934185wmn.70.1629719575454; Mon, 23 Aug 2021 04:52:55 -0700 (PDT) Received: from vm.nix.is (vm.nix.is. [2a01:4f8:120:2468::2]) by smtp.gmail.com with ESMTPSA id l2sm12350713wmi.1.2021.08.23.04.52.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Aug 2021 04:52:54 -0700 (PDT) From: =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBCamFybWFzb24=?= To: git@vger.kernel.org Cc: Junio C Hamano , Jeff King , Han-Wen Nienhuys , Michael Haggerty , Jonathan Tan , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBC?= =?utf-8?b?amFybWFzb24=?= Subject: [PATCH v10 4/8] refs: make errno output explicit for read_raw_ref_fn Date: Mon, 23 Aug 2021 13:52:40 +0200 Message-Id: X-Mailer: git-send-email 2.33.0.662.g438caf9576d In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Han-Wen Nienhuys This makes it explicit how alternative ref backends should report errors in read_raw_ref_fn. read_raw_ref_fn needs to supply a credible errno for a number of cases. These are primarily: 1) The files backend calls read_raw_ref from lock_raw_ref, and uses the resulting error codes to create/remove directories as needed. 2) ENOENT should be translated in a zero OID, optionally with REF_ISBROKEN set, returning the last successfully resolved symref. This is necessary so read_raw_ref("HEAD") on an empty repo returns refs/heads/main (or the default branch du-jour), and we know on which branch to create the first commit. Make this information flow explicit by adding a failure_errno to the signature of read_raw_ref. All errnos from the files backend are still propagated unchanged, even though inspection suggests only ENOTDIR, EISDIR and ENOENT are relevant. Signed-off-by: Han-Wen Nienhuys Signed-off-by: Ævar Arnfjörð Bjarmason --- refs.c | 2 +- refs/debug.c | 7 +++---- refs/files-backend.c | 29 +++++++++++++++-------------- refs/packed-backend.c | 8 ++++---- refs/refs-internal.h | 20 ++++++++++++-------- 5 files changed, 35 insertions(+), 31 deletions(-) diff --git a/refs.c b/refs.c index 05944d8e725..da0cc82ca66 100644 --- a/refs.c +++ b/refs.c @@ -1682,7 +1682,7 @@ int refs_read_raw_ref(struct ref_store *ref_store, } return ref_store->be->read_raw_ref(ref_store, refname, oid, referent, - type); + type, &errno); } /* This function needs to return a meaningful errno on failure */ diff --git a/refs/debug.c b/refs/debug.c index bf4a82bccb6..8667c640237 100644 --- a/refs/debug.c +++ b/refs/debug.c @@ -239,15 +239,14 @@ debug_ref_iterator_begin(struct ref_store *ref_store, const char *prefix, static int debug_read_raw_ref(struct ref_store *ref_store, const char *refname, struct object_id *oid, struct strbuf *referent, - unsigned int *type) + unsigned int *type, int *failure_errno) { struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store; int res = 0; oidcpy(oid, null_oid()); - errno = 0; res = drefs->refs->be->read_raw_ref(drefs->refs, refname, oid, referent, - type); + type, failure_errno); if (res == 0) { trace_printf_key(&trace_refs, "read_raw_ref: %s: %s (=> %s) type %x: %d\n", @@ -255,7 +254,7 @@ static int debug_read_raw_ref(struct ref_store *ref_store, const char *refname, } else { trace_printf_key(&trace_refs, "read_raw_ref: %s: %d (errno %d)\n", refname, - res, errno); + res, *failure_errno); } return res; } diff --git a/refs/files-backend.c b/refs/files-backend.c index c1794dcd295..b3de3633969 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -341,9 +341,9 @@ static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs) return refs->loose; } -static int files_read_raw_ref(struct ref_store *ref_store, - const char *refname, struct object_id *oid, - struct strbuf *referent, unsigned int *type) +static int files_read_raw_ref(struct ref_store *ref_store, const char *refname, + struct object_id *oid, struct strbuf *referent, + unsigned int *type, int *failure_errno) { struct files_ref_store *refs = files_downcast(ref_store, REF_STORE_READ, "read_raw_ref"); @@ -354,7 +354,6 @@ static int files_read_raw_ref(struct ref_store *ref_store, struct stat st; int fd; int ret = -1; - int save_errno; int remaining_retries = 3; *type = 0; @@ -459,10 +458,9 @@ static int files_read_raw_ref(struct ref_store *ref_store, ret = parse_loose_ref_contents(buf, oid, referent, type); out: - save_errno = errno; + *failure_errno = errno; strbuf_release(&sb_path); strbuf_release(&sb_contents); - errno = save_errno; return ret; } @@ -540,6 +538,7 @@ static int lock_raw_ref(struct files_ref_store *refs, struct strbuf ref_file = STRBUF_INIT; int attempts_remaining = 3; int ret = TRANSACTION_GENERIC_ERROR; + int failure_errno; assert(err); files_assert_main_repository(refs, "lock_raw_ref"); @@ -610,7 +609,9 @@ static int lock_raw_ref(struct files_ref_store *refs, if (hold_lock_file_for_update_timeout( &lock->lk, ref_file.buf, LOCK_NO_DEREF, get_files_ref_lock_timeout_ms()) < 0) { - if (errno == ENOENT && --attempts_remaining > 0) { + int myerr = errno; + errno = 0; + if (myerr == ENOENT && --attempts_remaining > 0) { /* * Maybe somebody just deleted one of the * directories leading to ref_file. Try @@ -618,7 +619,7 @@ static int lock_raw_ref(struct files_ref_store *refs, */ goto retry; } else { - unable_to_lock_message(ref_file.buf, errno, err); + unable_to_lock_message(ref_file.buf, myerr, err); goto error_return; } } @@ -628,9 +629,9 @@ static int lock_raw_ref(struct files_ref_store *refs, * fear that its value will change. */ - if (files_read_raw_ref(&refs->base, refname, - &lock->old_oid, referent, type)) { - if (errno == ENOENT) { + if (files_read_raw_ref(&refs->base, refname, &lock->old_oid, referent, + type, &failure_errno)) { + if (failure_errno == ENOENT) { if (mustexist) { /* Garden variety missing reference. */ strbuf_addf(err, "unable to resolve reference '%s'", @@ -654,7 +655,7 @@ static int lock_raw_ref(struct files_ref_store *refs, * reference named "refs/foo/bar/baz". */ } - } else if (errno == EISDIR) { + } else if (failure_errno == EISDIR) { /* * There is a directory in the way. It might have * contained references that have been deleted. If @@ -692,13 +693,13 @@ static int lock_raw_ref(struct files_ref_store *refs, goto error_return; } } - } else if (errno == EINVAL && (*type & REF_ISBROKEN)) { + } else if (failure_errno == EINVAL && (*type & REF_ISBROKEN)) { strbuf_addf(err, "unable to resolve reference '%s': " "reference broken", refname); goto error_return; } else { strbuf_addf(err, "unable to resolve reference '%s': %s", - refname, strerror(errno)); + refname, strerror(failure_errno)); goto error_return; } diff --git a/refs/packed-backend.c b/refs/packed-backend.c index 65ba4214b8d..47247a14917 100644 --- a/refs/packed-backend.c +++ b/refs/packed-backend.c @@ -724,9 +724,9 @@ static struct snapshot *get_snapshot(struct packed_ref_store *refs) return refs->snapshot; } -static int packed_read_raw_ref(struct ref_store *ref_store, - const char *refname, struct object_id *oid, - struct strbuf *referent, unsigned int *type) +static int packed_read_raw_ref(struct ref_store *ref_store, const char *refname, + struct object_id *oid, struct strbuf *referent, + unsigned int *type, int *failure_errno) { struct packed_ref_store *refs = packed_downcast(ref_store, REF_STORE_READ, "read_raw_ref"); @@ -739,7 +739,7 @@ static int packed_read_raw_ref(struct ref_store *ref_store, if (!rec) { /* refname is not a packed reference. */ - errno = ENOENT; + *failure_errno = ENOENT; return -1; } diff --git a/refs/refs-internal.h b/refs/refs-internal.h index 1c6e5ab51d7..ddd6d7f8ebd 100644 --- a/refs/refs-internal.h +++ b/refs/refs-internal.h @@ -620,11 +620,15 @@ typedef int reflog_expire_fn(struct ref_store *ref_store, * properly-formatted or even safe reference name. NEITHER INPUT NOR * OUTPUT REFERENCE NAMES ARE VALIDATED WITHIN THIS FUNCTION. * - * Return 0 on success. If the ref doesn't exist, set errno to ENOENT - * and return -1. If the ref exists but is neither a symbolic ref nor - * an object ID, it is broken; set REF_ISBROKEN in type, and return -1 - * (errno should not be ENOENT) If there is another error reading the - * ref, set errno appropriately and return -1. + * Return 0 on success, or -1 on failure. If the ref exists but is neither a + * symbolic ref nor an object ID, it is broken. In this case set REF_ISBROKEN in + * type, and return -1 (failure_errno should not be ENOENT) + * + * failure_errno provides errno codes that are interpreted beyond error + * reporting. The following error codes have special meaning: + * * ENOENT: the ref doesn't exist + * * EISDIR: ref name is a directory + * * ENOTDIR: ref prefix is not a directory * * Backend-specific flags might be set in type as well, regardless of * outcome. @@ -638,9 +642,9 @@ typedef int reflog_expire_fn(struct ref_store *ref_store, * - in all other cases, referent will be untouched, and therefore * refname will still be valid and unchanged. */ -typedef int read_raw_ref_fn(struct ref_store *ref_store, - const char *refname, struct object_id *oid, - struct strbuf *referent, unsigned int *type); +typedef int read_raw_ref_fn(struct ref_store *ref_store, const char *refname, + struct object_id *oid, struct strbuf *referent, + unsigned int *type, int *failure_errno); struct ref_storage_be { struct ref_storage_be *next; From patchwork Mon Aug 23 11:52:41 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBCamFybWFzb24=?= X-Patchwork-Id: 12452541 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 792C2C432BE for ; Mon, 23 Aug 2021 11:53:08 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5BFA96138B for ; Mon, 23 Aug 2021 11:53:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236777AbhHWLxt (ORCPT ); Mon, 23 Aug 2021 07:53:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50486 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235953AbhHWLxk (ORCPT ); Mon, 23 Aug 2021 07:53:40 -0400 Received: from mail-wr1-x429.google.com (mail-wr1-x429.google.com [IPv6:2a00:1450:4864:20::429]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D5F7EC061757 for ; Mon, 23 Aug 2021 04:52:57 -0700 (PDT) Received: by mail-wr1-x429.google.com with SMTP id i6so2117556wrv.2 for ; Mon, 23 Aug 2021 04:52:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=lf7zgcG9atqJliFE2QfHCXLCjkFtyRS61xXO/OaXndg=; b=uLhYpz/jbEueKebQDPJSxMapuun6Qq6aNiI+3dGLD5dLwD2fqI5SsxwepRNb/t3qzl PYyPUIFf1pRCPVIrIRlXyS1BxkkUPI6ECOwO2paUpmwD+Uca4QWY4hOEa/OdCq7L7c1x 6+B43us9l4dOsay0FqC+POyyysMsGFj5elMtSnfNt4bCYYGxPBj4Zumo4cM0segNkyMy 44PZFy1rUzFGA18feoOrJVeIO0l11Ppv0q0lZ3GLC5fB3UUNbBG17fvzPnT3IUevXtw0 A0scaKQRbliOpD+jZGEdkd0KeHBznKHCgkXWnwasU4MfkuCI2Ae6XRl3i8Mz2hDkDj1A G9Aw== 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=lf7zgcG9atqJliFE2QfHCXLCjkFtyRS61xXO/OaXndg=; b=hYAJ5iwnrEOjEGD0wBRhUJQu/bERChfIL7/5Z+zYzbYFEl5zmO3zZuSFTFnY+LYwFe kzJd+s36FloFmFXtH2SRbwYCIPt6LY/edXG8VjGEdq6tOY48rst5aBaWCfmSz5v7Lq+v dOBcIa71/TqPcGYISPhFwbrRmH7kE+yzsPpTlznkP/hZBgnn00yYg9pYwFYs5cwMbWxv KjtIPErJDCXuqgWbhXGLDm+YXCcGpFEQXxR7EdaomhQWd4VKmj5PuUl8CPsBPftnqoeJ /VllIaw6mdVB8MuS/0lZanEzwhY/9gC92vFzDeFS3/nBlEXqYFm6G1Kd7NG4yP5GG3hF Rq0Q== X-Gm-Message-State: AOAM532BpB/bYQYudIE5T+u3o9Pp81+f2d4Y+U70EBWJXUvbhbZsUjM6 bWPEgyO8RwiFzule+FT09zxuuJf80PS/KVJ/ X-Google-Smtp-Source: ABdhPJwfwqtczHEcUdneVw8YbTJ270ChcZtoH6zp6xw8S1J8VfqW41p+/ySKaSUm/2VyCuvv6qX14Q== X-Received: by 2002:adf:dd11:: with SMTP id a17mr13054960wrm.132.1629719576230; Mon, 23 Aug 2021 04:52:56 -0700 (PDT) Received: from vm.nix.is (vm.nix.is. [2a01:4f8:120:2468::2]) by smtp.gmail.com with ESMTPSA id l2sm12350713wmi.1.2021.08.23.04.52.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Aug 2021 04:52:55 -0700 (PDT) From: =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBCamFybWFzb24=?= To: git@vger.kernel.org Cc: Junio C Hamano , Jeff King , Han-Wen Nienhuys , Michael Haggerty , Jonathan Tan , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBC?= =?utf-8?b?amFybWFzb24=?= Subject: [PATCH v10 5/8] refs: add failure_errno to refs_read_raw_ref() signature Date: Mon, 23 Aug 2021 13:52:41 +0200 Message-Id: X-Mailer: git-send-email 2.33.0.662.g438caf9576d In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Han-Wen Nienhuys This lets us use the explicit errno output parameter in refs_resolve_ref_unsafe. Some of our callers explicitly do not care about the errno, rather than understanding NULL let's have them declare that they don't care by passing in an "ignore_errno". There's only three of them, and using that pattern will make it more obvious that they want to throw away data, let's also add a comment to one of the callers about why we'd like to ignore the errno. Let's not extend that to refs_resolve_ref_unsafe() itself for now, it has a large set of legacy callers, so we're faking up the old "errno" behavior for it. We can convert those callers to refs_resolve_ref_unsafe_with_errno() later. We are leaving out out the refs_read_special_head() in refs_read_raw_ref() for now, as noted in the next commit moving it to "failure_errno" will require some special consideration. We're intentionally mis-indenting the argument list of the new refs_resolve_ref_unsafe_with_errno(), it will be non-static in a subsequent commit, doing it this way makes that diff smaller. Signed-off-by: Han-Wen Nienhuys Signed-off-by: Ævar Arnfjörð Bjarmason --- refs.c | 61 ++++++++++++++++++++++++++++++------------- refs/files-backend.c | 10 ++++--- refs/packed-backend.c | 7 ++--- refs/refs-internal.h | 6 ++--- 4 files changed, 56 insertions(+), 28 deletions(-) diff --git a/refs.c b/refs.c index da0cc82ca66..4c782fa2978 100644 --- a/refs.c +++ b/refs.c @@ -1672,30 +1672,33 @@ static int refs_read_special_head(struct ref_store *ref_store, return result; } -int refs_read_raw_ref(struct ref_store *ref_store, - const char *refname, struct object_id *oid, - struct strbuf *referent, unsigned int *type) +int refs_read_raw_ref(struct ref_store *ref_store, const char *refname, + struct object_id *oid, struct strbuf *referent, + unsigned int *type, int *failure_errno) { + assert(failure_errno); if (!strcmp(refname, "FETCH_HEAD") || !strcmp(refname, "MERGE_HEAD")) { return refs_read_special_head(ref_store, refname, oid, referent, type); } return ref_store->be->read_raw_ref(ref_store, refname, oid, referent, - type, &errno); + type, failure_errno); } -/* This function needs to return a meaningful errno on failure */ -const char *refs_resolve_ref_unsafe(struct ref_store *refs, - const char *refname, - int resolve_flags, - struct object_id *oid, int *flags) +static const char *refs_resolve_ref_unsafe_with_errno(struct ref_store *refs, + const char *refname, + int resolve_flags, + struct object_id *oid, + int *flags, int *failure_errno) { static struct strbuf sb_refname = STRBUF_INIT; struct object_id unused_oid; int unused_flags; int symref_count; + assert(failure_errno); + if (!oid) oid = &unused_oid; if (!flags) @@ -1706,7 +1709,7 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs, if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) { if (!(resolve_flags & RESOLVE_REF_ALLOW_BAD_NAME) || !refname_is_safe(refname)) { - errno = EINVAL; + *failure_errno = EINVAL; return NULL; } @@ -1724,8 +1727,8 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs, for (symref_count = 0; symref_count < SYMREF_MAXDEPTH; symref_count++) { unsigned int read_flags = 0; - if (refs_read_raw_ref(refs, refname, - oid, &sb_refname, &read_flags)) { + if (refs_read_raw_ref(refs, refname, oid, &sb_refname, + &read_flags, failure_errno)) { *flags |= read_flags; /* In reading mode, refs must eventually resolve */ @@ -1737,9 +1740,9 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs, * may show errors besides ENOENT if there are * similarly-named refs. */ - if (errno != ENOENT && - errno != EISDIR && - errno != ENOTDIR) + if (*failure_errno != ENOENT && + *failure_errno != EISDIR && + *failure_errno != ENOTDIR) return NULL; oidclr(oid); @@ -1766,7 +1769,7 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs, if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) { if (!(resolve_flags & RESOLVE_REF_ALLOW_BAD_NAME) || !refname_is_safe(refname)) { - errno = EINVAL; + *failure_errno = EINVAL; return NULL; } @@ -1774,10 +1777,24 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs, } } - errno = ELOOP; + *failure_errno = ELOOP; return NULL; } +const char *refs_resolve_ref_unsafe(struct ref_store *refs, const char *refname, + int resolve_flags, struct object_id *oid, + int *flags) +{ + int failure_errno = 0; + const char *refn; + refn = refs_resolve_ref_unsafe_with_errno(refs, refname, resolve_flags, + oid, flags, &failure_errno); + if (!refn) + /* For unmigrated legacy callers */ + errno = failure_errno; + return refn; +} + /* backend functions */ int refs_init_db(struct strbuf *err) { @@ -2228,6 +2245,13 @@ int refs_verify_refname_available(struct ref_store *refs, strbuf_grow(&dirname, strlen(refname) + 1); for (slash = strchr(refname, '/'); slash; slash = strchr(slash + 1, '/')) { + /* + * Just saying "Is a directory" when we e.g. can't + * lock some multi-level ref isn't very informative, + * the user won't be told *what* is a directory, so + * let's not use strerror() below. + */ + int ignore_errno; /* Expand dirname to the new prefix, not including the trailing slash: */ strbuf_add(&dirname, refname + dirname.len, slash - refname - dirname.len); @@ -2239,7 +2263,8 @@ int refs_verify_refname_available(struct ref_store *refs, if (skip && string_list_has_string(skip, dirname.buf)) continue; - if (!refs_read_raw_ref(refs, dirname.buf, &oid, &referent, &type)) { + if (!refs_read_raw_ref(refs, dirname.buf, &oid, &referent, + &type, &ignore_errno)) { strbuf_addf(err, _("'%s' exists; cannot create '%s'"), dirname.buf, refname); goto cleanup; diff --git a/refs/files-backend.c b/refs/files-backend.c index b3de3633969..f962495e456 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -381,10 +381,11 @@ static int files_read_raw_ref(struct ref_store *ref_store, const char *refname, goto out; if (lstat(path, &st) < 0) { + int ignore_errno; if (errno != ENOENT) goto out; - if (refs_read_raw_ref(refs->packed_ref_store, refname, - oid, referent, type)) { + if (refs_read_raw_ref(refs->packed_ref_store, refname, oid, + referent, type, &ignore_errno)) { errno = ENOENT; goto out; } @@ -418,13 +419,14 @@ static int files_read_raw_ref(struct ref_store *ref_store, const char *refname, /* Is it a directory? */ if (S_ISDIR(st.st_mode)) { + int ignore_errno; /* * Even though there is a directory where the loose * ref is supposed to be, there could still be a * packed ref: */ - if (refs_read_raw_ref(refs->packed_ref_store, refname, - oid, referent, type)) { + if (refs_read_raw_ref(refs->packed_ref_store, refname, oid, + referent, type, &ignore_errno)) { errno = EISDIR; goto out; } diff --git a/refs/packed-backend.c b/refs/packed-backend.c index 47247a14917..52cdc94a26e 100644 --- a/refs/packed-backend.c +++ b/refs/packed-backend.c @@ -1347,6 +1347,7 @@ int is_packed_transaction_needed(struct ref_store *ref_store, ret = 0; for (i = 0; i < transaction->nr; i++) { struct ref_update *update = transaction->updates[i]; + int failure_errno; unsigned int type; struct object_id oid; @@ -1357,9 +1358,9 @@ int is_packed_transaction_needed(struct ref_store *ref_store, */ continue; - if (!refs_read_raw_ref(ref_store, update->refname, - &oid, &referent, &type) || - errno != ENOENT) { + if (!refs_read_raw_ref(ref_store, update->refname, &oid, + &referent, &type, &failure_errno) || + failure_errno != ENOENT) { /* * We have to actually delete that reference * -> this transaction is needed. diff --git a/refs/refs-internal.h b/refs/refs-internal.h index ddd6d7f8ebd..7ade286260c 100644 --- a/refs/refs-internal.h +++ b/refs/refs-internal.h @@ -149,9 +149,9 @@ struct ref_update { const char refname[FLEX_ARRAY]; }; -int refs_read_raw_ref(struct ref_store *ref_store, - const char *refname, struct object_id *oid, - struct strbuf *referent, unsigned int *type); +int refs_read_raw_ref(struct ref_store *ref_store, const char *refname, + struct object_id *oid, struct strbuf *referent, + unsigned int *type, int *failure_errno); /* * Write an error to `err` and return a nonzero value iff the same From patchwork Mon Aug 23 11:52:42 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBCamFybWFzb24=?= X-Patchwork-Id: 12452543 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1E06AC4338F for ; Mon, 23 Aug 2021 11:53:10 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id F1A026138B for ; Mon, 23 Aug 2021 11:53:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236788AbhHWLxu (ORCPT ); Mon, 23 Aug 2021 07:53:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50492 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236735AbhHWLxl (ORCPT ); Mon, 23 Aug 2021 07:53:41 -0400 Received: from mail-wm1-x331.google.com (mail-wm1-x331.google.com [IPv6:2a00:1450:4864:20::331]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A54BFC0613C1 for ; Mon, 23 Aug 2021 04:52:58 -0700 (PDT) Received: by mail-wm1-x331.google.com with SMTP id c129-20020a1c35870000b02902e6b6135279so10583700wma.0 for ; Mon, 23 Aug 2021 04:52:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=S4gcPPuG2g0togwK1CRtX5RPklILwP9gyGXZqErg0iA=; b=J1z5gv34icqM7Gb8iDaLoEwrmv5Z1va3bZTgTpe/wy6glyxaxsXkhlHxn/3MMfQqjl mO+IiyT1UpybZy/Yds/D9RPaOLAlY/dtAME87P2Jcl3tNvNDP8kALkELFbqKZmuE7TEG RQrrHtwbb5adIoSKTawgIM4lPilmG7srcPYwuXvvyvzPkUKpGr8aT0wCZIS5c7je2cJ6 zl3KJDrzBKqRgg1m1kHHqVrPmP8WVTVjIgrBHtH5fKu/DAhBEIvLy/4ZceQQnDv6Oki4 wMqFWKrpX0K3I29uMcTEGbGaewgks7WUPNUMxnl+P3oTSDu/XCl01jCrYX/h7rYb2cRs BEIA== 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=S4gcPPuG2g0togwK1CRtX5RPklILwP9gyGXZqErg0iA=; b=SQAaoMaTXupTFBR/gsxrI3+yxPZRKNyBZ/TmZbypcjsZkjxxx1wDhcP4cqqPqX+dpx EDDBFCvm0xb/YJH3QVtzzDcOcSWZKgPz+Q2jwviUKmQrC/1Lyibrunqz/1Ct5e1w+xRq izvbvAHxUagjA26EUhqsj3Gka/0OWiQXHjP3iOckIkDouTRYVvTtN9QGNTSHW5StpRhd zXsYS108IwB6qvIGCOllG5e/NkYjgwgDrmI9YkIWYY7OM7GhKmJb7doVKyU2QVBxjol1 7brjoq1onftrLEv2pDSZZhKmodRyR5qtAkLzJpY4bZleWUyhz06/qobwwScgk5POqXUb FX4w== X-Gm-Message-State: AOAM5339xQ7+GeUIrq0IUI1mjVTh3dSljUJly4wStBZHdTx4AO5aZgIa 3bDFosU+TevThyOOSvU/7ii8Kq6VVyUYZCQ0 X-Google-Smtp-Source: ABdhPJy3j1I5YB1jSwvp2wKyVNN+f7cI9ismnR5cKlnXhJb7HIGjhbR3CZJqprCgTy7HjWC50AxhrA== X-Received: by 2002:a05:600c:2e48:: with SMTP id q8mr15466031wmf.38.1629719576979; Mon, 23 Aug 2021 04:52:56 -0700 (PDT) Received: from vm.nix.is (vm.nix.is. [2a01:4f8:120:2468::2]) by smtp.gmail.com with ESMTPSA id l2sm12350713wmi.1.2021.08.23.04.52.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Aug 2021 04:52:56 -0700 (PDT) From: =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBCamFybWFzb24=?= To: git@vger.kernel.org Cc: Junio C Hamano , Jeff King , Han-Wen Nienhuys , Michael Haggerty , Jonathan Tan , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBC?= =?utf-8?b?amFybWFzb24=?= Subject: [PATCH v10 6/8] branch tests: test for errno propagating on failing read Date: Mon, 23 Aug 2021 13:52:42 +0200 Message-Id: X-Mailer: git-send-email 2.33.0.662.g438caf9576d In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Han-Wen Nienhuys Add a test for "git branch" to cover the case where .git/refs is symlinked. To check availability, refs_verify_refname_available() will run refs_read_raw_ref() on each prefix, leading to a read() from .git/refs (which is a directory). It would probably be more robust to re-issue the lstat() as a normal stat(), in which case, we would fall back to the directory case, but for now let's just test for the existing behavior as-is. This test covers a regression in a commit that only ever made it to "next", see [1]. 1. http://lore.kernel.org/git/pull.1068.git.git.1629203489546.gitgitgadget@gmail.com Signed-off-by: Han-Wen Nienhuys Signed-off-by: Ævar Arnfjörð Bjarmason --- t/t3200-branch.sh | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index cc4b10236e2..9fae13c2dea 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -731,6 +731,26 @@ test_expect_success SYMLINKS 'git branch -m u v should fail when the reflog for test_must_fail git branch -m u v ' +test_expect_success SYMLINKS 'git branch -m with symlinked .git/refs' ' + test_when_finished "rm -rf subdir" && + git init subdir && + + ( + cd subdir && + for d in refs objects packed-refs + do + rm -rf .git/$d && + ln -s ../../.git/$d .git/$d + done + ) && + git --git-dir subdir/.git/ branch rename-src && + git rev-parse rename-src >expect && + git --git-dir subdir/.git/ branch -m rename-src rename-dest && + git rev-parse rename-dest >actual && + test_cmp expect actual && + git branch -D rename-dest +' + test_expect_success 'test tracking setup via --track' ' git config remote.local.url . && git config remote.local.fetch refs/heads/*:refs/remotes/local/* && From patchwork Mon Aug 23 11:52:43 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBCamFybWFzb24=?= X-Patchwork-Id: 12452545 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 43C93C4338F for ; Mon, 23 Aug 2021 11:53:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1AE526138E for ; Mon, 23 Aug 2021 11:53:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236802AbhHWLxx (ORCPT ); Mon, 23 Aug 2021 07:53:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50506 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236754AbhHWLxn (ORCPT ); Mon, 23 Aug 2021 07:53:43 -0400 Received: from mail-wr1-x429.google.com (mail-wr1-x429.google.com [IPv6:2a00:1450:4864:20::429]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6AF99C061796 for ; Mon, 23 Aug 2021 04:52:59 -0700 (PDT) Received: by mail-wr1-x429.google.com with SMTP id z4so10253206wrr.6 for ; Mon, 23 Aug 2021 04:52:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=yZU4BYN9oegfLYIv6gT1VoAXcVa2Tk1DqvY95ZR0pQQ=; b=tlMdlbDgHkaoHPykFOVZuNMF1YnkcpIsFImY6tKulCQBwEjGChJGeUVOGt2q1Xg5ZM TbAZ6ccWWRXJdLHEKCCTpm2ecnGE0Jogr7UIeVOHVV+Z7+zrqYxDrOg+6hiaecWqH09v 8KdZE685UV9TgJWjYCm50b2ux3qSzrCjYI/UDLm/zpISfJ/Gqex6Lz4kQajOfqbwHXAN tjImKUsM0I0RaehgoJnCeEtkXgze+2zn4sELOYZ8+IlVspqtRXCM3Iy5xVsacsp0ir2+ +EIYljZfI8AdzqAVC1V99+s1/zlzHbv2A4s07MUxk9qVSM+/WIfXmITCGKNeS7PHU8om fKjg== 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=yZU4BYN9oegfLYIv6gT1VoAXcVa2Tk1DqvY95ZR0pQQ=; b=mdTpo/BRDUYm09/j7GrBPLocLrBh9eJdZ54ROSZ0qDQBSzUBN9AxGmrM1UeHw1qFYz M2IYev/ypvx/A/Gt3rgLPGc9D30rmhbn67UpWkC3TMRYCV5n2H6YF1fODfLZnxXTDHK1 ulpAiTCC7hhxSbGYEvt1mMkFvV7fDbBbDK8F7xzISD9bAKuDXvJ4o5UhreCUoQxUo+7G Urq8MBEnS4GWoLgqZL4No/qLPZHWD0OuwibTLrpGPm3zJlk14Dzi7rFCLgZ/oIDtmwcS NutZNlhuw36rOqtBvUhzIlqXUGJdD5jEov6YvG86/8vP3WWj+FqdUel+SkWw/6Lyy+ar kOOg== X-Gm-Message-State: AOAM531Xv+xxoav7MWqAG++uW2THv2PakwLzQKwzREUWDEPNSK8bTMeP ooDMZZPNASgmm6jrxq+QYkU92ABUfOd6Eivq X-Google-Smtp-Source: ABdhPJzTJ4rJWcWMu+7RN/ggHc12hsA2P/ApBuC2wOKg9okRlMYfrzGr0vKvi2CoeWK8d1lZ321DKA== X-Received: by 2002:adf:d4c7:: with SMTP id w7mr13261183wrk.301.1629719577791; Mon, 23 Aug 2021 04:52:57 -0700 (PDT) Received: from vm.nix.is (vm.nix.is. [2a01:4f8:120:2468::2]) by smtp.gmail.com with ESMTPSA id l2sm12350713wmi.1.2021.08.23.04.52.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Aug 2021 04:52:57 -0700 (PDT) From: =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBCamFybWFzb24=?= To: git@vger.kernel.org Cc: Junio C Hamano , Jeff King , Han-Wen Nienhuys , Michael Haggerty , Jonathan Tan , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBC?= =?utf-8?b?amFybWFzb24=?= Subject: [PATCH v10 7/8] refs: explicitly return failure_errno from parse_loose_ref_contents Date: Mon, 23 Aug 2021 13:52:43 +0200 Message-Id: X-Mailer: git-send-email 2.33.0.662.g438caf9576d In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Han-Wen Nienhuys The EINVAL error from parse_loose_ref_contents is used in files-backend to create a custom error message. In untangling this we discovered a tricky edge case. The refs_read_special_head() function was relying on parse_loose_ref_contents() setting EINVAL. By converting it to use "saved_errno" we can migrate away from "errno" in this part of the code entirely, and do away with an existing "save_errno" pattern, its only purpose was to not clobber the "errno" we previously needed at the end of files_read_raw_ref(). Let's assert that we can do that by not having files_read_raw_ref() itself operate on *failure_errno in addition to passing it on. Instead we'll assert that if we return non-zero we actually do set errno, thus assuring ourselves and callers that they can trust the resulting "failure_errno". Signed-off-by: Han-Wen Nienhuys Signed-off-by: Ævar Arnfjörð Bjarmason --- refs.c | 8 +++++--- refs/files-backend.c | 31 ++++++++++++++++++++----------- refs/refs-internal.h | 6 ++++-- t/t3200-branch.sh | 1 + 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/refs.c b/refs.c index 4c782fa2978..b83fd8c36b3 100644 --- a/refs.c +++ b/refs.c @@ -1654,7 +1654,8 @@ int for_each_fullref_in_prefixes(const char *namespace, static int refs_read_special_head(struct ref_store *ref_store, const char *refname, struct object_id *oid, - struct strbuf *referent, unsigned int *type) + struct strbuf *referent, unsigned int *type, + int *failure_errno) { struct strbuf full_path = STRBUF_INIT; struct strbuf content = STRBUF_INIT; @@ -1664,7 +1665,8 @@ static int refs_read_special_head(struct ref_store *ref_store, if (strbuf_read_file(&content, full_path.buf, 0) < 0) goto done; - result = parse_loose_ref_contents(content.buf, oid, referent, type); + result = parse_loose_ref_contents(content.buf, oid, referent, type, + failure_errno); done: strbuf_release(&full_path); @@ -1679,7 +1681,7 @@ int refs_read_raw_ref(struct ref_store *ref_store, const char *refname, assert(failure_errno); if (!strcmp(refname, "FETCH_HEAD") || !strcmp(refname, "MERGE_HEAD")) { return refs_read_special_head(ref_store, refname, oid, referent, - type); + type, failure_errno); } return ref_store->be->read_raw_ref(ref_store, refname, oid, referent, diff --git a/refs/files-backend.c b/refs/files-backend.c index f962495e456..41efe5352b5 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -355,6 +355,7 @@ static int files_read_raw_ref(struct ref_store *ref_store, const char *refname, int fd; int ret = -1; int remaining_retries = 3; + int myerr = 0; *type = 0; strbuf_reset(&sb_path); @@ -382,11 +383,13 @@ static int files_read_raw_ref(struct ref_store *ref_store, const char *refname, if (lstat(path, &st) < 0) { int ignore_errno; - if (errno != ENOENT) + myerr = errno; + errno = 0; + if (myerr != ENOENT) goto out; if (refs_read_raw_ref(refs->packed_ref_store, refname, oid, referent, type, &ignore_errno)) { - errno = ENOENT; + myerr = ENOENT; goto out; } ret = 0; @@ -397,7 +400,9 @@ static int files_read_raw_ref(struct ref_store *ref_store, const char *refname, if (S_ISLNK(st.st_mode)) { strbuf_reset(&sb_contents); if (strbuf_readlink(&sb_contents, path, st.st_size) < 0) { - if (errno == ENOENT || errno == EINVAL) + myerr = errno; + errno = 0; + if (myerr == ENOENT || myerr == EINVAL) /* inconsistent with lstat; retry */ goto stat_ref; else @@ -427,7 +432,7 @@ static int files_read_raw_ref(struct ref_store *ref_store, const char *refname, */ if (refs_read_raw_ref(refs->packed_ref_store, refname, oid, referent, type, &ignore_errno)) { - errno = EISDIR; + myerr = EISDIR; goto out; } ret = 0; @@ -440,7 +445,8 @@ static int files_read_raw_ref(struct ref_store *ref_store, const char *refname, */ fd = open(path, O_RDONLY); if (fd < 0) { - if (errno == ENOENT && !S_ISLNK(st.st_mode)) + myerr = errno; + if (myerr == ENOENT && !S_ISLNK(st.st_mode)) /* inconsistent with lstat; retry */ goto stat_ref; else @@ -448,26 +454,29 @@ static int files_read_raw_ref(struct ref_store *ref_store, const char *refname, } strbuf_reset(&sb_contents); if (strbuf_read(&sb_contents, fd, 256) < 0) { - int save_errno = errno; + myerr = errno; close(fd); - errno = save_errno; goto out; } close(fd); strbuf_rtrim(&sb_contents); buf = sb_contents.buf; - ret = parse_loose_ref_contents(buf, oid, referent, type); + ret = parse_loose_ref_contents(buf, oid, referent, type, &myerr); out: - *failure_errno = errno; + if (ret && !myerr) + BUG("returning non-zero %d, should have set myerr!", ret); + *failure_errno = myerr; + strbuf_release(&sb_path); strbuf_release(&sb_contents); return ret; } int parse_loose_ref_contents(const char *buf, struct object_id *oid, - struct strbuf *referent, unsigned int *type) + struct strbuf *referent, unsigned int *type, + int *failure_errno) { const char *p; if (skip_prefix(buf, "ref:", &buf)) { @@ -486,7 +495,7 @@ int parse_loose_ref_contents(const char *buf, struct object_id *oid, if (parse_oid_hex(buf, oid, &p) || (*p != '\0' && !isspace(*p))) { *type |= REF_ISBROKEN; - errno = EINVAL; + *failure_errno = EINVAL; return -1; } return 0; diff --git a/refs/refs-internal.h b/refs/refs-internal.h index 7ade286260c..7a3a61ac22f 100644 --- a/refs/refs-internal.h +++ b/refs/refs-internal.h @@ -692,10 +692,12 @@ struct ref_store { }; /* - * Parse contents of a loose ref file. + * Parse contents of a loose ref file. *failure_errno maybe be set to EINVAL for + * invalid contents. */ int parse_loose_ref_contents(const char *buf, struct object_id *oid, - struct strbuf *referent, unsigned int *type); + struct strbuf *referent, unsigned int *type, + int *failure_errno); /* * Fill in the generic part of refs and add it to our collection of diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index 9fae13c2dea..63fbd71dc5c 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -745,6 +745,7 @@ test_expect_success SYMLINKS 'git branch -m with symlinked .git/refs' ' ) && git --git-dir subdir/.git/ branch rename-src && git rev-parse rename-src >expect && + # Tests a BUG() assertion in files_read_raw_ref() git --git-dir subdir/.git/ branch -m rename-src rename-dest && git rev-parse rename-dest >actual && test_cmp expect actual && From patchwork Mon Aug 23 11:52:44 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBCamFybWFzb24=?= X-Patchwork-Id: 12452547 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3FDEEC4320A for ; Mon, 23 Aug 2021 11:53:13 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2D09261357 for ; Mon, 23 Aug 2021 11:53:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236819AbhHWLxy (ORCPT ); Mon, 23 Aug 2021 07:53:54 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50518 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236760AbhHWLxp (ORCPT ); Mon, 23 Aug 2021 07:53:45 -0400 Received: from mail-wr1-x42c.google.com (mail-wr1-x42c.google.com [IPv6:2a00:1450:4864:20::42c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2D0EFC0617AD for ; Mon, 23 Aug 2021 04:53:00 -0700 (PDT) Received: by mail-wr1-x42c.google.com with SMTP id k29so25862375wrd.7 for ; Mon, 23 Aug 2021 04:53:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ucrSFt1OnM/isq91yj9IogbAvkgZRJQrJyiE2R+YP40=; b=sFCaXIsjUOTtT0xJWK8OUIgsIjgRjtWC2bKe8vWRnKWK5CgPbAjHdy/XTgjvYfrCeY pISaSmjPXNT21Bf9hSu9Qg/qQpVmJHbYa9kOlEYauV80KfQyqyX+F4t2GlyavdUhfefw 0m/z15GwR408M7pV3xwNeDlDcOwoEeAg30AuyomlLICfBzMGynGoya9UsElM6Q4orAP5 Xj3S2cgUiVtb+CRKxCtW7bJ4g+T4oZoGrKuEvdMgcAQv6UDxbom7zFuf8svdmKWI2YAP Pnm3S09KAX7cuxt98xfePjdqe4EvvgyRvoahZmCRGE3ARnYGCNGCNOTN3Lwqw7dHzVoy egmA== 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=ucrSFt1OnM/isq91yj9IogbAvkgZRJQrJyiE2R+YP40=; b=LRP9ik/XqYM7ux5WLEpQNebtn2oPdIAQ8cxWVCykcVh/7eEv/BxWFJ0tSkbA3IM2Gh kvBweJ8oFvHmjId7PnDvFO+OEw2QCP8U948PWyyK7y/xfddMrHQPpQMTrVEoLEi9d24l +ZcfojP5pRwN3V0+T+4qXBhIHcilJ59bbnUFJc2ESbXFV4S0g+NeOuYkwbia1ISDmxA3 UvhaBzohodY1N6oSrp7iSqqx04V6AbS9HKqVsmdWnZK5ZS/lu2ZBvC9/6CZZ8JgTMxCG H7GbhITs4GvfKkGpyO0dQRn/REsXRezQR4226+Ykzq57AcWCP+NDTnSb26amgfgPyT0D MUbA== X-Gm-Message-State: AOAM533fmlc5Z9Kpf34f1E5VyquoZ0HSIUefQV00WXxQ5+2YUBTsmjAi nYU+bFLthVUdrhWXloAbQIX3xL+qtSniqUWJ X-Google-Smtp-Source: ABdhPJzMFVUCYdxGnZ/yAYS0r3vYb49TNjgmzqTNI9DKHuFzJMsXhCROMIZY885agLl7pBdTGdAknw== X-Received: by 2002:a5d:65cd:: with SMTP id e13mr13105383wrw.368.1629719578602; Mon, 23 Aug 2021 04:52:58 -0700 (PDT) Received: from vm.nix.is (vm.nix.is. [2a01:4f8:120:2468::2]) by smtp.gmail.com with ESMTPSA id l2sm12350713wmi.1.2021.08.23.04.52.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Aug 2021 04:52:58 -0700 (PDT) From: =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBCamFybWFzb24=?= To: git@vger.kernel.org Cc: Junio C Hamano , Jeff King , Han-Wen Nienhuys , Michael Haggerty , Jonathan Tan , =?utf-8?b?w4Z2YXIgQXJuZmrDtnLDsCBC?= =?utf-8?b?amFybWFzb24=?= Subject: [PATCH v10 8/8] refs: make errno output explicit for refs_resolve_ref_unsafe Date: Mon, 23 Aug 2021 13:52:44 +0200 Message-Id: X-Mailer: git-send-email 2.33.0.662.g438caf9576d In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Han-Wen Nienhuys This introduces refs_resolve_ref_unsafe_with_errno(), which makes the API contract for the errno output explicit. The implementation still relies on the global errno variable to ensure no side effects of this refactoring. lock_ref_oid_basic() in files-backend.c is the only caller of refs_resolve_ref() that needs error information to make logic decisions, so update that caller Signed-off-by: Han-Wen Nienhuys Signed-off-by: Ævar Arnfjörð Bjarmason --- refs.c | 2 +- refs.h | 11 +++++++++++ refs/files-backend.c | 10 ++++++---- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/refs.c b/refs.c index b83fd8c36b3..e3b6d8f8dc0 100644 --- a/refs.c +++ b/refs.c @@ -1688,7 +1688,7 @@ int refs_read_raw_ref(struct ref_store *ref_store, const char *refname, type, failure_errno); } -static const char *refs_resolve_ref_unsafe_with_errno(struct ref_store *refs, +const char *refs_resolve_ref_unsafe_with_errno(struct ref_store *refs, const char *refname, int resolve_flags, struct object_id *oid, diff --git a/refs.h b/refs.h index fda8aef1547..a5685c891a9 100644 --- a/refs.h +++ b/refs.h @@ -68,6 +68,17 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs, int resolve_flags, struct object_id *oid, int *flags); +/** + * refs_resolve_ref_unsafe_with_errno() is like + * refs_resolve_ref_unsafe(), but provide access to errno code that + * lead to a failure. We guarantee that errno is set to a meaningful + * value on non-zero return. + */ +const char *refs_resolve_ref_unsafe_with_errno(struct ref_store *refs, + const char *refname, + int resolve_flags, + struct object_id *oid, + int *flags, int *failure_errno); const char *resolve_ref_unsafe(const char *refname, int resolve_flags, struct object_id *oid, int *flags); diff --git a/refs/files-backend.c b/refs/files-backend.c index 41efe5352b5..a14bb6eb96e 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -1001,6 +1001,7 @@ static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs, { struct strbuf ref_file = STRBUF_INIT; struct ref_lock *lock; + int resolve_errno = 0; files_assert_main_repository(refs, "lock_ref_oid_basic"); assert(err); @@ -1008,13 +1009,14 @@ static struct ref_lock *lock_ref_oid_basic(struct files_ref_store *refs, CALLOC_ARRAY(lock, 1); files_ref_path(refs, &ref_file, refname); - if (!refs_resolve_ref_unsafe(&refs->base, refname, - RESOLVE_REF_NO_RECURSE, - &lock->old_oid, type)) { + if (!refs_resolve_ref_unsafe_with_errno(&refs->base, refname, + RESOLVE_REF_NO_RECURSE, + &lock->old_oid, type, + &resolve_errno)) { if (!refs_verify_refname_available(&refs->base, refname, NULL, NULL, err)) strbuf_addf(err, "unable to resolve reference '%s': %s", - refname, strerror(errno)); + refname, strerror(resolve_errno)); goto error_return; }