From 604fcd8f1d2c9a720176192f982064e4f7df4aeb Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Mon, 8 Jan 2024 13:46:08 -0700 Subject: [PATCH] No .. paths... --- crates/project/src/project.rs | 9 +++- crates/project/src/project_tests.rs | 75 +++++++++++++++++++++++++++++ crates/project/src/worktree.rs | 32 +++++++----- 3 files changed, 103 insertions(+), 13 deletions(-) diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index fb3eae1945f13fb1403b89b7556d548caaa76fff..584638a47a355495d2ffdf9f7da4712c23e30c4a 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -6581,7 +6581,14 @@ impl Project { let removed = *change == PathChange::Removed; let abs_path = worktree.absolutize(path); settings_contents.push(async move { - (settings_dir, (!removed).then_some(fs.load(&abs_path).await)) + ( + settings_dir, + if removed { + None + } else { + Some(async move { fs.load(&abs_path?).await }.await) + }, + ) }); } } diff --git a/crates/project/src/project_tests.rs b/crates/project/src/project_tests.rs index 8f41c75fb4de0415089c1ce66c30cb93278c079c..5c3c21fd08c988a0987a1e1acf0a3c8eb28e38d7 100644 --- a/crates/project/src/project_tests.rs +++ b/crates/project/src/project_tests.rs @@ -4278,6 +4278,81 @@ fn test_glob_literal_prefix() { assert_eq!(glob_literal_prefix("foo/bar/baz.js"), "foo/bar/baz.js"); } +#[gpui::test] +async fn test_create_entry(cx: &mut gpui::TestAppContext) { + init_test(cx); + + let fs = FakeFs::new(cx.executor().clone()); + fs.insert_tree( + "/one/two", + json!({ + "three": { + "a.txt": "", + "four": {} + }, + "c.rs": "" + }), + ) + .await; + + let project = Project::test(fs.clone(), ["/one/two/three".as_ref()], cx).await; + project + .update(cx, |project, cx| { + let id = project.worktrees().next().unwrap().read(cx).id(); + project.create_entry((id, "b.."), true, cx) + }) + .unwrap() + .await + .unwrap(); + + // Can't create paths outside the project + let result = project + .update(cx, |project, cx| { + let id = project.worktrees().next().unwrap().read(cx).id(); + project.create_entry((id, "../../boop"), true, cx) + }) + .await; + assert!(result.is_err()); + + // Can't create paths with '..' + let result = project + .update(cx, |project, cx| { + let id = project.worktrees().next().unwrap().read(cx).id(); + project.create_entry((id, "four/../beep"), true, cx) + }) + .await; + assert!(result.is_err()); + + assert_eq!( + fs.paths(true), + vec![ + PathBuf::from("/"), + PathBuf::from("/one"), + PathBuf::from("/one/two"), + PathBuf::from("/one/two/c.rs"), + PathBuf::from("/one/two/three"), + PathBuf::from("/one/two/three/a.txt"), + PathBuf::from("/one/two/three/b.."), + PathBuf::from("/one/two/three/four"), + ] + ); + + // ************************************ + // Note: unsure if this is the best fix for the integration failure, but assuming we want + // to keep that behavior, then this test should cover it + // ************************************ + + // But we can open buffers with '..' + let result = project + .update(cx, |project, cx| { + let id = project.worktrees().next().unwrap().read(cx).id(); + project.open_buffer((id, "../c.rs"), cx) + }) + .await; + + assert!(dbg!(result).is_ok()) +} + async fn search( project: &Model, query: SearchQuery, diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index ae0c074188274b95fbed3b078f68378ce715e570..461ea303b3d42cedb577d53f22c9e1de75a14b6a 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -965,6 +965,7 @@ impl LocalWorktree { let entry = self.refresh_entry(path.clone(), None, cx); cx.spawn(|this, mut cx| async move { + let abs_path = abs_path?; let text = fs.load(&abs_path).await?; let mut index_task = None; let snapshot = this.update(&mut cx, |this, _| this.as_local().unwrap().snapshot())?; @@ -1050,6 +1051,7 @@ impl LocalWorktree { cx.spawn(move |this, mut cx| async move { let entry = save.await?; + let abs_path = abs_path?; let this = this.upgrade().context("worktree dropped")?; let (entry_id, mtime, path) = match entry { @@ -1139,9 +1141,9 @@ impl LocalWorktree { let fs = self.fs.clone(); let write = cx.background_executor().spawn(async move { if is_dir { - fs.create_dir(&abs_path).await + fs.create_dir(&abs_path?).await } else { - fs.save(&abs_path, &Default::default(), Default::default()) + fs.save(&abs_path?, &Default::default(), Default::default()) .await } }); @@ -1188,7 +1190,7 @@ impl LocalWorktree { let fs = self.fs.clone(); let write = cx .background_executor() - .spawn(async move { fs.save(&abs_path, &text, line_ending).await }); + .spawn(async move { fs.save(&abs_path?, &text, line_ending).await }); cx.spawn(|this, mut cx| async move { write.await?; @@ -1210,10 +1212,10 @@ impl LocalWorktree { let delete = cx.background_executor().spawn(async move { if entry.is_file() { - fs.remove_file(&abs_path, Default::default()).await?; + fs.remove_file(&abs_path?, Default::default()).await?; } else { fs.remove_dir( - &abs_path, + &abs_path?, RemoveOptions { recursive: true, ignore_if_not_exists: false, @@ -1252,7 +1254,7 @@ impl LocalWorktree { let abs_new_path = self.absolutize(&new_path); let fs = self.fs.clone(); let rename = cx.background_executor().spawn(async move { - fs.rename(&abs_old_path, &abs_new_path, Default::default()) + fs.rename(&abs_old_path?, &abs_new_path?, Default::default()) .await }); @@ -1284,8 +1286,8 @@ impl LocalWorktree { let copy = cx.background_executor().spawn(async move { copy_recursive( fs.as_ref(), - &abs_old_path, - &abs_new_path, + &abs_old_path?, + &abs_new_path?, Default::default(), ) .await @@ -1609,11 +1611,17 @@ impl Snapshot { &self.abs_path } - pub fn absolutize(&self, path: &Path) -> PathBuf { + pub fn absolutize(&self, path: &Path) -> Result { + if path + .components() + .any(|component| !matches!(component, std::path::Component::Normal(_))) + { + return Err(anyhow!("invalid path")); + } if path.file_name().is_some() { - self.abs_path.join(path) + Ok(self.abs_path.join(path)) } else { - self.abs_path.to_path_buf() + Ok(self.abs_path.to_path_buf()) } } @@ -2823,7 +2831,7 @@ impl language::LocalFile for File { let abs_path = worktree.absolutize(&self.path); let fs = worktree.fs.clone(); cx.background_executor() - .spawn(async move { fs.load(&abs_path).await }) + .spawn(async move { fs.load(&abs_path?).await }) } fn buffer_reloaded(