Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 130 additions & 0 deletions Packages/ContainerizationEngine/Sources/DoryHV/LZFSE.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import Compression
import Foundation

public enum LZFSEError: Error, CustomStringConvertible {
case openInput(String)
case openOutput(String)
case streamInit
case read
case write
case process

public var description: String {
switch self {
case .openInput(let path): "cannot open input \(path)"
case .openOutput(let path): "cannot open output \(path)"
case .streamInit: "compression_stream_init failed"
case .read: "read failed"
case .write: "write failed"
case .process: "compression_stream_process failed"
}
}
}

/// Streaming LZFSE codec over Apple's Compression framework. Release assembly uses this exact
/// implementation to compress guest payloads, while the installed app uses the same format when it
/// expands those payloads on first launch. Keeping the codec in the signed runner avoids an ambient
/// Homebrew or system-tool dependency in the public release path.
public enum LZFSE {
private static let chunk = 1 << 20

public static func compress(source: String, destination: String) throws {
try transform(source: source, destination: destination, operation: COMPRESSION_STREAM_ENCODE)
}

public static func decompress(source: String, destination: String) throws {
try transform(source: source, destination: destination, operation: COMPRESSION_STREAM_DECODE)
}

private static func transform(
source: String,
destination: String,
operation: compression_stream_operation
) throws {
guard FileManager.default.isReadableFile(atPath: source),
let input = InputStream(fileAtPath: source) else {
throw LZFSEError.openInput(source)
}
guard let output = OutputStream(toFileAtPath: destination, append: false) else {
throw LZFSEError.openOutput(destination)
}
input.open()
output.open()
defer {
input.close()
output.close()
}

let sourceBuffer = UnsafeMutablePointer<UInt8>.allocate(capacity: chunk)
let destinationBuffer = UnsafeMutablePointer<UInt8>.allocate(capacity: chunk)
defer {
sourceBuffer.deallocate()
destinationBuffer.deallocate()
}

var stream = compression_stream(
dst_ptr: destinationBuffer,
dst_size: chunk,
src_ptr: UnsafePointer(sourceBuffer),
src_size: 0,
state: nil
)
guard compression_stream_init(&stream, operation, COMPRESSION_LZFSE)
== COMPRESSION_STATUS_OK else {
throw LZFSEError.streamInit
}
defer { compression_stream_destroy(&stream) }

// compression_stream_init resets the caller-owned source/destination fields.
stream.src_ptr = UnsafePointer(sourceBuffer)
stream.src_size = 0
stream.dst_ptr = destinationBuffer
stream.dst_size = chunk

var inputExhausted = false
while true {
if stream.src_size == 0, !inputExhausted {
let read = input.read(sourceBuffer, maxLength: chunk)
if read < 0 { throw LZFSEError.read }
if read == 0 { inputExhausted = true }
stream.src_ptr = UnsafePointer(sourceBuffer)
stream.src_size = read
}

let flags = inputExhausted ? Int32(COMPRESSION_STREAM_FINALIZE.rawValue) : 0
let status = compression_stream_process(&stream, flags)
guard status == COMPRESSION_STATUS_OK || status == COMPRESSION_STATUS_END else {
throw LZFSEError.process
}

// Compression.framework owns the partially filled destination buffer while it returns
// OK. Publish and reset that buffer only once it is full, or publish the final partial
// buffer when the stream ends. Resetting a partially filled buffer between OK calls
// produces a malformed stream once a payload crosses the input chunk boundary.
let produced: Int
switch status {
case COMPRESSION_STATUS_OK where stream.dst_size == 0:
produced = chunk
case COMPRESSION_STATUS_END:
produced = chunk - stream.dst_size
default:
produced = 0
}
var offset = 0
while offset < produced {
let written = output.write(
destinationBuffer + offset,
maxLength: produced - offset
)
if written <= 0 { throw LZFSEError.write }
offset += written
}
if status == COMPRESSION_STATUS_OK, stream.dst_size == 0 {
stream.dst_ptr = destinationBuffer
stream.dst_size = chunk
}

if status == COMPRESSION_STATUS_END { return }
}
}
}
20 changes: 19 additions & 1 deletion Packages/ContainerizationEngine/Sources/dory-hv/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,28 @@ do {
fail("application launch authority handoff failed: \(error)")
}
guard let command = arguments.first else {
fail("usage: dory-hv <smoke|madvtest|desktop|agent-ping|data-drive|engine|usb|renderer-qualify> [options]")
fail("usage: dory-hv <desktop|agent-ping|data-drive|engine|usb|renderer-qualify|lzfse> [options]")
}

switch command {
case "lzfse":
let operation = arguments.dropFirst().first
let paths = Array(arguments.dropFirst(2))
guard let operation, paths.count == 2 else {
fail("usage: dory-hv lzfse <compress|decompress> <input> <output>")
}
do {
switch operation {
case "compress":
try LZFSE.compress(source: paths[0], destination: paths[1])
case "decompress":
try LZFSE.decompress(source: paths[0], destination: paths[1])
default:
fail("usage: dory-hv lzfse <compress|decompress> <input> <output>")
}
} catch {
fail("lzfse \(operation) failed: \(error)")
}
case "data-drive":
guard arguments.count >= 2 else {
fail("usage: dory-hv data-drive <resolve|prepare|id|selected-path|select|bind-existing|recover-existing|capacity|grow|backup|verify-backup|restore> [paths]")
Expand Down
38 changes: 38 additions & 0 deletions Packages/ContainerizationEngine/Tests/DoryHVTests/LZFSETests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import Foundation
import XCTest
@testable import DoryHV

final class LZFSETests: XCTestCase {
func testRoundTripAcrossMultipleStreamChunks() throws {
let directory = FileManager.default.temporaryDirectory
.appendingPathComponent(UUID().uuidString, isDirectory: true)
try FileManager.default.createDirectory(
at: directory,
withIntermediateDirectories: true
)
defer { try? FileManager.default.removeItem(at: directory) }

let input = directory.appendingPathComponent("input.bin")
let compressed = directory.appendingPathComponent("input.bin.lzfse")
let restored = directory.appendingPathComponent("restored.bin")
let bytes = Data((0..<(3 * 1_048_576 + 257)).map { UInt8(truncatingIfNeeded: $0) })
try bytes.write(to: input)

try LZFSE.compress(source: input.path, destination: compressed.path)
try LZFSE.decompress(source: compressed.path, destination: restored.path)

XCTAssertEqual(try Data(contentsOf: restored), bytes)
}

func testMissingInputReportsItsPath() {
let missing = "/tmp/dory-lzfse-missing-\(UUID().uuidString)"
XCTAssertThrowsError(
try LZFSE.compress(source: missing, destination: "\(missing).lzfse")
) { error in
guard case .openInput(let path) = error as? LZFSEError else {
return XCTFail("unexpected error: \(error)")
}
XCTAssertEqual(path, missing)
}
}
}
Loading