X-Git-Url: https://git.saurik.com/uikittools.git/blobdiff_plain/2a72f832e35d56a748537c894b00a236bae8f16a..73b6bd3c3bfaa9fafbb3ab511cdd89f5ccddee46:/uicache.mm?ds=inline diff --git a/uicache.mm b/uicache.mm index e08fe5d..2eafcdd 100644 --- a/uicache.mm +++ b/uicache.mm @@ -1,3 +1,42 @@ +/* UIKit Tools - command-line utilities for UIKit + * Copyright (C) 2008-2012 Jay Freeman (saurik) +*/ + +/* Modified BSD License {{{ */ +/* + * Redistribution and use in source and binary + * forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the + * above copyright notice, this list of conditions + * and the following disclaimer. + * 2. Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions + * and the following disclaimer in the documentation + * and/or other materials provided with the + * distribution. + * 3. The name of the author may not be used to endorse + * or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/* }}} */ + #import #include @@ -5,6 +44,12 @@ #include #include +#include + +#include + +#include "csstore.hpp" + @interface NSMutableArray (Cydia) - (void) addInfoDictionary:(NSDictionary *)info; @end @@ -15,6 +60,10 @@ [self addObject:info]; } +- (NSArray *) allInfoDictionaries { + return self; +} + @end @interface NSMutableDictionary (Cydia) @@ -28,50 +77,150 @@ [self setObject:info forKey:bundle]; } +- (NSArray *) allInfoDictionaries { + return [self allValues]; +} + @end -int main() { +int main(int argc, const char *argv[]) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSString *path([NSString stringWithFormat:@"%@/Library/Caches/com.apple.mobile.installation.plist", NSHomeDirectory()]); + Class $LSApplicationWorkspace(objc_getClass("LSApplicationWorkspace")); + LSApplicationWorkspace *workspace($LSApplicationWorkspace == nil ? nil : [$LSApplicationWorkspace defaultWorkspace]); + + if ([workspace respondsToSelector:@selector(_LSPrivateRebuildApplicationDatabasesForSystemApps:internal:user:)]) { + if (![workspace _LSPrivateRebuildApplicationDatabasesForSystemApps:YES internal:YES user:NO]) + fprintf(stderr, "failed to rebuild application databases"); + return 0; + } - if (NSMutableDictionary *cache = [[NSMutableDictionary alloc] initWithContentsOfFile:path]) { - [cache autorelease]; + bool respring(false); + NSString *home(NSHomeDirectory()); + NSString *path([NSString stringWithFormat:@"%@/Library/Caches/com.apple.mobile.installation.plist", home]); + + system("killall -SIGSTOP SpringBoard"); + sleep(1); + + @try { + + DeleteCSStores([home UTF8String]); + + system("killall lsd"); + + if ([workspace respondsToSelector:@selector(invalidateIconCache:)]) + while (![workspace invalidateIconCache:nil]) + sleep(1); + + if (NSMutableDictionary *cache = [NSMutableDictionary dictionaryWithContentsOfFile:path]) { NSFileManager *manager = [NSFileManager defaultManager]; NSError *error = nil; - id system = [cache objectForKey:@"System"]; - if (system == nil) - goto error; + NSMutableDictionary *bundles([NSMutableDictionary dictionaryWithCapacity:16]); + + id after = [cache objectForKey:@"System"]; + if (after == nil) { error: + fprintf(stderr, "%s\n", error == nil ? strerror(errno) : [[error localizedDescription] UTF8String]); + goto cached; + } + + id before([[after copy] autorelease]); + [after removeAllObjects]; + + NSArray *cached([cache objectForKey:@"InfoPlistCachedKeys"]); - [system removeAllObjects]; + NSMutableSet *removed([NSMutableSet set]); + for (NSDictionary *info in [before allInfoDictionaries]) + if (NSString *path = [info objectForKey:@"Path"]) + [removed addObject:path]; if (NSArray *apps = [manager contentsOfDirectoryAtPath:@"/Applications" error:&error]) { for (NSString *app in apps) if ([app hasSuffix:@".app"]) { NSString *path = [@"/Applications" stringByAppendingPathComponent:app]; NSString *plist = [path stringByAppendingPathComponent:@"Info.plist"]; - if (NSMutableDictionary *info = [[NSMutableDictionary alloc] initWithContentsOfFile:plist]) { - [info autorelease]; - if ([info objectForKey:@"CFBundleIdentifier"] == nil) - fprintf(stderr, "%s missing CFBundleIdentifier", [app UTF8String]); - else { + + if (NSMutableDictionary *info = [NSMutableDictionary dictionaryWithContentsOfFile:plist]) { + if (NSString *identifier = [info objectForKey:@"CFBundleIdentifier"]) { + [bundles setObject:path forKey:identifier]; + [removed removeObject:path]; + + if (cached != nil) { + NSMutableDictionary *merged([before objectForKey:identifier]); + if (merged == nil) + merged = [NSMutableDictionary dictionary]; + else + merged = [[merged mutableCopy] autorelease]; + + for (NSString *key in cached) + if (NSObject *value = [info objectForKey:key]) + [merged setObject:value forKey:key]; + else + [merged removeObjectForKey:key]; + + info = merged; + } + [info setObject:path forKey:@"Path"]; [info setObject:@"System" forKey:@"ApplicationType"]; - [system addInfoDictionary:info]; - } + [after addInfoDictionary:info]; + } else + fprintf(stderr, "%s missing CFBundleIdentifier", [app UTF8String]); } } } else goto error; [cache writeToFile:path atomically:YES]; - if (false) error: - fprintf(stderr, "%s\n", error == nil ? strerror(errno) : [[error localizedDescription] UTF8String]); + if (workspace != nil) { + if ([workspace respondsToSelector:@selector(invalidateIconCache:)]) { + for (NSString *identifier in bundles) + [workspace invalidateIconCache:identifier]; + } else { + for (NSString *identifier in bundles) { + NSString *path([bundles objectForKey:identifier]); + [workspace unregisterApplication:[NSURL fileURLWithPath:path]]; + } + } + + for (NSString *identifier in bundles) { + NSString *path([bundles objectForKey:identifier]); + if (kCFCoreFoundationVersionNumber >= 800) + [workspace registerApplicationDictionary:[after objectForKey:identifier]]; + else + [workspace registerApplication:[NSURL fileURLWithPath:path]]; + } + + for (NSString *path in removed) + [workspace unregisterApplication:[NSURL fileURLWithPath:path]]; + } } else fprintf(stderr, "cannot open cache file. incorrect user?\n"); + cached: + + if (respring || kCFCoreFoundationVersionNumber >= 550.32) { + unlink([[NSString stringWithFormat:@"%@/Library/Caches/com.apple.springboard-imagecache-icons", home] UTF8String]); + unlink([[NSString stringWithFormat:@"%@/Library/Caches/com.apple.springboard-imagecache-icons.plist", home] UTF8String]); + + unlink([[NSString stringWithFormat:@"%@/Library/Caches/com.apple.springboard-imagecache-smallicons", home] UTF8String]); + unlink([[NSString stringWithFormat:@"%@/Library/Caches/com.apple.springboard-imagecache-smallicons.plist", home] UTF8String]); + + system([[NSString stringWithFormat:@"rm -rf %@/Library/Caches/SpringBoardIconCache", home] UTF8String]); + system([[NSString stringWithFormat:@"rm -rf %@/Library/Caches/SpringBoardIconCache-small", home] UTF8String]); + + system([[NSString stringWithFormat:@"rm -rf %@/Library/Caches/com.apple.IconsCache", home] UTF8String]); + } + + system("killall installd"); + + } @finally { + system("killall -SIGCONT SpringBoard"); + } - notify_post("com.apple.mobile.application_installed"); + if (respring) + system("launchctl stop com.apple.SpringBoard"); + else + notify_post("com.apple.mobile.application_installed"); [pool release];