Subject: [PATCH] Fix #23802: Don't overwrite valid preferences files with invalid preferences files
---
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
diff --git a/src/org/openstreetmap/josm/data/Preferences.java b/src/org/openstreetmap/josm/data/Preferences.java
|
a
|
b
|
|
| 439 | 439 | |
| 440 | 440 | // Backup old preferences if there are old preferences |
| 441 | 441 | if (initSuccessful && prefFile.exists() && prefFile.length() > 0) { |
| 442 | | Utils.copyFile(prefFile, backupFile); |
| | 442 | checkFileValidity(prefFile, f -> Utils.copyFile(f, backupFile)); |
| 443 | 443 | } |
| 444 | 444 | |
| 445 | 445 | try (PreferencesWriter writer = new PreferencesWriter( |
| … |
… |
|
| 450 | 450 | } |
| 451 | 451 | |
| 452 | 452 | File tmpFile = new File(prefFile + "_tmp"); |
| 453 | | Files.move(tmpFile.toPath(), prefFile.toPath(), StandardCopyOption.REPLACE_EXISTING); |
| | 453 | // Only replace the pref file if the _tmp file is valid |
| | 454 | checkFileValidity(tmpFile, f -> Files.move(f.toPath(), prefFile.toPath(), StandardCopyOption.REPLACE_EXISTING)); |
| 454 | 455 | |
| 455 | 456 | setCorrectPermissions(prefFile); |
| 456 | 457 | setCorrectPermissions(backupFile); |
| 457 | 458 | } |
| 458 | 459 | |
| | 460 | /** |
| | 461 | * Ensure that a preferences file is "ok" before copying/moving it over another preferences file |
| | 462 | * @param file The file to check |
| | 463 | * @param consumer The consumer that will perform the copy/move action |
| | 464 | * @throws IOException If there is an issue reading/writing the file |
| | 465 | */ |
| | 466 | private static void checkFileValidity(File file, ThrowingConsumer<File, IOException> consumer) throws IOException { |
| | 467 | try { |
| | 468 | // But don't back up if the current preferences are invalid. |
| | 469 | // The validations are expensive (~2/3 CPU, ~1/3 memory), but this isn't a "hot" method |
| | 470 | PreferencesReader.validateXML(file); |
| | 471 | PreferencesReader reader = new PreferencesReader(file, false); |
| | 472 | reader.parse(); |
| | 473 | consumer.accept(file); |
| | 474 | } catch (SAXException | XMLStreamException e) { |
| | 475 | Logging.trace(e); |
| | 476 | Logging.debug("Invalid preferences file (" + file + ") due to: " + e.getMessage()); |
| | 477 | } |
| | 478 | } |
| | 479 | |
| 459 | 480 | private static void setCorrectPermissions(File file) { |
| 460 | 481 | if (!file.setReadable(false, false) && Logging.isTraceEnabled()) { |
| 461 | 482 | Logging.trace(tr("Unable to set file non-readable {0}", file.getAbsolutePath())); |
| … |
… |
|
| 973 | 994 | saveOnPut = enable; |
| 974 | 995 | } |
| 975 | 996 | } |
| | 997 | |
| | 998 | /** |
| | 999 | * A consumer that can throw an exception |
| | 1000 | * @param <T> The object type to accept |
| | 1001 | * @param <E> The throwable type |
| | 1002 | */ |
| | 1003 | private interface ThrowingConsumer<T, E extends Throwable> { |
| | 1004 | /** |
| | 1005 | * Accept an object |
| | 1006 | * @param object The object to accept |
| | 1007 | * @throws E The exception that can be thrown |
| | 1008 | */ |
| | 1009 | void accept(T object) throws E; |
| | 1010 | } |
| 976 | 1011 | } |