mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2024-11-28 17:44:10 +00:00
ext2: Support longer symlinks
Symbolic links that are longer than or equal to 60 bytes require a block allocated to store its destination because it won't fit in Inode's i_block. BUG=b:342937495 TEST=cargo test Change-Id: Iadab10887c136019fe85e74fa981542384f48ad2 Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/5569438 Reviewed-by: Junichi Uekawa <uekawa@chromium.org> Commit-Queue: Keiichi Watanabe <keiichiw@chromium.org>
This commit is contained in:
parent
ac825c410a
commit
c8bb0b0be5
3 changed files with 81 additions and 3 deletions
|
@ -558,8 +558,7 @@ impl<'a> Ext2<'a> {
|
|||
.context("failed to convert symlink destination to str")?;
|
||||
|
||||
if dst.len() >= InodeBlock::max_inline_symlink_len() {
|
||||
// TODO(b/342937495): Support symlink longer than or equal to 60 bytes.
|
||||
unimplemented!("long symlink is not supported yet: {:?}", dst);
|
||||
return self.add_long_symlink(arena, parent, &link, dst);
|
||||
}
|
||||
|
||||
let inode_num = self.allocate_inode()?;
|
||||
|
@ -584,6 +583,46 @@ impl<'a> Ext2<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn add_long_symlink(
|
||||
&mut self,
|
||||
arena: &'a Arena<'a>,
|
||||
parent: InodeNum,
|
||||
link: &Path,
|
||||
dst: &str,
|
||||
) -> Result<()> {
|
||||
let dst_len = dst.len();
|
||||
if dst_len > self.block_size() as usize {
|
||||
bail!("symlink longer than block size: {:?}", dst);
|
||||
}
|
||||
|
||||
// Copy symlink's destination to the block.
|
||||
let symlink_block = self.allocate_block()?;
|
||||
let buf = arena.allocate_slice(symlink_block, 0, dst_len)?;
|
||||
buf.copy_from_slice(dst.as_bytes());
|
||||
|
||||
let inode_num = self.allocate_inode()?;
|
||||
let mut block = InodeBlock::default();
|
||||
block.set_direct_blocks(&[symlink_block])?;
|
||||
|
||||
let block_size = self.block_size() as u32;
|
||||
let inode = Inode::from_metadata(
|
||||
arena,
|
||||
&mut self.group_metadata,
|
||||
inode_num,
|
||||
&std::fs::symlink_metadata(link)?,
|
||||
dst_len as u32,
|
||||
1, //links_count,
|
||||
InodeBlocksCount::from_bytes_len(block_size),
|
||||
block,
|
||||
)?;
|
||||
self.add_inode(inode_num, inode)?;
|
||||
|
||||
let link_name = link.file_name().context("failed to get symlink name")?;
|
||||
self.allocate_dir_entry(arena, parent, inode_num, InodeType::Symlink, link_name)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Walks through `src_dir` and copies directories and files to the new file system.
|
||||
fn copy_dirtree<P: AsRef<Path>>(&mut self, arena: &'a Arena<'a>, src_dir: P) -> Result<()> {
|
||||
self.copy_dirtree_rec(arena, InodeNum(2), src_dir)
|
||||
|
|
|
@ -152,7 +152,6 @@ impl InodeBlock {
|
|||
Self::max_inline_symlink_len()
|
||||
);
|
||||
}
|
||||
|
||||
self.0[..bytes.len()].copy_from_slice(bytes);
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -426,3 +426,43 @@ fn test_mkfs_symlink_to_deleted() {
|
|||
|
||||
assert_eq_dirs(&td, &dir, &disk);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mkfs_long_symlink() {
|
||||
// testdata
|
||||
// ├── /(long name directory)/a.txt
|
||||
// └── symlink -> /(long name directory)/a.txt
|
||||
// ├── (60-byte filename)
|
||||
// └── symlink60 -> (60-byte filename)
|
||||
|
||||
let td = tempdir().unwrap();
|
||||
let dir = td.path().join("testdata");
|
||||
|
||||
create_dir(&dir).unwrap();
|
||||
|
||||
const LONG_DIR_NAME: &str =
|
||||
"this_is_a_very_long_directory_name_so_that_name_cannoot_fit_in_60_characters_in_inode";
|
||||
assert!(LONG_DIR_NAME.len() > 60);
|
||||
|
||||
let long_dir = dir.join(LONG_DIR_NAME);
|
||||
create_dir(&long_dir).unwrap();
|
||||
File::create(long_dir.join("a.txt")).unwrap();
|
||||
symlink(long_dir.join("a.txt"), dir.join("symlink")).unwrap();
|
||||
|
||||
const SIXTY_CHAR_DIR_NAME: &str =
|
||||
"./this_is_just_60_byte_long_so_it_can_work_as_a_corner_case.";
|
||||
assert_eq!(SIXTY_CHAR_DIR_NAME.len(), 60);
|
||||
File::create(dir.join(SIXTY_CHAR_DIR_NAME)).unwrap();
|
||||
symlink(SIXTY_CHAR_DIR_NAME, dir.join("symlink60")).unwrap();
|
||||
|
||||
let disk = mkfs(
|
||||
&td,
|
||||
&Config {
|
||||
blocks_per_group: 2048,
|
||||
inodes_per_group: 4096,
|
||||
},
|
||||
Some(&dir),
|
||||
);
|
||||
|
||||
assert_eq_dirs(&td, &dir, &disk);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue