fix: close Windows extraction namespace gaps
Reject alternate data streams, reserved Win32 device names, and trailing-dot or trailing-space aliases before internal ZIP, JVM, or native extraction writes. Preflight native archive entry lists, reconcile opened JVM outputs to partial or removed state on abnormal results, and replace hardlink-based owner markers with portable exclusive reservation plus atomic replacement while allowing direct scoped extraction to continue when marker persistence is unavailable.
This commit is contained in:
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
@@ -668,20 +668,25 @@ public final class JBindExtractorMain {
|
||||
return output;
|
||||
}
|
||||
|
||||
private static String normalizeEntryName(String value, String fallback) {
|
||||
String entry = value == null ? "" : value.trim();
|
||||
if (entry.length() == 0) {
|
||||
return fallback;
|
||||
}
|
||||
entry = entry.replace('\\', '/');
|
||||
private static String normalizeEntryName(String value, String fallback) {
|
||||
String entry = value == null ? "" : value;
|
||||
if (entry.trim().length() == 0) {
|
||||
return fallback;
|
||||
}
|
||||
entry = entry.replace('\\', '/');
|
||||
while (entry.startsWith("./")) {
|
||||
entry = entry.substring(2);
|
||||
}
|
||||
if (entry.length() == 0) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
String[] segments = entry.split("/", -1);
|
||||
if (entry.length() == 0) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
while (entry.endsWith("/")) {
|
||||
entry = entry.substring(0, entry.length() - 1);
|
||||
}
|
||||
validateWindowsEntryName(entry);
|
||||
|
||||
String[] segments = entry.split("/", -1);
|
||||
StringBuilder sanitized = new StringBuilder();
|
||||
for (int i = 0; i < segments.length; i++) {
|
||||
if (i > 0) {
|
||||
@@ -693,8 +698,33 @@ public final class JBindExtractorMain {
|
||||
if (entry.length() == 0) {
|
||||
return fallback;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
private static void validateWindowsEntryName(String entry) {
|
||||
if (entry.startsWith("/") || entry.matches("^[a-zA-Z]:.*")) {
|
||||
throw new IllegalArgumentException("Ungueltiger Windows-Archivpfad: " + entry);
|
||||
}
|
||||
String[] segments = entry.split("/", -1);
|
||||
for (String segment : segments) {
|
||||
if (segment.length() == 0 || ".".equals(segment) || "..".equals(segment)
|
||||
|| segment.endsWith(".") || segment.endsWith(" ")
|
||||
|| WINDOWS_SPECIAL_CHARS_RE.matcher(segment).find()) {
|
||||
throw new IllegalArgumentException("Ungueltiger Windows-Archivpfad: " + entry);
|
||||
}
|
||||
for (int i = 0; i < segment.length(); i++) {
|
||||
if (segment.charAt(i) < 32) {
|
||||
throw new IllegalArgumentException("Ungueltiger Windows-Archivpfad: " + entry);
|
||||
}
|
||||
}
|
||||
int dot = segment.indexOf('.');
|
||||
String base = (dot >= 0 ? segment.substring(0, dot) : segment).toUpperCase(Locale.ROOT);
|
||||
if ("CON".equals(base) || "PRN".equals(base) || "AUX".equals(base) || "NUL".equals(base)
|
||||
|| base.matches("COM[1-9¹²³]") || base.matches("LPT[1-9¹²³]")) {
|
||||
throw new IllegalArgumentException("Reservierter Windows-Archivpfad: " + entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static long safeSize(Long value) {
|
||||
if (value == null) {
|
||||
|
||||
Reference in New Issue
Block a user