summaryrefslogtreecommitdiff
path: root/cli/standalone/virtual_fs.rs
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2023-05-27 10:33:15 -0400
committerGitHub <noreply@github.com>2023-05-27 10:33:15 -0400
commita96844118c24d870abfe5332547dab99dc53d09c (patch)
tree194bde1661ad66e41efc912ccbb151edf268c643 /cli/standalone/virtual_fs.rs
parentbe59e93220e24a2e66ae2843a136e61eab9d8ac3 (diff)
fix(compile): inline symlinks as files outside node_modules dir and warn for directories (#19285)
If a symlink within the `node_modules` directory lies outside that directory, it will now warn and inline the file. For directories, it will just warn for now. Probably fixes #19251 (I'm still unable to reproduce).
Diffstat (limited to 'cli/standalone/virtual_fs.rs')
-rw-r--r--cli/standalone/virtual_fs.rs151
1 files changed, 112 insertions, 39 deletions
diff --git a/cli/standalone/virtual_fs.rs b/cli/standalone/virtual_fs.rs
index e94758bd9..42416554d 100644
--- a/cli/standalone/virtual_fs.rs
+++ b/cli/standalone/virtual_fs.rs
@@ -24,9 +24,19 @@ use deno_runtime::deno_io::fs::FsResult;
use deno_runtime::deno_io::fs::FsStat;
use serde::Deserialize;
use serde::Serialize;
+use thiserror::Error;
use crate::util;
+#[derive(Error, Debug)]
+#[error(
+ "Failed to strip prefix '{}' from '{}'", root_path.display(), target.display()
+)]
+pub struct StripRootError {
+ root_path: PathBuf,
+ target: PathBuf,
+}
+
pub struct VfsBuilder {
root_path: PathBuf,
root_dir: VirtualDirectory,
@@ -37,6 +47,7 @@ pub struct VfsBuilder {
impl VfsBuilder {
pub fn new(root_path: PathBuf) -> Self {
+ log::debug!("Building vfs with root '{}'", root_path.display());
Self {
root_dir: VirtualDirectory {
name: root_path
@@ -58,7 +69,7 @@ impl VfsBuilder {
}
pub fn add_dir_recursive(&mut self, path: &Path) -> Result<(), AnyError> {
- self.add_dir(path);
+ self.add_dir(path)?;
let read_dir = std::fs::read_dir(path)
.with_context(|| format!("Reading {}", path.display()))?;
@@ -72,19 +83,44 @@ impl VfsBuilder {
} else if file_type.is_file() {
let file_bytes = std::fs::read(&path)
.with_context(|| format!("Reading {}", path.display()))?;
- self.add_file(&path, file_bytes);
+ self.add_file(&path, file_bytes)?;
} else if file_type.is_symlink() {
- let target = std::fs::read_link(&path)
+ let target = util::fs::canonicalize_path(&path)
.with_context(|| format!("Reading symlink {}", path.display()))?;
- self.add_symlink(&path, &target);
+ if let Err(StripRootError { .. }) = self.add_symlink(&path, &target) {
+ if target.is_file() {
+ // this may change behavior, so warn the user about it
+ log::warn!(
+ "Symlink target is outside '{}'. Inlining symlink at '{}' to '{}' as file.",
+ self.root_path.display(),
+ path.display(),
+ target.display(),
+ );
+ // inline the symlink and make the target file
+ let file_bytes = std::fs::read(&target)
+ .with_context(|| format!("Reading {}", path.display()))?;
+ self.add_file(&path, file_bytes)?;
+ } else {
+ log::warn!(
+ "Symlink target is outside '{}'. Excluding symlink at '{}' with target '{}'.",
+ self.root_path.display(),
+ path.display(),
+ target.display(),
+ );
+ }
+ }
}
}
Ok(())
}
- pub fn add_dir(&mut self, path: &Path) -> &mut VirtualDirectory {
- let path = self.path_relative_root(path);
+ pub fn add_dir(
+ &mut self,
+ path: &Path,
+ ) -> Result<&mut VirtualDirectory, StripRootError> {
+ log::debug!("Ensuring directory '{}'", path.display());
+ let path = self.path_relative_root(path)?;
let mut current_dir = &mut self.root_dir;
for component in path.components() {
@@ -113,10 +149,15 @@ impl VfsBuilder {
};
}
- current_dir
+ Ok(current_dir)
}
- pub fn add_file(&mut self, path: &Path, data: Vec<u8>) {
+ pub fn add_file(
+ &mut self,
+ path: &Path,
+ data: Vec<u8>,
+ ) -> Result<(), AnyError> {
+ log::debug!("Adding file '{}'", path.display());
let checksum = util::checksum::gen(&[&data]);
let offset = if let Some(offset) = self.file_offsets.get(&checksum) {
// duplicate file, reuse an old offset
@@ -126,7 +167,7 @@ impl VfsBuilder {
self.current_offset
};
- let dir = self.add_dir(path.parent().unwrap());
+ let dir = self.add_dir(path.parent().unwrap())?;
let name = path.file_name().unwrap().to_string_lossy();
let data_len = data.len();
match dir.entries.binary_search_by(|e| e.name().cmp(&name)) {
@@ -148,11 +189,22 @@ impl VfsBuilder {
self.files.push(data);
self.current_offset += data_len as u64;
}
+
+ Ok(())
}
- pub fn add_symlink(&mut self, path: &Path, target: &Path) {
- let dest = self.path_relative_root(target);
- let dir = self.add_dir(path.parent().unwrap());
+ pub fn add_symlink(
+ &mut self,
+ path: &Path,
+ target: &Path,
+ ) -> Result<(), StripRootError> {
+ log::debug!(
+ "Adding symlink '{}' to '{}'",
+ path.display(),
+ target.display()
+ );
+ let dest = self.path_relative_root(target)?;
+ let dir = self.add_dir(path.parent().unwrap())?;
let name = path.file_name().unwrap().to_string_lossy();
match dir.entries.binary_search_by(|e| e.name().cmp(&name)) {
Ok(_) => unreachable!(),
@@ -169,23 +221,20 @@ impl VfsBuilder {
);
}
}
+ Ok(())
}
pub fn into_dir_and_files(self) -> (VirtualDirectory, Vec<Vec<u8>>) {
(self.root_dir, self.files)
}
- fn path_relative_root(&self, path: &Path) -> PathBuf {
+ fn path_relative_root(&self, path: &Path) -> Result<PathBuf, StripRootError> {
match path.strip_prefix(&self.root_path) {
- Ok(p) => p.to_path_buf(),
- Err(err) => {
- panic!(
- "Failed to strip prefix '{}' from '{}': {:#}",
- self.root_path.display(),
- path.display(),
- err
- )
- }
+ Ok(p) => Ok(p.to_path_buf()),
+ Err(_) => Err(StripRootError {
+ root_path: self.root_path.clone(),
+ target: path.to_path_buf(),
+ }),
}
}
}
@@ -457,7 +506,11 @@ impl FileBackedVfsFile {
}
SeekFrom::End(offset) => {
if offset < 0 && -offset as u64 > self.file.len {
- Err(std::io::Error::new(std::io::ErrorKind::PermissionDenied, "An attempt was made to move the file pointer before the beginning of the file.").into())
+ let msg = "An attempt was made to move the file pointer before the beginning of the file.";
+ Err(
+ std::io::Error::new(std::io::ErrorKind::PermissionDenied, msg)
+ .into(),
+ )
} else {
let mut current_pos = self.pos.lock();
*current_pos = if offset >= 0 {
@@ -790,16 +843,28 @@ mod test {
let temp_dir = TempDir::new();
let src_path = temp_dir.path().join("src");
let mut builder = VfsBuilder::new(src_path.clone());
- builder.add_file(&src_path.join("a.txt"), "data".into());
- builder.add_file(&src_path.join("b.txt"), "data".into());
+ builder
+ .add_file(&src_path.join("a.txt"), "data".into())
+ .unwrap();
+ builder
+ .add_file(&src_path.join("b.txt"), "data".into())
+ .unwrap();
assert_eq!(builder.files.len(), 1); // because duplicate data
- builder.add_file(&src_path.join("c.txt"), "c".into());
- builder.add_file(&src_path.join("sub_dir").join("d.txt"), "d".into());
- builder.add_file(&src_path.join("e.txt"), "e".into());
- builder.add_symlink(
- &src_path.join("sub_dir").join("e.txt"),
- &src_path.join("e.txt"),
- );
+ builder
+ .add_file(&src_path.join("c.txt"), "c".into())
+ .unwrap();
+ builder
+ .add_file(&src_path.join("sub_dir").join("d.txt"), "d".into())
+ .unwrap();
+ builder
+ .add_file(&src_path.join("e.txt"), "e".into())
+ .unwrap();
+ builder
+ .add_symlink(
+ &src_path.join("sub_dir").join("e.txt"),
+ &src_path.join("e.txt"),
+ )
+ .unwrap();
// get the virtual fs
let (dest_path, virtual_fs) = into_virtual_fs(builder, &temp_dir);
@@ -923,9 +988,15 @@ mod test {
let temp_dir = TempDir::new();
let src_path = temp_dir.path().join("src");
let mut builder = VfsBuilder::new(src_path.clone());
- builder.add_symlink(&src_path.join("a.txt"), &src_path.join("b.txt"));
- builder.add_symlink(&src_path.join("b.txt"), &src_path.join("c.txt"));
- builder.add_symlink(&src_path.join("c.txt"), &src_path.join("a.txt"));
+ builder
+ .add_symlink(&src_path.join("a.txt"), &src_path.join("b.txt"))
+ .unwrap();
+ builder
+ .add_symlink(&src_path.join("b.txt"), &src_path.join("c.txt"))
+ .unwrap();
+ builder
+ .add_symlink(&src_path.join("c.txt"), &src_path.join("a.txt"))
+ .unwrap();
let (dest_path, virtual_fs) = into_virtual_fs(builder, &temp_dir);
assert_eq!(
virtual_fs
@@ -950,10 +1021,12 @@ mod test {
let temp_dir = TempDir::new();
let temp_path = temp_dir.path();
let mut builder = VfsBuilder::new(temp_path.to_path_buf());
- builder.add_file(
- &temp_path.join("a.txt"),
- "0123456789".to_string().into_bytes(),
- );
+ builder
+ .add_file(
+ &temp_path.join("a.txt"),
+ "0123456789".to_string().into_bytes(),
+ )
+ .unwrap();
let (dest_path, virtual_fs) = into_virtual_fs(builder, &temp_dir);
let virtual_fs = Arc::new(virtual_fs);
let file = virtual_fs.open_file(&dest_path.join("a.txt")).unwrap();