]> vilimpoc.org git repositories - dotfiles/commitdiff
dotfiles: take the native arm64 rsync now that one is published master
authorMax Vilimpoc <max@vilimpoc.org>
Sun, 6 Sep 2026 08:14:46 +0000 (10:14 +0200)
committerMax Vilimpoc <max@vilimpoc.org>
Sun, 6 Sep 2026 08:14:46 +0000 (10:14 +0200)
nuket/rsync-windows publishes an arm64 asset as of v3.5.0-gdeeda96f, so
ARM64 stops taking the x64 zip under emulation.

The rsync.exe was never the problem - a transfer is bounded by the
socket, not by emulated CPU. The ssh.exe beside it was: it links against
System32\libcrypto.dll, which on ARM64 is an ARM64 binary an x64 process
cannot load, so it died with 0xC0000135 (STATUS_DLL_NOT_FOUND) and the
verification step deleted it on every single run. Both binaries in the
arm64 zip are 0xAA64, and its ssh.exe reports

    OpenSSH_for_Windows_10.0p2 Win32-OpenSSH-GitHub, LibreSSL 3.8.2

so the fast client survives the run now instead of being thrown away.
Checked the published .sha256 against the download the way the script
does; it matches.

Keep the run-it-to-verify check on every architecture. It is cheap, it
is what found the mismatch in the first place, and it still covers a
missing or too-old libcrypto.dll anywhere.

Drop rsync from the audit's accepted-emulation table and give it a
remedy instead: an x64 rsync.exe on an ARM64 box is now a leftover from
a run before this asset existed, not an exception to tolerate, so it
should warn and say to re-run the elevated half.

Also correct a stale README bullet claiming NASM is still installed on
ARM64 - it went into the x64-only set with the rest.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ak6VzfGyaocrykX1LhNMwt

README.md
setup-windows-no-uac.ps1
setup-windows-with-uac.ps1
setup-windows.bat

index ed5d49d6ae8cfd9a4025ef6e0dcdb42264dfe88a..933c53478030a3a03bc3856f42d0dae3c3b155b3 100644 (file)
--- a/README.md
+++ b/README.md
@@ -101,12 +101,11 @@ on each: x64 is the full workstation, ARM64 a lean single-compiler build box. Se
   `SYSTEM`; accounts in the Administrators group use
   `C:\ProgramData\ssh\administrators_authorized_keys` instead.
 - **rsync brings its own `ssh.exe`.** That release ships as one zip per
-  architecture — `rsync-windows-x64.zip` / `rsync-windows-x86.zip`, each holding
-  `rsync.exe`, an `ssh.exe`, `COPYING.txt` and `NOTICE-ssh.txt` — and the
-  elevated half picks the zip for the host architecture (ARM64 takes the x64 one;
-  there is no ARM64 asset), verifies it against the published `.sha256`, unpacks
-  the pair together, then **runs** the unpacked `ssh.exe` and removes it if it
-  will not start. Together is the point:
+  architecture — `rsync-windows-x86.zip`, `-x64.zip` and `-arm64.zip`, each
+  holding `rsync.exe`, an `ssh.exe`, `COPYING.txt` and `NOTICE-ssh.txt` — and the
+  elevated half picks the zip matching the host, verifies it against the
+  published `.sha256`, unpacks the pair together, then **runs** the unpacked
+  `ssh.exe` and removes it if it will not start. Together is the point:
   `rsync.exe` prefers an `ssh.exe` sitting in its own directory, and the release
   builds one because the client Windows ships reads its stdin 3 KB at a time,
   which holds a transfer *from* the box at ~17 MB/s however fast the link is.
@@ -377,7 +376,7 @@ What you end up with on ARM64:
 | | On ARM64 |
 | --- | --- |
 | **Native ARM64** | Git, Python, .NET SDK, PowerShell, VS Code, Windows Terminal, Sysinternals, Claude Code, CMake, Ninja, the VS installer, **MSVC**, MSBuild, the SDK tools (`rc`, `signtool`), the in-box OpenSSH client, and the Windows Performance Toolkit. |
-| **Emulated x64** | `iperf3` and `rsync.exe` — both network-bound — and the ADK *installer* (the toolkit it lays down is native). |
+| **Emulated x64** | `iperf3` (network-bound) and the ADK *installer* (the toolkit it lays down is native). |
 | **Emulated, minor** | `py.exe` (python.org ships the launcher shim as x86; it execs the native `python.exe`) and `vswhere.exe` (Microsoft ships x86 only; runs once). |
 | **Not installed** | Brave, WinMerge, upstream LLVM, NASM, Android GPU Inspector, OpenCppCoverage, BinSkim, VS `clang-cl`, and the WDK — see the table above. |
 | **Unavailable** | VirtualBox, the Windows 7 x86 test VM, Intel VTune, and the `v141` / Windows XP targeting toolset. |
