# How the vphone-cli `vm clone` Command Performs APFS Snapshot-Based Cloning with Fresh Device Identity

> Discover how vphone-cli vm clone uses APFS snapshots for fast VM cloning. Learn how it resets device identity by clearing NVRAM, UDID, and manifest data.

- Repository: [Lakr/vphone-cli](https://github.com/Lakr233/vphone-cli)
- Tags: internals
- Published: 2026-09-08

---

**The `vphone-cli clone` command creates a lightweight copy-on-write (CoW) clone of a VM bundle using the macOS `clonefile(2)` system call, then resets the device identity by clearing NVRAM, UDID predictions, and the machine identifier in the manifest.**

The `vphone-cli` tool from the [Lakr233/vphone-cli](https://github.com/Lakr233/vphone-cli) repository provides efficient virtual machine management for iOS device emulation on macOS. Its `vm clone` functionality leverages APFS filesystem features to create near-instantaneous VM copies, then sanitizes hardware-specific identifiers to ensure the cloned instance appears as a fresh device to iOS and Apple's activation servers.

## APFS Copy-on-Write Cloning Mechanism

The core cloning operation relies on the macOS APFS filesystem's ability to create lightweight snapshots that share underlying storage blocks until modified.

### The `clonefile(2)` System Call

In [`sources/VPhoneCore/VPhoneBundleOps.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/VPhoneCore/VPhoneBundleOps.swift), the `clone()` method invokes the low-level `clonefile(2)` system call to perform the actual copy-on-write operation. This creates a new directory entry that points to the same physical blocks as the source bundle, completing in milliseconds regardless of file size.

```swift
// VPhoneBundleOps.clone – lines 147-150
if clonefile(src.path, dst.path, 0) != 0 {
    try? fm.removeItem(at: dst)               // clear any partial clonefile output
    try fm.copyItem(at: src, to: dst)          // fallback copy
}

```

When `clonefile()` succeeds, the destination becomes an APFS snapshot of the source, consuming negligible additional disk space until either the original or clone is modified.

### Fallback to Standard File Copy

If the target volume does not support APFS—indicated by `clonefile()` returning a non-zero value—the implementation automatically falls back to `FileManager.copyItem`. The code first attempts to clean up any partial clonefile output before performing a conventional recursive copy, ensuring robustness across different storage configurations.

## Resetting Device Identity for Fresh Activation

After the filesystem clone completes, the command transforms the copied bundle into a distinct virtual device by stripping all hardware-specific identifiers.

### Removing Identity Artifacts

The `resetIdentity()` method in [`VPhoneBundleOps.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneBundleOps.swift) (lines 55-66) deletes files that tie the VM to its previous hardware state:

- **nvram.bin**: Contains non-volatile RAM settings including device-specific boot parameters
- **udid-prediction.txt**: Stores predicted unique device identifiers
- **\*.shsh**: SHSH blob caches used for firmware signing verification

```swift
// VPhoneBundleOps.resetIdentity – lines 55-66
for name in ["nvram.bin", "udid-prediction.txt"] { … }
for u in entries where u.pathExtension == "shsh" { … }
let manifest = try VPhoneVirtualMachineManifest.load(from: configURL)
try manifest.updating(machineIdentifier: Data()).write(to: configURL)

```

### Clearing the Machine Identifier

The code loads the bundle's `config.plist` via `VPhoneVirtualMachineManifest`, replaces the `machineIdentifier` field with an empty `Data()` value, and persists the updated manifest. This ensures the cloned VM generates a new machine identifier on next boot, appearing as a fresh device to iOS.

## CLI Command Structure

The command-line interface in [`sources/vphone-cli/VPhoneVMTransferCLI.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/vphone-cli/VPhoneVMTransferCLI.swift) provides the user-facing entry point for the cloning operation.

### Command Resolution and Execution

Lines 5-21 of [`VPhoneVMTransferCLI.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneVMTransferCLI.swift) resolve the source and destination VM names using `VPhoneVMSelection`, then delegate to the core cloning logic:

```swift
// VPhoneVMTransferCLI.swift – lines 5-21
let name    = try VPhoneVMSelection.resolveExisting(name,   in: lib.library)
let newName = try VPhoneVMSelection.resolveNewName(newName, prompt: "New VM name:")
let clone   = try VPhoneBundleOps.clone(bundleNamed: name, to: newName, in: lib.library)
print("cloned \(name) → \(clone.name)")

```

This separation of concerns allows the CLI to handle user interaction while delegating filesystem operations to `VPhoneBundleOps`.

## Usage Examples

### Shell Execution

Clone an existing VM named "myPhone" to a new instance called "myPhone-clone":

```bash
vphone-cli clone myPhone myPhone-clone

```

### Programmatic Integration

For automation or custom tooling, import the `VPhoneCore` framework:

```swift
import VPhoneCore

let library = try VPhoneLibrary(at: URL(fileURLWithPath: "/path/to/vphone/library"))
let clonedBundle = try VPhoneBundleOps.clone(
    bundleNamed: "myPhone",
    to: "myPhone-clone",
    in: library
)
// clonedBundle points to a VM with reset identity

```

## Summary

- **APFS CoW Cloning**: The `clone` command uses `clonefile(2)` to create space-efficient snapshots that share underlying blocks with the source VM.
- **Automatic Fallback**: When APFS is unavailable, the system transparently falls back to `FileManager.copyItem` for standard file copying.
- **Identity Sanitization**: The process removes `nvram.bin`, [`udid-prediction.txt`](https://github.com/Lakr233/vphone-cli/blob/main/udid-prediction.txt), and SHSH files to eliminate hardware fingerprints.
- **Manifest Reset**: The `machineIdentifier` field in `config.plist` is cleared to force generation of a fresh device identity on next boot.
- **Performance**: Copy-on-write operations complete in milliseconds regardless of VM bundle size, making cloning effectively instantaneous.

## Frequently Asked Questions

### What happens if my destination drive is not formatted as APFS?

If the destination volume does not support APFS, the `clonefile(2)` call fails and the implementation automatically falls back to `FileManager.copyItem`, performing a conventional recursive copy. This ensures compatibility with HFS+ or external drives while sacrificing the space and speed benefits of copy-on-write cloning.

### Why does the clone command need to reset the device identity?

iOS and Apple's activation servers track devices using unique identifiers stored in NVRAM and the machine manifest. Without clearing `nvram.bin`, [`udid-prediction.txt`](https://github.com/Lakr233/vphone-cli/blob/main/udid-prediction.txt), and the `machineIdentifier` field, the cloned VM would retain its parent's hardware identity, causing conflicts with activation, iCloud, and enterprise MDM systems. The reset ensures the clone appears as a physically distinct device.

### How much disk space does a cloned VM consume initially?

Because `clonefile(2)` creates a copy-on-write snapshot, the cloned bundle initially consumes only the metadata overhead required for the new directory structure—typically a few kilobytes. Storage usage increases only as files are modified in either the source or clone, at which point APFS allocates new blocks for the changed data.

### Can I clone a VM to the same name as the source?

No, the CLI requires distinct source and destination names. The `VPhoneVMSelection.resolveNewName()` function validates that the target name does not already exist in the library, preventing accidental overwrites and ensuring the operation creates a distinct VM entry.