From 5fb130498fe49d2a3e81748a08510e888efbdc61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20Carpenter=E2=84=A2=EF=B8=8F?= Date: Thu, 26 Feb 2026 16:58:27 -0300 Subject: [PATCH] Disable filesystem timestamp resolution persistence to JGit config When user.home resolves to a relative or invalid path (e.g. "?" on JDK 8-18 in containers without a /etc/passwd entry for the running UID), FileStoreAttributes.saveToConfig() creates a config file inside the working directory. This pollutes the repository working tree, and the file ends up in the LST manifest. On Windows, the "?" character is illegal in paths, causing InvalidPathException when processing the LST. The in-memory FileStoreAttributes cache is sufficient for the lifetime of a JVM process. The only cost of not persisting is re-measuring filesystem timestamp resolution on the next JVM start, which is fast. --- .../java/org/openrewrite/jgit/util/FS.java | 66 ++----------------- 1 file changed, 5 insertions(+), 61 deletions(-) diff --git a/jgit/src/main/java/org/openrewrite/jgit/util/FS.java b/jgit/src/main/java/org/openrewrite/jgit/util/FS.java index 75aa34979..e67722192 100644 --- a/jgit/src/main/java/org/openrewrite/jgit/util/FS.java +++ b/jgit/src/main/java/org/openrewrite/jgit/util/FS.java @@ -712,67 +712,11 @@ private static Optional readFromConfig( private static void saveToConfig(FileStore s, FileStoreAttributes c) { - StoredConfig jgitConfig; - try { - jgitConfig = SystemReader.getInstance().getJGitConfig(); - } catch (IOException | ConfigInvalidException e) { - LOG.error(JGitText.get().saveFileStoreAttributesFailed, e); - return; - } - long resolution = c.getFsTimestampResolution().toNanos(); - TimeUnit resolutionUnit = getUnit(resolution); - long resolutionValue = resolutionUnit.convert(resolution, - TimeUnit.NANOSECONDS); - - long minRacyThreshold = c.getMinimalRacyInterval().toNanos(); - TimeUnit minRacyThresholdUnit = getUnit(minRacyThreshold); - long minRacyThresholdValue = minRacyThresholdUnit - .convert(minRacyThreshold, TimeUnit.NANOSECONDS); - - final int max_retries = 5; - int retries = 0; - boolean succeeded = false; - String key = getConfigKey(s); - while (!succeeded && retries < max_retries) { - try { - jgitConfig.setString( - ConfigConstants.CONFIG_FILESYSTEM_SECTION, key, - ConfigConstants.CONFIG_KEY_TIMESTAMP_RESOLUTION, - String.format("%d %s", //$NON-NLS-1$ - Long.valueOf(resolutionValue), - resolutionUnit.name().toLowerCase())); - jgitConfig.setString( - ConfigConstants.CONFIG_FILESYSTEM_SECTION, key, - ConfigConstants.CONFIG_KEY_MIN_RACY_THRESHOLD, - String.format("%d %s", //$NON-NLS-1$ - Long.valueOf(minRacyThresholdValue), - minRacyThresholdUnit.name().toLowerCase())); - jgitConfig.save(); - succeeded = true; - } catch (LockFailedException e) { - // race with another thread, wait a bit and try again - try { - retries++; - if (retries < max_retries) { - Thread.sleep(100); - LOG.debug("locking {} failed, retries {}/{}", //$NON-NLS-1$ - jgitConfig, Integer.valueOf(retries), - Integer.valueOf(max_retries)); - } else { - LOG.warn(MessageFormat.format( - JGitText.get().lockFailedRetry, jgitConfig, - Integer.valueOf(retries))); - } - } catch (InterruptedException e1) { - Thread.currentThread().interrupt(); - break; - } - } catch (IOException e) { - LOG.error(MessageFormat.format( - JGitText.get().cannotSaveConfig, jgitConfig), e); - break; - } - } + // Don't persist filesystem timestamp resolution to the JGit config + // file. When user.home resolves to a relative or invalid path (e.g. + // "?" on JDK 8-18 in containers), this creates files inside the + // working tree that pollute the repository. The in-memory cache is + // sufficient; the only cost is re-measuring on the next JVM start. } private static String getConfigKey(FileStore s) {