gnodet opened a new pull request, #2205: URL: https://github.com/apache/maven-resolver/pull/2205
## Summary Fixes a Windows regression introduced by PR #2083 (resolver 2.0.24 / Maven 3.10.0): `mvn install` throws `java.nio.file.AccessDeniedException` when an IDE (e.g. IntelliJ IDEA) keeps the installed `.jar` open. Closes #2204 · Closes apache/maven#13329 ## Root Cause PR #2083 replaced the old stream-based file copy with `Files.move()` + `ATOMIC_MOVE` in `PathProcessorSupport.retryingMove()` to fix the f007 security finding. That was the right thing to do — but it introduced a behavioral regression on Windows. **Old behavior (resolver ≤ 1.9.x):** `classicCopy()` opens the target with a truncating `FileOutputStream`. On Windows, this succeeds even when another process has the file open for reading, because the stream open uses `FILE_SHARE_READ` semantics. **New behavior (resolver 2.0.24):** `Files.move()` maps to `MoveFileEx`/`ReplaceFile` on Windows. These system calls **require exclusive access** to the destination — any open handle (including a shared read-only handle from an IDE's class loader) causes `AccessDeniedException`. With only 5 retries at 50 ms (250 ms total), a persistent IDE lock is never released and all retries fail. | Operation | Target open by reader? | Succeeds on Windows? | |---|---|---| | `FileOutputStream(target)` (stream write) | Yes (shared read) | ✅ Yes | | `Files.move(src, target, ATOMIC_MOVE)` | Yes (shared read) | ❌ No — needs exclusive | ## Fix After exhausting all `WINDOWS_MOVE_ATTEMPTS` with `AccessDeniedException`, fall back to `classicCopy()` directly to the target as a last resort, logging a `WARN` to identify the situation. The atomicity guarantee is lost for this edge case (a concurrent reader may observe a partially written file), but the build completes — matching the pre-2.0.24 behavior that users relied on. A new system property controls the fallback: ``` -Dorg.eclipse.aether.spi.io.PathProcessor.WINDOWS_CLASSIC_COPY_FALLBACK=false ``` Setting it to `false` disables the fallback and propagates the original `AccessDeniedException` (strict never-truncate mode). The fallback is also exposed as an overridable `protected boolean isClassicCopyFallbackEnabled()` method for subclasses and tests. ## Note on PR #2198 The open PR #2198 (hard-link install) sidesteps this problem for `mvn install` by not copying at all. This PR fixes the underlying `retryingMove` logic, which is also exercised in other code paths (download to local repo, `writeFile`). The two PRs are complementary. ## Changes - `maven-resolver-spi/pom.xml` — add `slf4j-api` compile dependency and `slf4j-simple` test dependency - `PathProcessorSupport.java` — add `WINDOWS_CLASSIC_COPY_FALLBACK` constant, `isClassicCopyFallbackEnabled()` hook, fallback logic in `retryingMove()` - `PathProcessorSupportTest.java` — rename `retryingMoveNeverTruncatesTargetOnFailure` → `...WhenFallbackDisabled` (adds subclass override), add `retryingMoveFallsBackToClassicCopyOnPersistentLock` _Hermès Agent (Claude Sonnet 4.6) on behalf of Guillaume Nodet_ -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
