{"thread":{"id":"61886","subject":"quiltimport mode detection oddity","startedAt":"2024-08-01T22:57:03Z","lastAt":"2024-08-15T16:41:50Z","messageCount":10,"participants":["Andrew Morton","Junio C Hamano","Jeff King"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"499915","messageId":"20240801155702.70242c31d476c46c84ee11a3@linux-foundation.org","threadId":"61886","inReplyTo":null,"subject":"quiltimport mode detection oddity","fromName":"Andrew Morton","fromEmail":"akpm@linux-foundation.org","sentAt":"2024-08-01T22:57:02Z","receivedAt":"2024-08-01T22:57:03Z","isPatch":false,"sender":{"key":"akpm@linux-foundation.org","avatar":null},"body":"\nHi all.\n\nhp2:/usr/src/mm> git --version\ngit version 2.43.0\n\n\nI'm getting an odd warning from quiltimport:\n\nhp2:/usr/src/mm> ls -l tools/testing/radix-tree/generated/autoconf.h\n-rw-rw-r-- 1 akpm akpm 54 Aug  1 15:43 tools/testing/radix-tree/generated/autoconf.h\n\nhp2:/usr/src/mm> git quiltimport --series series\ntools-separate-out-shared-radix-tree-components.patch\nwarning: tools/testing/radix-tree/generated/autoconf.h has type 100644, expected 100664\n\n\n\n\nThat patch has\n\ndiff --git a/tools/testing/radix-tree/generated/autoconf.h a/tools/testing/radix-tree/generated/autoconf.h\ndeleted file mode 100664\n--- a/tools/testing/radix-tree/generated/autoconf.h\n+++ /dev/null\n@@ -1,2 +0,0 @@\n-#include \"bit-length.h\"\n-#define CONFIG_XARRAY_MULTI 1\n\n\n\n\nafter quiltimport:\n\nhp2:/usr/src/mm> ls -l tools/testing/radix-tree/generated/autoconf.h\nls: cannot access 'tools/testing/radix-tree/generated/autoconf.h': No such file or directory\n\n\n\nI can't figure what I've done to make quiltimport (git-apply?) think that the file\nhad 100644 permissions.  Maybe the lack of an index line tripped it up.\n\n\n(btw, \"has type\" should be \"has permissions\" in that message, no?)\n\n\nThanks.\n\n"},{"id":"499917","messageId":"xmqqed77hifn.fsf@gitster.g","threadId":"61886","inReplyTo":"20240801155702.70242c31d476c46c84ee11a3@linux-foundation.org","subject":"Re: quiltimport mode detection oddity","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-08-02T00:33:48Z","receivedAt":"2024-08-02T00:33:51Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Andrew Morton <akpm@linux-foundation.org> writes:\n\n> hp2:/usr/src/mm> git quiltimport --series series\n> tools-separate-out-shared-radix-tree-components.patch\n> warning: tools/testing/radix-tree/generated/autoconf.h has type 100644, expected 100664\n>\n>\n>\n>\n> That patch has\n>\n> diff --git a/tools/testing/radix-tree/generated/autoconf.h a/tools/testing/radix-tree/generated/autoconf.h\n> deleted file mode 100664\n> --- a/tools/testing/radix-tree/generated/autoconf.h\n> +++ /dev/null\n> @@ -1,2 +0,0 @@\n> -#include \"bit-length.h\"\n> -#define CONFIG_XARRAY_MULTI 1\n\nSo, the patch removes autoconf.h file from that directory.  The\n\"extended header\" part between \"diff --git\" and \"--- a/...\" has\n\"deleted file mode 100664\" and that is where the warning comes.\n\nI do not quite recall at which point \"git quiltimport\" calls \"git\napply\", but the \"has type 100644, expected 100664\" does ring a bell.\n\n> after quiltimport:\n>\n> hp2:/usr/src/mm> ls -l tools/testing/radix-tree/generated/autoconf.h\n> ls: cannot access 'tools/testing/radix-tree/generated/autoconf.h': No such file or directory\n\nThat is to be expected, if that patch was successfully applied, no?\nAfter all, the patch you quoted above seems to be a removal of\nautoconf.h from that path.\n\n> I can't figure what I've done to make quiltimport (git-apply?) think that the file\n> had 100644 permissions.  Maybe the lack of an index line tripped it up.\n\nYou said \"That patch has\", and I take it to mean that the input\nmaterial before \"git quiltimport\" touched it already had the\nextended header that records the removal of a file whose mode is\n100664?  \n\nAnd lack of the index line is probably a red herring.  EVen if there\nwere an index line, it would just have recorded the two object names\n(the blob object name of the original contents before removal,\nfollowed by a double-dot \"..\", followed by all-0 to signal removal).\nWe do not read mode bits out of that line.\n\n> (btw, \"has type\" should be \"has permissions\" in that message, no?)\n\nIf leading prefix 100 did not exist, yes, permissions would be more\nappropriate, but if the prefix changed from 100644 to say 120000,\nthat would be a type change from plain blob to a symlink.  So \"type\"\nis not quite wrong, either.\n"},{"id":"499920","messageId":"20240801180706.933d797b0ae5744fdcdf47d2@linux-foundation.org","threadId":"61886","inReplyTo":"xmqqed77hifn.fsf@gitster.g","subject":"Re: quiltimport mode detection oddity","fromName":"Andrew Morton","fromEmail":"akpm@linux-foundation.org","sentAt":"2024-08-02T01:07:06Z","receivedAt":"2024-08-02T01:07:22Z","isPatch":false,"sender":{"key":"akpm@linux-foundation.org","avatar":null},"body":"On Thu, 01 Aug 2024 17:33:48 -0700 Junio C Hamano <gitster@pobox.com> wrote:\n\n> > hp2:/usr/src/mm> git quiltimport --series series\n> > tools-separate-out-shared-radix-tree-components.patch\n> > warning: tools/testing/radix-tree/generated/autoconf.h has type 100644, expected 100664\n> >\n> >\n> >\n> >\n> > That patch has\n> >\n> > diff --git a/tools/testing/radix-tree/generated/autoconf.h a/tools/testing/radix-tree/generated/autoconf.h\n> > deleted file mode 100664\n> > --- a/tools/testing/radix-tree/generated/autoconf.h\n> > +++ /dev/null\n> > @@ -1,2 +0,0 @@\n> > -#include \"bit-length.h\"\n> > -#define CONFIG_XARRAY_MULTI 1\n> \n> So, the patch removes autoconf.h file from that directory.  The\n> \"extended header\" part between \"diff --git\" and \"--- a/...\" has\n> \"deleted file mode 100664\" and that is where the warning comes.\n\nyup yup.  The patch says \"remove this file which has mode 100664\".\n\nThe file has mode 100664.\n\nquiltimport says it had mode 100644.  Incorrectly, I suggest.\n"},{"id":"499924","messageId":"20240802035121.GB1246312@coredump.intra.peff.net","threadId":"61886","inReplyTo":"20240801180706.933d797b0ae5744fdcdf47d2@linux-foundation.org","subject":"Re: quiltimport mode detection oddity","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2024-08-02T03:51:21Z","receivedAt":"2024-08-02T03:51:23Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Aug 01, 2024 at 06:07:06PM -0700, Andrew Morton wrote:\n\n> > So, the patch removes autoconf.h file from that directory.  The\n> > \"extended header\" part between \"diff --git\" and \"--- a/...\" has\n> > \"deleted file mode 100664\" and that is where the warning comes.\n> \n> yup yup.  The patch says \"remove this file which has mode 100664\".\n> \n> The file has mode 100664.\n> \n> quiltimport says it had mode 100644.  Incorrectly, I suggest.\n\nIt's definitely a weird case. Git does not record full modes, but just\ncares about the execute bit. So it normalizes modes for regular files to\n100644 or 100755. You can see that with a simple example:\n\n  git init\n  echo foo >file\n  chmod 664 file\n  git add file\n  git commit -m 'add file'\n\n  git ls-files -s\n\n  cat >patch <<\\EOF\n  diff --git a/file b/file\n  deleted file mode 100664\n  --- a/file\n  +++ /dev/null\n  @@ -1 +0,0 @@\n  -foo\n  EOF\n  ls -l file\n  git apply patch\n\nEven though the filesystem has 100664, the index records 100644 (which\nyou can see from the \"ls-files\" output). And then when we apply the\npatch, we get the \"file has type 100644, expected 100664\" message.\nAFAICT, it has been that way forever (I tried as far back as git 1.6.6).\nSo this is nothing new, and I don't think Git would ever produce a patch\nthat said \"file mode 100664\" itself (I'm assuming in your case the patch\nis coming from quilt).\n\nGiven that, I think it is reasonable for git to also normalize the mode\nof the patches it reads, so that we are consistently working in the\nworld of simplified modes. I.e., this:\n\ndiff --git a/apply.c b/apply.c\nindex 142e3d913c..3d50fade78 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -995,6 +995,7 @@ static int parse_mode_line(const char *line, int linenr, unsigned int *mode)\n \t*mode = strtoul(line, &end, 8);\n \tif (end == line || !isspace(*end))\n \t\treturn error(_(\"invalid mode on line %d: %s\"), linenr, line);\n+\t*mode = canon_mode(*mode);\n \treturn 0;\n }\n \n\nwhich makes the warning go away in the example above. But I'm not sure\nif there could be other fallout. E.g., is there a mode for git-apply to\njust touch the working tree and not the index, where we'd perhaps want\nto retain the original to compare against the filesystem mode? I don't\nthink so.\n\nAlternatively (or maybe in addition), I wonder if quilt should similarly\ncanonicalize the mode. git-apply is certainly meant to work with patches\ngenerated elsewhere, but normal patches don't have modes in them at all.\nThe \"deleted file mode\" line is git-ism, so here we have something which\nis implementing the git line in a (slightly) incompatible way.\n\n-Peff\n"},{"id":"499932","messageId":"20240801223347.f3ecc32d6afebcd2e42cc3f7@linux-foundation.org","threadId":"61886","inReplyTo":"20240802035121.GB1246312@coredump.intra.peff.net","subject":"Re: quiltimport mode detection oddity","fromName":"Andrew Morton","fromEmail":"akpm@linux-foundation.org","sentAt":"2024-08-02T05:33:47Z","receivedAt":"2024-08-02T05:33:48Z","isPatch":false,"sender":{"key":"akpm@linux-foundation.org","avatar":null},"body":"On Thu, 1 Aug 2024 23:51:21 -0400 Jeff King <peff@peff.net> wrote:\n\n> On Thu, Aug 01, 2024 at 06:07:06PM -0700, Andrew Morton wrote:\n> \n> > > So, the patch removes autoconf.h file from that directory.  The\n> > > \"extended header\" part between \"diff --git\" and \"--- a/...\" has\n> > > \"deleted file mode 100664\" and that is where the warning comes.\n> > \n> > yup yup.  The patch says \"remove this file which has mode 100664\".\n> > \n> > The file has mode 100664.\n> > \n> > quiltimport says it had mode 100644.  Incorrectly, I suggest.\n> \n> It's definitely a weird case. Git does not record full modes, but just\n> cares about the execute bit. So it normalizes modes for regular files to\n> 100644 or 100755. You can see that with a simple example:\n> \n>   git init\n>   echo foo >file\n>   chmod 664 file\n>   git add file\n>   git commit -m 'add file'\n> \n>   git ls-files -s\n> \n>   cat >patch <<\\EOF\n>   diff --git a/file b/file\n>   deleted file mode 100664\n>   --- a/file\n>   +++ /dev/null\n>   @@ -1 +0,0 @@\n>   -foo\n>   EOF\n>   ls -l file\n>   git apply patch\n> \n> Even though the filesystem has 100664, the index records 100644 (which\n> you can see from the \"ls-files\" output). And then when we apply the\n> patch, we get the \"file has type 100644, expected 100664\" message.\n\nOK.\n\n> AFAICT, it has been that way forever (I tried as far back as git 1.6.6).\n> So this is nothing new, and I don't think Git would ever produce a patch\n> that said \"file mode 100664\" itself (I'm assuming in your case the patch\n> is coming from quilt).\n\nyup.\n\n> Alternatively (or maybe in addition), I wonder if quilt should similarly\n> canonicalize the mode.\n\nI'll hard code 100644 ;)\n\n> generated elsewhere, but normal patches don't have modes in them at all.\n> The \"deleted file mode\" line is git-ism, so here we have something which\n> is implementing the git line in a (slightly) incompatible way.\n\nyup, thanks.\n"},{"id":"499948","messageId":"xmqq7cczgefh.fsf@gitster.g","threadId":"61886","inReplyTo":"20240802035121.GB1246312@coredump.intra.peff.net","subject":"Re: quiltimport mode detection oddity","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-08-02T14:57:54Z","receivedAt":"2024-08-02T14:58:03Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> Given that, I think it is reasonable for git to also normalize the mode\n> of the patches it reads, so that we are consistently working in the\n> world of simplified modes. I.e., this:\n>\n> diff --git a/apply.c b/apply.c\n> index 142e3d913c..3d50fade78 100644\n> --- a/apply.c\n> +++ b/apply.c\n> @@ -995,6 +995,7 @@ static int parse_mode_line(const char *line, int linenr, unsigned int *mode)\n>  \t*mode = strtoul(line, &end, 8);\n>  \tif (end == line || !isspace(*end))\n>  \t\treturn error(_(\"invalid mode on line %d: %s\"), linenr, line);\n> +\t*mode = canon_mode(*mode);\n>  \treturn 0;\n>  }\n>  \n>\n> which makes the warning go away in the example above. But I'm not sure\n> if there could be other fallout. E.g., is there a mode for git-apply to\n> just touch the working tree and not the index, where we'd perhaps want\n> to retain the original to compare against the filesystem mode? I don't\n> think so.\n\nMakes sense.\n\nThe above is consistent with what we do for the permission bits;\nonly the execute bit matters, and the patch recording 100664 should\nmean the same thing to us as permission bits 100644---we should warn\nif the on-disk file is executable while applying such a patch, and\nwe should not warn otherwise.\n\n> Alternatively (or maybe in addition), I wonder if quilt should similarly\n> canonicalize the mode. git-apply is certainly meant to work with patches\n> generated elsewhere, but normal patches don't have modes in them at all.\n> The \"deleted file mode\" line is git-ism, so here we have something which\n> is implementing the git line in a (slightly) incompatible way.\n\nIt's an orthogonal fix and probably worth doing.\n\nIf a third-party tool adds git-ism mode lines, we should be lenient\nwhen we see a wrong mode, as long as the leniency does not affect\nour normal mode of operation negatively.  It is OK if they record a\nnon-executable regular file with 100666.  Using 664 (no type bits)\nor 100755, however, crosses the line and they must stop producing\nsuch a bogus mode line, if they do not want to see a warning.\n\n\n"},{"id":"500045","messageId":"20240805060010.GA120016@coredump.intra.peff.net","threadId":"61886","inReplyTo":"xmqq7cczgefh.fsf@gitster.g","subject":"[PATCH] apply: canonicalize modes read from patches","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2024-08-05T06:00:10Z","receivedAt":"2024-08-05T06:00:13Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Aug 02, 2024 at 07:57:54AM -0700, Junio C Hamano wrote:\n\n> Makes sense.\n> \n> The above is consistent with what we do for the permission bits;\n> only the execute bit matters, and the patch recording 100664 should\n> mean the same thing to us as permission bits 100644---we should warn\n> if the on-disk file is executable while applying such a patch, and\n> we should not warn otherwise.\n\nOK, here it is with tests and a commit message. I dug around to make\nsure there were no cases where the unusual mode would cause other\nbehavior changes, but there aren't any. We are careful to use the\ncanonical mode whenever we create a file.\n\nSo the tests here may be overkill (since except for the warning message,\nthey'd pass already), but I thought it worth demonstrating the complete\nset of expected behavior. Likewise the commit message is long because I\nlaid out all of the things I poked at.\n\nI didn't add tests confirming that we complain when the executable bit\nis not as expected. Earlier tests in t4129 already cover that.\n\n-- >8 --\nSubject: apply: canonicalize modes read from patches\n\nGit stores only canonical modes for blobs. So for a regular file, we\ncare about only \"100644\" or \"100755\" (depending only on the executable\nbit), but never modes where the group or other permissions are more\nexotic. So never \"100664\", \"100700\", etc. When a file in the working\ntree has such a mode, we quietly turn it into one of the two canonical\nmodes, and that's what is stored both in the index and in tree objects.\n\nHowever, we don't canonicalize modes we read from incoming patches in\ngit-apply. These may appear in a few lines:\n\n  - \"old mode\" / \"new mode\" lines for mode changes\n\n  - \"new file mode\" lines for newly created files\n\n  - \"deleted file mode\" for removing files\n\nFor \"new mode\" and for \"new file mode\", this is harmless. The patch is\nasking the result to have a certain mode, but:\n\n  - when we add an index entry (for --index or --cached), it is\n    canonicalized as we create the entry, via create_ce_mode().\n\n  - for a working tree file, try_create_file() passes either 0777 or\n    0666 to open(), so what you get depends only on your umask, not any\n    other bits (aside from the executable bit) in the original mode.\n\nHowever, for \"old mode\" and \"deleted file mode\", there is a minor\nannoyance. We compare the patch's expected preimage mode with the\ncurrent state. But that current state is always going to be a canonical\nmode itself:\n\n  - updating an index entry via --cached will have the canonical mode in\n    the index\n\n  - for updating a working tree file, check_preimage() runs the mode\n    through ce_mode_from_stat(), which does the usual canonicalization\n\nSo if the patch feeds a non-canonical mode, it's impossible for it to\nmatch, and we will always complain with something like:\n\n  file has type 100644, expected 100664\n\nSince this is just a warning, the operation proceeds, but it's\nconfusing and annoying.\n\nThese cases should be pretty rare in practice. Git would never produce a\npatch with non-canonical modes itself (since it doesn't store them).\nAnd while we do accept patches from other programs, all of those lines\nwere invented by Git. So you'd need a program trying to be Git\ncompatible, but not handling canonicalization the same way. Reportedly\n\"quilt\" is such a program.\n\nWe should canonicalize the modes as we read them so that the user never\nsees the useless warning.\n\nA few notes on the tests:\n\n  - I've covered instances of all lines for completeness, even though\n    the \"new mode\" / \"new file mode\" ones behave OK currently.\n\n  - the tests apply patches to both the index and working tree, and\n    check the result of both. Again, we know that all of these paths\n    canonicalize anyway, but it's giving us extra coverage (although we\n    are even less likely to have such a bug now since we canonicalize up\n    front).\n\n  - the test patches are missing \"index\" lines, which is also something\n    Git would never produce. But they don't matter for the test, they do\n    match the case from quilt we saw in the wild, and they avoid some\n    sha1/sha256 complexity.\n\nReported-by: Andrew Morton <akpm@linux-foundation.org>\nSigned-off-by: Jeff King <peff@peff.net>\n---\n apply.c                   |  1 +\n t/t4129-apply-samemode.sh | 62 +++++++++++++++++++++++++++++++++++++++\n 2 files changed, 63 insertions(+)\n\ndiff --git a/apply.c b/apply.c\nindex 0f2f5dabe3..6e1060a952 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -995,6 +995,7 @@ static int parse_mode_line(const char *line, int linenr, unsigned int *mode)\n \t*mode = strtoul(line, &end, 8);\n \tif (end == line || !isspace(*end))\n \t\treturn error(_(\"invalid mode on line %d: %s\"), linenr, line);\n+\t*mode = canon_mode(*mode);\n \treturn 0;\n }\n \ndiff --git a/t/t4129-apply-samemode.sh b/t/t4129-apply-samemode.sh\nindex 4eb8444029..d9a1084b5e 100755\n--- a/t/t4129-apply-samemode.sh\n+++ b/t/t4129-apply-samemode.sh\n@@ -130,4 +130,66 @@ test_expect_success 'git apply respects core.fileMode' '\n \ttest_grep ! \"has type 100644, expected 100755\" err\n '\n \n+test_expect_success POSIXPERM 'patch mode for new file is canonicalized' '\n+\tcat >patch <<-\\EOF &&\n+\tdiff --git a/non-canon b/non-canon\n+\tnew file mode 100660\n+\t--- /dev/null\n+\t+++ b/non-canon\n+\t+content\n+\tEOF\n+\ttest_when_finished \"git reset --hard\" &&\n+\t(\n+\t\tumask 0 &&\n+\t\tgit apply --index patch 2>err\n+\t) &&\n+\ttest_must_be_empty err &&\n+\tgit ls-files -s -- non-canon >staged &&\n+\ttest_grep \"^100644\" staged &&\n+\tls -l non-canon >worktree &&\n+\ttest_grep \"^-rw-rw-rw\" worktree\n+'\n+\n+test_expect_success POSIXPERM 'patch mode for deleted file is canonicalized' '\n+\ttest_when_finished \"git reset --hard\" &&\n+\techo content >non-canon &&\n+\tgit add non-canon &&\n+\tchmod 666 non-canon &&\n+\n+\tcat >patch <<-\\EOF &&\n+\tdiff --git a/non-canon b/non-canon\n+\tdeleted file mode 100660\n+\t--- a/non-canon\n+\t+++ /dev/null\n+\t@@ -1 +0,0 @@\n+\t-content\n+\tEOF\n+\tgit apply --index patch 2>err &&\n+\ttest_must_be_empty err &&\n+\tgit ls-files -- non-canon >staged &&\n+\ttest_must_be_empty staged &&\n+\ttest_path_is_missing non-canon\n+'\n+\n+test_expect_success POSIXPERM 'patch mode for mode change is canonicalized' '\n+\ttest_when_finished \"git reset --hard\" &&\n+\techo content >non-canon &&\n+\tgit add non-canon &&\n+\n+\tcat >patch <<-\\EOF &&\n+\tdiff --git a/non-canon b/non-canon\n+\told mode 100660\n+\tnew mode 100770\n+\tEOF\n+\t(\n+\t\tumask 0 &&\n+\t\tgit apply --index patch 2>err\n+\t) &&\n+\ttest_must_be_empty err &&\n+\tgit ls-files -s -- non-canon >staged &&\n+\ttest_grep \"^100755\" staged &&\n+\tls -l non-canon >worktree &&\n+\ttest_grep \"^-rwxrwxrwx\" worktree\n+'\n+\n test_done\n-- \n2.46.0.257.g39958a5326\n\n"},{"id":"501013","messageId":"xmqqcym9vnwg.fsf@gitster.g","threadId":"61886","inReplyTo":"20240805060010.GA120016@coredump.intra.peff.net","subject":"Re: [PATCH] apply: canonicalize modes read from patches","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-08-15T14:52:47Z","receivedAt":"2024-08-15T14:52:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> +test_expect_success POSIXPERM 'patch mode for deleted file is canonicalized' '\n\nThis test seems to fail under \"--stress\" and I need to borrow a\nbrain better clued than mine.  It appears to be fooled by mtime that\nis not updated immediately and failing match_stat check, but since\nthe index file is written on the other side of the second resolution\nboundary, racy-git double-checking code does not trigger, or\nsomething like that.\n\nHere is how it fails:\n\nexpecting success of 4129.13 'patch mode for deleted file is canonicalized':\n        test_when_finished \"git reset --hard\" &&\n        echo content >non-canon &&\n        git add non-canon &&\n        chmod 666 non-canon &&\n\n        cat >patch <<-\\EOF &&\n        diff --git a/non-canon b/non-canon\n        deleted file mode 100660\n        --- a/non-canon\n        +++ /dev/null\n        @@ -1 +0,0 @@\n        -content\n        EOF\n        git apply --index patch 2>err &&\n        test_must_be_empty err &&\n        git ls-files -- non-canon >staged &&\n        test_must_be_empty staged &&\n        test_path_is_missing non-canon\n\n++ test_when_finished 'git reset --hard'\n++ test 0 = 0\n++ test_cleanup='{ git reset --hard\n                } && (exit \"$eval_ret\"); eval_ret=$?; :'\n++ echo content\n++ git add non-canon\n++ chmod 666 non-canon\n++ cat\n++ git apply --index patch\nerror: last command exited with $?=1\nnot ok 13 - patch mode for deleted file is canonicalized\n#\n#               test_when_finished \"git reset --hard\" &&\n#               echo content >non-canon &&\n#               git add non-canon &&\n#               chmod 666 non-canon &&\n#\n#               cat >patch <<-\\EOF &&\n#               diff --git a/non-canon b/non-canon\n#               deleted file mode 100660\n#               --- a/non-canon\n#               +++ /dev/null\n#               @@ -1 +0,0 @@\n#               -content\n#               EOF\n#               git apply --index patch 2>err &&\n#               test_must_be_empty err &&\n#               git ls-files -- non-canon >staged &&\n#               test_must_be_empty staged &&\n#               test_path_is_missing non-canon\n#\n1..13\n$ echo $?\n1\n$ git -C trash\\ directory.t4129-apply-samemode.stress-failed/.git ls-files --debug non-canon\nnon-canon\n  ctime: 1723701364:980719772\n  mtime: 1723701364:980719772\n  dev: 65024    ino: 1980747\n  uid: 110493   gid: 89939\n  size: 8       flags: 0\n: git t/master; stat trash\\ directory.t4129-apply-samemode.stress-failed/non-canon\n  File: trash directory.t4129-apply-samemode.stress-failed/non-canon\n  Size: 8               Blocks: 8          IO Block: 4096   regular file\nDevice: 254,0   Inode: 1980747     Links: 1\nAccess: (0666/-rw-rw-rw-)  Uid: (110493/     jch)   Gid: (89939/primarygroup)\nAccess: 2024-08-15 06:54:43.808293635 -0700\nModify: 2024-08-14 22:56:04.980719772 -0700\nChange: 2024-08-14 22:56:05.020719706 -0700\n Birth: 2024-08-14 22:56:04.980719772 -0700\n$ stat trash\\ directory.t4129-apply-samemode.stress-failed/.git/index\n  File: trash directory.t4129-apply-samemode.stress-failed/.git/index\n  Size: 432             Blocks: 8          IO Block: 4096   regular file\nDevice: 254,0   Inode: 1980724     Links: 1\nAccess: (0600/-rw-------)  Uid: (110493/     jch)   Gid: (89939/primarygroup)\nAccess: 2024-08-14 22:56:05.044719667 -0700\nModify: 2024-08-14 22:56:05.008719726 -0700\nChange: 2024-08-14 22:56:05.016719713 -0700\n Birth: 2024-08-14 22:56:04.996719746 -0700\n\n"},{"id":"501015","messageId":"20240815153007.GA1477220@coredump.intra.peff.net","threadId":"61886","inReplyTo":"xmqqcym9vnwg.fsf@gitster.g","subject":"[PATCH] t4129: fix racy index when calling chmod after git-add","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2024-08-15T15:30:07Z","receivedAt":"2024-08-15T15:30:08Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Aug 15, 2024 at 07:52:47AM -0700, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> > +test_expect_success POSIXPERM 'patch mode for deleted file is canonicalized' '\n> \n> This test seems to fail under \"--stress\" and I need to borrow a\n> brain better clued than mine.  It appears to be fooled by mtime that\n> is not updated immediately and failing match_stat check, but since\n> the index file is written on the other side of the second resolution\n> boundary, racy-git double-checking code does not trigger, or\n> something like that.\n\nAh, thanks. I saw this fail once in CI, and then later succeed. But for\nsome reason I wrote it off as CI flakiness rather than trying --stress\nlocally. It's easy to reproduce the issue.\n\nI didn't puzzle out the exact condition that causes the race, but I\nthink the fix is pretty clearly this:\n\n-- >8 --\nSubject: [PATCH] t4129: fix racy index when calling chmod after git-add\n\nThis patch fixes a racy test failure in t4129.\n\nThe deletion test added by e95d515141 (apply: canonicalize modes read\nfrom patches, 2024-08-05) wants to make sure that git-apply does not\ncomplain about a non-canonical mode in the patch, even if that mode does\nnot match the working tree file. So it does this:\n\n\techo content >non-canon &&\n\tgit add non-canon &&\n\tchmod 666 non-canon &&\n\nThis is wrong, because running chmod will update the ctime on the file,\nmaking it stat-dirty and causing git-apply to refuse to apply the patch.\nBut this only happens sometimes, since it depends on the timestamps\ncrossing a second boundary (but it triggers pretty quickly when run with\n--stress).\n\nWe can fix this by doing the chmod before updating the index. The order\nisn't important here, as the mode will be canonicalized to 100644 in the\nindex anyway (in fact, the chmod is not even that important in the first\nplace, since git-apply will only look at the index; I only added it as\nan extra confirmation that git-apply would not be confused by it).\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n t/t4129-apply-samemode.sh | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/t/t4129-apply-samemode.sh b/t/t4129-apply-samemode.sh\nindex d9a1084b5e..87ffd2b8e1 100755\n--- a/t/t4129-apply-samemode.sh\n+++ b/t/t4129-apply-samemode.sh\n@@ -153,8 +153,8 @@ test_expect_success POSIXPERM 'patch mode for new file is canonicalized' '\n test_expect_success POSIXPERM 'patch mode for deleted file is canonicalized' '\n \ttest_when_finished \"git reset --hard\" &&\n \techo content >non-canon &&\n-\tgit add non-canon &&\n \tchmod 666 non-canon &&\n+\tgit add non-canon &&\n \n \tcat >patch <<-\\EOF &&\n \tdiff --git a/non-canon b/non-canon\n-- \n2.46.0.476.g32f0e7348d\n\n"},{"id":"501021","messageId":"xmqqcym9u4ak.fsf@gitster.g","threadId":"61886","inReplyTo":"20240815153007.GA1477220@coredump.intra.peff.net","subject":"Re: [PATCH] t4129: fix racy index when calling chmod after git-add","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-08-15T16:41:39Z","receivedAt":"2024-08-15T16:41:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> Ah, thanks. I saw this fail once in CI, and then later succeed. But for\n> some reason I wrote it off as CI flakiness rather than trying --stress\n> locally. It's easy to reproduce the issue.\n\nThanks.  Will queue.\n"}]}