mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-15 13:36:49 +00:00
Merge 20ff46587d
into 65fa0ab924
This commit is contained in:
commit
fce9941cc5
@ -116,6 +116,13 @@ pub struct File {
|
||||
inner: fs_imp::File,
|
||||
}
|
||||
|
||||
#[unstable(feature = "dirfd", issue = "120426")]
|
||||
#[cfg(target_family = "unix")]
|
||||
/// An object providing access to a directory on the filesystem.
|
||||
pub struct Dir {
|
||||
inner: fs_imp::Dir,
|
||||
}
|
||||
|
||||
/// Metadata information about a file.
|
||||
///
|
||||
/// This structure is returned from the [`metadata`] or
|
||||
@ -1353,6 +1360,25 @@ impl Seek for Arc<File> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "dirfd", issue = "120426")]
|
||||
impl Dir {
|
||||
/// Opens a file relative to this directory.
|
||||
pub fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
|
||||
self.inner.open(path).map(|f| File { inner: f })
|
||||
}
|
||||
/// Opens a file relative to this directory with the specified options.
|
||||
pub fn open_with<P: AsRef<Path>>(&self, path: P, opts: &OpenOptions) -> io::Result<File> {
|
||||
self.inner.open_with(path, &opts.0).map(|f| File { inner: f })
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "dirfd", issue = "120426")]
|
||||
impl fmt::Debug for Dir {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.inner.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl OpenOptions {
|
||||
/// Creates a blank new set of options ready for configuration.
|
||||
///
|
||||
|
@ -45,6 +45,8 @@ pub fn with_native_path<T>(path: &Path, f: &dyn Fn(&Path) -> io::Result<T>) -> i
|
||||
f(path)
|
||||
}
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
pub use imp::Dir;
|
||||
pub use imp::{
|
||||
DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions,
|
||||
ReadDir,
|
||||
|
@ -53,7 +53,7 @@ use libc::{c_int, mode_t};
|
||||
#[cfg(target_os = "android")]
|
||||
use libc::{
|
||||
dirent as dirent64, fstat as fstat64, fstatat as fstatat64, ftruncate64, lseek64,
|
||||
lstat as lstat64, off64_t, open as open64, stat as stat64,
|
||||
lstat as lstat64, off64_t, open as open64, openat as openat64, stat as stat64,
|
||||
};
|
||||
#[cfg(not(any(
|
||||
all(target_os = "linux", not(target_env = "musl")),
|
||||
@ -63,14 +63,14 @@ use libc::{
|
||||
)))]
|
||||
use libc::{
|
||||
dirent as dirent64, fstat as fstat64, ftruncate as ftruncate64, lseek as lseek64,
|
||||
lstat as lstat64, off_t as off64_t, open as open64, stat as stat64,
|
||||
lstat as lstat64, off_t as off64_t, open as open64, openat as openat64, stat as stat64,
|
||||
};
|
||||
#[cfg(any(
|
||||
all(target_os = "linux", not(target_env = "musl")),
|
||||
target_os = "l4re",
|
||||
target_os = "hurd"
|
||||
))]
|
||||
use libc::{dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, stat64};
|
||||
use libc::{dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, openat64, stat64};
|
||||
|
||||
use crate::ffi::{CStr, OsStr, OsString};
|
||||
use crate::fmt::{self, Write as _};
|
||||
@ -262,7 +262,154 @@ impl ReadDir {
|
||||
}
|
||||
}
|
||||
|
||||
struct Dir(*mut libc::DIR);
|
||||
pub struct Dir(*mut libc::DIR);
|
||||
|
||||
// dirfd isn't supported everywhere
|
||||
#[cfg(not(any(
|
||||
miri,
|
||||
target_os = "redox",
|
||||
target_os = "nto",
|
||||
target_os = "vita",
|
||||
target_os = "hurd",
|
||||
target_os = "espidf",
|
||||
target_os = "horizon",
|
||||
target_os = "vxworks",
|
||||
target_os = "rtems",
|
||||
target_os = "nuttx",
|
||||
)))]
|
||||
impl Dir {
|
||||
pub fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
|
||||
let mut opts = OpenOptions::new();
|
||||
opts.read(true);
|
||||
run_path_with_cstr(path.as_ref(), &|path| self.open_c(path, &opts))
|
||||
}
|
||||
|
||||
pub fn open_with<P: AsRef<Path>>(&self, path: P, opts: &OpenOptions) -> io::Result<File> {
|
||||
run_path_with_cstr(path.as_ref(), &|path| self.open_c(path, opts))
|
||||
}
|
||||
|
||||
pub fn open_c(&self, path: &CStr, opts: &OpenOptions) -> io::Result<File> {
|
||||
let flags = libc::O_CLOEXEC
|
||||
| opts.get_access_mode()?
|
||||
| opts.get_creation_mode()?
|
||||
| (opts.custom_flags as c_int & !libc::O_ACCMODE);
|
||||
let fd = cvt_r(|| unsafe {
|
||||
openat64(libc::dirfd(self.0), path.as_ptr(), flags, opts.mode as c_int)
|
||||
})?;
|
||||
Ok(File(unsafe { FileDesc::from_raw_fd(fd) }))
|
||||
}
|
||||
|
||||
// pub fn create_dir<P: AsRef<Path>>(&self, path: P) -> Result<()>
|
||||
// pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(&self, from: P, to_dir: &Self, to: Q) -> Result<()>
|
||||
// pub fn remove_file<P: AsRef<Path>>(&self, path: P) -> Result<()>
|
||||
// pub fn remove_dir<P: AsRef<Path>>(&self, path: P) -> Result<()>
|
||||
// pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(&self, original: P, link: Q)
|
||||
}
|
||||
|
||||
fn get_path_from_fd(fd: c_int) -> Option<PathBuf> {
|
||||
#[cfg(any(target_os = "linux", target_os = "illumos", target_os = "solaris"))]
|
||||
fn get_path(fd: c_int) -> Option<PathBuf> {
|
||||
let mut p = PathBuf::from("/proc/self/fd");
|
||||
p.push(&fd.to_string());
|
||||
run_path_with_cstr(&p, &readlink).ok()
|
||||
}
|
||||
|
||||
#[cfg(any(target_vendor = "apple", target_os = "netbsd"))]
|
||||
fn get_path(fd: c_int) -> Option<PathBuf> {
|
||||
// FIXME: The use of PATH_MAX is generally not encouraged, but it
|
||||
// is inevitable in this case because Apple targets and NetBSD define `fcntl`
|
||||
// with `F_GETPATH` in terms of `MAXPATHLEN`, and there are no
|
||||
// alternatives. If a better method is invented, it should be used
|
||||
// instead.
|
||||
let mut buf = vec![0; libc::PATH_MAX as usize];
|
||||
let n = unsafe { libc::fcntl(fd, libc::F_GETPATH, buf.as_ptr()) };
|
||||
if n == -1 {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_os = "netbsd")] {
|
||||
// fallback to procfs as last resort
|
||||
let mut p = PathBuf::from("/proc/self/fd");
|
||||
p.push(&fd.to_string());
|
||||
return run_path_with_cstr(&p, &readlink).ok()
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
let l = buf.iter().position(|&c| c == 0).unwrap();
|
||||
buf.truncate(l as usize);
|
||||
buf.shrink_to_fit();
|
||||
Some(PathBuf::from(OsString::from_vec(buf)))
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn get_path(fd: c_int) -> Option<PathBuf> {
|
||||
let info = Box::<libc::kinfo_file>::new_zeroed();
|
||||
let mut info = unsafe { info.assume_init() };
|
||||
info.kf_structsize = size_of::<libc::kinfo_file>() as libc::c_int;
|
||||
let n = unsafe { libc::fcntl(fd, libc::F_KINFO, &mut *info) };
|
||||
if n == -1 {
|
||||
return None;
|
||||
}
|
||||
let buf = unsafe { CStr::from_ptr(info.kf_path.as_mut_ptr()).to_bytes().to_vec() };
|
||||
Some(PathBuf::from(OsString::from_vec(buf)))
|
||||
}
|
||||
|
||||
#[cfg(target_os = "vxworks")]
|
||||
fn get_path(fd: c_int) -> Option<PathBuf> {
|
||||
let mut buf = vec![0; libc::PATH_MAX as usize];
|
||||
let n = unsafe { libc::ioctl(fd, libc::FIOGETNAME, buf.as_ptr()) };
|
||||
if n == -1 {
|
||||
return None;
|
||||
}
|
||||
let l = buf.iter().position(|&c| c == 0).unwrap();
|
||||
buf.truncate(l as usize);
|
||||
Some(PathBuf::from(OsString::from_vec(buf)))
|
||||
}
|
||||
|
||||
#[cfg(not(any(
|
||||
target_os = "linux",
|
||||
target_os = "vxworks",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "illumos",
|
||||
target_os = "solaris",
|
||||
target_vendor = "apple",
|
||||
)))]
|
||||
fn get_path(_fd: c_int) -> Option<PathBuf> {
|
||||
// FIXME(#24570): implement this for other Unix platforms
|
||||
None
|
||||
}
|
||||
|
||||
get_path(fd)
|
||||
}
|
||||
|
||||
impl fmt::Debug for Dir {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fn get_mode(fd: c_int) -> Option<(bool, bool)> {
|
||||
let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) };
|
||||
if mode == -1 {
|
||||
return None;
|
||||
}
|
||||
match mode & libc::O_ACCMODE {
|
||||
libc::O_RDONLY => Some((true, false)),
|
||||
libc::O_RDWR => Some((true, true)),
|
||||
libc::O_WRONLY => Some((false, true)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
let fd = unsafe { dirfd(self.0) };
|
||||
let mut b = f.debug_struct("Dir");
|
||||
b.field("fd", &fd);
|
||||
if let Some(path) = get_path_from_fd(fd) {
|
||||
b.field("path", &path);
|
||||
}
|
||||
if let Some((read, write)) = get_mode(fd) {
|
||||
b.field("read", &read).field("write", &write);
|
||||
}
|
||||
b.finish()
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for Dir {}
|
||||
unsafe impl Sync for Dir {}
|
||||
@ -1653,79 +1800,6 @@ impl FromRawFd for File {
|
||||
|
||||
impl fmt::Debug for File {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
#[cfg(any(target_os = "linux", target_os = "illumos", target_os = "solaris"))]
|
||||
fn get_path(fd: c_int) -> Option<PathBuf> {
|
||||
let mut p = PathBuf::from("/proc/self/fd");
|
||||
p.push(&fd.to_string());
|
||||
run_path_with_cstr(&p, &readlink).ok()
|
||||
}
|
||||
|
||||
#[cfg(any(target_vendor = "apple", target_os = "netbsd"))]
|
||||
fn get_path(fd: c_int) -> Option<PathBuf> {
|
||||
// FIXME: The use of PATH_MAX is generally not encouraged, but it
|
||||
// is inevitable in this case because Apple targets and NetBSD define `fcntl`
|
||||
// with `F_GETPATH` in terms of `MAXPATHLEN`, and there are no
|
||||
// alternatives. If a better method is invented, it should be used
|
||||
// instead.
|
||||
let mut buf = vec![0; libc::PATH_MAX as usize];
|
||||
let n = unsafe { libc::fcntl(fd, libc::F_GETPATH, buf.as_ptr()) };
|
||||
if n == -1 {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_os = "netbsd")] {
|
||||
// fallback to procfs as last resort
|
||||
let mut p = PathBuf::from("/proc/self/fd");
|
||||
p.push(&fd.to_string());
|
||||
return run_path_with_cstr(&p, &readlink).ok()
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
let l = buf.iter().position(|&c| c == 0).unwrap();
|
||||
buf.truncate(l as usize);
|
||||
buf.shrink_to_fit();
|
||||
Some(PathBuf::from(OsString::from_vec(buf)))
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
fn get_path(fd: c_int) -> Option<PathBuf> {
|
||||
let info = Box::<libc::kinfo_file>::new_zeroed();
|
||||
let mut info = unsafe { info.assume_init() };
|
||||
info.kf_structsize = size_of::<libc::kinfo_file>() as libc::c_int;
|
||||
let n = unsafe { libc::fcntl(fd, libc::F_KINFO, &mut *info) };
|
||||
if n == -1 {
|
||||
return None;
|
||||
}
|
||||
let buf = unsafe { CStr::from_ptr(info.kf_path.as_mut_ptr()).to_bytes().to_vec() };
|
||||
Some(PathBuf::from(OsString::from_vec(buf)))
|
||||
}
|
||||
|
||||
#[cfg(target_os = "vxworks")]
|
||||
fn get_path(fd: c_int) -> Option<PathBuf> {
|
||||
let mut buf = vec![0; libc::PATH_MAX as usize];
|
||||
let n = unsafe { libc::ioctl(fd, libc::FIOGETNAME, buf.as_ptr()) };
|
||||
if n == -1 {
|
||||
return None;
|
||||
}
|
||||
let l = buf.iter().position(|&c| c == 0).unwrap();
|
||||
buf.truncate(l as usize);
|
||||
Some(PathBuf::from(OsString::from_vec(buf)))
|
||||
}
|
||||
|
||||
#[cfg(not(any(
|
||||
target_os = "linux",
|
||||
target_os = "vxworks",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd",
|
||||
target_os = "illumos",
|
||||
target_os = "solaris",
|
||||
target_vendor = "apple",
|
||||
)))]
|
||||
fn get_path(_fd: c_int) -> Option<PathBuf> {
|
||||
// FIXME(#24570): implement this for other Unix platforms
|
||||
None
|
||||
}
|
||||
|
||||
fn get_mode(fd: c_int) -> Option<(bool, bool)> {
|
||||
let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) };
|
||||
if mode == -1 {
|
||||
@ -1742,7 +1816,7 @@ impl fmt::Debug for File {
|
||||
let fd = self.as_raw_fd();
|
||||
let mut b = f.debug_struct("File");
|
||||
b.field("fd", &fd);
|
||||
if let Some(path) = get_path(fd) {
|
||||
if let Some(path) = get_path_from_fd(fd) {
|
||||
b.field("path", &path);
|
||||
}
|
||||
if let Some((read, write)) = get_mode(fd) {
|
||||
|
Loading…
Reference in New Issue
Block a user