support for symbolic links
This commit is contained in:
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)
|
||||
|
||||
Reference in new issue
Block a user