read individual files rather than all at once

This commit is contained in:
leminlimez
2025-03-13 21:29:37 -04:00
parent 86bb3958de
commit fd4502dd4f
5 changed files with 44 additions and 23 deletions

View File

@@ -23,19 +23,35 @@ class BackupFile:
@dataclass
class ConcreteFile(BackupFile):
contents: bytes
src_path: Optional[str] = None
owner: int = 0
group: int = 0
inode: Optional[int] = None
mode: _FileMode = DEFAULT
hash: bytes = None
size: int = None
def read_contents(self) -> bytes:
contents = self.contents
if self.contents == None:
with open(self.src_path, "rb") as in_file:
contents = in_file.read()
# prepopulate hash and size
self.hash = sha1(contents).digest()
self.size = len(contents)
return contents
def to_record(self) -> mbdb.MbdbRecord:
if self.inode is None:
self.inode = int.from_bytes(randbytes(8), "big")
if self.hash == None or self.size == None:
self.read_contents()
return mbdb.MbdbRecord(
domain=self.domain,
filename=self.path,
link="",
hash=sha1(self.contents).digest(),
hash=self.hash,
key=b"",
mode=self.mode | _FileMode.S_IFREG,
#unknown2=0,
@@ -46,7 +62,7 @@ class ConcreteFile(BackupFile):
mtime=int(datetime.now().timestamp()),
atime=int(datetime.now().timestamp()),
ctime=int(datetime.now().timestamp()),
size=len(self.contents),
size=self.size,
flags=4,
properties=[]
)
@@ -126,7 +142,7 @@ class Backup:
if isinstance(file, ConcreteFile):
#print("Writing", file.path, "to", directory / sha1((file.domain + "-" + file.path).encode()).digest().hex())
with open(directory / sha1((file.domain + "-" + file.path).encode()).digest().hex(), "wb") as f:
f.write(file.contents)
f.write(file.read_contents())
with open(directory / "Manifest.mbdb", "wb") as f:
f.write(self.generate_manifest_db().to_bytes())

View File

@@ -4,8 +4,9 @@ from pymobiledevice3.services.installation_proxy import InstallationProxyService
import os
class FileToRestore:
def __init__(self, contents: str, restore_path: str, domain: str = None, owner: int = 501, group: int = 501):
def __init__(self, contents: str, restore_path: str, contents_path: str = None, domain: str = None, owner: int = 501, group: int = 501):
self.contents = contents
self.contents_path = contents_path
self.restore_path = restore_path
self.domain = domain
self.owner = owner
@@ -75,7 +76,8 @@ def concat_regular_file(file: FileToRestore, files_list: list[FileToRestore], la
file.domain,
owner=file.owner,
group=file.group,
contents=file.contents
contents=file.contents,
src_path=file.contents_path
))
return new_last_domain, full_path

View File

@@ -1,6 +1,6 @@
import traceback
import plistlib
from pathlib import Path
from tempfile import TemporaryDirectory
from PySide6.QtWidgets import QMessageBox
from PySide6.QtCore import QSettings
@@ -304,6 +304,7 @@ class DeviceManager:
# create the restore file list
files_to_restore: dict[FileToRestore] = [
]
tmp_pb_dir = None # temporary directory for unzipping pb files
# set the plist keys
if not resetting:
@@ -325,7 +326,8 @@ class DeviceManager:
if tweak.enabled and tweak.file_location.value.startswith("/var/mobile/"):
uses_domains = True
elif isinstance(tweak, PosterboardTweak):
tweak.apply_tweak(files_to_restore=files_to_restore)
tmp_pb_dir = TemporaryDirectory()
tweak.apply_tweak(files_to_restore=files_to_restore, output_dir=tmp_pb_dir.name)
else:
if gestalt_plist != None:
gestalt_plist = tweak.apply_tweak(gestalt_plist)
@@ -413,12 +415,16 @@ class DeviceManager:
update_label("Restoring to device...")
try:
restore_files(files=files_to_restore, reboot=self.auto_reboot, lockdown_client=self.data_singleton.current_device.ld)
if tmp_pb_dir != None:
tmp_pb_dir.cleanup()
msg = "Your device will now restart."
if not self.auto_reboot:
msg = "Please restart your device to see changes."
QMessageBox.information(None, "Success!", "All done! " + msg)
update_label("Success!")
except Exception as e:
if tmp_pb_dir != None:
tmp_pb_dir.cleanup()
show_apply_error(e, update_label)
## RESETTING MOBILE GESTALT

View File

@@ -19,7 +19,7 @@ from tweaks.custom_gestalt_tweaks import CustomGestaltTweaks, ValueTypeStrings
from tweaks.daemons_tweak import Daemon
App_Version = "5.0"
App_Build = 1
App_Build = 2
class Page(Enum):
Home = 0

View File

@@ -2,7 +2,6 @@ from .tweak_classes import Tweak
from Sparserestore.restore import FileToRestore
import os
import zipfile
from tempfile import TemporaryDirectory
class PosterboardTweak(Tweak):
def __init__(self):
@@ -13,19 +12,18 @@ class PosterboardTweak(Tweak):
def recursive_add(self, files_to_restore: list[FileToRestore], curr_path: str, restore_path: str = "", isAdding: bool = False):
for folder in sorted(os.listdir(curr_path)):
if folder == ".DS_Store" or folder == "__MACOSX":
if folder.startswith('.') or folder == "__MACOSX":
continue
if isAdding:
# if file then add it, otherwise recursively call again
if os.path.isfile(os.path.join(curr_path, folder)):
try:
with open(os.path.join(curr_path, folder), "rb") as in_file:
contents = in_file.read()
files_to_restore.append(FileToRestore(
contents=contents,
restore_path=f"{restore_path}/{folder}",
domain=f"AppDomain-{self.bundle_id}"
))
files_to_restore.append(FileToRestore(
contents=None,
contents_path=os.path.join(curr_path, folder),
restore_path=f"{restore_path}/{folder}",
domain=f"AppDomain-{self.bundle_id}"
))
except IOError:
print(f"Failed to open file: {folder}") # TODO: Add QDebug equivalent
else:
@@ -38,7 +36,7 @@ class PosterboardTweak(Tweak):
else:
self.recursive_add(files_to_restore, os.path.join(curr_path, folder), isAdding=False)
def apply_tweak(self, files_to_restore: list[FileToRestore]):
def apply_tweak(self, files_to_restore: list[FileToRestore], output_dir: str):
# unzip the file
if not self.enabled:
return
@@ -52,8 +50,7 @@ class PosterboardTweak(Tweak):
return
elif self.zip_path == None:
return
with TemporaryDirectory() as output_dir:
with zipfile.ZipFile(self.zip_path, 'r') as zip_ref:
zip_ref.extractall(output_dir)
# add the files
self.recursive_add(files_to_restore, curr_path=output_dir)
with zipfile.ZipFile(self.zip_path, 'r') as zip_ref:
zip_ref.extractall(output_dir)
# add the files
self.recursive_add(files_to_restore, curr_path=output_dir)