support for symbolic links

This commit is contained in:
iceBear67 committed 2025-10-01 23:37:44 +08:00
1 parent 9ce86ce964
commit 482b975c79
4 files changed
+37 -4

No files matched your search

@@ -15,5 +15,6 @@ public record BundleEntry(
String name
) {
public static short ATTR_REASSEMBLE = 1;
public static short ATTR_SYMLINK = 2;
public static short MAGIC = (short) 0xA2E3;
}
@@ -16,21 +16,24 @@ import java.util.HashMap;
public class BundleReader {
protected final long maxTime;
protected final long minTime;
protected final boolean linkSymbol;
private final byte[] buffer = new byte[4096];
protected final boolean skipOldEntry;
protected final ByteBufAllocator allocator;
protected final byte[] dict;
@Builder
public BundleReader(long maxTime, long minTime, boolean skipOldEntry, ByteBufAllocator allocator, byte[] dict) {
public BundleReader(long maxTime, long minTime, boolean linkSymbol, boolean skipOldEntry, ByteBufAllocator allocator, byte[] dict) {
this.maxTime = maxTime == 0 ? Long.MAX_VALUE : maxTime;
this.minTime = minTime;
this.linkSymbol = linkSymbol;
this.skipOldEntry = skipOldEntry;
this.allocator = allocator == null ? ByteBufAllocator.DEFAULT : allocator;
this.dict = dict;
}
public void extract(Path bundle, Path destination) throws IOException {
var symbolsToLink = new HashMap<String, String>();
var readMaps = new HashMap<String, Long>();
try (var zstd = new ZstdInputStreamNoFinalizer(Files.newInputStream(bundle, StandardOpenOption.READ));
var in = new EntryInputStream(zstd)) {
@@ -52,7 +55,14 @@ public class BundleReader {
var path = destination.resolve(entry.name()); // todo prevent path underflow
var parentDir = path.getParent();
if (Files.notExists(parentDir)) Files.createDirectories(parentDir);
if ((entry.attribute() & BundleEntry.ATTR_REASSEMBLE) != 0) {
if ((entry.attribute() & BundleEntry.ATTR_SYMLINK) != 0) {
var toRead = (int) entry.length();
var strArr = new byte[toRead];
while ((toRead -= in.read(strArr, (int) (entry.length() - toRead), toRead)) > 0) ;
var target = new String(strArr);
var targetPath = Path.of(target);
Files.createSymbolicLink(targetPath, path);
} else if ((entry.attribute() & BundleEntry.ATTR_REASSEMBLE) != 0) {
var entryData = allocator.buffer();
var toRead = entry.length();
var buffer = this.buffer;
@@ -12,6 +12,7 @@ import lombok.Builder;
import lombok.SneakyThrows;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
@@ -142,6 +143,11 @@ public class BundleWriter implements Closeable {
}
public void write(Path path, boolean suggestGunzip) throws IOException {
if(Files.isDirectory(path)) return;
if(Files.isSymbolicLink(path)) {
writeSymbol(path);
return;
}
if (suggestGunzip && allowReassemble) {
//todo size limit
writeReassembleInMem(path);
@@ -150,6 +156,22 @@ public class BundleWriter implements Closeable {
writePlain(path);
}
private void writeSymbol(Path path) throws IOException {
if (!Files.isSymbolicLink(path)) return;
var target = Files.readSymbolicLink(path);
var rPath = relativeRoot.toAbsolutePath().relativize(path.toAbsolutePath());
String linkTarget;
try{
linkTarget = relativeRoot.relativize(target).toString();
} catch (Exception e) {
linkTarget = target.toAbsolutePath().toString();
}
var targetBytes = linkTarget.getBytes(StandardCharsets.UTF_8);
this.outputStream.writeEntryHeader(rPath.toString(), BundleEntry.ATTR_SYMLINK,targetBytes.length, System.currentTimeMillis());
this.outputStream.write(targetBytes);
}
@SneakyThrows
private void writeReassembleInMem(Path path) {
if (!"region".equals(path.getParent().toString()) && !path.toString().endsWith(".mca")) { // todo use pattern matcher
@@ -31,7 +31,7 @@ public class Main {
var out = opts.string("out", "Output. Can be jpack bundle or directory", null);
var help = opts.bool("help", false);
var allowGunzip = opts.bool("reasm", "Should we reassemble NBT files for maximum compression rate", true);
var linkSymbol = opts.bool("link","Should we store/decompress symbol links? This may set you vulnerable if you're decompressing a malformed archive.", true);
// useless parallel
var parallel = opts.bool("parallel", "Use parallelized bundler. This conflicts with compress options", false);
var parallelThreshold = opts.integer("threshold", "The threshold of parallel bundling", 512);
@@ -82,7 +82,7 @@ public class Main {
}
if (in.endsWith(".swb.zst")) {
BundleReader.builder().build().extract(inPath, outPath);
BundleReader.builder().linkSymbol(linkSymbol).build().extract(inPath, outPath);
} else if (out.endsWith(".swb.zst")) {
UnaryOperator<BundleWriter.BundleWriterBuilder> cfg = it -> it
.allowGunzip(allowGunzip)