From fb1e29e0eb8bf35a9bbfa4fded95a246bd5ebedc Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Thu, 9 Jul 2026 11:39:41 -0700 Subject: [PATCH] fix(vfs): propagate guest deletions in shadow->kernel sync (rm/rmdir/failed-clone cleanup) --- .../execution/assets/runners/wasi-module.js | 3 + crates/native-sidecar/src/execution.rs | 102 ++++++++++- crates/native-sidecar/src/state.rs | 9 + crates/native-sidecar/src/vm.rs | 1 + crates/native-sidecar/tests/filesystem.rs | 165 ++++++++++++++++++ crates/vfs/src/posix/overlay_fs.rs | 58 +++++- .../tests/integration/vfs-consistency.test.ts | 63 +++++++ toolchain/c/build/cat | Bin 3629 -> 0 bytes toolchain/c/build/env | Bin 11072 -> 0 bytes toolchain/c/build/sort | Bin 16019 -> 0 bytes toolchain/c/build/wc | Bin 16509 -> 0 bytes toolchain/test-programs/{cat.c => c-cat.c} | 0 toolchain/test-programs/{env.c => c-env.c} | 0 toolchain/test-programs/{sort.c => c-sort.c} | 0 toolchain/test-programs/{wc.c => c-wc.c} | 0 15 files changed, 395 insertions(+), 6 deletions(-) delete mode 100644 toolchain/c/build/cat delete mode 100644 toolchain/c/build/env delete mode 100644 toolchain/c/build/sort delete mode 100644 toolchain/c/build/wc rename toolchain/test-programs/{cat.c => c-cat.c} (100%) rename toolchain/test-programs/{env.c => c-env.c} (100%) rename toolchain/test-programs/{sort.c => c-sort.c} (100%) rename toolchain/test-programs/{wc.c => c-wc.c} (100%) diff --git a/crates/execution/assets/runners/wasi-module.js b/crates/execution/assets/runners/wasi-module.js index b861b77ba9..769b0be992 100644 --- a/crates/execution/assets/runners/wasi-module.js +++ b/crates/execution/assets/runners/wasi-module.js @@ -40,6 +40,7 @@ if (typeof globalThis !== "undefined" && typeof globalThis.__agentOSWasiModule = const __agentOSWasiErrnoNoent = 44; const __agentOSWasiErrnoNosys = 52; const __agentOSWasiErrnoNotdir = 54; + const __agentOSWasiErrnoNotempty = 55; const __agentOSWasiErrnoPipe = 64; const __agentOSWasiErrnoRofs = 69; const __agentOSWasiErrnoNotcapable = 76; @@ -799,6 +800,8 @@ if (typeof globalThis !== "undefined" && typeof globalThis.__agentOSWasiModule = return __agentOSWasiErrnoNoent; case "ENOTDIR": return __agentOSWasiErrnoNotdir; + case "ENOTEMPTY": + return __agentOSWasiErrnoNotempty; case "EEXIST": return __agentOSWasiErrnoExist; case "EINVAL": diff --git a/crates/native-sidecar/src/execution.rs b/crates/native-sidecar/src/execution.rs index 6448bb7583..68979f9430 100644 --- a/crates/native-sidecar/src/execution.rs +++ b/crates/native-sidecar/src/execution.rs @@ -9939,8 +9939,7 @@ pub(crate) fn sync_active_process_host_writes_to_kernel( vm: &mut VmState, ) -> Result<(), SidecarError> { if vm.root_filesystem_mode != RootFilesystemMode::ReadOnly { - let shadow_root = vm.cwd.clone(); - sync_host_directory_tree_to_kernel(vm, &shadow_root, "/")?; + sync_vm_shadow_root_to_kernel(vm)?; } let normalized_vm_root = normalize_host_path(&vm.cwd); @@ -9952,6 +9951,90 @@ pub(crate) fn sync_active_process_host_writes_to_kernel( Ok(()) } +/// Syncs the VM shadow root into the kernel VFS and reconciles deletions. +/// +/// The walk itself is additive (it copies shadow entries into the kernel), so +/// on its own it can never express a guest deletion performed directly on the +/// shadow tree — a removed file would be resurrected forever. To get real +/// Linux semantics the walk records every guest path it sees and diffs that +/// set against the previous walk's inventory: paths that were present in the +/// shadow before and are gone now are removed from the kernel VFS as well. +/// +/// Deletion propagation is scoped to the guest-writable shadow region: it only +/// runs for the VM shadow root walk (never for external host roots), re-checks +/// the protected/mount skip list, never touches the POSIX bootstrap skeleton, +/// and removes directories non-recursively so a kernel directory that still +/// has kernel-only content (for example a mount point or a path that was never +/// materialized into the shadow) is left in place with a warning. +fn sync_vm_shadow_root_to_kernel(vm: &mut VmState) -> Result<(), SidecarError> { + let shadow_root = normalize_host_path(&vm.cwd); + if host_sync_root_is_filesystem_root(&shadow_root) { + tracing::warn!("skipping host shadow sync rooted at the host filesystem root"); + return Ok(()); + } + let mut synced_file_times = BTreeMap::new(); + let mut inventory = BTreeSet::new(); + sync_host_directory_tree_to_kernel_inner( + vm, + &shadow_root, + &shadow_root, + "/", + &mut synced_file_times, + Some(&mut inventory), + )?; + propagate_shadow_deletions_to_kernel(vm, &inventory); + vm.shadow_sync_inventory = inventory; + Ok(()) +} + +/// Removes kernel paths whose shadow copy disappeared since the last walk. +/// +/// Best-effort by design: a failure to reconcile one stale path must not +/// poison the guest filesystem operation that triggered the sync, so failures +/// are surfaced as host-visible warnings instead of errors. Children sort +/// after their parents in the `BTreeSet`, so the reverse iteration removes +/// leaves before the directories that contain them. +fn propagate_shadow_deletions_to_kernel(vm: &mut VmState, current: &BTreeSet) { + if vm.shadow_sync_inventory.is_empty() { + return; + } + let stale: Vec = vm + .shadow_sync_inventory + .iter() + .rev() + .filter(|path| !current.contains(*path)) + .cloned() + .collect(); + for path in stale { + if path == "/" + || should_skip_shadow_sync_path(vm, &path) + || is_shadow_bootstrap_dir(&path) + { + continue; + } + let stat = match vm.kernel.lstat(&path) { + Ok(stat) => stat, + // Already gone (for example removed through the kernel-direct + // guest fs path, which mirrors deletions into the shadow itself). + Err(_) => continue, + }; + let result = if stat.is_directory && !stat.is_symbolic_link { + vm.kernel.remove_dir(&path) + } else { + vm.kernel.remove_file(&path) + }; + if let Err(error) = result { + if error.code() != "ENOENT" { + tracing::warn!( + path = %path, + error = %error, + "failed to propagate guest shadow deletion into the kernel VFS" + ); + } + } + } +} + fn collect_active_process_host_sync_roots( vm: &VmState, normalized_vm_root: &Path, @@ -9998,8 +10081,7 @@ fn sync_process_host_roots_to_kernel( process_guest_cwd: &str, ) -> Result<(), SidecarError> { if vm.root_filesystem_mode != RootFilesystemMode::ReadOnly { - let shadow_root = vm.cwd.clone(); - sync_host_directory_tree_to_kernel(vm, &shadow_root, "/")?; + sync_vm_shadow_root_to_kernel(vm)?; } if !path_is_within_root( @@ -10038,6 +10120,7 @@ fn sync_host_directory_tree_to_kernel( &normalized_host_root, &normalized_guest_root, &mut synced_file_times, + None, ) } @@ -10047,6 +10130,7 @@ fn sync_host_directory_tree_to_kernel_inner( current_host_dir: &Path, guest_root: &str, synced_file_times: &mut BTreeMap<(u64, u64), (u64, u64)>, + mut inventory: Option<&mut BTreeSet>, ) -> Result<(), SidecarError> { let entries = match fs::read_dir(current_host_dir) { Ok(entries) => entries, @@ -10108,6 +10192,15 @@ fn sync_host_directory_tree_to_kernel_inner( continue; } + // Record every shadow entry we can represent in the kernel (dirs, + // files, symlinks) so the deletion reconcile can tell "was in the + // shadow, now gone" apart from "never came from the shadow". + if let Some(inventory) = inventory.as_deref_mut() { + if file_type.is_dir() || file_type.is_file() || file_type.is_symlink() { + inventory.insert(guest_path.clone()); + } + } + if file_type.is_dir() { let metadata = entry.metadata().map_err(|error| { SidecarError::Io(format!( @@ -10143,6 +10236,7 @@ fn sync_host_directory_tree_to_kernel_inner( &host_path, guest_root, synced_file_times, + inventory.as_deref_mut(), )?; continue; } diff --git a/crates/native-sidecar/src/state.rs b/crates/native-sidecar/src/state.rs index 973d8534df..9cf857c76d 100644 --- a/crates/native-sidecar/src/state.rs +++ b/crates/native-sidecar/src/state.rs @@ -357,6 +357,15 @@ pub(crate) struct VmState { /// packages ship no `agentos-package.json`, so agent enumeration and /// resolution read this instead of the guest filesystem. pub(crate) projected_agent_launch: BTreeMap, + /// Guest paths that were present in the VM shadow root during the last + /// shadow->kernel sync walk. The next walk diffs the current shadow tree + /// against this set so guest deletions performed directly on the shadow + /// (host-side runtimes, WASI passthrough writes) propagate into the kernel + /// VFS instead of being resurrected by the otherwise additive sync. + /// Memory is bounded by the shadow tree itself, which is capped by the + /// kernel filesystem inode/byte resource limits that bound what the walk + /// can materialize. + pub(crate) shadow_sync_inventory: BTreeSet, } /// Launch parameters for one projected agent package. diff --git a/crates/native-sidecar/src/vm.rs b/crates/native-sidecar/src/vm.rs index cad03aa8c3..300ad28dc3 100644 --- a/crates/native-sidecar/src/vm.rs +++ b/crates/native-sidecar/src/vm.rs @@ -373,6 +373,7 @@ where signal_states: BTreeMap::new(), packages_staging_root: None, projected_agent_launch: BTreeMap::new(), + shadow_sync_inventory: BTreeSet::new(), }, ); diff --git a/crates/native-sidecar/tests/filesystem.rs b/crates/native-sidecar/tests/filesystem.rs index e414eff247..ad0329d229 100644 --- a/crates/native-sidecar/tests/filesystem.rs +++ b/crates/native-sidecar/tests/filesystem.rs @@ -463,6 +463,171 @@ mod shadow_root { } } + fn base_guest_filesystem_request( + operation: GuestFilesystemOperation, + path: &str, + ) -> GuestFilesystemCallRequest { + GuestFilesystemCallRequest { + operation, + path: String::from(path), + destination_path: None, + target: None, + content: None, + encoding: None, + recursive: false, + max_depth: None, + mode: None, + uid: None, + gid: None, + atime_ms: None, + mtime_ms: None, + len: None, + offset: None, + } + } + + fn guest_path_exists( + sidecar: &mut agentos_native_sidecar::NativeSidecar, + connection_id: &str, + session_id: &str, + vm_id: &str, + request_id: i64, + path: &str, + ) -> bool { + let response = sidecar + .dispatch_wire_blocking(wire_request( + request_id, + wire_vm(connection_id, session_id, vm_id), + RequestPayload::GuestFilesystemCallRequest(base_guest_filesystem_request( + GuestFilesystemOperation::Exists, + path, + )), + )) + .expect("dispatch guest filesystem exists"); + match response.response.payload { + ResponsePayload::GuestFilesystemResultResponse(result) => { + result.exists.unwrap_or(false) + } + other => panic!("expected guest_filesystem_result response, got {other:?}"), + } + } + + /// Deleting a path directly from the VM shadow root (the way host-side + /// guest runtimes delete files, without a kernel-direct unlink) must + /// propagate into the kernel VFS on the next shadow sync walk instead of + /// being resurrected by the additive copy-in. + #[test] + fn shadow_direct_deletions_propagate_into_kernel_vfs() { + let mut sidecar = create_test_sidecar(); + let (connection_id, session_id) = authenticate_and_open_session(&mut sidecar); + // Guest filesystem calls need no command mounts; create the VM bare so + // this regression test runs even without built registry commands. + let cwd = temp_dir("filesystem-shadow-reconcile-cwd"); + let (vm_id, _) = create_vm_wire( + &mut sidecar, + 3, + &connection_id, + &session_id, + GuestRuntimeKind::JavaScript, + &cwd, + ); + + let nonce = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .expect("system clock") + .as_nanos(); + let doomed_root = format!("/workspace/reconcile-{nonce}"); + let doomed_dir = format!("{doomed_root}/nested"); + let doomed_file = format!("{doomed_dir}/probe.txt"); + let survivor_file = format!("/workspace/reconcile-survivor-{nonce}.txt"); + + let mut mkdir = + base_guest_filesystem_request(GuestFilesystemOperation::CreateDir, &doomed_dir); + mkdir.recursive = true; + guest_filesystem_call(&mut sidecar, &connection_id, &session_id, &vm_id, 20, mkdir); + + let mut write = + base_guest_filesystem_request(GuestFilesystemOperation::WriteFile, &doomed_file); + write.content = Some(String::from("doomed\n")); + write.encoding = Some(RootFilesystemEntryEncoding::Utf8); + guest_filesystem_call(&mut sidecar, &connection_id, &session_id, &vm_id, 21, write); + + let mut survivor = + base_guest_filesystem_request(GuestFilesystemOperation::WriteFile, &survivor_file); + survivor.content = Some(String::from("survivor\n")); + survivor.encoding = Some(RootFilesystemEntryEncoding::Utf8); + guest_filesystem_call(&mut sidecar, &connection_id, &session_id, &vm_id, 22, survivor); + + // This read-side call walks the shadow tree and records the inventory + // the deletion reconcile diffs against. + assert!(guest_path_exists( + &mut sidecar, + &connection_id, + &session_id, + &vm_id, + 23, + &doomed_file, + )); + + // Locate this VM's shadow root through the mirrored unique file, then + // delete the subtree exactly as a host-side guest runtime would: on + // the shadow filesystem only, with no kernel-direct unlink. + let marker_rel = format!( + "workspace/reconcile-{nonce}/nested/probe.txt" + ); + let shadow_root = std::fs::read_dir(std::env::temp_dir()) + .expect("list temp dir") + .filter_map(|entry| entry.ok().map(|entry| entry.path())) + .find(|candidate| { + candidate + .file_name() + .and_then(|name| name.to_str()) + .is_some_and(|name| name.starts_with("agentos-native-sidecar-shadow-")) + && candidate.join(&marker_rel).is_file() + }) + .expect("locate VM shadow root through mirrored probe file"); + fs::remove_dir_all(shadow_root.join(format!("workspace/reconcile-{nonce}"))) + .expect("delete subtree from the shadow root"); + + // The next host filesystem call re-walks the shadow; the kernel must + // drop the deleted subtree instead of resurrecting it forever. + assert!( + !guest_path_exists( + &mut sidecar, + &connection_id, + &session_id, + &vm_id, + 24, + &doomed_file, + ), + "kernel resurrected a file deleted from the shadow root" + ); + assert!( + !guest_path_exists( + &mut sidecar, + &connection_id, + &session_id, + &vm_id, + 25, + &doomed_root, + ), + "kernel resurrected a directory deleted from the shadow root" + ); + assert!( + guest_path_exists( + &mut sidecar, + &connection_id, + &session_id, + &vm_id, + 26, + &survivor_file, + ), + "deletion reconcile must not remove shadow-backed paths that still exist" + ); + + dispose_vm_and_close_session(&mut sidecar, &connection_id, &session_id, &vm_id); + } + #[allow(clippy::too_many_arguments)] fn execute_command( sidecar: &mut agentos_native_sidecar::NativeSidecar, diff --git a/crates/vfs/src/posix/overlay_fs.rs b/crates/vfs/src/posix/overlay_fs.rs index 9fd0600587..653d18c819 100644 --- a/crates/vfs/src/posix/overlay_fs.rs +++ b/crates/vfs/src/posix/overlay_fs.rs @@ -1563,8 +1563,13 @@ impl VirtualFileSystem for OverlayFileSystem { if self.is_whited_out(path) { return Err(Self::entry_not_found(path)); } - let lower_exists = self.find_lower_by_exists(path).is_some(); - let upper_exists = self.exists_in_upper(path); + // POSIX unlink(2) removes the directory entry itself and never follows + // a symlink leaf, so existence must be checked with lstat semantics. + // `exists()` resolves symlinks, which made dangling symlinks (for + // example git's `.git/tXXXXXX` symlink-support probe) unremovable: + // the entry stayed listed by readdir while unlink reported ENOENT. + let lower_exists = self.find_lower_by_entry(path).is_some(); + let upper_exists = self.has_entry_in_upper(path); if !lower_exists && !upper_exists { return Err(Self::entry_not_found(path)); } @@ -2013,6 +2018,55 @@ mod tests { assert!(!overlay.exists("/workspace-temp")); } + #[test] + fn remove_file_unlinks_dangling_symlink() { + // git's symlink-support probe creates `.git/tXXXXXX -> testing` (a + // dangling symlink), lstats it, and unlinks it. unlink(2) must remove + // the link itself without resolving it. + let lower = MemoryFileSystem::new(); + let mut overlay = OverlayFileSystem::new(vec![lower], OverlayMode::Ephemeral); + overlay.mkdir("/repo", true).expect("create directory"); + overlay + .symlink("testing", "/repo/probe") + .expect("create dangling symlink"); + assert!(overlay + .lstat("/repo/probe") + .expect("lstat dangling symlink") + .is_symbolic_link); + + overlay + .remove_file("/repo/probe") + .expect("unlink dangling symlink"); + + assert!(overlay.lstat("/repo/probe").is_err()); + assert_eq!( + overlay.read_dir("/repo").expect("read emptied directory"), + Vec::::new() + ); + overlay + .remove_dir("/repo") + .expect("rmdir emptied directory"); + } + + #[test] + fn remove_file_unlinks_dangling_symlink_from_lower_layer() { + let mut lower = MemoryFileSystem::new(); + lower.mkdir("/repo", true).expect("create lower directory"); + lower + .symlink("missing-target", "/repo/probe") + .expect("seed lower dangling symlink"); + + let mut overlay = OverlayFileSystem::new(vec![lower], OverlayMode::Ephemeral); + overlay + .remove_file("/repo/probe") + .expect("whiteout lower dangling symlink"); + + assert!(overlay.lstat("/repo/probe").is_err()); + overlay + .remove_dir("/repo") + .expect("rmdir merged-empty directory"); + } + #[test] fn remove_dir_still_rejects_visible_children() { let mut lower = MemoryFileSystem::new(); diff --git a/packages/runtime-core/tests/integration/vfs-consistency.test.ts b/packages/runtime-core/tests/integration/vfs-consistency.test.ts index 19939a6ff8..128ee05196 100644 --- a/packages/runtime-core/tests/integration/vfs-consistency.test.ts +++ b/packages/runtime-core/tests/integration/vfs-consistency.test.ts @@ -109,4 +109,67 @@ describeIf(!skipReason, 'cross-runtime VFS consistency', () => { ); expect(nodeResult.exitCode).not.toBe(0); }); + + // Guest deletions must propagate into the kernel VFS instead of being + // resurrected by the (otherwise additive) shadow->kernel sync. This is the + // failure mode behind git's failed-clone junk surviving `remove_junk`. + it('guest rm -r removes the tree from the kernel VFS', async () => { + ctx = await createIntegrationKernel(); + + const create = await ctx.kernel.exec( + 'sh -c "mkdir -p /tmp/doomed/nested && echo payload > /tmp/doomed/nested/file.txt"', + ); + expect(create.exitCode).toBe(0); + expect(await ctx.vfs.exists('/tmp/doomed/nested/file.txt')).toBe(true); + + const remove = await ctx.kernel.exec('rm -r /tmp/doomed'); + expect(remove.exitCode).toBe(0); + + expect(await ctx.vfs.exists('/tmp/doomed/nested/file.txt')).toBe(false); + expect(await ctx.vfs.exists('/tmp/doomed/nested')).toBe(false); + expect(await ctx.vfs.exists('/tmp/doomed')).toBe(false); + + const ls = await ctx.kernel.exec('ls /tmp/doomed'); + expect(ls.exitCode).not.toBe(0); + }); + + it('guest rmdir on an empty directory succeeds and propagates', async () => { + ctx = await createIntegrationKernel(); + + const mkdir = await ctx.kernel.exec('mkdir /tmp/empty-dir'); + expect(mkdir.exitCode).toBe(0); + expect(await ctx.vfs.exists('/tmp/empty-dir')).toBe(true); + + const rmdir = await ctx.kernel.exec('rmdir /tmp/empty-dir'); + expect(rmdir.exitCode, rmdir.stderr).toBe(0); + expect(await ctx.vfs.exists('/tmp/empty-dir')).toBe(false); + }); + + it('guest unlink removes a dangling symlink so its directory can be emptied', async () => { + // git's symlink-support probe: create `tXXXXXX -> testing` (dangling), + // lstat it, unlink it, then remove the directory. unlink(2) must not + // resolve the symlink leaf, and rmdir must not report EIO afterwards. + ctx = await createIntegrationKernel(); + + const probe = await ctx.kernel.exec( + 'sh -c "mkdir /tmp/probe-dir && ln -s missing-target /tmp/probe-dir/probe && rm /tmp/probe-dir/probe && rmdir /tmp/probe-dir"', + ); + expect(probe.exitCode, probe.stderr).toBe(0); + expect(await ctx.vfs.exists('/tmp/probe-dir')).toBe(false); + }); + + it('guest rmdir on a non-empty directory reports ENOTEMPTY, not EIO', async () => { + ctx = await createIntegrationKernel(); + + const setup = await ctx.kernel.exec( + 'sh -c "mkdir /tmp/full-dir && echo keep > /tmp/full-dir/keep.txt"', + ); + expect(setup.exitCode).toBe(0); + + const rmdir = await ctx.kernel.exec('rmdir /tmp/full-dir'); + expect(rmdir.exitCode).not.toBe(0); + expect(rmdir.stderr.toLowerCase()).toContain('not empty'); + expect(rmdir.stderr.toLowerCase()).not.toContain('i/o error'); + expect(await ctx.vfs.exists('/tmp/full-dir/keep.txt')).toBe(true); + }); }); diff --git a/toolchain/c/build/cat b/toolchain/c/build/cat deleted file mode 100644 index f59943b868abeb421d0c33e9b373aad2f1a7d675..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3629 zcmb_fzi%7K6@K$$mrE@vu52L@tOGLKxS$}*vUIj2>s)9qu$_Z1xGuR)M@lPMB=w72 z%5h`5xFUs-CaF>cDN+VO%9KHhQ~~m@q`V@4^L?|l4u|svDNcrWe!cnTz4yKMW+>h9 zsS**jm3(2Q)2W)Gc{Nq9zOWc^sQ9s%V;gaj9UZ^+&>tej|(y1AyI?GsOTPw{vQJ4q8Nz%4gsF=Vsug#qLb(6<8uG3C=>h# z?7@{p^)NRX7o+%O+%3zO5}UbtO&g)jVk32-;y5x&bezCY|Cis{w02X+r^V^{=%to; ze_VD)rNs4AiC1Zq)aM$_hN{o~=7;sa*Hkj~uje{i9@{;1yxP+8WAU%uAeYy zR{nKpBeSQcPTJN*F6!tzNONQNa0<_vouPS#es{(qPgr_t_gv(~3rB82p^asl5#01PS@x?EU1poa&4zhM=(Tj{0Q1y8-g*lOQ@atrgjSYLzl3plWUp; zi7mazhCp}Vw9HG|3?f;|xy3vlJPTOV8WX`MFczm9XC61@mX|gh&b2)+Kg9$F@Ow?e z-2krjq1~E@pL+sen1*4l`>@U#I!(bJBn%YK;GOv-NRqsuLpuf^ps;OROz&m$w<_7q_OVad>QMD|TXpK+^L{)t{b0G;~VT`gKAhkg2C}P}c&$c#CL;KWe!R8hAhg^q=x%`Rh#}HAUpU zQw9m_<E}wJsM4#Zat8{peg!=2^KaFq6QA@mbipl(3SH{|flR~d z%%YD&U6U1)q-_Q90IbqqC_Q8OYkoA6zk>K+X4))x$e4K-Fo8A(%=>6df3L5@$C5{u zrv_7p)`tLD%0onjJ_=VAIbOF}4QVOJ&{>+pK$et*S#8?}l|TjcU_z+nQq}U{X)qE> zIO5dnCrxvUd%;Sm$n+HldHgJ|c~kcDI%ZgpYRiK>cFbT<5u(Z?M3z~{umQXcIGs?( zz}$|j^A>Y8qy{y7%9`?yYZ$eJJ{lAi8~{^7HFi2}!w;3;CGErSFabg7^qvz|)xXJQ zRgJDmhUY?Ywsd^NYmY&V41?|Tx<#@e=~zu?z_@CFI^EKHR0zJy8tK1k%7)BAFu0$= zjmn$L$EeGiA4pXp7s`1X366*aphA<|AgNvSxTz~iwJQucJqVJzlGN{$)Vsp)GnJ&N zB*EmjG0m>R#AhXz zvnym2Yx|8po_OdBs zcZ2|~0I<*p&xrFGfd+37mVKhktRf!X?v+P|I~RVLdR6i5bISr&>o7*2ypn`7BG35NTT01+VQiPOQjl zi+56zDop(r4c_m6Owt=#sy~BfDZ&R*UnOasJNOrge}l(9r2kM)=P5wRP8}ae{KCK)!^uH08tY`(Jv*Lsj|*jfvaulztQ-{MadEiTd#R!WuI_I< zyt{Gt!5V)zt&I-{uJgPsFUGs;>&GYM^GWaS!TIU>aClXH)_~A24ocVU-S0i})=Ku+u%-D2fm7?R2*v-a9xt?A_n&9d6#=-n_RWKX2hz%Q1ci9TnYjGAhQ=YU^}T zc6-BO?Ra?J>kh}OX>T$dtW`gBR+I6`@!4AO%W}0fDvpX#aduFwl`k)f@#@^^WLTbD Ib%&GUzps-ID*ylh diff --git a/toolchain/c/build/env b/toolchain/c/build/env deleted file mode 100644 index 401e013931e8be387fab4c74b87d32b24e2e1bbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11072 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 P+_*fww7q`$#^`?m@5N3d diff --git a/toolchain/c/build/sort b/toolchain/c/build/sort deleted file mode 100644 index 95605b0e06e9b3e365143aa6702ff5cefd43e657..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16019 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
  • !%UWg2ZDA(ODn?PQrHUi3AkG5vC0ZgzhGj>R)7vkk=)4{)8=&9s-bC(F-G! z$9#i#_zi&$!EyxFJNx|!GRa4<3OZ!Pxjc3{YxWt_O{` zc$+Gv_LEApH8N({vHGtfDdj#=E5G0IDBaYWZghWabD|kOr%%;DlCx%HWKmWK2DxoJ zlu{d(z$CIE55?mHN+>j7qd-*@fiCJBSo^_jaaA!eiF^)N7=fd)J&@wj#Mc>K94~Dnk*01(o-#gVNSz8U;(RFIvZCnM8S_!8Ie4&613M1D*Y>Fqxl{tn zh=E~^Jyb_Ubjq>xq0r0@6??lNlVaH(svYpQVCx}>xv7HV30P6+E`@HTK+=e0mZ`Xj zwmS9sY`O(?omf1574g*rwC-zfIkrE(?)A;$&F(EBP)I`t8KvEnL`AC`V z^dk!c9SSNq`=L;;UvW|RGsr`}?UuHEE6)($ZH*aOS!?7;#4z*9zw$UMii#($BEmHNczb~uOU zk2?2NRG=Rm*!xnv-d9x*B>TLzAv%(!?I?bM>nwV2Fr3pPUP@<2QkTSlONm7mrH9a) zKAf=MZ8;E8n9LP3OmsRPaE1FQAA}<~XdaGCPbNA>bOd8$JczM755@FhM+e%5VM2L0 zt`16dpjydMbuhLL#?zBd9jsXgN2k~sVr&hV;kQ;xU(QPXx#V<|^I=z43rY#72PnmQK3ao^!u~4Vg{OSWR;^d`=Z{m=LZ|dL%uiGgUxuxXg z$6pC<5e1LG^aQ@~H&abEV=Z~$cb=T~sI0llPCi9CoFo;spg7|!M4DAwO0r_$RTG6T zBSWQIih(GU3KJj3N-&UmFgdKbrDbZT`SGM{ptmG}ET7J*YCdrMa<}T0xpTL3)|zFN zaO-V85*NN#R`;bY{+IDl_W6faKP#(&-q3#q>+FHGes@qEDY&DS$1DD!<@>|&F43FpLz7rt1r#3-MaMU%Qs$r^!oL^_|GYNm~LI3 z`^`&FUV3Wti7S_$disg4JoWVEi;r(@{nleoZ=U(eW0zmNa_Pw@E?s%z$umzp_OSbd zHGcbim0wlAxV1UIwX?NbJhJxkt@-Aq>szO;UcYf^^ZM>1)umh4XQ$%Nr5`DGU%L9r osjb)MkF4!%y|}fr^~&X~Q}fqvZtXrYeEHV(`Ad77*Kck84;(?3UH||9 diff --git a/toolchain/c/build/wc b/toolchain/c/build/wc deleted file mode 100644 index 40bcb6891dc6c4363bac2d9434ce00b315ac16b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16509 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 RI4cEK?`UyFVu|&U{|h=TSkV9g diff --git a/toolchain/test-programs/cat.c b/toolchain/test-programs/c-cat.c similarity index 100% rename from toolchain/test-programs/cat.c rename to toolchain/test-programs/c-cat.c diff --git a/toolchain/test-programs/env.c b/toolchain/test-programs/c-env.c similarity index 100% rename from toolchain/test-programs/env.c rename to toolchain/test-programs/c-env.c diff --git a/toolchain/test-programs/sort.c b/toolchain/test-programs/c-sort.c similarity index 100% rename from toolchain/test-programs/sort.c rename to toolchain/test-programs/c-sort.c diff --git a/toolchain/test-programs/wc.c b/toolchain/test-programs/c-wc.c similarity index 100% rename from toolchain/test-programs/wc.c rename to toolchain/test-programs/c-wc.c