field_ios

In-the-field app for Radroots on iOS
git clone https://radroots.dev/git/field_ios.git
Log | Files | Refs | README | LICENSE

TeraDurableMediaRoots.swift (2191B)


      1 import CryptoKit
      2 import Foundation
      3 import RadrootsKit
      4 
      5 /// Prepared photos live with application data. Existing temporary copies stay
      6 /// untouched and are migrated lazily when an acknowledged reference is opened.
      7 enum TeraDurableMediaRoots {
      8   static func selectingStaging(in base: RadrootsAppleFileRoots) throws -> RadrootsAppleFileRoots {
      9     try RadrootsAppleFileRoots(
     10       appIdentifier: base.appIdentifier, dataRoot: base.dataRoot, cacheRoot: base.cacheRoot,
     11       temporaryRoot: base.temporaryRoot, logsRoot: base.logsRoot,
     12       stagedBlobsRoot: base.dataRoot.appendingPathComponent("staged_blobs", isDirectory: true)
     13     )
     14   }
     15 
     16   static func restoreLegacyBlob(_ blob: RadrootsStagedBlobReference, roots: RadrootsAppleFileRoots) throws {
     17     let access = RadrootsAppleFileAccess(roots: roots)
     18     do {
     19       try validate(access.readStagedBlob(blob), reference: blob)
     20       return
     21     } catch RadrootsAppleFileError.notFound {
     22       // Only definitive absence permits the legacy copy to be installed.
     23       // Conflicting, protected or unsafe destinations require recovery.
     24     }
     25     let legacy = try RadrootsAppleFileRoots(
     26       appIdentifier: roots.appIdentifier, dataRoot: roots.dataRoot, cacheRoot: roots.cacheRoot,
     27       temporaryRoot: roots.temporaryRoot, logsRoot: roots.logsRoot
     28     )
     29     guard legacy.stagedBlobsRoot != roots.stagedBlobsRoot else { throw RadrootsAppleFileError.notFound }
     30     let bytes = try RadrootsAppleFileAccess(roots: legacy).readStagedBlob(blob)
     31     try validate(bytes, reference: blob)
     32     // Preserve the legacy copy and reconcile a completed install by its exact
     33     // existing reference on restart, without introducing a second journal.
     34     try access.installStagedBlob(bytes, reference: blob)
     35   }
     36 
     37   private static func validate(_ bytes: Data, reference blob: RadrootsStagedBlobReference) throws {
     38     let digest = SHA256.hash(data: bytes).map { String(format: "%02x", $0) }.joined()
     39     guard digest == blob.blobID else {
     40       throw TeraRuntimeFailure.local(operation: "add.media.migrate", code: "ios.add.media_corrupt",
     41                                      safeMessage: "A prepared photo could not be verified on this device.")
     42     }
     43   }
     44 }