Skip to content

Commit

Permalink
Replace CoreData deb path with inode. Closes #23
Browse files Browse the repository at this point in the history
  • Loading branch information
danpashin committed Jul 6, 2024
1 parent 06b5909 commit 53a90ac
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 47 deletions.
5 changes: 3 additions & 2 deletions twackup-gui/Twackup/Sources/App Lifecycle/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
let preferences = Preferences()
let preferences = try! Preferences()

private var consoleLoggerIsSet = false

private(set) lazy var mainModel: MainModel = {
let dpkg = Dpkg(path: jbRootPath("/var/lib/dpkg"), preferences: preferences)
return MainModel(database: Database(), dpkg: dpkg, preferences: preferences)
let database = Database(preferences: preferences)
return MainModel(database: database, dpkg: dpkg, preferences: preferences)
}()

func application(
Expand Down
29 changes: 1 addition & 28 deletions twackup-gui/Twackup/Sources/FFI Models/Dpkg.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,33 +25,6 @@ actor Dpkg {
case error
}

nonisolated static let defaultSaveDirectory: URL = {
var url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]

let proxy = LSApplicationProxy.forCurrentProcess()
let unsandboxed = (proxy?.entitlements["com.apple.private.security.no-sandbox"] as? Bool) ?? false
if unsandboxed {
url = URL(fileURLWithPath: "/var/mobile/Documents/Twackup")
}

var isDir: ObjCBool = true
var exists = FileManager.default.fileExists(atPath: url.path, isDirectory: &isDir)

// Application is not usable without directories created
// swiftlint:disable force_try
if exists && !isDir.boolValue {
try! FileManager.default.removeItem(at: url)
exists = false
}

if !exists {
try! FileManager.default.createDirectory(at: url, withIntermediateDirectories: true)
}
// swiftlint:enable force_try

return url
}()

private let innerDpkg: UnsafeMutablePointer<TwDpkg_t>

