diff --git a/changelog.html b/changelog.html index a4af17ce93eda1c416099a455d8f17dcf9362b54..2540ce9d85f01774de4a9ac3e885a0ad27ab91a5 100644 --- a/changelog.html +++ b/changelog.html @@ -67,6 +67,9 @@ Upcoming changes
  • Since 1.518, fingerprint serialization broke when job or file names contained XML special characters like ampersands. (issue 18337) +
  • + Robustness against truncated fingerprint files. + (issue 19515)
  • JavaScript error in the checkUrl computation shouldn't break the job configuration page. (issue 19457) diff --git a/core/src/main/java/hudson/model/Fingerprint.java b/core/src/main/java/hudson/model/Fingerprint.java index 59a759460e2152a58f3cf71ae8de4edaffede145..0e91bf7cf2ec76fcf634c3bf47799ba1a151013a 100644 --- a/core/src/main/java/hudson/model/Fingerprint.java +++ b/core/src/main/java/hudson/model/Fingerprint.java @@ -38,11 +38,13 @@ import hudson.BulkChange; import hudson.Extension; import hudson.model.listeners.ItemListener; import hudson.model.listeners.SaveableListener; +import hudson.util.AtomicFileWriter; import hudson.util.HexBinaryConverter; import hudson.util.Iterators; import hudson.util.PersistedList; import hudson.util.RunList; import hudson.util.XStream2; +import java.io.EOFException; import jenkins.model.FingerprintFacet; import jenkins.model.Jenkins; import jenkins.model.TransientFingerprintFacetFactory; @@ -995,8 +997,12 @@ public class Fingerprint implements ModelObject, Saveable { } } - if (modified) + if (modified) { + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, "Saving trimmed {0}", getFingerprintFile(md5sum)); + } save(); + } return modified; } @@ -1101,8 +1107,9 @@ public class Fingerprint implements ModelObject, Saveable { if (facets.isEmpty()) { file.getParentFile().mkdirs(); // JENKINS-16301: fast path for the common case. - PrintWriter w = new PrintWriter(file, "UTF-8"); + AtomicFileWriter afw = new AtomicFileWriter(file); try { + PrintWriter w = new PrintWriter(afw); w.println(""); w.println(""); w.print(" "); @@ -1139,8 +1146,9 @@ public class Fingerprint implements ModelObject, Saveable { w.println(" "); w.print(""); w.flush(); + afw.commit(); } finally { - w.close(); + afw.abort(); } } else { // Slower fallback that can persist facets. @@ -1230,7 +1238,7 @@ public class Fingerprint implements ModelObject, Saveable { file.delete(); return null; } - String parseError = messageOfXmlPullParserException(e); + String parseError = messageOfParseException(e); if (parseError != null) { logger.log(Level.WARNING, "Malformed XML in {0}: {1}", new Object[] {configFile, parseError}); file.delete(); @@ -1240,13 +1248,13 @@ public class Fingerprint implements ModelObject, Saveable { throw e; } } - private static String messageOfXmlPullParserException(Throwable t) { - if (t instanceof XmlPullParserException) { + private static String messageOfParseException(Throwable t) { + if (t instanceof XmlPullParserException || t instanceof EOFException) { return t.getMessage(); } Throwable t2 = t.getCause(); if (t2 != null) { - return messageOfXmlPullParserException(t2); + return messageOfParseException(t2); } else { return null; } diff --git a/core/src/main/java/hudson/model/FingerprintCleanupThread.java b/core/src/main/java/hudson/model/FingerprintCleanupThread.java index f8be385ba0cb3af6acec6eb46bab9eac52e4d59e..c04830911d751933cf3dc2a35a828dedf8c47063 100644 --- a/core/src/main/java/hudson/model/FingerprintCleanupThread.java +++ b/core/src/main/java/hudson/model/FingerprintCleanupThread.java @@ -101,11 +101,13 @@ public final class FingerprintCleanupThread extends AsyncPeriodicWork { try { Fingerprint fp = Fingerprint.load(fingerprintFile); if (fp == null || !fp.isAlive()) { + logger.fine("deleting obsolete " + fingerprintFile); fingerprintFile.delete(); return true; } else { // get the fingerprint in the official map so have the changes visible to Jenkins // otherwise the mutation made in FingerprintMap can override our trimming. + logger.finer("possibly trimming " + fingerprintFile); fp = Jenkins.getInstance()._getFingerprint(fp.getHashString()); return fp.trim(); }