blob: 99e093d358af303057adaa965ccc54fc8a6762e1 [file] [log] [blame]
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +01001package eu.mulk.jgvariant.ostree;
2
3import eu.mulk.jgvariant.core.Decoder;
Matthias Andreas Benkarde74b8002021-12-30 18:52:10 +01004import java.nio.ByteBuffer;
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +01005import java.nio.ByteOrder;
6import java.util.List;
7
8/**
Matthias Andreas Benkard05114642021-12-29 21:51:29 +01009 * A payload file from a static delta.
10 *
11 * <p>The first byte is a compression byte: {@code 0} for none, {@code 'x'} for LZMA. The actual
12 * GVariant data begins right after.
13 *
14 * <p>Reference: {@code
15 * ostree-repo-static-delta-private.h#OSTREE_STATIC_DELTA_PART_PAYLOAD_FORMAT_V0}
16 *
17 * @param fileModes the {@link FileMode}s of the files generated by this delta payload.
18 * @param xattrs the {@link Xattr}s of the files generated by this delta payload.
19 * @param rawDataSource the data bytes used in the delta operations.
20 * @param operations the operations to apply during delta patching.
21 * @see DeltaSuperblock
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010022 */
23public record DeltaPartPayload(
24 List<FileMode> fileModes,
25 List<List<Xattr>> xattrs,
26 ByteString rawDataSource,
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010027 List<DeltaOperation> operations) {
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010028
29 private static final Decoder<DeltaPartPayload> DECODER =
30 Decoder.ofStructure(
Matthias Andreas Benkarde74b8002021-12-30 18:52:10 +010031 DeltaPartPayload.class,
32 Decoder.ofArray(FileMode.decoder()),
33 Decoder.ofArray(Decoder.ofArray(Xattr.decoder())),
34 ByteString.decoder(),
35 ByteString.decoder().map(DeltaPartPayload::parseDeltaOperationList))
36 .contramap(DeltaPartPayload::preparse);
37
38 private static ByteBuffer preparse(ByteBuffer byteBuffer) {
39 byte compressionByte = byteBuffer.get(0);
40 return switch (compressionByte) {
41 case 0 -> byteBuffer.slice(1, byteBuffer.limit());
42 case (byte) 'x' -> throw new UnsupportedOperationException(
43 "LZMA compression of static deltas is unsupported");
44 default -> throw new IllegalArgumentException(
45 "unrecognized compression byte '%d'".formatted(compressionByte));
46 };
47 }
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010048
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010049 private static List<DeltaOperation> parseDeltaOperationList(ByteString byteString) {
50 return byteString.stream().map(DeltaOperation::valueOf).toList();
51 }
52
53 /**
54 * A file mode triple (UID, GID, and permission bits).
55 *
56 * @param uid
57 * @param gid
58 * @param mode
59 */
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010060 public record FileMode(int uid, int gid, int mode) {
61
62 private static final Decoder<FileMode> DECODER =
63 Decoder.ofStructure(
64 FileMode.class,
65 Decoder.ofInt().withByteOrder(ByteOrder.LITTLE_ENDIAN),
66 Decoder.ofInt().withByteOrder(ByteOrder.LITTLE_ENDIAN),
67 Decoder.ofInt().withByteOrder(ByteOrder.LITTLE_ENDIAN));
68
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010069 /**
70 * Acquires a {@link Decoder} for the enclosing type.
71 *
72 * @return a possibly shared {@link Decoder}.
73 */
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010074 public static Decoder<FileMode> decoder() {
75 return DECODER;
76 }
77 }
78
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010079 /**
80 * Acquires a {@link Decoder} for the enclosing type.
81 *
82 * <p>FIXME: The first byte is actually a compression byte: {@code 0} for none, {@code 'x'} for
83 * LZMA.
84 *
85 * @return a possibly shared {@link Decoder}.
86 */
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010087 public static Decoder<DeltaPartPayload> decoder() {
88 return DECODER;
89 }
90}