Bugfix Pfaderkennung
This commit is contained in:
+36
-8
@@ -1,5 +1,6 @@
|
||||
package de.gecheckt.pdf.umbenenner.adapter.out.pathcheck;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Path;
|
||||
@@ -14,8 +15,8 @@ import de.gecheckt.pdf.umbenenner.application.validation.technicaltest.PathCheck
|
||||
* Dateisystem-basierte Implementierung von {@link PathCheckPort}.
|
||||
* <p>
|
||||
* Prüft die Zugänglichkeit von Pfaden für Quellordner, Zielordner, SQLite-Datei
|
||||
* und Prompt-Datei ausschließlich lesend. Es werden keinerlei Dateien, Ordner oder
|
||||
* andere Ressourcen angelegt, verändert oder gelöscht.
|
||||
* und Prompt-Datei. Schreibbarkeitstests erfolgen über kurzlebige Probe-Dateien,
|
||||
* die unmittelbar nach dem Schreibversuch wieder gelöscht werden.
|
||||
*
|
||||
* <h2>Windows- und Netzlaufwerk-Unterstützung</h2>
|
||||
* <p>
|
||||
@@ -27,8 +28,9 @@ import de.gecheckt.pdf.umbenenner.application.validation.technicaltest.PathCheck
|
||||
* Laufwerksbuchstaben und UNC-Pfaden statt.
|
||||
* <p>
|
||||
* Die Implementierung nutzt {@link Paths#get(String)}, {@link Files#exists(Path, java.nio.file.LinkOption...)},
|
||||
* {@link Files#isReadable(Path)} und {@link Files#isWritable(Path)}, die unter Windows
|
||||
* gemappte Laufwerke korrekt respektieren.
|
||||
* {@link Files#isReadable(Path)} sowie einen Probe-Datei-Ansatz ({@link Files#createTempFile})
|
||||
* für Schreibbarkeitstests. Dieser Ansatz ist auf gemappten Windows-Netzlaufwerken
|
||||
* zuverlässiger als {@link Files#isWritable(Path)}, das dort bekannte False Negatives liefert.
|
||||
*
|
||||
* <h2>Thread-Safety</h2>
|
||||
* <p>
|
||||
@@ -108,7 +110,7 @@ public class FilesystemPathCheckAdapter implements PathCheckPort {
|
||||
return false;
|
||||
}
|
||||
if (Files.exists(resolved)) {
|
||||
boolean writable = Files.isDirectory(resolved) && Files.isWritable(resolved);
|
||||
boolean writable = Files.isDirectory(resolved) && probeDirectoryWritable(resolved);
|
||||
if (writable) {
|
||||
LOG.debug("Ordner vorhanden und schreibbar: {}", resolved);
|
||||
} else {
|
||||
@@ -118,7 +120,7 @@ public class FilesystemPathCheckAdapter implements PathCheckPort {
|
||||
}
|
||||
// Ordner existiert nicht — prüfen ob Elternpfad schreibbar ist
|
||||
Path parent = resolved.getParent();
|
||||
if (parent != null && Files.exists(parent) && Files.isDirectory(parent) && Files.isWritable(parent)) {
|
||||
if (parent != null && Files.exists(parent) && Files.isDirectory(parent) && probeDirectoryWritable(parent)) {
|
||||
LOG.debug("Ordner nicht vorhanden, aber anlegbar (Elternpfad schreibbar): {}", resolved);
|
||||
return true;
|
||||
}
|
||||
@@ -179,9 +181,11 @@ public class FilesystemPathCheckAdapter implements PathCheckPort {
|
||||
return false;
|
||||
}
|
||||
if (Files.exists(resolved)) {
|
||||
Path parentDir = resolved.getParent();
|
||||
boolean usable = Files.isRegularFile(resolved)
|
||||
&& Files.isReadable(resolved)
|
||||
&& Files.isWritable(resolved);
|
||||
&& parentDir != null
|
||||
&& probeDirectoryWritable(parentDir);
|
||||
if (usable) {
|
||||
LOG.debug("SQLite-Datei vorhanden und nutzbar: {}", resolved);
|
||||
} else {
|
||||
@@ -191,7 +195,7 @@ public class FilesystemPathCheckAdapter implements PathCheckPort {
|
||||
}
|
||||
// Datei existiert nicht — prüfen ob Elternordner schreibbar ist
|
||||
Path parent = resolved.getParent();
|
||||
if (parent != null && Files.exists(parent) && Files.isDirectory(parent) && Files.isWritable(parent)) {
|
||||
if (parent != null && Files.exists(parent) && Files.isDirectory(parent) && probeDirectoryWritable(parent)) {
|
||||
LOG.debug("SQLite-Datei nicht vorhanden, aber anlegbar (Elternordner schreibbar): {}", resolved);
|
||||
return true;
|
||||
}
|
||||
@@ -199,6 +203,30 @@ public class FilesystemPathCheckAdapter implements PathCheckPort {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prüft die Schreibbarkeit eines Verzeichnisses durch einen echten Schreibversuch.
|
||||
* <p>
|
||||
* Eine temporäre Probe-Datei wird im übergebenen Verzeichnis angelegt und sofort
|
||||
* wieder gelöscht. Dieses Vorgehen ist auf gemappten Windows-Netzlaufwerken
|
||||
* zuverlässiger als {@link Files#isWritable(Path)}, das dort False Negatives liefern kann.
|
||||
*
|
||||
* @param directory das zu prüfende Verzeichnis; muss ein existierendes Verzeichnis sein
|
||||
* @return {@code true} wenn eine Datei im Verzeichnis angelegt werden konnte
|
||||
*/
|
||||
private static boolean probeDirectoryWritable(Path directory) {
|
||||
try {
|
||||
Path probe = Files.createTempFile(directory, ".writetest-", ".tmp");
|
||||
try {
|
||||
Files.deleteIfExists(probe);
|
||||
} catch (IOException cleanupFailure) {
|
||||
LOG.debug("Probe-Datei konnte nicht gelöscht werden: {} — {}", probe, cleanupFailure.getMessage());
|
||||
}
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Konvertiert den übergebenen Pfad-String in ein {@link Path}-Objekt.
|
||||
* <p>
|
||||
|
||||
Reference in New Issue
Block a user