Your issue
Version: 0.1.8, the official AppSandbox-0.1.8-win-x64.zip. The same code is in 0.1.4. Windows 11 host.
What happens. The first snapshot of a VM works as expected. Every snapshot after it saves the
disk as it was at the first snapshot, not the VM's current state, and then switches the VM onto
a new branch of that old state. The work done in between is not deleted. It stays on the previous
branch, and selecting that branch brings it back. But nothing says so, and the VM now boots without
it, so it looks as if the work is gone.
Steps (observed on a freshly installed Windows 11 VM, no GPU):
- Shut the VM down. Take snapshot A. The VM moves to A's "Default Branch", which is correct.
- Start the VM, create
after-A.txt on the desktop, shut it down.
- Take snapshot B. Start the VM.
- Expected:
after-A.txt is there. B was taken after it was created.
- Actual:
after-A.txt is gone. The VM boots B's new branch, and B holds the disk as it was at A.
The differencing disks afterwards, with the parent read from each file's parent locator:
| file |
size |
parent |
snapshot_c3883d92-….vhdx (A) |
4 MB |
disk.vhdx |
branch_55e7a34a-….vhdx (A's Default Branch) |
1.6 GB |
A — holds after-A.txt |
snapshot_0c308386-….vhdx (B) |
4 MB |
disk.vhdx |
branch_ca059406-….vhdx (B's Default Branch) |
0.9 GB |
B — the VM's disk now |
Cause. snapshot_take in src/backend_win/snapshot.c always parents the new snapshot on the
base disk:
/* line 258 */
hr = vhdx_create_differencing(vhdx_path, tree->base_vhdx);
tree->base_vhdx is set once, on the first snapshot (lines 250–251), and nothing ever updates it to
the disk the VM is running on. The only other writes load it from tree.dat (line 177) and clear it
when the tree is empty (line 77). asb_snap_take in asb_core.c calls snapshot_take directly,
with no merge first. So from the second snapshot on, the parent is always the original base.
Is the flat layout intended? The code disagrees with itself here, which is why this is an issue
and not only a PR:
- For:
get_branch_list hands out base_vhdx as the parent (line 37), the header describes each
snapshot as a "frozen fork off base", and the New Snapshot dialog says "Create a new snapshot of
the base disk" (web/app.js, line 1560).
- Against: the header documents
snapshot_take as "freeze current state as a named fork of the
base". Both halves can only be true for the first snapshot, which is the one that works.
If the flat layout is intended, the dialog and API should say plainly that a snapshot does not
contain the current state, and that taking one moves the VM off the branch it was on.
Why the obvious fix is not enough. Parenting B on the VM's current disk (instance->vhdx_path)
captures the right content, but it makes A's branch an ancestor of B. That branch must then never
be written again, yet it is still listed as a selectable branch of A, and booting it would corrupt B
and everything built on it.
Suggested fix: PR #"linked below". On a working branch, snapshot_take renames that branch into the new
snapshot, removes it from its old branch list, and continues on a fresh branch of it: the Hyper-V
checkpoint model. That is O(1), with no copying. Snapshots then form a real tree, so:
- the parent is recorded in
tree.dat as an optional Parent= line, and flat trees are read and
written exactly as before;
- deleting a snapshot that another was taken on is refused, with a message;
- the snapshot window nests each snapshot under its parent, and the API reports
parent.
Testing: built on 0.1.8 (only AppSandbox.exe, appsandbox_core.dll and web/app.js
replaced; the released drivers are unchanged) and run against the same VM after the stock build.
It loaded the stock tree unchanged. A snapshot taken from A's branch held after-A.txt, and so did
the VM afterwards. A second level (D on C) held both files. Deleting A was refused while C existed.
The tree survived a restart. A new branch from C had C's content and nothing later.
Why it matters to us. We use snapshots as rollback points for an automated build VM: take a
baseline after a warm build, and branch from it when a run goes wrong. Until this is resolved we can
only rely on the first snapshot.
🤖 Generated with Claude Code
Your issue
Version: 0.1.8, the official
AppSandbox-0.1.8-win-x64.zip. The same code is in 0.1.4. Windows 11 host.What happens. The first snapshot of a VM works as expected. Every snapshot after it saves the
disk as it was at the first snapshot, not the VM's current state, and then switches the VM onto
a new branch of that old state. The work done in between is not deleted. It stays on the previous
branch, and selecting that branch brings it back. But nothing says so, and the VM now boots without
it, so it looks as if the work is gone.
Steps (observed on a freshly installed Windows 11 VM, no GPU):
after-A.txton the desktop, shut it down.after-A.txtis there. B was taken after it was created.after-A.txtis gone. The VM boots B's new branch, and B holds the disk as it was at A.The differencing disks afterwards, with the parent read from each file's parent locator:
snapshot_c3883d92-….vhdx(A)disk.vhdxbranch_55e7a34a-….vhdx(A's Default Branch)after-A.txtsnapshot_0c308386-….vhdx(B)disk.vhdxbranch_ca059406-….vhdx(B's Default Branch)Cause.
snapshot_takeinsrc/backend_win/snapshot.calways parents the new snapshot on thebase disk:
tree->base_vhdxis set once, on the first snapshot (lines 250–251), and nothing ever updates it tothe disk the VM is running on. The only other writes load it from
tree.dat(line 177) and clear itwhen the tree is empty (line 77).
asb_snap_takeinasb_core.ccallssnapshot_takedirectly,with no merge first. So from the second snapshot on, the parent is always the original base.
Is the flat layout intended? The code disagrees with itself here, which is why this is an issue
and not only a PR:
get_branch_listhands outbase_vhdxas the parent (line 37), the header describes eachsnapshot as a "frozen fork off base", and the New Snapshot dialog says "Create a new snapshot of
the base disk" (
web/app.js, line 1560).snapshot_takeas "freeze current state as a named fork of thebase". Both halves can only be true for the first snapshot, which is the one that works.
If the flat layout is intended, the dialog and API should say plainly that a snapshot does not
contain the current state, and that taking one moves the VM off the branch it was on.
Why the obvious fix is not enough. Parenting B on the VM's current disk (
instance->vhdx_path)captures the right content, but it makes A's branch an ancestor of B. That branch must then never
be written again, yet it is still listed as a selectable branch of A, and booting it would corrupt B
and everything built on it.
Suggested fix: PR #"linked below". On a working branch,
snapshot_takerenames that branch into the newsnapshot, removes it from its old branch list, and continues on a fresh branch of it: the Hyper-V
checkpoint model. That is O(1), with no copying. Snapshots then form a real tree, so:
tree.datas an optionalParent=line, and flat trees are read andwritten exactly as before;
parent.Testing: built on 0.1.8 (only
AppSandbox.exe,appsandbox_core.dllandweb/app.jsreplaced; the released drivers are unchanged) and run against the same VM after the stock build.
It loaded the stock tree unchanged. A snapshot taken from A's branch held
after-A.txt, and so didthe VM afterwards. A second level (D on C) held both files. Deleting A was refused while C existed.
The tree survived a restart. A new branch from C had C's content and nothing later.
Why it matters to us. We use snapshots as rollback points for an automated build VM: take a
baseline after a warm build, and branch from it when a run goes wrong. Until this is resolved we can
only rely on the first snapshot.
🤖 Generated with Claude Code