Skip to content

Commit

Permalink
Rewrite backup generator fot multiple files
Browse files Browse the repository at this point in the history
  • Loading branch information
khanhduytran0 committed Sep 15, 2024
1 parent 306b36e commit a07c02a
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 34 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ SparseBox_FILES = \
include/SwiftBridgeCore.swift \
Sources/SparseRestore/MBDB.swift \
Sources/SparseRestore/Backup.swift \
Sources/SparseRestore/Restore.swift \
Sources/LogView.swift \
Sources/MyApp.swift \
Sources/MobileDevice/MobileDevice.swift \
Expand Down
32 changes: 19 additions & 13 deletions Sources/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ extension UIDocumentPickerViewController {

struct ContentView: View {
let os = ProcessInfo().operatingSystemVersion
let originalMobileGestalt: URL
let modifiedMobileGestalt: URL
let origMGURL, modMGURL: URL
@AppStorage("PairingFile") var pairingFile: String?
@State var mobileGestalt: NSMutableDictionary
@State var reboot = true
Expand Down Expand Up @@ -74,13 +73,13 @@ struct ContentView: View {
Section {
Toggle("Reboot after finish restoring", isOn: $reboot)
Button("Apply changes") {
try! mobileGestalt.write(to: modifiedMobileGestalt)
try! mobileGestalt.write(to: modMGURL)
applyChanges()
}
Button("Reset changes") {
try! FileManager.default.removeItem(at: modifiedMobileGestalt)
try! FileManager.default.copyItem(at: originalMobileGestalt, to: modifiedMobileGestalt)
mobileGestalt = try! NSMutableDictionary(contentsOf: modifiedMobileGestalt, error: ())
try! FileManager.default.removeItem(at: modMGURL)
try! FileManager.default.copyItem(at: origMGURL, to: modMGURL)
mobileGestalt = try! NSMutableDictionary(contentsOf: modMGURL, error: ())
applyChanges()
}
} footer: {
Expand Down Expand Up @@ -111,7 +110,8 @@ Thanks to:
}
.navigationDestination(for: String.self) { view in
if view == "ApplyChanges" {
LogView(mgURL: modifiedMobileGestalt, reboot: reboot)
let mbdb = Restore.createBackupFiles(files: generateFilesToRestore())
LogView(mbdb: mbdb, reboot: reboot)
}
}
.navigationTitle("SparseBox")
Expand All @@ -127,14 +127,14 @@ Thanks to:

init() {
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
originalMobileGestalt = documentsDirectory.appendingPathComponent("OriginalMobileGestalt.plist", conformingTo: .data)
modifiedMobileGestalt = documentsDirectory.appendingPathComponent("ModifiedMobileGestalt.plist", conformingTo: .data)
if !FileManager.default.fileExists(atPath: originalMobileGestalt.path) {
origMGURL = documentsDirectory.appendingPathComponent("OriginalMobileGestalt.plist", conformingTo: .data)
modMGURL = documentsDirectory.appendingPathComponent("ModifiedMobileGestalt.plist", conformingTo: .data)
if !FileManager.default.fileExists(atPath: origMGURL.path) {
let url = URL(filePath: "/var/containers/Shared/SystemGroup/systemgroup.com.apple.mobilegestaltcache/Library/Caches/com.apple.MobileGestalt.plist")
try! FileManager.default.copyItem(at: url, to: originalMobileGestalt)
try! FileManager.default.copyItem(at: url, to: modifiedMobileGestalt)
try! FileManager.default.copyItem(at: url, to: origMGURL)
try! FileManager.default.copyItem(at: url, to: modMGURL)
}
_mobileGestalt = State(initialValue: try! NSMutableDictionary(contentsOf: modifiedMobileGestalt, error: ()))
_mobileGestalt = State(initialValue: try! NSMutableDictionary(contentsOf: modMGURL, error: ()))

// Fix file picker
let fixMethod = class_getInstanceMethod(UIDocumentPickerViewController.self, Selector("fix_initForOpeningContentTypes:asCopy:"))!
Expand Down Expand Up @@ -173,6 +173,12 @@ Thanks to:
)
}

func generateFilesToRestore() -> [FileToRestore] {
return [
FileToRestore(from: modMGURL, to: URL(filePath: "/var/containers/Shared/SystemGroup/systemgroup.com.apple.mobilegestaltcache/Library/Caches/NOT.apple.MobileGestalt.plist"), owner: 501, group: 501)
]
}

func startMinimuxer() {
guard pairingFile != nil else {
return
Expand Down
26 changes: 5 additions & 21 deletions Sources/LogView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ let logPipe = Pipe()
struct LogView: View {
let udid: String
let willReboot: Bool
let mobileGestaltURL: URL
let mbdb: Backup
@State var log: String = ""
@State var ran = false
@State var isRebooting = false
Expand Down Expand Up @@ -44,16 +44,16 @@ struct LogView: View {
.navigationTitle(isRebooting ? "Rebooting device" : "Log output")
}

init(mgURL: URL, reboot: Bool) {
init(mbdb: Backup, reboot: Bool) {
setvbuf(stdout, nil, _IOLBF, 0) // make stdout line-buffered
setvbuf(stderr, nil, _IONBF, 0) // make stderr unbuffered

// create the pipe and redirect stdout and stderr
dup2(logPipe.fileHandleForWriting.fileDescriptor, fileno(stdout))
dup2(logPipe.fileHandleForWriting.fileDescriptor, fileno(stderr))

mobileGestaltURL = mgURL
willReboot = reboot
self.mbdb = mbdb
self.willReboot = reboot

let deviceList = MobileDevice.deviceList()
guard deviceList.count == 1 else {
Expand All @@ -71,8 +71,6 @@ struct LogView: View {
do {
try? FileManager.default.removeItem(at: folder)
try FileManager.default.createDirectory(at: folder, withIntermediateDirectories: false)

let mbdb = createBackupFile(from: mobileGestaltURL, to: URL(filePath: "/var/containers/Shared/SystemGroup/systemgroup.com.apple.mobilegestaltcache/Library/Caches/com.apple.MobileGestalt.plist"))
try mbdb.writeTo(directory: folder)

// Restore now
Expand Down Expand Up @@ -101,19 +99,5 @@ struct LogView: View {
}
}

func createBackupFile(from: URL, to: URL) -> Backup {
// open the file and read the contents
let contents = try! Data(contentsOf: from)

// required on iOS 17.0+ since /var/mobile is on a separate partition
let basePath = to.path(percentEncoded: false).hasPrefix("/var/mobile/") ? "/var/mobile/backup" : "/var/backup"

// create the backup
return Backup(files: [
//Directory(path: "", domain: "SysContainerDomain-../../../../../../../..\(basePath)\(to.deletingLastPathComponent().path(percentEncoded: false))", owner: 501, group: 501),
//ConcreteFile(path: "", domain: "SysContainerDomain-../../../../../../../..\(basePath)\(to.path(percentEncoded: false))", contents: contents, owner: 501, group: 501),
ConcreteFile(path: "", domain: "SysContainerDomain-../../../../../../../..\(to.path(percentEncoded: false))", contents: contents, owner: 501, group: 501),
ConcreteFile(path: "", domain: "SysContainerDomain-../../../../../../../../crash_on_purpose", contents: Data()),
])
}

}
79 changes: 79 additions & 0 deletions Sources/SparseRestore/Restore.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import Foundation

class FileToRestore {
var from, to: URL
var owner, group: Int32
init(from: URL, to: URL, owner: Int32 = 0, group: Int32 = 0) {
self.from = from
self.to = to
self.owner = owner
self.group = group
}
}

struct Restore {
static func createBackupFiles(files: [FileToRestore]) -> Backup {
// create the files to be backed up
var filesList : [BackupFile] = [
Directory(path: "", domain: "RootDomain"),
Directory(path: "Library", domain: "RootDomain"),
Directory(path: "Library/Preferences", domain: "RootDomain")
]

// create the links
for (index, file) in files.enumerated() {
let contents = try! Data(contentsOf: file.from)
filesList.append(ConcreteFile(
path: "Library/Preferences/temp\(index)",
domain: "RootDomain",
contents: contents,
owner: file.owner,
group: file.group,
inode: UInt64(index)))
}

// add the file paths
for (index, file) in files.enumerated() {
let restoreFilePath = file.to.path(percentEncoded: false)
var basePath = "/var/backup"
// set it to work in the separate volumes (prevents a bootloop)
if restoreFilePath.hasPrefix("/var/mobile/") {
// required on iOS 17.0+ since /var/mobile is on a separate partition
basePath = "/var/mobile/backup"
} else if restoreFilePath.hasPrefix("/private/var/mobile/") {
basePath = "/private/var/mobile/backup"
} else if restoreFilePath.hasPrefix("/private/var/") {
basePath = "/private/var/backup"
}
filesList.append(Directory(
path: "",
domain: "SysContainerDomain-../../../../../../../..\(basePath)\(file.to.deletingLastPathComponent().path(percentEncoded: false))",
owner: file.owner,
group: file.group
))
filesList.append(ConcreteFile(
path: "",
domain: "SysContainerDomain-../../../../../../../..\(basePath)\(file.to.path(percentEncoded: false))",
contents: Data(),
owner: file.owner,
group: file.group,
inode: UInt64(index)))
}

// break the hard links
for (index, _) in files.enumerated() {
filesList.append(ConcreteFile(
path: "",
domain: "SysContainerDomain-../../../../../../../../var/.backup.i/var/root/Library/Preferences/temp\(index)",
contents: Data(),
owner: 501,
group: 501))
}

// crash on purpose
filesList.append(ConcreteFile(path: "", domain: "SysContainerDomain-../../../../../../../../crash_on_purpose", contents: Data()))

// create the backup
return Backup(files: filesList)
}
}

0 comments on commit a07c02a

Please sign in to comment.