提交 aa799e39 编写于 作者: D Daniel Trebbien 提交者: Oliver Gondža

[JENKINS-49971] Fix a race condition in Util.loadFile() (#3225)

* Fix a race condition in Util.loadFile()

If the file is deleted in between when its existence is checked and the
file is opened for reading, then the method will fail to return an empty
string.

* Switch to using FileUtils.readFileToString()

(cherry picked from commit aaae71af)
上级 99592e0a
...@@ -87,6 +87,9 @@ import javax.annotation.Nullable; ...@@ -87,6 +87,9 @@ import javax.annotation.Nullable;
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
/** /**
* Various utility methods that don't have more proper home. * Various utility methods that don't have more proper home.
* *
...@@ -179,43 +182,54 @@ public class Util { ...@@ -179,43 +182,54 @@ public class Util {
} }
/** /**
* Loads the contents of a file into a string. * Reads the entire contents of the text file at <code>logfile</code> into a
* string using the {@link Charset#defaultCharset() default charset} for
* decoding. If no such file exists, an empty string is returned.
* @param logfile The text file to read in its entirety.
* @return The entire text content of <code>logfile</code>.
* @throws IOException If an error occurs while reading the file.
* @deprecated call {@link #loadFile(java.io.File, java.nio.charset.Charset)}
* instead to specify the charset to use for decoding (preferably
* {@link java.nio.charset.StandardCharsets#UTF_8}).
*/ */
@Nonnull @Nonnull
@Deprecated
public static String loadFile(@Nonnull File logfile) throws IOException { public static String loadFile(@Nonnull File logfile) throws IOException {
return loadFile(logfile, Charset.defaultCharset()); return loadFile(logfile, Charset.defaultCharset());
} }
/**
* Reads the entire contents of the text file at <code>logfile</code> into a
* string using <code>charset</code> for decoding. If no such file exists,
* an empty string is returned.
* @param logfile The text file to read in its entirety.
* @param charset The charset to use for decoding the bytes in <code>logfile</code>.
* @return The entire text content of <code>logfile</code>.
* @throws IOException If an error occurs while reading the file.
*/
@Nonnull @Nonnull
public static String loadFile(@Nonnull File logfile, @Nonnull Charset charset) throws IOException { public static String loadFile(@Nonnull File logfile, @Nonnull Charset charset) throws IOException {
if(!logfile.exists()) // Note: Until charset handling is resolved (e.g. by implementing
return ""; // https://issues.jenkins-ci.org/browse/JENKINS-48923 ), this method
// must be able to handle character encoding errors. As reported at
StringBuilder str = new StringBuilder((int)logfile.length()); // https://issues.jenkins-ci.org/browse/JENKINS-49112 Run.getLog() calls
// loadFile() to fully read the generated log file. This file might
// We're not using Files.newBufferedReader() here because there is a // contain unmappable and/or malformed byte sequences. We need to make
// difference in how an InputStreamReader constructed from a Charset and // sure that in such cases, no CharacterCodingException is thrown.
// the reader returned by Files.newBufferedReader() handle malformed and
// unmappable byte sequences for the specified encoding; the latter is
// more picky and will throw a CharacterCodingException. See:
// https://issues.jenkins-ci.org/browse/JENKINS-49060?focusedCommentId=325989&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-325989
// //
// As reported at https://issues.jenkins-ci.org/browse/JENKINS-49112 // One approach that cannot be used is to call Files.newBufferedReader()
// Run.getLog() calls loadFile() to fully read the generated log file. // because there is a difference in how an InputStreamReader constructed
// Until charset handling is resolved (e.g. by implementing // from a Charset and the reader returned by Files.newBufferedReader()
// https://issues.jenkins-ci.org/browse/JENKINS-48923 ), malformed // handle malformed and unmappable byte sequences for the specified
// bytes will need to be tolerated. // encoding; the latter is more picky and will throw an exception.
try (InputStream rawIn = Files.newInputStream(fileToPath(logfile)); // See: https://issues.jenkins-ci.org/browse/JENKINS-49060?focusedCommentId=325989&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-325989
Reader r = new BufferedReader(new InputStreamReader(rawIn, charset))) { try {
char[] buf = new char[1024]; return FileUtils.readFileToString(logfile, charset);
int len; } catch (FileNotFoundException e) {
while ((len = r.read(buf, 0, buf.length)) > 0) return "";
str.append(buf, 0, len);
} catch (Exception e) { } catch (Exception e) {
throw new IOException("Failed to fully read " + logfile + " using charset " + charset.name(), e); throw new IOException("Failed to fully read " + logfile, e);
} }
return str.toString();
} }
/** /**
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册