diff --git a/native/src/base/files.rs b/native/src/base/files.rs index a24ca6110..25f29e3d0 100644 --- a/native/src/base/files.rs +++ b/native/src/base/files.rs @@ -4,16 +4,14 @@ use std::ffi::CStr; use std::fs::File; use std::io::{BufRead, BufReader, Read, Seek, SeekFrom, Write}; use std::ops::Deref; -use std::os::android::fs::MetadataExt; use std::os::fd::{AsFd, BorrowedFd, IntoRawFd}; -use std::os::unix::fs::FileTypeExt; use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd, RawFd}; use std::{io, mem, ptr, slice}; use bytemuck::{bytes_of_mut, Pod}; use libc::{ c_uint, dirent, makedev, mode_t, EEXIST, ENOENT, F_OK, O_CLOEXEC, O_CREAT, O_PATH, O_RDONLY, - O_RDWR, O_TRUNC, O_WRONLY, S_IFDIR, S_IFLNK, S_IFREG, + O_RDWR, O_TRUNC, O_WRONLY, }; use num_traits::AsPrimitive; @@ -151,6 +149,40 @@ impl FileAttr { con: Utf8CStrBufArr::new(), } } + + #[inline(always)] + #[allow(clippy::unnecessary_cast)] + fn is(&self, mode: mode_t) -> bool { + (self.st.st_mode & libc::S_IFMT as u32) as mode_t == mode + } + + pub fn is_dir(&self) -> bool { + self.is(libc::S_IFDIR) + } + + pub fn is_file(&self) -> bool { + self.is(libc::S_IFREG) + } + + pub fn is_symlink(&self) -> bool { + self.is(libc::S_IFLNK) + } + + pub fn is_block_device(&self) -> bool { + self.is(libc::S_IFBLK) + } + + pub fn is_char_device(&self) -> bool { + self.is(libc::S_IFCHR) + } + + pub fn is_fifo(&self) -> bool { + self.is(libc::S_IFIFO) + } + + pub fn is_socket(&self) -> bool { + self.is(libc::S_IFSOCK) + } } #[cfg(feature = "selinux")] @@ -187,10 +219,26 @@ impl DirEntry<'_> { self.d_type == libc::DT_REG } - pub fn is_lnk(&self) -> bool { + pub fn is_symlink(&self) -> bool { self.d_type == libc::DT_LNK } + pub fn is_block_device(&self) -> bool { + self.d_type == libc::DT_BLK + } + + pub fn is_char_device(&self) -> bool { + self.d_type == libc::DT_CHR + } + + pub fn is_fifo(&self) -> bool { + self.d_type == libc::DT_FIFO + } + + pub fn is_socket(&self) -> bool { + self.d_type == libc::DT_SOCK + } + pub fn unlink(&self) -> io::Result<()> { let flag = if self.is_dir() { libc::AT_REMOVEDIR } else { 0 }; unsafe { @@ -372,7 +420,7 @@ impl Directory { }; std::io::copy(&mut src, &mut dest)?; fd_set_attr(dest.as_raw_fd(), &attr)?; - } else if e.is_lnk() { + } else if e.is_symlink() { let mut path = Utf8CStrBufArr::default(); e.read_link(&mut path)?; unsafe { @@ -550,10 +598,9 @@ impl FsPath { } pub fn remove_all(&self) -> io::Result<()> { - let f = self.open(O_RDONLY | O_CLOEXEC)?; - let st = f.metadata()?; - if st.is_dir() { - let mut dir = Directory::try_from(OwnedFd::from(f))?; + let attr = self.get_attr()?; + if attr.is_dir() { + let mut dir = Directory::try_from(open_fd!(self, O_RDONLY | O_CLOEXEC)?)?; dir.remove_all()?; } self.remove() @@ -652,7 +699,7 @@ impl FsPath { pub fn set_attr(&self, attr: &FileAttr) -> io::Result<()> { unsafe { - if (attr.st.st_mode & libc::S_IFMT as c_uint) != S_IFLNK.as_() { + if !attr.is_symlink() { libc::chmod(self.as_ptr(), (attr.st.st_mode & 0o777).as_()).as_os_err()?; } libc::lchown(self.as_ptr(), attr.st.st_uid, attr.st.st_gid).as_os_err()?; @@ -674,7 +721,7 @@ impl FsPath { pub fn copy_to(&self, path: &FsPath) -> io::Result<()> { let attr = self.get_attr()?; - if (attr.st.st_mode & libc::S_IFMT as c_uint) == S_IFDIR.as_() { + if attr.is_dir() { path.mkdir(0o777)?; let mut src = Directory::open(self)?; let dest = Directory::open(path)?; @@ -682,11 +729,11 @@ impl FsPath { } else { // It's OK if remove failed path.remove().ok(); - if (attr.st.st_mode & libc::S_IFMT as c_uint) == S_IFREG.as_() { + if attr.is_file() { let mut src = self.open(O_RDONLY | O_CLOEXEC)?; let mut dest = path.create(O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0o777)?; std::io::copy(&mut src, &mut dest)?; - } else if (attr.st.st_mode & libc::S_IFMT as c_uint) == S_IFLNK.as_() { + } else if attr.is_symlink() { let mut buf = Utf8CStrBufArr::default(); self.read_link(&mut buf)?; unsafe { @@ -701,7 +748,7 @@ impl FsPath { pub fn move_to(&self, path: &FsPath) -> io::Result<()> { if path.exists() { let attr = path.get_attr()?; - if (attr.st.st_mode & libc::S_IFMT as c_uint) == S_IFDIR.as_() { + if attr.is_dir() { let mut src = Directory::open(self)?; let dest = Directory::open(path)?; return src.move_into(&dest); @@ -714,7 +761,7 @@ impl FsPath { pub fn link_to(&self, path: &FsPath) -> io::Result<()> { let attr = self.get_attr()?; - if (attr.st.st_mode & libc::S_IFMT as c_uint) == S_IFDIR.as_() { + if attr.is_dir() { path.mkdir(0o777)?; path.set_attr(&attr)?; let mut src = Directory::open(self)?; @@ -828,13 +875,13 @@ pub(crate) fn map_file(path: &Utf8CStr, rw: bool) -> io::Result<&'static mut [u8 let flag = if rw { O_RDWR } else { O_RDONLY }; let f = File::from(open_fd!(path, flag | O_CLOEXEC)?); - let st = f.metadata()?; - let sz = if st.file_type().is_block_device() { + let attr = FsPath::from(path).get_attr()?; + let sz = if attr.is_block_device() { let mut sz = 0_u64; unsafe { ioctl(f.as_raw_fd(), BLKGETSIZE64, &mut sz) }.as_os_err()?; sz } else { - st.st_size() + attr.st.st_size as u64 }; map_fd(f.as_fd(), sz as usize, rw) diff --git a/native/src/boot/cpio.rs b/native/src/boot/cpio.rs index b613d9c12..d622e76b9 100644 --- a/native/src/boot/cpio.rs +++ b/native/src/boot/cpio.rs @@ -2,10 +2,10 @@ use std::collections::BTreeMap; use std::fmt::{Display, Formatter}; -use std::fs::{metadata, read, DirBuilder, File}; -use std::io::Write; +use std::fs::{DirBuilder, File}; +use std::io::{Read, Write}; use std::mem::size_of; -use std::os::unix::fs::{symlink, DirBuilderExt, FileTypeExt, MetadataExt}; +use std::os::unix::fs::{symlink, DirBuilderExt}; use std::path::Path; use std::process::exit; use std::str; @@ -15,16 +15,17 @@ use bytemuck::{from_bytes, Pod, Zeroable}; use num_traits::cast::AsPrimitive; use size::{Base, Size, Style}; -use crate::ffi::{unxz, xz}; use base::libc::{ - c_char, dev_t, gid_t, major, makedev, minor, mknod, mode_t, uid_t, S_IFBLK, S_IFCHR, S_IFDIR, - S_IFLNK, S_IFMT, S_IFREG, S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR, S_IXGRP, - S_IXOTH, S_IXUSR, + c_char, dev_t, gid_t, major, makedev, minor, mknod, mode_t, uid_t, O_CLOEXEC, O_RDONLY, + S_IFBLK, S_IFCHR, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG, S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, + S_IWOTH, S_IWUSR, S_IXGRP, S_IXOTH, S_IXUSR, }; use base::{ - log_err, map_args, EarlyExitExt, LoggedResult, MappedFile, ResultExt, Utf8CStr, WriteExt, + log_err, map_args, EarlyExitExt, FsPath, LoggedResult, MappedFile, ResultExt, Utf8CStr, + WriteExt, }; +use crate::ffi::{unxz, xz}; use crate::ramdisk::MagiskCpio; #[derive(FromArgs)] @@ -397,28 +398,35 @@ impl Cpio { self.entries.contains_key(&norm_path(path)) } - fn add(&mut self, mode: &mode_t, path: &str, file: &str) -> LoggedResult<()> { + fn add(&mut self, mode: mode_t, path: &str, file: &mut String) -> LoggedResult<()> { if path.ends_with('/') { return Err(log_err!("path cannot end with / for add")); } - let file = Path::new(file); - let content = read(file)?; - let metadata = metadata(file)?; - let mut rdevmajor: dev_t = 0; - let mut rdevminor: dev_t = 0; - let mode = if metadata.file_type().is_file() { + let file = Utf8CStr::from_string(file); + let file = FsPath::from(&file); + let attr = file.get_attr()?; + + let mut content = Vec::::new(); + let rdevmajor: dev_t; + let rdevminor: dev_t; + + let mode = if attr.is_file() { + rdevmajor = 0; + rdevminor = 0; + file.open(O_RDONLY | O_CLOEXEC)?.read_to_end(&mut content)?; mode | S_IFREG } else { - rdevmajor = unsafe { major(metadata.rdev().try_into()?).try_into()? }; - rdevminor = unsafe { minor(metadata.rdev().try_into()?).try_into()? }; - if metadata.file_type().is_block_device() { + rdevmajor = unsafe { major(attr.st.st_rdev.as_()) }.as_(); + rdevminor = unsafe { minor(attr.st.st_rdev.as_()) }.as_(); + if attr.is_block_device() { mode | S_IFBLK - } else if metadata.file_type().is_char_device() { + } else if attr.is_char_device() { mode | S_IFCHR } else { return Err(log_err!("unsupported file type")); } }; + self.entries.insert( norm_path(path), Box::new(CpioEntry { @@ -611,7 +619,7 @@ pub fn cpio_commands(argc: i32, argv: *const *const c_char) -> bool { CpioSubCommand::Move(Move { from, to }) => cpio.mv(from, to)?, CpioSubCommand::MakeDir(MakeDir { mode, dir }) => cpio.mkdir(mode, dir), CpioSubCommand::Link(Link { src, dst }) => cpio.ln(src, dst), - CpioSubCommand::Add(Add { mode, path, file }) => cpio.add(mode, path, file)?, + CpioSubCommand::Add(Add { mode, path, file }) => cpio.add(*mode, path, file)?, CpioSubCommand::Extract(Extract { paths }) => { if !paths.is_empty() && paths.len() != 2 { return Err(log_err!("invalid arguments"));