@@ -512,27 +511,37 @@ Two consequences worth knowing rather than rediscovering:
   rest of the x64-only set to keep the rule simple, not because it was broken.
   The RID list is still ordered preference on x64, so a future `win-arm64` build
   would be picked up with no further change.
-- **`rsync` gets the x64 zip, and its `ssh.exe` is verified by running it.** The
-  release publishes x64 and x86 assets and no ARM64 one. x64 is still the right
-  pick — a transfer is bounded by the socket, not by emulated CPU, so lifting the
-  in-box client's 3 KB stdin cap wins by far more than emulation costs. But that
-  `ssh.exe` links against a `System32\libcrypto.dll` which on ARM64 is an **ARM64**
-  binary, so it may not load at all. That matters more than it sounds:
-  `rsync.exe` *prefers* an `ssh.exe` in its own directory, so a present-but-broken
-  one does not degrade to the in-box client — it breaks rsync outright, with an
-  error that names a dead remote shell rather than `ssh.exe`. The elevated half
-  therefore runs `ssh -V` after unpacking and **deletes** the binary if it will
-  not start, so `rsync` falls back to the native in-box client. The
-  `core.sshCommand` step in the non-elevated half already picked its candidate by
-  running it, and is unchanged.
+- **`rsync` is native on ARM64 now**, and its `ssh.exe` is still verified by
+  running it. The release publishes an `arm64` asset as of `v3.5.0-gdeeda96f`;
+  both binaries in it are `0xAA64`, and the `ssh.exe` reports
+  `OpenSSH_for_Windows_10.0p2 ... LibreSSL 3.8.2` on this box.
+
+  Before that asset existed, ARM64 took the x64 zip. The `rsync.exe` was fine —
+  a transfer is bounded by the socket, not by emulated CPU — but its `ssh.exe`
+  links against `System32\libcrypto.dll`, which on ARM64 is an **ARM64** binary
+  an x64 process cannot load. It died with `0xC0000135`
+  (`STATUS_DLL_NOT_FOUND`) and had to be deleted on every run. That matters more
+  than it sounds: `rsync.exe` *prefers* an `ssh.exe` in its own directory, so a
+  present-but-broken one does not degrade to the in-box client — it breaks rsync
+  outright, with an error naming a dead remote shell rather than `ssh.exe`.
+
+  The elevated half still runs `ssh -V` after unpacking and **deletes** the
+  binary if it will not start. The check is kept because it is what found that
+  problem, and it still covers a missing or too-old `libcrypto.dll` on any
+  architecture. An x64 `rsync.exe` surviving on an ARM64 box now shows up in the
+  audit as emulation *without* a listed reason, with a remedy pointing at a
+  re-run. The `core.sshCommand` step in the non-elevated half already picked its
+  candidate by running it, and is unchanged.
 - **Intel VTune reports `n/a`** rather than printing a download link: there is no
   Windows-on-Arm build, and its value is reading Intel PMU counters. Use the
   Windows Performance Toolkit (`wpr`/`xperf` to collect, `wpa` to analyse), or
   Arm Performance Studio / Streamline for Arm PMU sampling.
-- **NASM is still installed** (as emulated x64) because this box cross-compiles
-  x86/x64, where NASM is the assembler that builds them. If you only target
-  ARM64, nothing uses it — the ARM64 assembler is `armasm64.exe`, which ships
-  with MSVC.
+- **NASM is not installed on ARM64.** It assembles x86/x86-64 only — there is no
+  ARM64 target in it and no ARM64 build of it — so it went into the x64-only set
+  with the rest. The ARM64 assembler is `armasm64.exe`, which ships with MSVC.
+  Its installer is also one of the two here that fall back to a per-user
+  directory it never registers (`%LOCALAPPDATA%\bin\NASM`), so `winget uninstall`
+  cannot find it afterwards; the `Uninstall.exe` in that directory is the way out.
 - **`vswhere` stays under the 32-bit Program Files** on ARM64 too
   (`%ProgramFiles(x86)%\Microsoft Visual Studio\Installer`), so that path is
   unchanged. The VS Installer is x86-registered there by contract even though the
