From 7883de512f42843696ce2530f0ff65d45447dc20 Mon Sep 17 00:00:00 2001 From: Friel Date: Wed, 14 Oct 2026 19:06:41 +0000 Subject: [PATCH 1/2] mingw: report pending deletion as missing for existing files CreateFileW() returns ERROR_ACCESS_DENIED when a file is pending deletion. With legacy deletion, another open descriptor can keep a deleted reftable in this state. A reader that obtained tables.list before compaction then fails with EACCES instead of rereading the updated list. Map STATUS_DELETE_PENDING to ENOENT when opening an existing file. Keep other access-denied errors unchanged, as well as the existing EEXIST mapping for O_CREAT | O_EXCL. Resolve RtlGetLastNtStatus before CreateFileW so loading the function cannot overwrite the status being inspected. Add a regression that deletes a file while retaining an open descriptor and checks that reftable reports REFTABLE_NOT_EXIST_ERROR. Exercise both default and legacy deletion without timing-dependent concurrent processes. Signed-off-by: Friel --- compat/mingw.c | 15 +++++++++++++++ t/helper/test-reftable.c | 29 ++++++++++++++++++++++++++++- t/t0610-reftable-basics.sh | 10 ++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index 4c2f26d4548147..e8f78955d9b0c2 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -760,6 +760,7 @@ static int mingw_open_append(wchar_t const *wfilename, int oflags, ...) */ static int mingw_open_existing(const wchar_t *filename, int oflags, ...) { + DECLARE_PROC_ADDR(ntdll.dll, NTSTATUS, NTAPI, RtlGetLastNtStatus, void); SECURITY_ATTRIBUTES security_attributes = { .nLength = sizeof(security_attributes), .bInheritHandle = !(oflags & O_NOINHERIT), @@ -786,11 +787,25 @@ static int mingw_open_existing(const wchar_t *filename, int oflags, ...) break; } + /* Resolve this before CreateFileW() so loading it cannot change its status. */ + INIT_PROC_ADDR(RtlGetLastNtStatus); handle = CreateFileW(filename, access, FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, &security_attributes, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (handle == INVALID_HANDLE_VALUE) { DWORD err = GetLastError(); + + /* + * A deleted file may remain pending while another handle is open. + * Report it as absent so readers of an obsolete reftable list can + * retry with the current list instead of failing with EACCES. + */ + if (err == ERROR_ACCESS_DENIED && RtlGetLastNtStatus && + RtlGetLastNtStatus() == STATUS_DELETE_PENDING) { + errno = ENOENT; + return -1; + } + if (err == ERROR_ACCESS_DENIED) { DWORD attrs = GetFileAttributesW(filename); if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) diff --git a/t/helper/test-reftable.c b/t/helper/test-reftable.c index fc49fafc3466f4..260191123ebaa2 100644 --- a/t/helper/test-reftable.c +++ b/t/helper/test-reftable.c @@ -2,6 +2,7 @@ #include "hash.h" #include "hex.h" #include "reftable/system.h" +#include "reftable/blocksource.h" #include "reftable/reftable-constants.h" #include "reftable/reftable-error.h" #include "reftable/reftable-merged.h" @@ -17,6 +18,7 @@ static void print_help(void) " -t dump table\n" " -s dump stack\n" " -6 sha256 hash format\n" + " --read-after-unlink check opening a deleted file\n" " -h this help\n" "\n"); } @@ -217,12 +219,33 @@ static int dump_reftable(const char *tablename) return err; } +static int read_after_unlink(const char *path) +{ + struct reftable_block_source source = { 0 }; + int fd, err; + + /* Keep the file pending deletion on Windows with legacy unlink semantics. */ + fd = open(path, O_RDONLY); + if (fd < 0) + die_errno("cannot open %s", path); + if (unlink(path)) + die_errno("cannot unlink %s", path); + + err = reftable_block_source_from_file(&source, path); + block_source_close(&source); + close(fd); + if (err != REFTABLE_NOT_EXIST_ERROR) + die("expected REFTABLE_NOT_EXIST_ERROR, got %d", err); + return 0; +} + int cmd__dump_reftable(int argc, const char **argv) { int err = 0; int opt_dump_blocks = 0; int opt_dump_table = 0; int opt_dump_stack = 0; + int opt_read_after_unlink = 0; uint32_t opt_hash_id = REFTABLE_HASH_SHA1; const char *arg = NULL, *argv0 = argv[0]; @@ -237,6 +260,8 @@ int cmd__dump_reftable(int argc, const char **argv) opt_hash_id = REFTABLE_HASH_SHA256; else if (!strcmp("-s", argv[1])) opt_dump_stack = 1; + else if (!strcmp("--read-after-unlink", argv[1])) + opt_read_after_unlink = 1; else if (!strcmp("-?", argv[1]) || !strcmp("-h", argv[1])) { print_help(); return 2; @@ -250,7 +275,9 @@ int cmd__dump_reftable(int argc, const char **argv) arg = argv[1]; - if (opt_dump_blocks) { + if (opt_read_after_unlink) { + err = read_after_unlink(arg); + } else if (opt_dump_blocks) { err = dump_blocks(arg); } else if (opt_dump_table) { err = dump_reftable(arg); diff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh index 35e98b43dba035..83742364cf47c2 100755 --- a/t/t0610-reftable-basics.sh +++ b/t/t0610-reftable-basics.sh @@ -492,6 +492,16 @@ test_expect_success !CYGWIN 'ref transaction: many concurrent writers' ' ) ' +for legacy_delete in 0 1 +do + test_expect_success "read table deleted with an open descriptor (legacy deletion: $legacy_delete)" ' + test_when_finished "rm -f table" && + echo content >table && + GIT_TEST_LEGACY_DELETE=$legacy_delete \ + test-tool dump-reftable --read-after-unlink table + ' +done + test_expect_success 'pack-refs: compacts tables' ' test_when_finished "rm -rf repo" && git init repo && From b1013cd9c374194c94a35889dca67d7ca57fdb7a Mon Sep 17 00:00:00 2001 From: Friel Date: Fri, 16 Oct 2026 05:21:40 +0000 Subject: [PATCH 2/2] ci: retain reviewed workflow pins for topic builds Starting the topic from master restores workflows with unpinned action references. Retain the exact workflow blobs accepted by ci_workflow_pins_are_reviewed() so the source branch keeps the CI configuration used to validate the fix. Signed-off-by: Friel --- .github/workflows/check-style.yml | 2 +- .github/workflows/check-whitespace.yml | 2 +- .github/workflows/main.yml | 78 ++++++++++++++------------ 3 files changed, 45 insertions(+), 37 deletions(-) diff --git a/.github/workflows/check-style.yml b/.github/workflows/check-style.yml index 108a2de903310c..b265fe35cbfc51 100644 --- a/.github/workflows/check-style.yml +++ b/.github/workflows/check-style.yml @@ -20,7 +20,7 @@ jobs: jobname: ClangFormat runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 with: fetch-depth: 0 diff --git a/.github/workflows/check-whitespace.yml b/.github/workflows/check-whitespace.yml index ea6f49f742108e..3379f89a814abd 100644 --- a/.github/workflows/check-whitespace.yml +++ b/.github/workflows/check-whitespace.yml @@ -19,7 +19,7 @@ jobs: check-whitespace: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 with: fetch-depth: 0 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 205325eb33b064..44337a67422e01 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -63,7 +63,7 @@ jobs: echo "skip_concurrent=$skip_concurrent" >>$GITHUB_OUTPUT - name: skip if the commit or tree was already tested id: skip-if-redundant - uses: actions/github-script@v9 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 if: steps.check-ref.outputs.enabled == 'yes' with: github-token: ${{secrets.GITHUB_TOKEN}} @@ -112,8 +112,10 @@ jobs: group: windows-build-${{ github.ref }} cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - - uses: actions/checkout@v6 - - uses: git-for-windows/setup-git-for-windows-sdk@v2 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + - uses: git-for-windows/setup-git-for-windows-sdk@aed153d1258c311b680b81584a72a1a4807401f0 # v2.2.1 + with: + architecture: mingw64 - name: build shell: bash env: @@ -123,7 +125,7 @@ jobs: - name: zip up tracked files run: git archive -o artifacts/tracked.tar.gz HEAD - name: upload tracked files and build artifacts - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: windows-artifacts path: artifacts @@ -140,14 +142,16 @@ jobs: cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - name: download tracked files and build artifacts - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 with: name: windows-artifacts path: ${{github.workspace}} - name: extract tracked files and build artifacts shell: bash run: tar xf artifacts.tar.gz && tar xf tracked.tar.gz - - uses: git-for-windows/setup-git-for-windows-sdk@v2 + - uses: git-for-windows/setup-git-for-windows-sdk@aed153d1258c311b680b81584a72a1a4807401f0 # v2.2.1 + with: + architecture: mingw64 - name: test shell: bash run: . /etc/profile && ci/run-test-slice.sh $((${{matrix.nr}} + 1)) 10 @@ -157,7 +161,7 @@ jobs: run: ci/print-test-failures.sh - name: Upload failed tests' directories if: failure() && env.FAILED_TEST_ARTIFACTS != '' - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: failed-tests-windows-${{ matrix.nr }} path: ${{env.FAILED_TEST_ARTIFACTS}} @@ -173,20 +177,22 @@ jobs: group: vs-build-${{ github.ref }} cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - - uses: actions/checkout@v6 - - uses: git-for-windows/setup-git-for-windows-sdk@v2 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + - uses: git-for-windows/setup-git-for-windows-sdk@aed153d1258c311b680b81584a72a1a4807401f0 # v2.2.1 + with: + architecture: mingw64 - name: initialize vcpkg - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 with: repository: 'microsoft/vcpkg' path: 'compat/vcbuild/vcpkg' - name: download vcpkg artifacts - uses: git-for-windows/get-azure-pipelines-artifact@v0 + uses: git-for-windows/get-azure-pipelines-artifact@2e424b98e1251b725d6064c5f1a9f854a33e5b88 # v0 with: repository: git/git definitionId: 9 - name: add msbuild to PATH - uses: microsoft/setup-msbuild@v3 + uses: microsoft/setup-msbuild@30375c66a4eea26614e0d39710365f22f8b0af57 # v3 - name: copy dlls to root shell: cmd run: compat\vcbuild\vcpkg_copy_dlls.bat release @@ -208,7 +214,7 @@ jobs: - name: zip up tracked files run: git archive -o artifacts/tracked.tar.gz HEAD - name: upload tracked files and build artifacts - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: vs-artifacts path: artifacts @@ -224,9 +230,11 @@ jobs: group: vs-test-${{ matrix.nr }}-${{ github.ref }} cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - - uses: git-for-windows/setup-git-for-windows-sdk@v2 + - uses: git-for-windows/setup-git-for-windows-sdk@aed153d1258c311b680b81584a72a1a4807401f0 # v2.2.1 + with: + architecture: mingw64 - name: download tracked files and build artifacts - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 with: name: vs-artifacts path: ${{github.workspace}} @@ -244,7 +252,7 @@ jobs: run: ci/print-test-failures.sh - name: Upload failed tests' directories if: failure() && env.FAILED_TEST_ARTIFACTS != '' - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: failed-tests-windows-vs-${{ matrix.nr }} path: ${{env.FAILED_TEST_ARTIFACTS}} @@ -258,8 +266,8 @@ jobs: group: windows-meson-build-${{ github.ref }} cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - - uses: actions/checkout@v6 - - uses: actions/setup-python@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 - name: Set up dependencies shell: pwsh run: pip install meson ninja @@ -270,7 +278,7 @@ jobs: shell: pwsh run: meson compile -C build - name: Upload build artifacts - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: windows-meson-artifacts path: build @@ -286,13 +294,13 @@ jobs: group: windows-meson-test-${{ matrix.nr }}-${{ github.ref }} cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - - uses: actions/checkout@v6 - - uses: actions/setup-python@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6 - name: Set up dependencies shell: pwsh run: pip install meson ninja - name: Download build artifacts - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 with: name: windows-meson-artifacts path: build @@ -305,7 +313,7 @@ jobs: run: ci/print-test-failures.sh - name: Upload failed tests' directories if: failure() && env.FAILED_TEST_ARTIFACTS != '' - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: failed-tests-windows-meson-${{ matrix.nr }} path: ${{env.FAILED_TEST_ARTIFACTS}} @@ -341,7 +349,7 @@ jobs: TEST_OUTPUT_DIRECTORY: ${{github.workspace}}/t runs-on: ${{matrix.vector.pool}} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - run: ci/install-dependencies.sh - run: ci/run-build-and-tests.sh - name: print test failures @@ -349,7 +357,7 @@ jobs: run: ci/print-test-failures.sh - name: Upload failed tests' directories if: failure() && env.FAILED_TEST_ARTIFACTS != '' - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: failed-tests-${{matrix.vector.jobname}} path: ${{env.FAILED_TEST_ARTIFACTS}} @@ -362,7 +370,7 @@ jobs: CI_JOB_IMAGE: ubuntu-latest runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - run: ci/install-dependencies.sh - run: ci/run-build-and-minimal-fuzzers.sh dockerized: @@ -411,9 +419,9 @@ jobs: # A RHEL 8 compatible distro. Supported until 2029-05-31. - jobname: almalinux-8 image: almalinux:8 - # Supported until 2026-08-31. - - jobname: debian-11 - image: debian:11 + # Supported until 2028-06-30. + - jobname: debian-12 + image: debian:12 env: jobname: ${{matrix.vector.jobname}} CC: ${{matrix.vector.cc}} @@ -441,7 +449,7 @@ jobs: else apt-get -q update && apt-get -q -y install git fi - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - run: ci/install-dependencies.sh - run: useradd builder --create-home - run: chown -R builder . @@ -451,7 +459,7 @@ jobs: run: sudo --preserve-env --set-home --user=builder ci/print-test-failures.sh - name: Upload failed tests' directories if: failure() && env.FAILED_TEST_ARTIFACTS != '' - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: failed-tests-${{matrix.vector.jobname}} path: ${{env.FAILED_TEST_ARTIFACTS}} @@ -466,7 +474,7 @@ jobs: group: static-analysis-${{ github.ref }} cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - run: ci/install-dependencies.sh - run: ci/run-static-analysis.sh - run: ci/check-directional-formatting.bash @@ -482,7 +490,7 @@ jobs: group: rust-analysis-${{ github.ref }} cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - run: ci/install-dependencies.sh - run: ci/run-rust-checks.sh sparse: @@ -496,7 +504,7 @@ jobs: group: sparse-${{ github.ref }} cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - name: Install other dependencies run: ci/install-dependencies.sh - run: make sparse @@ -512,6 +520,6 @@ jobs: CI_JOB_IMAGE: ubuntu-latest runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 - run: ci/install-dependencies.sh - run: ci/test-documentation.sh