11#import < Foundation/Foundation.h>
2+ #include < sys/clonefile.h>
23#include < sys/stat.h>
34#include " AppInfo.h"
45#include " common.h"
7374 return relPath;
7475}
7576
76- NSArray * appBackupFileNames = @[
77- @" Info.plist" ,
78- @" _CodeSignature" ,
79- @" SC_Info" ,
80- ];
81-
82- // will skip empty dir
83- int backupApp (NSString * bundlePath)
84- {
85- NSFileManager * fm = NSFileManager .defaultManager ;
86-
87- NSString * backup = [bundlePath stringByAppendingPathExtension: @" appbackup" ];
88-
89- if ([fm fileExistsAtPath: backup]) {
90- ASSERT (![fm fileExistsAtPath: [backup.stringByDeletingLastPathComponent stringByAppendingPathComponent: @" .appbackup" ]]);
91- ASSERT ([fm removeItemAtPath: backup error: nil ]);
92- }
93-
94- NSDictionary * appInfo = [NSDictionary dictionaryWithContentsOfFile: [bundlePath stringByAppendingPathComponent: @" Info.plist" ]];
95- BOOL encryptedApp = [[NSFileManager defaultManager ] fileExistsAtPath: [bundlePath stringByAppendingPathComponent: @" SC_Info" ]];
96-
97- NSString *resolvedPath = [[bundlePath stringByResolvingSymlinksInPath ] stringByStandardizingPath ];
98- NSDirectoryEnumerator <NSURL *> *directoryEnumerator = [fm enumeratorAtURL: [NSURL fileURLWithPath: resolvedPath isDirectory: YES ] includingPropertiesForKeys: @[NSURLIsRegularFileKey ] options: 0 errorHandler: nil ];
99-
100- int backupFileCount=0 ;
101- for (NSURL *enumURL in directoryEnumerator) { @autoreleasepool {
102- NSNumber *isFile=nil ;
103- ASSERT ([enumURL getResourceValue: &isFile forKey: NSURLIsRegularFileKey error: nil ] && isFile!=nil );
104- if (![isFile boolValue ]) continue ;
105-
106- BOOL copy = NO ;
107-
108- if ([appBackupFileNames containsObject: enumURL.path.lastPathComponent]) {
109- copy = YES ;
110- }
111- else if (encryptedApp) {
112- if ([appInfo[@" CFBundleExecutable" ] isEqualToString: enumURL.path.lastPathComponent]) {
113- copy = YES ;
114- }
115- }
116- else {
117- bool ismacho=false , islib=false ;
118- ASSERT (machoGetInfo (enumURL.fileSystemRepresentation , &ismacho, &islib));
119- if (ismacho) {
120- copy = YES ;
121- }
122- }
123-
124-
125- // bundlePath should be a real-path
126- NSString * subPath = relativize (enumURL, [NSURL fileURLWithPath: bundlePath], YES );
127- NSString * backupPath = [backup stringByAppendingPathComponent: subPath];
128-
129- if (![fm fileExistsAtPath: backupPath.stringByDeletingLastPathComponent])
130- ASSERT ([fm createDirectoryAtPath: backupPath.stringByDeletingLastPathComponent withIntermediateDirectories: YES attributes: nil error: nil ]);
131-
132- if (copy)
133- {
134- NSError * err=nil ;
135- ASSERT ([fm copyItemAtPath: enumURL.path toPath: backupPath error: &err]);
136- SYSLOG (" copied %@ => %@" , enumURL.path , backupPath);
137-
138- backupFileCount++;
139- }
140- else {
141- ASSERT (link (enumURL.path .UTF8String , backupPath.UTF8String )==0 );
142- }
143-
144- } }
145-
146- ASSERT (backupFileCount > 0 );
147-
148- ASSERT ([[NSString new ] writeToFile: [backup.stringByDeletingLastPathComponent stringByAppendingPathComponent: @" .appbackup" ] atomically: YES encoding: NSUTF8StringEncoding error: nil ]);
149-
150- return 0 ;
151- }
152-
15377// if the app package is changed/upgraded, the directory structure may change and some paths may become invalid.
15478int restoreApp (NSString * bundlePath)
15579{
15680 SYSLOG (" restoreApp=%@" , bundlePath);
15781 NSFileManager * fm = NSFileManager .defaultManager ;
15882
15983 NSString * backup = [bundlePath stringByAppendingPathExtension: @" appbackup" ];
84+ NSString * backupFlag = [bundlePath.stringByDeletingLastPathComponent stringByAppendingPathComponent: @" .appbackup" ];
16085
16186 ASSERT ([fm fileExistsAtPath: backup]);
162- ASSERT ([fm fileExistsAtPath: [backup.stringByDeletingLastPathComponent stringByAppendingPathComponent: @" .appbackup" ]]);
87+ ASSERT ([fm fileExistsAtPath: backupFlag]);
88+ NSString * backupver = [NSString stringWithContentsOfFile: backupFlag encoding: NSASCIIStringEncoding error: nil ];
89+ if (backupver.intValue >= 1 ) {
90+ ASSERT ([fm removeItemAtPath: bundlePath error: nil ]);
91+ ASSERT ([fm moveItemAtPath: backup toPath: bundlePath error: nil ]);
92+ ASSERT ([fm removeItemAtPath: [backup.stringByDeletingLastPathComponent stringByAppendingPathComponent: @" .appbackup" ] error: nil ]);
93+ return 0 ;
94+ }
95+
96+ struct stat st;
97+ if (lstat ([bundlePath stringByAppendingString: @" /.jbroot" ].fileSystemRepresentation , &st)==0 )
98+ ASSERT ([fm removeItemAtPath: [bundlePath stringByAppendingString: @" /.jbroot" ] error: nil ]);
99+ if (lstat ([bundlePath stringByAppendingString: @" /.prelib" ].fileSystemRepresentation , &st)==0 )
100+ ASSERT ([fm removeItemAtPath: [bundlePath stringByAppendingString: @" /.prelib" ] error: nil ]);
101+ if (lstat ([bundlePath stringByAppendingString: @" /.preload" ].fileSystemRepresentation , &st)==0 )
102+ ASSERT ([fm removeItemAtPath: [bundlePath stringByAppendingString: @" /.preload" ] error: nil ]);
103+ if (lstat ([bundlePath stringByAppendingString: @" /.rebuild" ].fileSystemRepresentation , &st)==0 )
104+ ASSERT ([fm removeItemAtPath: [bundlePath stringByAppendingString: @" /.rebuild" ] error: nil ]);
163105
164106 NSString *resolvedPath = [[backup stringByResolvingSymlinksInPath ] stringByStandardizingPath ];
165107 NSDirectoryEnumerator <NSURL *> *directoryEnumerator = [fm enumeratorAtURL: [NSURL fileURLWithPath: resolvedPath isDirectory: YES ] includingPropertiesForKeys: @[NSURLIsRegularFileKey ] options: 0 errorHandler: nil ];
@@ -197,6 +139,23 @@ int restoreApp(NSString* bundlePath)
197139 return 0 ;
198140}
199141
142+ int backupApp (NSString * bundlePath)
143+ {
144+ NSFileManager * fm = NSFileManager .defaultManager ;
145+
146+ NSString * backup = [bundlePath stringByAppendingPathExtension: @" appbackup" ];
147+
148+ if ([fm fileExistsAtPath: backup]) {
149+ ASSERT (![fm fileExistsAtPath: [backup.stringByDeletingLastPathComponent stringByAppendingPathComponent: @" .appbackup" ]]);
150+ ASSERT ([fm removeItemAtPath: backup error: nil ]);
151+ }
152+
153+ ASSERT (clonefile (bundlePath.fileSystemRepresentation , backup.fileSystemRepresentation , CLONE_ACL) == 0 );
154+
155+ ASSERT ([@" 1" writeToFile: [backup.stringByDeletingLastPathComponent stringByAppendingPathComponent: @" .appbackup" ] atomically: YES encoding: NSUTF8StringEncoding error: nil ]);
156+
157+ return 0 ;
158+ }
200159
201160int enableForApp (NSString * bundlePath)
202161{
@@ -276,16 +235,6 @@ int disableForApp(NSString* bundlePath)
276235 else if ([appInfo[@" CFBundleIdentifier" ] hasPrefix: @" com.apple." ] || hasTrollstoreMarker (bundlePath.fileSystemRepresentation ))
277236 {
278237
279- struct stat st;
280- if (lstat ([bundlePath stringByAppendingString: @" /.jbroot" ].fileSystemRepresentation , &st)==0 )
281- ASSERT ([fm removeItemAtPath: [bundlePath stringByAppendingString: @" /.jbroot" ] error: nil ]);
282- if (lstat ([bundlePath stringByAppendingString: @" /.prelib" ].fileSystemRepresentation , &st)==0 )
283- ASSERT ([fm removeItemAtPath: [bundlePath stringByAppendingString: @" /.prelib" ] error: nil ]);
284- if (lstat ([bundlePath stringByAppendingString: @" /.preload" ].fileSystemRepresentation , &st)==0 )
285- ASSERT ([fm removeItemAtPath: [bundlePath stringByAppendingString: @" /.preload" ] error: nil ]);
286- if (lstat ([bundlePath stringByAppendingString: @" /.rebuild" ].fileSystemRepresentation , &st)==0 )
287- ASSERT ([fm removeItemAtPath: [bundlePath stringByAppendingString: @" /.rebuild" ] error: nil ]);
288-
289238 ASSERT (restoreApp (bundlePath) == 0 );
290239
291240 ASSERT (spawnBootstrap ((char *[]){" /usr/bin/uicache" ," -s" ," -p" , rootfsPrefix (bundlePath).UTF8String , NULL }, nil , nil ) == 0 );
@@ -294,18 +243,13 @@ int disableForApp(NSString* bundlePath)
294243 {
295244 // should be an appstored app
296245
297- struct stat st;
298- if (lstat ([bundlePath stringByAppendingString: @" /.jbroot" ].fileSystemRepresentation , &st)==0 )
299- ASSERT ([fm removeItemAtPath: [bundlePath stringByAppendingString: @" /.jbroot" ] error: nil ]);
300- if (lstat ([bundlePath stringByAppendingString: @" /.prelib" ].fileSystemRepresentation , &st)==0 )
301- ASSERT ([fm removeItemAtPath: [bundlePath stringByAppendingString: @" /.prelib" ] error: nil ]);
302- if (lstat ([bundlePath stringByAppendingString: @" /.preload" ].fileSystemRepresentation , &st)==0 )
303- ASSERT ([fm removeItemAtPath: [bundlePath stringByAppendingString: @" /.preload" ] error: nil ]);
304- if (lstat ([bundlePath stringByAppendingString: @" /.rebuild" ].fileSystemRepresentation , &st)==0 )
305- ASSERT ([fm removeItemAtPath: [bundlePath stringByAppendingString: @" /.rebuild" ] error: nil ]);
246+ BOOL encryptedApp = [NSFileManager .defaultManager fileExistsAtPath: [bundlePath stringByAppendingPathComponent: @" SC_Info" ]];
247+ NSString * backupVersion = [NSString stringWithContentsOfFile: [bundlePath stringByAppendingString: @" /../.appbackup" ] encoding: NSASCIIStringEncoding error: nil ];
306248
307249 ASSERT (restoreApp (bundlePath) == 0 );
308250
251+ if (encryptedApp && backupVersion.intValue >=1 ) return 0 ;
252+
309253 // unregister or respring to keep app's icon on home screen
310254 ASSERT (spawnBootstrap ((char *[]){" /usr/bin/uicache" ," -u" , rootfsPrefix (bundlePath).UTF8String , NULL }, nil , nil ) == 0 );
311255 // come back
0 commit comments