From a54c077e0c76bbbc690743c45ba116061d9add58 Mon Sep 17 00:00:00 2001 From: Sam Bingner Date: Wed, 14 Apr 2021 11:03:43 -1000 Subject: Better support for some older iOS versions --- uicache.mm | 154 +++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 84 insertions(+), 70 deletions(-) (limited to 'uicache.mm') diff --git a/uicache.mm b/uicache.mm index 7e4c830..31a6139 100644 --- a/uicache.mm +++ b/uicache.mm @@ -131,6 +131,7 @@ -(NSString*)applicationIdentifier; -(_LSApplicationState*)appState; -(NSURL*)bundleURL; +-(NSURL*)resourcesDirectoryURL; -(NSURL*)containerURL; -(NSDate*)registeredDate; @end @@ -168,6 +169,12 @@ typedef enum { +(id)actionWithReason:(id)reason options:(int64_t)options targetURL:(NSURL*)url; @end +@implementation LSApplicationProxy (uicache) +-(NSURL*)appURL { + return [self respondsToSelector:@selector(bundleURL)]?[self bundleURL]:[self resourcesDirectoryURL]; +} +@end + static int verbose=0; static int standard_uicache(void); static Class $MCMPluginKitPluginDataContainer; @@ -192,25 +199,11 @@ NSArray *getAllApplications() return [NSArray array]; } -const char *getFileSystemRepresentation(NSURL *url) -{ - if ([url respondsToSelector:@selector(fileSystemRepresentation)]) - return [url fileSystemRepresentation]; - void *buffer = malloc(0x400); - if (buffer) { - UInt8 *data = (UInt8 *)[NSData dataWithBytesNoCopy:buffer length:0x400].bytes; - if (CFURLGetFileSystemRepresentation((__bridge CFURLRef)url, true, data, 0x400)) - return (const char *)buffer; - free(buffer); - } - return ""; -} - int list_all_apps(void) { NSArray *allApps = getAllApplications(); for (LSApplicationProxy *app in allApps) { - printf("%s : %s\n", [[app applicationIdentifier] UTF8String], getFileSystemRepresentation([app bundleURL])); + printf("%s : %s\n", app.applicationIdentifier.UTF8String, app.appURL.path.UTF8String); } return 0; } @@ -232,20 +225,26 @@ int list_app(NSString *appid) { printf("Information for %s\n", appid.UTF8String); if (hasAppState) printf("State: %s\n", [[appState description] UTF8String]); - printf("Path: %s\n", getFileSystemRepresentation([app bundleURL])); - printf("Container Path: %s\n", getFileSystemRepresentation([app containerURL])); + printf("Path: %s\n", app.appURL.path.UTF8String); + printf("Container Path: %s\n", app.containerURL.path.UTF8String); return 0; } +NSString *pathInApplications(NSString *path) { + NSArray *pathComponents = [path pathComponents]; + if ([path hasPrefix:@"/Applications/"]) { + return [NSString pathWithComponents:[pathComponents subarrayWithRange:NSMakeRange(0, 3)]]; + } else if ([path hasPrefix:@"/var/stash"] && [pathComponents[4] isEqualToString:@"Applications"]) { + // Matches /var/stash/*/Applications/ + return [@"/Applications/" stringByAppendingPathComponent:pathComponents[5]]; + } + return nil; +} + NSString *getAppPath(NSString *path) { if (force) return path; - path = [path stringByResolvingSymlinksInPath]; - if (![path hasPrefix:@"/Applications/"]) { - fprintf(stderr, "Error: Path must be within /Applications/\n"); - return nil; - } - return [NSString pathWithComponents:[[path pathComponents] subarrayWithRange:NSMakeRange(0, 3)]]; + return pathInApplications(path);; } bool appIsRegistered(NSString *path) @@ -253,9 +252,9 @@ bool appIsRegistered(NSString *path) if (force) return true; @autoreleasepool { path = getAppPath(path); - if (!path) return false; for (LSApplicationProxy *app in getAllApplications()) { - if ([path isEqualToString:[[app bundleURL] path]]) return true; + NSString *appPath = getAppPath(app.appURL.path); + if ([path isEqualToString:appPath]) return true; } return false; } @@ -265,22 +264,24 @@ bool unregisterPath(NSString *path) { @autoreleasepool { NSURL *url = nil; - if (verbose) fprintf(stderr, "Unregistering %s\n", path.lastPathComponent.UTF8String); if (![path hasPrefix:@"/"]) { // Maybe it's an app_id LSApplicationProxy *app = [LSApplicationProxy applicationProxyForIdentifier:path]; if (app) { - url = [app bundleURL]; - if (verbose) fprintf(stderr, "Resolved bundle ID %s to path %s\n", path.UTF8String, getFileSystemRepresentation(url)); + url = [app appURL]; + if (verbose) fprintf(stderr, "Resolved bundle ID %s to path %s\n", path.UTF8String, url.path.UTF8String); path = [url path]; } } else { path = getAppPath(path); - if (path) { - url = [NSURL fileURLWithPath:path]; + if (!path) { + fprintf(stderr, "Error: Path \"%s\" must be within /Applications/\n", path.UTF8String); + return false; } + url = [NSURL fileURLWithPath:path]; } if (!url) return false; + if (verbose) fprintf(stderr, "Unregistering %s\n", path.lastPathComponent.UTF8String); if (appIsRegistered(path) && ![workspace unregisterApplication:url]) { fprintf(stderr, "Error: unregisterApplication failed for %s\n", path.lastPathComponent.UTF8String); return false; @@ -298,9 +299,10 @@ bool registerPath(NSString *path) } NSString *realPath = getAppPath(path); if (!realPath) { - if (verbose) fprintf(stderr, "unable to determine path for %s\n", path.UTF8String); + fprintf(stderr, "Error: Path \"%s\" must be within /Applications/\n", path.UTF8String); return false; } + if (verbose) fprintf(stderr, "Refreshing %s\n", realPath.lastPathComponent.UTF8String); NSDictionary *infoDictionary = [NSDictionary dictionaryWithContentsOfFile: [realPath stringByAppendingPathComponent:@"Info.plist"]]; NSString *bundleID = [infoDictionary objectForKey:@"CFBundleIdentifier"]; @@ -329,8 +331,8 @@ bool registerPath(NSString *path) [NSMutableDictionary dictionary], @"_LSBundlePlugins", nil]; - id appContainer = [$MCMAppDataContainer containerWithIdentifier:bundleID - createIfNecessary:YES existed:NULL error:nil]; + id appContainer = $MCMAppDataContainer?[$MCMAppDataContainer containerWithIdentifier:bundleID + createIfNecessary:YES existed:NULL error:nil]:nil; NSString *appContainerPath = [[appContainer url] path]; if (appContainerPath) { @@ -341,7 +343,7 @@ bool registerPath(NSString *path) NSString *pluginPath = [pluginsPath stringByAppendingPathComponent:plugin]; NSString *pluginInfoPlistPath = [pluginPath stringByAppendingPathComponent:@"Info.plist"]; NSString *pluginBundleIdentifier = [[NSDictionary dictionaryWithContentsOfFile:pluginInfoPlistPath] objectForKey:@"CFBundleIdentifier"]; - if (pluginBundleIdentifier) { + if ($MCMPluginKitPluginDataContainer && pluginBundleIdentifier) { id pluginContainer = [$MCMPluginKitPluginDataContainer containerWithIdentifier:pluginBundleIdentifier createIfNecessary:YES existed:NULL error:nil]; NSURL *pluginContainerURL = [pluginContainer url]; @@ -556,6 +558,7 @@ pid_t pidOfCydia(void) { if (verbose) fprintf(stderr, "Found Cydia running with PID: %d\n", pid); return false; } + if (verbose>2) fprintf(stderr, "%s is not Cydia...\n", program); } return true; }); @@ -566,6 +569,38 @@ pid_t pidOfCydia(void) { return -1; } +bool cydiaCache(pid_t cydia_pid) { + // We are in cydia and trying to refresh it - this will kill it. Let's schedule it for later. + if (verbose) fprintf(stderr, "Waiting to refresh Cydia...\n"); + pid_t pid = fork(); + if (pid == 0) { + setpgrp(); + signal(SIGHUP, SIG_IGN); + signal(SIGPIPE, SIG_IGN); + fclose(stdin); + freopen("/dev/null", "a", stderr); + freopen("/dev/null", "a", stdout); + pid = fork(); + if (pid == 0) { + while (kill(cydia_pid, 0)==0) { + sleep(1); + } + const char *uicache = (*_NSGetArgv())[0]; + execl(uicache, uicache, "-vvvvvvv", NULL); + fprintf(stderr, "Unable to exec\n"); + fflush(stderr); + exit(-1); + } + exit(0); + } else if (pid > 0) { + int stat; + waitpid(pid, &stat, 0); + return true; + } + fprintf(stderr, "Unable to fork\n"); + return false; +} + int optimized_uicache(void) { __block int rv=0; NSMutableDictionary *registered = [NSMutableDictionary new]; @@ -583,36 +618,10 @@ int optimized_uicache(void) { } pid_t cydia_pid; if ([found[2] isEqualToString:@"Cydia.app"] && - (cydia_pid = pidOfCydia()) > 0) { - // We are in cydia and trying to refresh it - this will kill it. Let's schedule it for later. - if (verbose) fprintf(stderr, "Waiting to refresh Cydia...\n"); - pid_t pid = fork(); - if (pid == 0) { - setpgrp(); - signal(SIGHUP, SIG_IGN); - signal(SIGPIPE, SIG_IGN); - fclose(stdin); - freopen("/dev/null", "a", stderr); - freopen("/dev/null", "a", stdout); - pid = fork(); - if (pid == 0) { - while (kill(cydia_pid, 0)==0) { - sleep(1); - } - const char *uicache = (*_NSGetArgv())[0]; - execl(uicache, uicache, "-vvvvvvv", NULL); - fprintf(stderr, "Unable to exec\n"); - fflush(stderr); - exit(-1); - } - exit(0); - } else if (pid > 0) { - int stat; - waitpid(pid, &stat, 0); - return; - } else { - fprintf(stderr, "Unable to fork\n"); - } + (cydia_pid = pidOfCydia()) > 0 && + cydiaCache(cydia_pid)) { + // Is cydia and we queued a uicache in background so skip + return; } if (!registerPath(appPath)) rv++; } @@ -623,13 +632,14 @@ int optimized_uicache(void) { NSMutableArray *finds = [NSMutableArray new]; if (verbose>1) fprintf(stderr, "Enumerating apps\n"); for (LSApplicationProxy *app in getAllApplications()) { - NSString *path = [[app bundleURL] path]; - if (![path hasPrefix:@"/Applications/"]) continue; + NSString *path = pathInApplications([[app appURL] path]); + if (!path) continue; if (verbose>1) fprintf(stderr, "Checking %s\n", path.lastPathComponent.UTF8String); - NSDate *lastRegistered = [app registeredDate]; if ([fm fileExistsAtPath:path]) { + NSDate *lastRegistered = [app registeredDate]; + pid_t cydia_pid; // Check for updated components NSTask *find = [NSTask new]; [find setLaunchPath:@"/usr/bin/find"]; @@ -740,14 +750,15 @@ int main(int argc, const char *argv[]) list_apps = true; break; case 'p': - paths[@(optarg)] = @YES; + [paths setObject:@YES forKey:@(optarg)]; have_path = true; break; case 'r': respring = true; break; case 'u': - unregister_paths[@(optarg)] = @YES; + [unregister_paths setObject:@YES forKey:@(optarg)]; + fprintf(stderr, "%s\n", optarg); have_path = true; break; case 'v': @@ -758,6 +769,7 @@ int main(int argc, const char *argv[]) } } if (list_apps) { + if (verbose>2) fprintf(stderr, "Listing apps\n"); if (do_all || have_path || respring) { usage(); return 1; @@ -768,16 +780,18 @@ int main(int argc, const char *argv[]) return list_all_apps(); } if (do_all || !$MCMPluginKitPluginDataContainer || !$MCMAppDataContainer || !$LSApplicationWorkspace) { + if (verbose>2) fprintf(stderr, "Using standard uicache\n"); rv = standard_uicache(); } else if (have_path) { + if (verbose>2) fprintf(stderr, "Using per-path uicache\n"); for (NSString *path in [paths allKeys]) { - if (verbose) fprintf(stderr, "Refreshing %s\n", path.UTF8String); if (!registerPath(path)) rv++; } for (NSString *path in [unregister_paths allKeys]) { if (!unregisterPath(path)) rv++; } } else { + if (verbose>2) fprintf(stderr, "Using optimized uicache\n"); rv += optimized_uicache(); } if ( respring ) -- cgit v1.2.3