From ecd82f5e2097be88024ccd82dfc697ba23a009f5 Mon Sep 17 00:00:00 2001 From: Lubos Dolezel Date: Wed, 19 Feb 2020 16:52:46 +0100 Subject: [PATCH] Incomplete PKSignedContainer code, used even by some non-Apple utilities --- src/external/foundation | 2 +- .../PackageKit/CMakeLists.txt | 9 + .../include/PackageKit/PKSignedContainer.h | 31 ++ .../PackageKit/src/PKSignedContainer.m | 282 +++++++++++++++++- 4 files changed, 319 insertions(+), 5 deletions(-) diff --git a/src/external/foundation b/src/external/foundation index 3315c85d6..ea28d29af 160000 --- a/src/external/foundation +++ b/src/external/foundation @@ -1 +1 @@ -Subproject commit 3315c85d62cdb45944fbe7bbe9827e67f474b1ea +Subproject commit ea28d29af1ef48d2fff9a13435c72f4fcd53e25b diff --git a/src/private-frameworks/PackageKit/CMakeLists.txt b/src/private-frameworks/PackageKit/CMakeLists.txt index 064184bd7..2c05cb1f8 100644 --- a/src/private-frameworks/PackageKit/CMakeLists.txt +++ b/src/private-frameworks/PackageKit/CMakeLists.txt @@ -1,5 +1,11 @@ project(PackageKit) +include_directories( + ${CMAKE_SOURCE_DIR}/src/external/libarchive/libarchive +) + +add_definitions(-fobjc-arc) + set(pk_sources src/functions.c src/PKAddExtendedAttributesInstallOperation.m @@ -135,5 +141,8 @@ add_framework(PackageKit DEPENDENCIES system Foundation + xar + archive + lzma ) diff --git a/src/private-frameworks/PackageKit/include/PackageKit/PKSignedContainer.h b/src/private-frameworks/PackageKit/include/PackageKit/PKSignedContainer.h index d795f9cf6..9630b1d2d 100644 --- a/src/private-frameworks/PackageKit/include/PackageKit/PKSignedContainer.h +++ b/src/private-frameworks/PackageKit/include/PackageKit/PKSignedContainer.h @@ -17,6 +17,37 @@ You should have received a copy of the GNU General Public License along with Darling. If not, see . */ +#import +#import +#import +#import +#import +#import +#import +#import + @interface PKSignedContainer : NSObject +{ + xar_t _xar; + xar_file_t _xar_file; + xar_stream _xar_stream; + struct archive* _archive; + lzma_stream _zs; + uint64_t _blockLength, _flags; + + char _inbuf[4096]; + char _outbuf[4096 * 1024]; + BOOL _abort; +} + +- (instancetype)initForReadingFromContainerAtURL:(NSURL *)url + error:(NSError **)error; + +- (void)startUnarchivingAtPath:(NSString *)path + notifyOnQueue:(dispatch_queue_t)queue + progress:(void (^)(double, NSString *))progressBlock + finish:(void (^)(BOOL))finishBlock; + +- (xar_stream*)_xarStream; @end diff --git a/src/private-frameworks/PackageKit/src/PKSignedContainer.m b/src/private-frameworks/PackageKit/src/PKSignedContainer.m index ab5a8f6e1..64e5570f1 100644 --- a/src/private-frameworks/PackageKit/src/PKSignedContainer.m +++ b/src/private-frameworks/PackageKit/src/PKSignedContainer.m @@ -18,15 +18,289 @@ along with Darling. If not, see . */ #import +#include +#include +#include +#include +#include + +static int open_cb(struct archive *a, void *_client_data) +{ + return ARCHIVE_OK; +} + +static int close_cb(struct archive *a, void *_client_data) +{ + return ARCHIVE_OK; +} + +struct ReadContext +{ + xar_stream* xs; + uint64_t blockLength; + + char inbuf[4096]; + char outbuf[4096 * 1024]; +}; + +static ssize_t read_cb(struct archive *a, void *_client_data, const void **_buffer) +{ + struct ReadContext* rc = (struct ReadContext*) _client_data; + + if (!rc->blockLength) + { + // TODO + } +} + +static NSError* makeError(NSURL* url, NSString* errorString) +{ + NSDictionary* userInfo = @{ + NSLocalizedDescriptionKey: errorString, + NSFilePathErrorKey: [url absoluteString] + }; + return [[NSError alloc] initWithDomain:@"PackageKit" + code: 0 + userInfo: userInfo]; +} + +static inline BOOL xar_read(char *buffer, uint32_t size, xar_stream *stream) { + stream->next_out = buffer; + stream->avail_out = size; + while (stream->avail_out) + { + if (xar_extract_tostream(stream) != XAR_STREAM_OK) + return NO; + } + return YES; +} + +static inline uint64_t xar_read_64(xar_stream *stream) { + char t[8]; + xar_read(t, 8, stream); + return __builtin_bswap64(*(uint64_t *)t); +} + +static int copy_data(struct archive *ar, struct archive *aw) +{ + int r; + const void *buff; + size_t size; + off_t offset; + + for (;;) + { + r = archive_read_data_block(ar, &buff, &size, &offset); + if (r == ARCHIVE_EOF) + return (ARCHIVE_OK); + if (r != ARCHIVE_OK) + return (r); + r = archive_write_data_block(aw, buff, size, offset); + if (r != ARCHIVE_OK) + { + NSLog(@"archive_write_data_block error\n"); + return (r); + } + } +} @implementation PKSignedContainer -- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { - return [NSMethodSignature signatureWithObjCTypes: "v@:"]; +- (instancetype)initForReadingFromContainerAtURL:(NSURL *)url + error:(NSError **)error +{ + const char* path = [url fileSystemRepresentation]; + + _xar = xar_open(path, READ); + + if (!_xar) + { + *error = makeError(url, @"Cannot open input XIP (XAR error)"); + return nil; + } + + xar_iter_t i = xar_iter_new(); + _xar_file = xar_file_first(_xar, i); + char *xarPath; + + while (strncmp((xarPath = xar_get_path(_xar_file)), "Content", 7) && (_xar_file = xar_file_next(i))) + free(xarPath); + + free(xarPath); + xar_iter_free(i); + + if (!_xar_file) + { + *error = makeError(url, @"Not a XIP, 'Content' not found"); + return nil; + } + + if (xar_verify(_xar, _xar_file) != XAR_STREAM_OK) + { + *error = makeError(url, @"xar_verify failed"); + return nil; + } + + if (xar_extract_tostream_init(_xar, _xar_file, &_xar_stream) != XAR_STREAM_OK) + { + *error = makeError(url, @"XAR init failed"); + return nil; + } + + char header[4]; + xar_read(header, sizeof(header), &_xar_stream); + + if (strncmp(header, "pbzx", 4) != 0) + { + *error = makeError(url, @"Not a pbzx stream"); + return nil; + } + + xar_extract_tostream_end(&_xar_stream); + + return self; +} + +- (void)dealloc +{ + lzma_end(&_zs); + + if (_xar) + xar_close(_xar); + if (_archive) + archive_read_finish(_archive); +} + +- (void)cancelOperation:(id)arg1 +{ + _abort = YES; +} + +- (void)startUnarchivingAtPath:(NSString *)path + notifyOnQueue:(dispatch_queue_t)queue + progress:(void (^)(double, NSString *))progressBlock + finish:(void (^)(BOOL))finishBlock +{ + if (_archive) + { + NSLog(@"PackageKit: Unarchiving already in progress\n"); + dispatch_async(queue, ^{ + finishBlock(NO); + }); + return; + } + + int dfd = open([path UTF8String], O_RDONLY | O_DIRECTORY); + if (dfd == -1) + { + NSLog(@"PackageKit: target directory cannot be opened\n"); + dispatch_async(queue, ^{ + finishBlock(NO); + }); + return; + } + + if (lzma_stream_decoder(&_zs, UINT64_MAX, LZMA_CONCATENATED) != LZMA_OK) + { + close(dfd); + NSLog(@"PackageKit: LZMA init failed\n"); + dispatch_async(queue, ^{ + finishBlock(NO); + }); + return; + } + + char header[4]; + xar_read(header, sizeof(header), &_xar_stream); + _flags = xar_read_64(&_xar_stream); + + _archive = archive_read_new(); + + archive_read_support_format_cpio(_archive); + + dispatch_queue_t q = dispatch_queue_create("org.darlinghq.PackageKit", NULL); + + _abort = NO; + dispatch_async(q, ^{ + BOOL result = YES; + struct ReadContext* rc = (struct ReadContext*) malloc(sizeof(struct ReadContext)); + + rc->xs = &_xar_stream; + rc->blockLength = 0; + + pthread_fchdir_np(dfd); + close(dfd); + + int err = archive_read_open(_archive, (__bridge void*) self, open_cb, read_cb, close_cb); + if (err != ARCHIVE_OK) + { + NSLog(@"archive_read_open error\n"); + result = NO; + goto out; + } + + struct archive* ext = archive_write_disk_new(); + + while (!_abort) + { + struct archive_entry *entry; + int r = archive_read_next_header(_archive, &entry); + + if (r == ARCHIVE_EOF) + break; + + if (r != ARCHIVE_OK) + { + NSLog(@"archive_read_next_header failed\n"); + result = NO; + break; + } + + r = archive_write_header(ext, entry); + if (r != ARCHIVE_OK) + { + NSLog(@"archive_write_header failed\n"); + result = NO; + break; + } + r = copy_data(_archive, ext); + if (r != ARCHIVE_OK) + { + NSLog(@"failed to write data\n"); + result = NO; + break; + } + + r = archive_write_finish_entry(ext); + if (r != ARCHIVE_OK) + { + NSLog(@"archive_write_finish_entry failed\n"); + result = NO; + break; + } + + // TODO: report progress + } + +out: + archive_write_finish(ext); + archive_read_close(_archive); + archive_read_finish(_archive); + _archive = NULL; + free(rc); + pthread_fchdir_np(-1); + + dispatch_async(queue, ^{ + finishBlock(result); + }); + }); + + dispatch_release(q); } -- (void)forwardInvocation:(NSInvocation *)anInvocation { - NSLog(@"Stub called: %@ in %@", NSStringFromSelector([anInvocation selector]), [self class]); +- (xar_stream*)_xarStream +{ + return &_xar_stream; } @end -- 2.51.2