index f0679f14bd8950eb33f8100189c48d875d46f8ac..27f7a0ea856bf8bab085eaf6374080186d843627 100644 (file)
@@ -566,8 +566,11 @@ function Invoke-ArchAudit {
     # here as accepted emulation, and are now simply not installed on ARM64. That
     # is the whole shape of the change - the exceptions that were tolerable one at
     # a time added up to a VM full of x64 binaries.
+    #
+    # rsync came off this list when the release started publishing an arm64
+    # asset. An x64 rsync.exe on an ARM64 box is now a leftover from a run before
+    # that, not an accepted exception, so it warns and gets a remedy below.
     $KnownEmulated = @{
-        'rsync.exe'            = 'no ARM64 asset published; transfer is socket-bound, not CPU-bound'
         'iperf3.exe'           = 'no ARM64 build published; network-bound anyway'
         'py.exe'               = 'python.org ships the launcher shim as x86; it execs the native python.exe'
         'vswhere.exe'          = 'Microsoft ships x86 only; runs once per script'
@@ -589,6 +592,7 @@ function Invoke-ArchAudit {
     $Remedies = @{
         'ninja.exe' = 'Visual Studio bundles an x64 ninja. Install the native one (winget install Ninja-build.Ninja) and re-run - the NinjaPath step puts its directory at the front of the user PATH.'
         'cmake.exe' = 'Install the native build with: winget install Kitware.CMake (its MSI is machine-scope, so it needs an administrator).'
+        'rsync.exe' = 'Left over from before the release published an arm64 asset. Re-run setup-windows-with-uac.ps1 as an administrator to replace it, and the ARM64 ssh.exe beside it, with the native build.'
     }
 
     $vs = $null
index 52384d4548e317250c822b2fcbfaa67b0d4bdd23..a11e1752ddba9ad4995d8797966e0ef8fdb018a8 100644 (file)
@@ -11,8 +11,8 @@
     - OpenSSH Server (sshd) capability: automatic + started + inbound TCP 22\r
     - rsync for Windows (nuket/rsync-windows) in C:\Tools\rsync, on the machine\r
       PATH: rsync.exe plus the ssh.exe it runs, out of the release zip for this\r
-      architecture (there is no ARM64 zip; ARM64 gets the x64 one, and the\r
-      ssh.exe is kept only if it actually starts)\r
+      architecture - x86, x64 and arm64 are all published, so both binaries are\r
+      native everywhere. The ssh.exe is kept only if it actually starts.\r
     - Visual Studio Community (C++ desktop workload, x86/x64 AND ARM64 build\r
       tools, Spectre libs, Win11 SDK 26100, and - on x64 only - the WDK VSIX,\r
       Clang/LLVM, and the v141 + Windows XP targeting toolset). VS 2022 on x64,\r
@@ -53,7 +53,7 @@ $ErrorActionPreference = 'Stop'
 # under .NET Framework on Prism it is not, so it is kept only as a fallback.\r
 #\r
 # $IsArm64 gates:\r
-#   - which rsync-windows release zip is fetched (there is no ARM64 one)\r
+#   - which rsync-windows release zip is fetched (x86 / x64 / arm64, all native)\r
 #   - which Visual Studio generation is driven ($VsChannel: 18 on Arm, 17 on x64)\r
 #   - the Visual Studio component groups: ARM64 build tools in; the v141/XP\r
 #     toolset out because it has no ARM64-hosted compiler and Microsoft does not\r
@@ -321,20 +321,23 @@ try {
 # ---------------------------------------------------------------------------\r
 Write-Step 'rsync for Windows'\r
 $RsyncRepo  = 'nuket/rsync-windows'\r
-# The release publishes exactly two assets - x64 and x86 - and no ARM64 one, so\r
-# on ARM64 the x64 build is the right pick: it runs under Prism, and an emulated\r
-# x64 rsync still moves data far faster than the ~17MB/s stdin cap that the whole\r
-# reason for using this build is to avoid. (The transfer is I/O-bound on the\r
-# socket, not on emulated CPU.) Selected off $HostArch rather than\r
-# Is64BitOperatingSystem, which answers "true" on ARM64 and so cannot tell the\r
-# two 64-bit cases apart.\r
+# The release publishes x86, x64 and - since v3.5.0-gdeeda96f - arm64, so every\r
+# architecture this script runs on gets a native build. ARM64 used to take the\r
+# x64 zip under emulation, which was defensible (a transfer is bound by the\r
+# socket, not by emulated CPU) but cost the release's ssh.exe: that x64 binary\r
+# could not load the ARM64 libcrypto.dll in System32 and had to be deleted on\r
+# every run. The arm64 asset ships an ARM64 rsync.exe AND an ARM64 ssh.exe, so\r
+# both halves are now native and the fast client survives.\r
+#\r
+# Selected off $HostArch rather than Is64BitOperatingSystem, which answers "true"\r
+# on ARM64 and so cannot tell the two 64-bit cases apart.\r
 $RsyncAsset = switch ($HostArch) {\r
     'X64'   { 'rsync-windows-x64.zip' }\r
-    'Arm64' { 'rsync-windows-x64.zip' }\r
+    'Arm64' { 'rsync-windows-arm64.zip' }\r
     default { 'rsync-windows-x86.zip' }\r
 }\r
 if ($IsArm64) {\r
-    Write-Host '    ARM64: no native asset is published, using the x64 build under emulation.' -ForegroundColor Yellow\r
+    Write-Host '    ARM64: using the native arm64 asset (rsync.exe and ssh.exe both ARM64).' -ForegroundColor Green\r
 }\r
 # The /releases/latest/download/ redirect rather than the API: unauthenticated\r
 # API calls are rate-limited to 60/hour per IP, which a provisioning run behind a\r
@@ -360,15 +363,11 @@ try {
         if ($v -and ([version]($v -replace '[^0-9.]', '')) -lt [version]'3.8.2') {\r
             Write-Warning "$SysCrypto is LibreSSL $v; the release's ssh.exe is built against 3.8.2 (Windows OpenSSH Client 9.5). Update Windows, or expect ssh.exe not to start."\r
         }\r
-        if ($IsArm64) {\r
-            # On ARM64 the presence of libcrypto.dll proves less than it does on\r
-            # x64: System32 holds the ARM64 build of it, and the ssh.exe in the\r
-            # zip is x64. Whether an emulated x64 process can load that DLL comes\r
-            # down to whether it is a plain ARM64 binary or an ARM64X one - not\r
-            # something worth deciding by parsing the PE header, when running the\r
-            # binary answers it outright. Unpack it, then run it (below).\r
-            Write-Host '    ARM64: the x64 ssh.exe will be verified by running it, not by assuming.' -ForegroundColor Yellow\r
-        }\r
+        # No architecture special-case here any more: the asset chosen above\r
+        # matches the host, so the release's ssh.exe and System32's libcrypto.dll\r
+        # are the same architecture on every box. The run-it check below still\r
+        # happens on all of them - it is cheap, and it is what caught the ARM64\r
+        # mismatch back when this took the x64 zip.\r
     }\r
 \r
     # Download and unpack beside the targets, not over them, so an interrupted\r
@@ -422,11 +421,14 @@ try {
     # This matters more than it looks. rsync.exe prefers an ssh.exe sitting in its\r
     # own directory, so a present-but-unstartable one does not degrade to the\r
     # in-box client - it breaks rsync outright, and the error you get is a remote\r
-    # shell that died rather than anything naming ssh.exe. The two ways to land\r
-    # there are a missing/old System32 libcrypto.dll (x64 boxes) and an ARM64 box\r
-    # whose ARM64 libcrypto cannot be loaded by this x64 binary. Removing it is\r
-    # the repair in both cases: rsync then falls back to the ssh on the PATH,\r
-    # which on ARM64 is the native in-box client.\r
+    # shell that died rather than anything naming ssh.exe. The way to land there\r
+    # is a missing or too-old System32 libcrypto.dll. Removing it is the repair:\r
+    # rsync then falls back to the ssh on the PATH, which is the in-box client.\r
+    #\r
+    # This also used to fire on every ARM64 run, when the x64 asset was the only\r
+    # 64-bit one published and its ssh.exe could not load the ARM64 libcrypto\r
+    # (exit 0xC0000135, STATUS_DLL_NOT_FOUND). The arm64 asset fixed that at the\r
+    # source; the check stays because it is how that was found in the first place.\r
     #\r
     # EAP back to Continue for the call: ssh -V writes its version to STDERR, and\r
     # under $ErrorActionPreference = 'Stop' a native command's stderr becomes a\r
index 0a69956da6768ce5b481324bd2dad576a0bf3366..c9c7efb009eb218b96288990518de99ce89fa0b9 100644 (file)
@@ -466,7 +466,7 @@ if "%IS_ARM64%"=="1" (
     echo [setup-windows]                 Ninja, and the SDK/WPT tools.\r
     echo [setup-windows]   compiler    : MSVC from Visual Studio 2026, native ARM64. One compiler by\r
     echo [setup-windows]                 design - clang-cl and upstream LLVM are x64-box only.\r
-    echo [setup-windows]   emulated x64: iperf3 and rsync.exe, both network-bound.\r
+    echo [setup-windows]   emulated x64: iperf3, which is network-bound anyway.\r
     echo [setup-windows]   not here    : Brave, WinMerge, LLVM, NASM, AGI, OpenCppCoverage, BinSkim\r
     echo [setup-windows]                 and the WDK - dropped on ARM64, see the x64-only set above.\r
     echo [setup-windows]   unavailable : VirtualBox, the Windows 7 x86 test VM, Intel VTune,\r