main.m 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104
  1. //
  2. // main.m
  3. // octalConversion
  4. //
  5. // Created by Kevin Bradley on 6/28/18.
  6. // Copyright © 2018 nito. All rights reserved.
  7. //
  8. #import <Foundation/Foundation.h>
  9. #include <stdio.h>
  10. #include <errno.h>
  11. #include <libgen.h>
  12. #include <string.h>
  13. #include <stdlib.h>
  14. #include <unistd.h>
  15. #include <getopt.h>
  16. #import <objc/runtime.h>
  17. #import <sys/utsname.h>
  18. typedef NS_ENUM(NSInteger, BSPackageFileType)
  19. {
  20. BSPackageFileTypeFile,
  21. BSPackageFileTypeDirectory,
  22. BSPackageFileTypeBlock,
  23. BSPackageFileTypeCharacter,
  24. BSPackageFileTypeLink,
  25. BSPackageFileTypePipe,
  26. BSPackageFileTypeSocket,
  27. BSPackageFileTypeUnknown
  28. };
  29. #define DLog(format, ...) CFShow((__bridge CFStringRef)[NSString stringWithFormat:format, ## __VA_ARGS__]);
  30. #define FM [NSFileManager defaultManager]
  31. /*
  32. fileType, @"fileType",octalPermissions, @"octalPermissions", octalUG, @"octalUG", size, @"size", date, @"date", time, @"time", linkDest, @"linkDest", fullPath, @"fullPath", nil];
  33. */
  34. @interface NSObject (Additions)
  35. -(NSArray *)ivars;
  36. -(NSArray *)properties;
  37. @end
  38. @implementation NSObject (Additions)
  39. - (NSArray *)properties
  40. {
  41. u_int count;
  42. objc_property_t* properties = class_copyPropertyList(self.class, &count);
  43. NSMutableArray* propArray = [NSMutableArray arrayWithCapacity:count];
  44. for (int i = 0; i < count ; i++)
  45. {
  46. const char* propertyName = property_getName(properties[i]);
  47. NSString *propName = [NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding];
  48. [propArray addObject:propName];
  49. }
  50. free(properties);
  51. return propArray;
  52. }
  53. -(NSArray *)ivars
  54. {
  55. Class clazz = [self class];
  56. u_int count;
  57. Ivar* ivars = class_copyIvarList(clazz, &count);
  58. NSMutableArray* ivarArray = [NSMutableArray arrayWithCapacity:count];
  59. for (int i = 0; i < count ; i++)
  60. {
  61. const char* ivarName = ivar_getName(ivars[i]);
  62. [ivarArray addObject:[NSString stringWithCString:ivarName encoding:NSUTF8StringEncoding]];
  63. }
  64. free(ivars);
  65. return ivarArray;
  66. }
  67. @end
  68. @interface DebPackageModel : NSObject
  69. @property (nonatomic, copy) NSString *name;
  70. @property (nonatomic, copy) NSString *package;
  71. @property (nonatomic, copy) NSString *source;
  72. @property (nonatomic, copy) NSString *version;
  73. @property (nonatomic, copy) NSString *priority;
  74. @property (nonatomic, copy) NSString *essential;
  75. @property (nonatomic, copy) NSArray *depends;
  76. @property (nonatomic, copy) NSString *maintainer;
  77. @property (nonatomic, copy) NSString *packageDescription; //cant be description, that is reservered
  78. @property (nonatomic, copy) NSString *homepage;
  79. @property (nonatomic, copy) NSString *author;
  80. @property (nonatomic, copy) NSString *icon;
  81. @property (nonatomic, copy) NSString *depiction;
  82. @property (nonatomic, copy) NSString *preDepends;
  83. @property (nonatomic, copy) NSString *breaks;
  84. @property (nonatomic, copy) NSString *status;
  85. @property (nonatomic, copy) NSString *tag;
  86. @property (nonatomic, copy) NSString *architecture;
  87. @property (nonatomic, copy) NSString *section;
  88. - (instancetype)initWithRawControlString:(NSString *)controlString;
  89. @end
  90. @implementation DebPackageModel
  91. - (NSString *)description {
  92. NSString *orig = [super description];
  93. return [NSString stringWithFormat:@"%@ = %@ (%@)", orig, self.package, self.version];
  94. }
  95. - (NSString*) fullDescription {
  96. NSString *orig = [super description];
  97. NSMutableDictionary *details = [NSMutableDictionary new];
  98. NSArray *props = [self properties];
  99. [props enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  100. NSString *cv = [self valueForKey:obj];
  101. if (cv){
  102. details[obj] = cv;
  103. }
  104. }];
  105. return [NSString stringWithFormat:@"%@ = %@", orig, details];
  106. }
  107. + (NSDictionary *)dependencyDictionaryFromString:(NSString *)depend
  108. {
  109. NSMutableCharacterSet *whitespaceAndPunctuationSet = [NSMutableCharacterSet characterSetWithCharactersInString:@"()"];
  110. [whitespaceAndPunctuationSet formUnionWithCharacterSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
  111. NSScanner *stringScanner = [[NSScanner alloc] initWithString:depend];
  112. stringScanner.charactersToBeSkipped = whitespaceAndPunctuationSet;
  113. NSString *name = nil;
  114. NSInteger i = 0;
  115. NSMutableDictionary *predicate = [NSMutableDictionary new];
  116. while ([stringScanner scanUpToCharactersFromSet:whitespaceAndPunctuationSet intoString:&name]) {
  117. // NSLog(@"%@ pass %li", name, (long)i);
  118. switch (i) {
  119. case 0 :
  120. predicate[@"package"] = name;
  121. break;
  122. case 1:
  123. predicate[@"predicate"] = name;
  124. break;
  125. case 2:
  126. predicate[@"requirement"] = name;
  127. break;
  128. default:
  129. break;
  130. }
  131. i++;
  132. }
  133. return predicate;
  134. }
  135. + (NSArray *)dependencyArrayFromString:(NSString *)depends
  136. {
  137. NSMutableArray *cleanArray = [[NSMutableArray alloc] init];
  138. NSArray *dependsArray = [depends componentsSeparatedByString:@","];
  139. for (id depend in dependsArray)
  140. {
  141. NSArray *spaceDelimitedArray = [depend componentsSeparatedByString:@" "];
  142. NSString *isolatedDependency = [[spaceDelimitedArray objectAtIndex:0] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
  143. if ([isolatedDependency length] == 0)
  144. isolatedDependency = [[spaceDelimitedArray objectAtIndex:1] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
  145. NSDictionary *dependDict = [self dependencyDictionaryFromString:depend];
  146. //DLog(@"depend dict: %@", dependDict);
  147. [cleanArray addObject:dependDict];
  148. }
  149. return cleanArray;
  150. }
  151. + (NSDictionary *)JSONKeyPathsByPropertyKey {
  152. return @{
  153. @"name": @"Name",
  154. @"package": @"Package",
  155. @"source": @"Source",
  156. @"version": @"Version",
  157. @"priority": @"Priority",
  158. @"essential": @"Essential",
  159. @"depends": @"Depends",
  160. @"maintainer": @"Maintainer",
  161. @"packageDescription": @"Description",
  162. @"homepage": @"Homepage",
  163. @"icon": @"Icon",
  164. @"author": @"Author",
  165. @"preDepends": @"Pre-Depends",
  166. @"breaks": @"Breaks",
  167. @"depiction": @"Depiction",
  168. @"tag": @"Tag",
  169. @"architecture": @"Architecture",
  170. @"section": @"Section",
  171. @"osMax": @"osMax",
  172. @"osMin": @"osMin",
  173. @"banner": @"Banner",
  174. @"topShelfImage": @"TopShelfImage"
  175. };
  176. }
  177. - (instancetype)initWithRawControlString:(NSString *)controlString
  178. {
  179. NSArray *packageArray = [controlString componentsSeparatedByString:@"\n"];
  180. NSMutableDictionary *currentPackage = [[NSMutableDictionary alloc] init];
  181. for (id currentLine in packageArray)
  182. {
  183. NSArray *itemArray = [currentLine componentsSeparatedByString:@": "];
  184. if ([itemArray count] >= 2)
  185. {
  186. NSString *key = [itemArray objectAtIndex:0];
  187. NSString *object = [itemArray objectAtIndex:1];
  188. if ([key isEqualToString:@"Depends"]) //process the array
  189. {
  190. NSArray *dependsObject = [DebPackageModel dependencyArrayFromString:object];
  191. [currentPackage setObject:dependsObject forKey:key];
  192. } else { //every other key, even if it has an array is treated as a string
  193. [currentPackage setObject:object forKey:key];
  194. }
  195. }
  196. }
  197. if ([[currentPackage allKeys] count] > 4)
  198. {
  199. self = [super init];
  200. [self mapDictionaryToProperties:currentPackage];
  201. return self;
  202. }
  203. return nil;
  204. }
  205. - (void)mapDictionaryToProperties:(NSDictionary *)theProps {
  206. NSArray *ourProps = [self properties];
  207. NSArray *allKeys = [theProps allKeys];
  208. NSDictionary *mappedKeys = [DebPackageModel JSONKeyPathsByPropertyKey];
  209. [ourProps enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  210. NSString *mappedProp = mappedKeys[obj];
  211. //DLog(@"allkeys: %@", allKeys);
  212. if ([allKeys containsObject:mappedProp]){
  213. if ([self respondsToSelector:NSSelectorFromString(obj)]){ //redudant
  214. id value = theProps[mappedProp];
  215. //DLog(@"setting value: %@ for key: %@ from mapped key: %@", value, obj, mappedProp);
  216. [self setValue:value forKey:obj];
  217. }
  218. } else {
  219. //DLog(@"%@ doesnt respond to %@", self, mappedProp);
  220. }
  221. }];
  222. }
  223. @end
  224. @interface NSString (Additions)
  225. - (void)writeToFileWithoutAttributes:(NSString *)theFile;
  226. @end
  227. @implementation NSString (Additions)
  228. - (void)writeToFileWithoutAttributes:(NSString *)theFile {
  229. if ([FM fileExistsAtPath:theFile]){
  230. DLog(@"overwriting file: %@", theFile);
  231. }
  232. FILE *fd = fopen([theFile UTF8String], "w+");
  233. const char *text = self.UTF8String;
  234. fwrite(text, strlen(text) + 1, 1, fd);
  235. fclose(fd);
  236. }
  237. @end
  238. @interface PackageFile: NSObject
  239. @property (nonatomic, strong) NSString *fileType;
  240. @property (nonatomic, strong) NSString *permissions;
  241. @property (nonatomic, strong) NSString *owner;
  242. @property (nonatomic, strong) NSString *size;
  243. @property (nonatomic, strong) NSString *date;
  244. @property (nonatomic, strong) NSString *time;
  245. @property (nonatomic, strong) NSString *linkDestination;
  246. @property (nonatomic, strong) NSString *path;
  247. @property (nonatomic, strong) NSString *basename;
  248. @property (readwrite, assign) BSPackageFileType type;
  249. - (void)_setFileTypeFromRaw:(NSString *)rawType;
  250. @end
  251. @implementation PackageFile
  252. - (void)_setFileTypeFromRaw:(NSString *)rawType {
  253. _fileType = [PackageFile readableFileTypeForRawMode:rawType];
  254. _type = [PackageFile fileTypeForRawMode:rawType];
  255. }
  256. /*
  257. - denotes a regular file
  258. d denotes a directory
  259. b denotes a block special file
  260. c denotes a character special file
  261. l denotes a symbolic link
  262. p denotes a named pipe
  263. s denotes a domain socket
  264. */
  265. + (NSString* )readableFileTypeForRawMode:(NSString *)fileTypeChar {
  266. NSString *fileType = nil;
  267. if ([fileTypeChar isEqualToString:@"-"])
  268. { fileType = @"file"; }
  269. else if ([fileTypeChar isEqualToString:@"d"])
  270. { fileType = @"directory"; }
  271. else if ([fileTypeChar isEqualToString:@"b"])
  272. { fileType = @"block"; }
  273. else if ([fileTypeChar isEqualToString:@"c"])
  274. { fileType = @"character"; }
  275. else if ([fileTypeChar isEqualToString:@"l"])
  276. { fileType = @"link"; }
  277. else if ([fileTypeChar isEqualToString:@"p"])
  278. { fileType = @"pipe"; }
  279. else if ([fileTypeChar isEqualToString:@"s"])
  280. { fileType = @"socket"; }
  281. return fileType;
  282. }
  283. + (BSPackageFileType)fileTypeForRawMode:(NSString *)fileTypeChar {
  284. BSPackageFileType type = BSPackageFileTypeUnknown;
  285. if ([fileTypeChar isEqualToString:@"-"])
  286. { type = BSPackageFileTypeFile; }
  287. else if ([fileTypeChar isEqualToString:@"d"])
  288. { type = BSPackageFileTypeDirectory; }
  289. else if ([fileTypeChar isEqualToString:@"b"])
  290. { type = BSPackageFileTypeBlock; }
  291. else if ([fileTypeChar isEqualToString:@"c"])
  292. { type = BSPackageFileTypeCharacter; }
  293. else if ([fileTypeChar isEqualToString:@"l"])
  294. { type = BSPackageFileTypeLink; }
  295. else if ([fileTypeChar isEqualToString:@"p"])
  296. { type = BSPackageFileTypePipe; }
  297. else if ([fileTypeChar isEqualToString:@"s"])
  298. { type = BSPackageFileTypeSocket; }
  299. return type;
  300. }
  301. - (NSString*) description {
  302. NSString *orig = [super description];
  303. NSMutableDictionary *details = [NSMutableDictionary new];
  304. NSArray *props = [self properties];
  305. [props enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  306. NSString *cv = [self valueForKey:obj];
  307. if (cv){
  308. details[obj] = cv;
  309. }
  310. }];
  311. return [NSString stringWithFormat:@"%@ = %@", orig, details];
  312. }
  313. @end
  314. @interface ErrorReturn: NSObject
  315. @property (nonatomic, strong) NSArray *overwriteFiles;
  316. @property (readwrite, assign) NSInteger returnStatus;
  317. @end
  318. @implementation ErrorReturn
  319. @end
  320. @interface Package: NSObject
  321. @property (nonatomic, strong) NSArray <PackageFile *> *files;
  322. @property (nonatomic, strong) NSArray *controlFiles;
  323. @property (nonatomic, strong) NSString *packageName;
  324. @property (nonatomic, strong) NSString *version;
  325. - (ErrorReturn *)errorReturnForBootstrap:(NSString *)bootstrapPath;
  326. - (NSString *)listfile;
  327. @end
  328. @implementation Package
  329. - (NSString*) description {
  330. NSString *orig = [super description];
  331. NSMutableDictionary *details = [NSMutableDictionary new];
  332. NSArray *props = [self properties];
  333. [props enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  334. NSString *cv = [self valueForKey:obj];
  335. if (cv){
  336. details[obj] = cv;
  337. }
  338. }];
  339. return [NSString stringWithFormat:@"%@ = %@", orig, details];
  340. }
  341. - (NSString *)listfile {
  342. __block NSMutableArray *outFiles = [NSMutableArray new];
  343. [self.files enumerateObjectsUsingBlock:^(PackageFile * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  344. if ([obj.fileType isEqualToString:@"link"]){ //does this need to handle things differently?
  345. [outFiles addObject:obj.path];
  346. } else {
  347. [outFiles addObject:obj.path];
  348. }
  349. }];
  350. return [outFiles componentsJoinedByString:@"\n"];
  351. }
  352. - (ErrorReturn *)errorReturnForBootstrap:(NSString *)bootstrapPath
  353. {
  354. NSArray *ignoreFiles = @[@".fauxsu", @".DS_Store"];
  355. NSArray *forbiddenRoots = @[@"etc", @"var", @"tmp"];
  356. NSFileManager *man = [NSFileManager defaultManager];
  357. __block NSInteger returnValue = 0; //0 = good to go 1 = over write warning, 2 = no go
  358. __block NSMutableArray *_overwriteArray = [NSMutableArray new];
  359. [self.files enumerateObjectsUsingBlock:^(PackageFile * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  360. if ([obj.fileType isEqualToString:@"file"]){
  361. NSString *fullPath = [bootstrapPath stringByAppendingPathComponent:obj.path];
  362. if ([man fileExistsAtPath:fullPath] && ![ignoreFiles containsObject:obj.basename]){
  363. //DLog(@"[WARNING] overwriting a file that already exists and isn't DS_Store or .fauxsu: %@", fullPath);
  364. [_overwriteArray addObject:obj.path];
  365. //*stop = TRUE;//return FALSE;
  366. returnValue = 1;
  367. }
  368. NSArray *pathComponents = [obj.path pathComponents];
  369. if ([pathComponents count] > 1)
  370. {
  371. NSString *rootPath = [pathComponents objectAtIndex:1];
  372. if ([forbiddenRoots containsObject:rootPath])
  373. {
  374. DLog(@"\n [ERROR] package file: '%@' would overwrite symbolic link at '%@'! Exiting!\n\n", obj.path, rootPath);
  375. *stop = TRUE;
  376. returnValue = 2;
  377. }
  378. }
  379. }
  380. }];
  381. ErrorReturn *er = [ErrorReturn new];
  382. er.returnStatus = returnValue;
  383. er.overwriteFiles = _overwriteArray;
  384. return er;
  385. }
  386. @end
  387. @interface HelperClass: NSObject
  388. + (BOOL)shouldContinueWithError:(NSString *)errorMessage;
  389. + (NSArray *)returnForProcess:(NSString *)call;
  390. + (Package *)packageForDeb:(NSString *)debFile;
  391. + (NSString *)octalFromSymbols:(NSString *)theSymbols;
  392. @end
  393. @implementation HelperClass
  394. + (NSArray <DebPackageModel*>*)statusInstalledPackagesFromFile:(NSString *)statusFile
  395. {
  396. if (![FM fileExistsAtPath:statusFile]) {
  397. return nil;
  398. }
  399. NSString *packageString = [NSString stringWithContentsOfFile:statusFile encoding:NSUTF8StringEncoding error:nil];
  400. NSArray *lineArray = [packageString componentsSeparatedByString:@"\n\n"];
  401. //DDLogInfo(@"lineArray: %@", lineArray);
  402. NSMutableArray *mutableList = [[NSMutableArray alloc] init];
  403. //NSMutableDictionary *mutableDict = [[NSMutableDictionary alloc] init];
  404. for (id currentItem in lineArray)
  405. {
  406. DebPackageModel *debModel = [[DebPackageModel alloc] initWithRawControlString:currentItem];
  407. if (debModel != nil)
  408. [mutableList addObject:debModel];
  409. }
  410. NSSortDescriptor *nameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES
  411. selector:@selector(localizedCaseInsensitiveCompare:)];
  412. NSSortDescriptor *packageDescriptor = [[NSSortDescriptor alloc] initWithKey:@"package" ascending:YES
  413. selector:@selector(localizedCaseInsensitiveCompare:)];
  414. NSArray *descriptors = [NSArray arrayWithObjects:nameDescriptor, packageDescriptor, nil];
  415. NSArray *sortedArray = [mutableList sortedArrayUsingDescriptors:descriptors];
  416. mutableList = nil;
  417. return sortedArray;
  418. }
  419. + (BOOL)shouldContinueWithError:(NSString *)errorMessage {
  420. NSString *errorString = [NSString stringWithFormat:@"\n%@Are you sure you want to continue? [y/n]?", errorMessage];
  421. char c;
  422. printf("%s", [errorString UTF8String] );
  423. c=getchar();
  424. while(c!='y' && c!='n')
  425. {
  426. if (c!='\n'){
  427. printf("[y/n]");
  428. }
  429. c=getchar();
  430. }
  431. if (c == 'n')
  432. {
  433. DLog(@"\nsmart move... exiting\n");
  434. return FALSE;
  435. } else if (c == 'y') {
  436. DLog(@"\nits your funeral....\n");
  437. }
  438. return TRUE;
  439. }
  440. + (NSArray *)returnForProcess:(NSString *)call
  441. {
  442. if (call==nil)
  443. return 0;
  444. char line[200];
  445. //DDLogInfo(@"running process: %@", call);
  446. FILE* fp = popen([call UTF8String], "r");
  447. NSMutableArray *lines = [[NSMutableArray alloc]init];
  448. if (fp)
  449. {
  450. while (fgets(line, sizeof line, fp))
  451. {
  452. NSString *s = [NSString stringWithCString:line encoding:NSUTF8StringEncoding];
  453. s = [s stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
  454. [lines addObject:s];
  455. }
  456. }
  457. pclose(fp);
  458. return lines;
  459. }
  460. + (PackageFile *)packageFileFromLine:(NSString *)inputLine {
  461. // "-rwxr-xr-x 0 root wheel 69424 Oct 22 03:56 ./Library/MobileSubstrate/DynamicLibraries/beigelist7.dylib\n",
  462. //-rwxr-xr-x root/staff 10860 2011-02-02 03:55 ./Library/Frameworks/CydiaSubstrate.framework/Commands/cycc
  463. inputLine = [inputLine stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
  464. inputLine = [inputLine stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"\t"]];
  465. NSMutableString *newString = [[NSMutableString alloc] initWithString:inputLine];
  466. [newString replaceOccurrencesOfString:@" " withString:@" " options:NSLiteralSearch range:NSMakeRange(0, [newString length])];
  467. [newString replaceOccurrencesOfString:@" " withString:@" " options:NSLiteralSearch range:NSMakeRange(0, [newString length])];
  468. [newString replaceOccurrencesOfString:@" " withString:@" " options:NSLiteralSearch range:NSMakeRange(0, [newString length])];
  469. [newString replaceOccurrencesOfString:@" " withString:@" " options:NSLiteralSearch range:NSMakeRange(0, [newString length])];
  470. [newString replaceOccurrencesOfString:@" " withString:@" " options:NSLiteralSearch range:NSMakeRange(0, [newString length])];
  471. NSArray *lineObjects = [newString componentsSeparatedByString:@" "];
  472. //NSLog(@"lineObjects: %@", lineObjects);
  473. /*
  474. "drwxr-xr-x",
  475. "root/wheel",
  476. 0,
  477. "2018-06-27",
  478. "01:21",
  479. "./"
  480. */
  481. NSString *permissionsAndType = [lineObjects objectAtIndex:0];
  482. NSString *userGroup = [lineObjects objectAtIndex:1];
  483. NSString *size = [lineObjects objectAtIndex:2];
  484. NSString *date = [lineObjects objectAtIndex:3];
  485. NSString *time = [lineObjects objectAtIndex:4];
  486. NSString *path = [lineObjects objectAtIndex:5];
  487. //@"drwxr-xr-x"
  488. NSString *fileTypeChar = [permissionsAndType substringWithRange:NSMakeRange(0, 1)];
  489. NSString *octalPermissions = [self octalFromSymbols:permissionsAndType];
  490. NSString *octalUG = [self octalFromGroupSymbols:userGroup];
  491. NSString *fileName = [path lastPathComponent];
  492. //NSString *fullPath = [NSString stringWithFormat:@"/%@", path];
  493. NSString *fullPath = [path substringFromIndex:1];
  494. PackageFile *pf = [PackageFile new];
  495. [pf _setFileTypeFromRaw:fileTypeChar];
  496. switch (pf.type) {
  497. case BSPackageFileTypeLink:
  498. {
  499. fullPath = [lineObjects objectAtIndex:7];
  500. NSString *linkDest = [NSString stringWithFormat:@"/%@", path];
  501. pf.permissions = octalPermissions;
  502. pf.owner = octalUG;
  503. pf.size = size;
  504. pf.time = time;
  505. pf.date = date;
  506. pf.path = fullPath;
  507. pf.basename = fileName;
  508. pf.linkDestination = linkDest;
  509. return pf;
  510. }
  511. break;
  512. case BSPackageFileTypeDirectory: //return for now
  513. //DLog(@"we dont want directory entries do we %@", lineObjects);
  514. pf.permissions = octalPermissions;
  515. pf.owner = octalUG;
  516. pf.size = size;
  517. pf.time = time;
  518. pf.date = date;
  519. pf.path = fullPath;
  520. pf.basename = fileName;
  521. return pf;
  522. break;
  523. default:
  524. break;
  525. }
  526. pf.permissions = octalPermissions;
  527. pf.owner = octalUG;
  528. pf.size = size;
  529. pf.time = time;
  530. pf.date = date;
  531. pf.path = fullPath;
  532. pf.basename = fileName;
  533. return pf;
  534. // return [NSDictionary dictionaryWithObjectsAndKeys:fileType, @"fileType",octalPermissions, @"octalPermissions", octalUG, @"octalUG", size, @"size", date, @"date", time, @"time", fileName, @"fileName", fullPath, @"fullPath", nil];
  535. }
  536. + (NSString *)octalFromGroupSymbols:(NSString *)theSymbols
  537. {
  538. NSArray *groupArray = [theSymbols componentsSeparatedByString:@"/"];
  539. NSString *user = [groupArray objectAtIndex:0];
  540. NSString *group = [groupArray objectAtIndex:1];
  541. NSString *octalUser = nil;
  542. NSString *octalGroup = nil;
  543. //uid=0(root) gid=0(wheel) groups=0(wheel),1(daemon),2(kmem),3(sys),4(tty),5(operator),8(procview),9(procmod),20(staff),29(certusers),80(admin)
  544. if ([user isEqualToString:@"root"])
  545. {
  546. octalUser = @"0";
  547. } else if ([user isEqualToString:@"mobile"])
  548. {
  549. octalUser = @"501";
  550. }
  551. //obviously more cases!! FIXME:
  552. if ([group isEqualToString:@"staff"])
  553. {
  554. octalGroup = @"20";
  555. } else if ([group isEqualToString:@"admin"])
  556. {
  557. octalGroup = @"80";
  558. } else if ([group isEqualToString:@"wheel"])
  559. {
  560. octalGroup = @"0";
  561. } else if ([group isEqualToString:@"daemon"])
  562. {
  563. octalGroup = @"1";
  564. } else if ([group isEqualToString:@"kmem"])
  565. {
  566. octalGroup = @"2";
  567. } else if ([group isEqualToString:@"sys"])
  568. {
  569. octalGroup = @"3";
  570. } else if ([group isEqualToString:@"tty"])
  571. {
  572. octalGroup = @"4";
  573. } else if ([group isEqualToString:@"operator"])
  574. {
  575. octalGroup = @"5";
  576. } else if ([group isEqualToString:@"procview"])
  577. {
  578. octalGroup = @"8";
  579. } else if ([group isEqualToString:@"procmod"])
  580. {
  581. octalGroup = @"9";
  582. } else if ([group isEqualToString:@"certusers"])
  583. {
  584. octalGroup = @"29";
  585. } else
  586. {
  587. octalGroup = @"501"; //default to mobile
  588. }
  589. //uid=0(root) gid=0(wheel) groups=0(wheel),1(daemon),2(kmem),3(sys),4(tty),5(operator),8(procview),9(procmod),20(staff),29(certusers),80(admin)
  590. return [NSString stringWithFormat:@"%@:%@", octalUser, octalGroup];
  591. }
  592. + (Package *)packageForDeb:(NSString *)debFile {
  593. NSString *packageName = [[self returnForProcess:[NSString stringWithFormat:@"/usr/local/bin/dpkg -f %@ Package", debFile]] componentsJoinedByString:@"\n"];
  594. NSString *packageVersion = [[self returnForProcess:[NSString stringWithFormat:@"/usr/local/bin/dpkg -f %@ Version", debFile]] componentsJoinedByString:@"\n"];
  595. NSArray <PackageFile *> *fileList = [self returnForProcess:[NSString stringWithFormat:@"/usr/local/bin/dpkg -c %@", debFile]];
  596. __block NSMutableArray *finalArray = [NSMutableArray new];
  597. [fileList enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  598. PackageFile *file = [self packageFileFromLine:obj];
  599. if (file) {
  600. //DLog(@"%@", file);
  601. [finalArray addObject:file];
  602. }
  603. }];
  604. Package *pkg = [Package new];
  605. pkg.files = finalArray;
  606. pkg.packageName = packageName;
  607. pkg.version = packageVersion;
  608. return pkg;
  609. }
  610. + (NSString *)octalFromSymbols:(NSString *)theSymbols
  611. {
  612. //NSLog(@"%@ %s", self, _cmd);
  613. NSString *U = [theSymbols substringWithRange:NSMakeRange(1, 3)];
  614. NSString *G = [theSymbols substringWithRange:NSMakeRange(4, 3)];
  615. NSString *O = [theSymbols substringWithRange:NSMakeRange(7, 3)];
  616. //NSLog(@"fileTypeChar: %@", fileTypeChar);
  617. //NSLog(@"U; %@", U);
  618. //NSLog(@"G; %@", G);
  619. //NSLog(@"O; %@", O);
  620. //USER
  621. int sIdBit = 0;
  622. int uOctal = 0;
  623. const char *uArray = [U cStringUsingEncoding:NSASCIIStringEncoding];
  624. int stringLength = [U length];
  625. int x;
  626. for( x=0; x<stringLength; x++ )
  627. {
  628. unsigned int aCharacter = uArray[x];
  629. if (aCharacter == 'r')
  630. {
  631. uOctal += 4;
  632. } else if (aCharacter == 'w')
  633. {
  634. uOctal += 2;
  635. } else if (aCharacter == 'x')
  636. {
  637. uOctal += 1;
  638. } else if (aCharacter == 's')
  639. {
  640. sIdBit += 4;
  641. }
  642. }
  643. //GROUP
  644. int gOctal = 0;
  645. const char *gArray = [G cStringUsingEncoding:NSASCIIStringEncoding];
  646. stringLength = [G length];
  647. int y;
  648. for( y=0; y<stringLength; y++ )
  649. {
  650. unsigned int aCharacter = gArray[y];
  651. if (aCharacter == 'r')
  652. {
  653. gOctal += 4;
  654. } else if (aCharacter == 'w')
  655. {
  656. gOctal += 2;
  657. } else if (aCharacter == 'x')
  658. {
  659. gOctal += 1;
  660. } else if (aCharacter == 's')
  661. {
  662. gOctal += 2;
  663. }
  664. }
  665. //OTHERS
  666. int z;
  667. int oOctal = 0;
  668. const char *oArray = [O cStringUsingEncoding:NSASCIIStringEncoding];
  669. stringLength = [O length];
  670. for( z=0; z<stringLength; z++ )
  671. {
  672. unsigned int aCharacter = oArray[z];
  673. if (aCharacter == 'r')
  674. {
  675. oOctal += 4;
  676. } else if (aCharacter == 'w')
  677. {
  678. oOctal += 2;
  679. } else if (aCharacter == 'x')
  680. {
  681. oOctal += 1;
  682. }
  683. }
  684. return [NSString stringWithFormat:@"%i%i%i%i", sIdBit, uOctal, gOctal, oOctal];
  685. }
  686. @end
  687. #define OPTION_FLAGS "o:f:b:"
  688. char *progname;
  689. char *path;
  690. static struct option longopts[] = {
  691. { "octal", required_argument, NULL, 'o' },
  692. { "file", required_argument, NULL, 'f' },
  693. { "bootstrap", required_argument, NULL, 'b' },
  694. { NULL, 0, NULL, 0 }
  695. };
  696. int main(int argc, const char * argv[]) {
  697. @autoreleasepool {
  698. setuid(0);
  699. setgid(0);
  700. // insert code here...
  701. progname = basename(argv[0]);
  702. path = dirname(argv[0]);
  703. int flag;
  704. NSString *octalFile = nil;
  705. NSString *debFile = nil;
  706. NSString *bootstrapPath = nil;
  707. while ((flag = getopt_long(argc, argv, OPTION_FLAGS, longopts, NULL)) != -1) {
  708. switch(flag) {
  709. case 'o':
  710. octalFile = [NSString stringWithUTF8String:optarg];
  711. break;
  712. case 'f':
  713. debFile = [NSString stringWithUTF8String:optarg];
  714. break;
  715. case 'b':
  716. bootstrapPath = [NSString stringWithUTF8String:optarg];
  717. break;
  718. }
  719. }
  720. //DLog(@"folder: %@ project: %@", folder, project);
  721. if (octalFile) {
  722. NSString *octal = [HelperClass octalFromSymbols:octalFile];
  723. DLog(@"%@", octal);
  724. }
  725. if (debFile && bootstrapPath) {
  726. NSString *statusFile = [bootstrapPath stringByAppendingPathComponent:@"Library/dpkg/status"];
  727. NSArray *installedPackages = [HelperClass statusInstalledPackagesFromFile:statusFile];
  728. //DLog(@"installedPackages: %@", installedPackages);
  729. DLog(@"\n\nProcessing file: %@\n", debFile);
  730. Package *output = [HelperClass packageForDeb:debFile];
  731. DLog(@"\nFound package: '%@' at version: '%@'...\n", output.packageName, output.version );
  732. DebPackageModel *model = [[installedPackages filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"package == %@", output.packageName]] lastObject];
  733. if (model) {
  734. DLog(@"\n [WARNING] This package has already been installed! %@", model);
  735. NSComparisonResult result = [output.version compare:model.version options:NSNumericSearch];
  736. DLog(@"\n [WARNING] Comparing version numbers...");
  737. switch (result) {
  738. case NSOrderedSame:
  739. DLog(@"\n [WARNING] %@ and %@ match!", output.version, model.version);
  740. break;
  741. case NSOrderedAscending:
  742. DLog(@"\n [WARNING] Package version %@ is less than installed version %@!", output.version, model.version);
  743. break;
  744. case NSOrderedDescending:
  745. DLog(@"\n [WARNING] Package version %@ is greater than installed version %@!", output.version, model.version);
  746. break;
  747. default:
  748. break;
  749. }
  750. }
  751. ErrorReturn *safePackage = [output errorReturnForBootstrap:bootstrapPath];
  752. if (safePackage.returnStatus != 0) { //zero is success
  753. if (safePackage.returnStatus == 1) //ovewrwrites, just warnings!
  754. {
  755. NSString *error = [NSString stringWithFormat:@" [WARNING] %@ may overwrite the following files: %@\n\n", debFile.lastPathComponent, [safePackage.overwriteFiles componentsJoinedByString:@"\n"]];
  756. if(![HelperClass shouldContinueWithError:error]){
  757. return -1;
  758. }
  759. } else if (safePackage.returnStatus == 2) //bail!!"
  760. {
  761. return 2;
  762. }
  763. }
  764. //NSString *runPath = [NSString stringWithUTF8String:path];
  765. NSString *pwd = [[HelperClass returnForProcess:@"/bin/pwd"] componentsJoinedByString:@"\n"];
  766. //DLog(@"run path: %@", runPath);
  767. //DLog(@"pwd: %@", pwd);
  768. //DLog(@"%@", output);
  769. //DLog(@"list: %@", output.listfile);
  770. NSFileManager *man = [NSFileManager defaultManager];
  771. NSString *tmpPath = [pwd stringByAppendingPathComponent:output.packageName];
  772. NSString *debian = [tmpPath stringByAppendingPathComponent:@"DEBIAN"];
  773. [man createDirectoryAtPath:tmpPath withIntermediateDirectories:TRUE attributes:nil error:nil];
  774. DLog(@"\nExtracting deb for processing...\n");
  775. [HelperClass returnForProcess:[NSString stringWithFormat:@"/usr/local/bin/dpkg -x %@ %@", debFile, tmpPath]];
  776. NSString *bootstrapInfoPath = [bootstrapPath stringByAppendingPathComponent:@"Library/dpkg/info"];
  777. NSString *listFile = [bootstrapInfoPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.list", output.packageName]];
  778. NSString *md5s = [bootstrapInfoPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.md5sums", output.packageName]];
  779. DLog(@"\nCreating list file '%@'...\n", listFile);
  780. [output.listfile writeToFile:listFile atomically:TRUE encoding:NSUTF8StringEncoding error:nil];
  781. DLog(@"\nGenerating md5sums...\n");
  782. NSString *runString = [NSString stringWithFormat:@"/usr/bin/find %@ -type f -not -path \"*.DS_Store*\" -exec /sbin/md5 -r {} \\; | /usr/bin/awk '{ print $1 \" \" $2 }' | /usr/bin/sed \"s|%@||g\"", tmpPath, tmpPath];
  783. NSString *outputs = [[HelperClass returnForProcess:runString] componentsJoinedByString:@"\n"];
  784. DLog(@"\nCreating md5sum file '%@'...\n", listFile);
  785. [outputs writeToFile:md5s atomically:TRUE encoding:NSUTF8StringEncoding error:nil];
  786. [man createDirectoryAtPath:debian withIntermediateDirectories:TRUE attributes:nil error:nil];
  787. [HelperClass returnForProcess:[NSString stringWithFormat:@"/usr/local/bin/dpkg -e %@ %@", debFile, debian]];
  788. //NSString *nextPath = [tmpPath stringByAppendingPathComponent:@"DEBIAN"];
  789. NSArray *files = [man contentsOfDirectoryAtPath:debian error:nil];
  790. [files enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  791. NSString *fullPath = [debian stringByAppendingPathComponent:obj];
  792. if (![obj isEqualToString:@"control"]){
  793. DLog(@"fullPath: %@", fullPath);
  794. NSString *fileName = [NSString stringWithFormat:@"%@.%@", output.packageName, obj];
  795. NSString *newPath = [bootstrapPath stringByAppendingPathComponent:@"Library/dpkg/info"];
  796. newPath = [newPath stringByAppendingPathComponent:fileName];
  797. DLog(@"newPath: %@", newPath);
  798. [man copyItemAtPath:fullPath toPath:newPath error:nil];
  799. } else {
  800. NSMutableString *controlFile = [[NSMutableString alloc] initWithContentsOfFile:fullPath encoding:NSUTF8StringEncoding error:nil];
  801. [controlFile replaceOccurrencesOfString:@"iphoneos-arm" withString:@"appletvos-arm64" options:NSLiteralSearch range:NSMakeRange(0, [controlFile length])];
  802. DLog(@"control file: %@", controlFile);
  803. NSString *statusFile = [bootstrapPath stringByAppendingPathComponent:@"Library/dpkg/status"];
  804. NSMutableString *statusContents = [[NSMutableString alloc] initWithContentsOfFile:statusFile encoding:NSUTF8StringEncoding error:nil];
  805. DLog(@"status contents: %@", statusContents);
  806. [statusContents appendFormat:@"%@\n", controlFile];
  807. [statusContents writeToFile:statusFile atomically:TRUE encoding:NSUTF8StringEncoding error:nil];
  808. }
  809. }];
  810. //finally actually install the package onto the bootstrap
  811. [HelperClass returnForProcess:[NSString stringWithFormat:@"/usr/local/bin/dpkg -x %@ %@", debFile, bootstrapPath]];
  812. //DLog(@"outputs: %@", outputs);
  813. ///usr/bin/find "$TARGET_DIR" -type f -not -path "$TARGET_DIR/DEBIAN/*" -exec "/sbin/md5 -r" {} \; | /usr/bin/awk '{ print $1 " " $2 }' | /usr/bin/sed "s|$TARGET_DIR/||g"
  814. }
  815. }
  816. return 0;
  817. }