private let preferences: Preferences
Expand Down Expand Up @@ -98,7 +71,7 @@ actor Dpkg {
/// - outDir: Directory that will contain debs of packages
/// - Returns: Array with results.
/// Every result contains full deb path if rebuild is success or error if not
func rebuild(packages: [FFIPackage], outDir: URL = defaultSaveDirectory) async throws -> [Result<URL, Error>] {
func rebuild(packages: [FFIPackage], outDir: URL) async throws -> [Result<URL, Error>] {
var ffiResults = slice_boxed_TwPackagesRebuildResult()
withUnsafeMutablePointer(to: &ffiResults) { buildParameters.results = $0 }

Expand Down
23 changes: 17 additions & 6 deletions twackup-gui/Twackup/Sources/Models/Database/Database.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@ import os
actor Database {
private let persistentContainer: NSPersistentContainer

let preferences: Preferences

var backroundContext: NSManagedObjectContext {
let context = persistentContainer.newBackgroundContext()
context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy

return context
}

init() {
init(preferences: Preferences) {
self.preferences = preferences

persistentContainer = NSPersistentContainer(name: "Twackup")
persistentContainer.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
persistentContainer.loadPersistentStores { _, error in
Expand Down Expand Up @@ -57,7 +61,11 @@ actor Database {
let package = packages[index]

object.fillFrom(package: package.package)
object.fillFrom(file: package.debURL)
do {
try object.fillFrom(file: package.debURL)
} catch {
return true
}
}

index += 1
Expand All @@ -67,18 +75,21 @@ actor Database {
_ = await execute(request: request, context: backroundContext)
}

func fetchPackages() throws -> [DebPackage] {
func fetchPackages() async throws -> [DebPackage] {
let request = DebPackageObject.fetchRequest()
return try backroundContext.fetch(request).map { DebPackage(object: $0) }

let saveDiskNode = try await preferences.saveDiskNode
return try backroundContext.fetch(request).map { DebPackage(object: $0, saveDiskNode: saveDiskNode) }
}

func fetch<P: Package>(package: P) throws -> DebPackage? {
func fetch<P: Package>(package: P) async throws -> DebPackage? {
let request = DebPackageObject.fetchRequest(package: package)
guard let object = try backroundContext.fetch(request).first else {
return nil
}

return DebPackage(object: object)
let saveDiskNode = try await preferences.saveDiskNode
return DebPackage(object: object, saveDiskNode: saveDiskNode)
}

func delete(package: DebPackage) async throws {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ final class DebPackage: Package, Sendable {

let debSize: Measurement<UnitInformationStorage>

init(object: DebPackageObject) {
init(object: DebPackageObject, saveDiskNode: Int64) {
databaseID = object.objectID

id = object.id
Expand All @@ -49,8 +49,7 @@ final class DebPackage: Package, Sendable {
humanDescription = object.humanDescription
installedSize = object.installedSize

fileURL = Dpkg.defaultSaveDirectory.appendingPathComponent(object.relPath)

fileURL = URL(fileURLWithPath: "/.file/id=\(saveDiskNode).\(object.inodeID)")
debSize = Measurement(value: Double(object.debSize), unit: .bytes)
}

Expand Down
18 changes: 13 additions & 5 deletions twackup-gui/Twackup/Sources/Models/Database/DebPackageObject.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ struct BuildedPackage: @unchecked Sendable {
let debURL: URL
}

struct UpdateMetadataError: Error {
}

class DebPackageObject: NSManagedObject {
static let entityName = "DebPackageObject"

Expand Down Expand Up @@ -53,16 +56,21 @@ class DebPackageObject: NSManagedObject {
@NSManaged var debSize: Int64

@NSManaged var buildDate: Date
@NSManaged var relPath: String
@NSManaged var inodeID: Int64

var icon: URL?
var depiction: URL?

func fillFrom(file: URL) {
let metadata = try? FileManager.default.attributesOfItem(atPath: file.path)
debSize = (metadata?[.size] as? Int64) ?? 0
func fillFrom(file: URL) throws {
let metadata = try FileManager.default.attributesOfItem(atPath: file.path)
guard let size = metadata[.size] as? Int64,
let inode = metadata[.systemFileNumber] as? Int64
else {
throw UpdateMetadataError()
}

relPath = file.path.deletePrefix(Dpkg.defaultSaveDirectory.path)
debSize = size
inodeID = inode
}

func fillFrom<P: Package>(package: P) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
<attribute name="debSize" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="humanDescription" optional="YES" attributeType="String"/>
<attribute name="id" attributeType="String"/>
<attribute name="inodeID" attributeType="Integer 64" usesScalarValueType="YES"/>
<attribute name="installedSize" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="name" attributeType="String"/>
<attribute name="relPath" attributeType="String"/>
<attribute name="section" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="version" attributeType="String"/>
<uniquenessConstraints>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ actor PackagesRebuilder: DpkgProgressSubscriber, Equatable, Hashable {
}

do {
let results = try await mainModel.dpkg.rebuild(packages: packages)
let saveDir = await mainModel.preferences.saveDirectory
let results = try await mainModel.dpkg.rebuild(packages: packages, outDir: saveDir)
for result in results {
switch result {
case .success: continue
Expand Down
41 changes: 40 additions & 1 deletion twackup-gui/Twackup/Sources/Models/Preferences/Preferences.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,46 @@ class Preferences: ObservableObject {
}
}

init() {
@AppStorage("saveDirectory")
var saveDirectory: URL = defaultSaveDirectory

var saveDiskNode: Int64 {
get throws {
let attrs = try FileManager.default.attributesOfItem(atPath: saveDirectory.path)
return attrs[.systemNumber] as! Int64
}
}

init() throws {
_compression.setPublisher(objectWillChange)

try createSaveDirectoryIfNeeded()
}

func createSaveDirectoryIfNeeded() throws {
var isDir: ObjCBool = true
var exists = FileManager.default.fileExists(atPath: saveDirectory.path, isDirectory: &isDir)

// Application is not usable without directories created
if exists && !isDir.boolValue {
try FileManager.default.removeItem(at: saveDirectory)
exists = false
}

if !exists {
try FileManager.default.createDirectory(at: saveDirectory, withIntermediateDirectories: true)
}
}
}

extension Preferences {
static let defaultSaveDirectory: URL = {
let proxy = LSApplicationProxy.forCurrentProcess()
let unsandboxed = (proxy?.entitlements["com.apple.private.security.no-sandbox"] as? Bool) ?? false
if unsandboxed {
return URL(fileURLWithPath: "/var/mobile/Documents/Twackup")
}

return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
}()
}

0 comments on commit 53a90ac

Please sign in to comment.