From nobody Sun Apr 24 13:29:20 2022 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 6A22E1A861AE; Sun, 24 Apr 2022 13:29:20 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4KmTWh21vkz4t5P; Sun, 24 Apr 2022 13:29:20 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1650806960; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=+27JRZ19EG1krPBCLyag7ME1RI7KY2pSzNEasv2GGzI=; b=UrhGKXxitb1DeET4/8PkX6+L7EiWbfZ7gwNZwtdebbHQg3WpBB1VQ9Oa+CtSEtLcxcrf2M fiOTaVXkx5tihsMatMZZZMx2qud3/kNFzTtnQeAuBRSkBHoh2U3JPCDg5ix2S6FS6o+S35 Q+iv8ux7FhZk4b7Y+Bf45k+4hwMK9n8LGLD1d34gnqAd/7C2eErOcTIrcn9fqXh1MxzB/a I7x9ggB4brXryf6bDlo7iyQb6QgAKJQFN/veNsk/vDgs5CSP+ZHSmD2ymF+VR2NSIY76/c j4NpN183F4CwfKarvjbVAoI1CmgT0McSKIsDqYsyWXRdq5lJmfZ+yKSpa0DtqA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 2035126DDB; Sun, 24 Apr 2022 13:29:20 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 23ODTKW4010512; Sun, 24 Apr 2022 13:29:20 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 23ODTKV3010511; Sun, 24 Apr 2022 13:29:20 GMT (envelope-from git) Date: Sun, 24 Apr 2022 13:29:20 GMT Message-Id: <202204241329.23ODTKV3010511@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Kyle Evans Subject: git: 587dacce01b3 - stable/13 - cp: fix -R recursion detection List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-branches@freebsd.org X-BeenThere: dev-commits-src-branches@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kevans X-Git-Repository: src X-Git-Refname: refs/heads/stable/13 X-Git-Reftype: branch X-Git-Commit: 587dacce01b34e67c297d185bf245a7649ed3cf3 Auto-Submitted: auto-generated ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1650806960; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=+27JRZ19EG1krPBCLyag7ME1RI7KY2pSzNEasv2GGzI=; b=ZaleR3I+J5BdT9+BRqGLBLFj84b7t8rFiy+RKz3i1Hgu7cgxz0BulZONd6WhoAh3I5kYoO Xk5PwABHB3Y5QbLU9RMNzHmKlSG+XH6QwqeqS9pUnCS9Vwqch1azNJmv0P3/JCaHXBtaI2 zNt7PWdqsxgODCT7cHFSHPaO/xSf+03SpiqmbqfgOwYo8ls8PwFLwdNUSBcErnT2CbXW7T YVuJLchKMn+jzrEJC6y7T5CNn6l0ZYNCCeCj/lF2kzFw0Wzcemy+rahDh3wSVVkzcJGiJd Wf5iXQOexjNywPekkNZ/QcQSp4SDjPS1/OmL+OuCEvnUURQezA+Ga9qyUx4LNg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1650806960; a=rsa-sha256; cv=none; b=I73zd2ZxSSwqaM2Pxqr7ZRkp6/5jXob0eOy/BwK4103rHAiPAAMVq0gs7ylXT5Tw6yXpYC l1tFbsdym7UaeAhrFdBoQW+Oh8XGabqU++vb47jGtOr7wGFgkd8CGQoHUITUg8+jxPnPhr Pqixv9oBAgwgeewfzkp3UFg5edrJANN9IXwDahIfFfbs1iRct6U/ehCYtNH17cFwNiDrLd W961R+h4a1sSCo7CLZkr4LBpK76qNxSbetse+6nSDebBf0LycWvjLrpdF9JCigbrvggHWp f866Pit3S+iQ1v92b+Won/+KFEPKjAIzdyHyq7Lg4t8/PY/qcO6V3zLaW/Jjwg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none X-ThisMailContainsUnwantedMimeParts: N The branch stable/13 has been updated by kevans: URL: https://cgit.FreeBSD.org/src/commit/?id=587dacce01b34e67c297d185bf245a7649ed3cf3 commit 587dacce01b34e67c297d185bf245a7649ed3cf3 Author: Kyle Evans AuthorDate: 2022-04-06 01:40:53 +0000 Commit: Kyle Evans CommitDate: 2022-04-24 03:51:28 +0000 cp: fix -R recursion detection The correct logic is a lot simpler than the previous iteration. We record the base fts_name to avoid having to worry about whether we needed the root symlink name or not (as applicable), then we can simply shift all of that logic to after path translation to make it less fragile. If we're copying to DNE, then we'll have swapped out the NULL root_stat pointer and then attempted to recurse on it. The previously nonexistent directory shouldn't exist at all in the new structure, so just back out from that tree entirely and move on. The tests have been amended to indicate our expectations better with subdirectory recursion. If we copy A to A/B, then we expect to copy everything from A/B/* into A/B/A/B, with exception to the A that we create in A/B. Reviewed by: bapt Sponsored by: Klara, Inc. (cherry picked from commit f00f8b4fbd268a212687984e44daa3e0d0a16b87) --- bin/cp/cp.c | 84 ++++++++++++++++++++++++++----------------------- bin/cp/tests/cp_test.sh | 15 +++++++-- 2 files changed, 57 insertions(+), 42 deletions(-) diff --git a/bin/cp/cp.c b/bin/cp/cp.c index f132bb940c09..dbae4b535843 100644 --- a/bin/cp/cp.c +++ b/bin/cp/cp.c @@ -292,6 +292,7 @@ copy_stat(const char *path, struct stat *sb) static int copy(char *argv[], enum op type, int fts_options, struct stat *root_stat) { + char rootname[NAME_MAX]; struct stat created_root_stat, to_stat; FTS *ftsp; FTSENT *curr; @@ -328,45 +329,15 @@ copy(char *argv[], enum op type, int fts_options, struct stat *root_stat) ; } - if (curr->fts_info == FTS_D && type != FILE_TO_FILE && - root_stat != NULL && - root_stat->st_dev == curr->fts_statp->st_dev && - root_stat->st_ino == curr->fts_statp->st_ino) { - assert(recurse_path == NULL); - if (curr->fts_level > FTS_ROOTLEVEL) { - /* - * If the recursion isn't at the immediate - * level, we can just not traverse into this - * directory. - */ - fts_set(ftsp, curr, FTS_SKIP); - continue; - } else { - const char *slash; - - /* - * Grab the last path component and double it, - * to make life easier later and ensure that - * we work even with fts_level == 0 is a couple - * of components deep in fts_path. No path - * separators are fine and expected in the - * common case, though. - */ - slash = strrchr(curr->fts_path, '/'); - if (slash != NULL) - slash++; - else - slash = curr->fts_path; - if (asprintf(&recurse_path, "%s/%s", - curr->fts_path, slash) == -1) - err(1, "asprintf"); - } - } - - if (recurse_path != NULL && - strcmp(curr->fts_path, recurse_path) == 0) { - fts_set(ftsp, curr, FTS_SKIP); - continue; + /* + * Stash the root basename off for detecting recursion later. + * + * This will be essential if the root is a symlink and we're + * rolling with -L or -H. The later bits will need this bit in + * particular. + */ + if (curr->fts_level == FTS_ROOTLEVEL) { + strlcpy(rootname, curr->fts_name, sizeof(rootname)); } /* @@ -422,6 +393,41 @@ copy(char *argv[], enum op type, int fts_options, struct stat *root_stat) to.p_end = target_mid + nlen; *to.p_end = 0; STRIP_TRAILING_SLASH(to); + + /* + * We're on the verge of recursing on ourselves. Either + * we need to stop right here (we knowingly just created + * it), or we will in an immediate descendant. Record + * the path of the immediate descendant to make our + * lives a little less complicated looking. + */ + if (curr->fts_info == FTS_D && root_stat != NULL && + root_stat->st_dev == curr->fts_statp->st_dev && + root_stat->st_ino == curr->fts_statp->st_ino) { + assert(recurse_path == NULL); + + if (root_stat == &created_root_stat) { + /* + * This directory didn't exist when we + * started, we created it as part of + * traversal. Stop right here before we + * do something silly. + */ + fts_set(ftsp, curr, FTS_SKIP); + continue; + } + + + if (asprintf(&recurse_path, "%s/%s", to.p_path, + rootname) == -1) + err(1, "asprintf"); + } + + if (recurse_path != NULL && + strcmp(to.p_path, recurse_path) == 0) { + fts_set(ftsp, curr, FTS_SKIP); + continue; + } } if (curr->fts_info == FTS_DP) { diff --git a/bin/cp/tests/cp_test.sh b/bin/cp/tests/cp_test.sh index adb6ea24d9e7..7362168d7303 100755 --- a/bin/cp/tests/cp_test.sh +++ b/bin/cp/tests/cp_test.sh @@ -95,16 +95,25 @@ matching_srctgt_contained_body() # Let's do the same thing, except we'll try to recursively copy foo into # one of its subdirectories. mkdir foo + ln -s foo coo echo "qux" > foo/bar - mkdir foo/loo mkdir foo/moo - mkdir foo/roo + touch foo/moo/roo cp foo/bar foo/zoo atf_check cp -R foo foo/moo + atf_check cp -RH coo foo/moo atf_check -o inline:"qux\n" cat foo/moo/foo/bar + atf_check -o inline:"qux\n" cat foo/moo/coo/bar atf_check -o inline:"qux\n" cat foo/moo/foo/zoo - atf_check -e not-empty -s not-exit:0 stat foo/moo/foo/moo + atf_check -o inline:"qux\n" cat foo/moo/coo/zoo + + # We should have copied the contents of foo/moo before foo, coo started + # getting copied in. + atf_check -o not-empty stat foo/moo/foo/moo/roo + atf_check -o not-empty stat foo/moo/coo/moo/roo + atf_check -e not-empty -s not-exit:0 stat foo/moo/foo/moo/foo + atf_check -e not-empty -s not-exit:0 stat foo/moo/coo/moo/coo } atf_test_case matching_srctgt_link