@@ -1964,8 +1964,13 @@ pub(crate) fn service_javascript_fs_sync_rpc(
19641964 }
19651965 kernel
19661966 . rename ( source, destination)
1967- . map ( |( ) | Value :: Null )
1968- . map_err ( kernel_error)
1967+ . map_err ( kernel_error) ?;
1968+ // Mirror the rename into the process shadow tree, otherwise the
1969+ // exit-time shadow->kernel sync resurrects the stale source path
1970+ // (the shadow walk only copies entries in, it cannot express
1971+ // deletions).
1972+ rename_process_shadow_path ( process, source, destination) ?;
1973+ Ok ( Value :: Null )
19691974 }
19701975 "fs.rmdirSync" | "fs.promises.rmdir" => {
19711976 let path =
@@ -1997,10 +2002,11 @@ pub(crate) fn service_javascript_fs_sync_rpc(
19972002 }
19982003 None => { }
19992004 }
2000- kernel
2001- . remove_dir ( path)
2002- . map ( |( ) | Value :: Null )
2003- . map_err ( kernel_error)
2005+ kernel. remove_dir ( path) . map_err ( kernel_error) ?;
2006+ // Mirror the removal into the process shadow tree, otherwise the
2007+ // exit-time shadow->kernel sync resurrects the deleted directory.
2008+ remove_process_shadow_path ( process, path) ?;
2009+ Ok ( Value :: Null )
20042010 }
20052011 "fs.unlinkSync" | "fs.promises.unlink" => {
20062012 let path =
@@ -2034,10 +2040,13 @@ pub(crate) fn service_javascript_fs_sync_rpc(
20342040 }
20352041 None => { }
20362042 }
2037- kernel
2038- . remove_file ( path)
2039- . map ( |( ) | Value :: Null )
2040- . map_err ( kernel_error)
2043+ kernel. remove_file ( path) . map_err ( kernel_error) ?;
2044+ // Mirror the deletion into the process shadow tree: wasm guest
2045+ // deletions route kernel-direct, and without removing the shadow
2046+ // copy the exit-time shadow->kernel sync resurrects the file for
2047+ // later builtins in the same shell and for subsequent execs.
2048+ remove_process_shadow_path ( process, path) ?;
2049+ Ok ( Value :: Null )
20412050 }
20422051 "fs.chmodSync" | "fs.promises.chmod" => {
20432052 let path =
@@ -4349,6 +4358,52 @@ fn resolve_process_guest_path_to_host(
43494358 ) )
43504359}
43514360
4361+ /// Removes the host shadow copy of `guest_path` after a kernel-direct guest
4362+ /// deletion so the exit-time shadow->kernel sync cannot resurrect it.
4363+ fn remove_process_shadow_path (
4364+ process : & ActiveProcess ,
4365+ guest_path : & str ,
4366+ ) -> Result < ( ) , SidecarError > {
4367+ let Some ( shadow_path) = resolve_process_guest_path_to_host ( process, guest_path) else {
4368+ return Ok ( ( ) ) ;
4369+ } ;
4370+ remove_shadow_path_if_exists ( & shadow_path, guest_path)
4371+ }
4372+
4373+ /// Mirrors a kernel-direct guest rename into the host shadow tree. If the
4374+ /// source shadow entry is missing the stale destination copy is still removed
4375+ /// so the shadow walk cannot resurrect pre-rename content.
4376+ fn rename_process_shadow_path (
4377+ process : & ActiveProcess ,
4378+ source : & str ,
4379+ destination : & str ,
4380+ ) -> Result < ( ) , SidecarError > {
4381+ let Some ( source_shadow) = resolve_process_guest_path_to_host ( process, source) else {
4382+ return Ok ( ( ) ) ;
4383+ } ;
4384+ let Some ( destination_shadow) = resolve_process_guest_path_to_host ( process, destination) else {
4385+ return Ok ( ( ) ) ;
4386+ } ;
4387+
4388+ if fs:: symlink_metadata ( & source_shadow) . is_err ( ) {
4389+ return remove_shadow_path_if_exists ( & destination_shadow, destination) ;
4390+ }
4391+
4392+ if let Some ( parent) = destination_shadow. parent ( ) {
4393+ fs:: create_dir_all ( parent) . map_err ( |error| {
4394+ SidecarError :: Io ( format ! (
4395+ "failed to create shadow parent for rename {source} -> {destination}: {error}"
4396+ ) )
4397+ } ) ?;
4398+ }
4399+ remove_shadow_path_if_exists ( & destination_shadow, destination) ?;
4400+ fs:: rename ( & source_shadow, & destination_shadow) . map_err ( |error| {
4401+ SidecarError :: Io ( format ! (
4402+ "failed to mirror guest rename {source} -> {destination} into shadow root: {error}"
4403+ ) )
4404+ } )
4405+ }
4406+
43524407fn sync_host_directory_to_kernel (
43534408 vm : & mut VmState ,
43544409 guest_path : & str ,
0 commit comments