Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 20ff465

Browse files
committed
dirfd: initial quick and dirty implementation for unix
1 parent c6c1796 commit 20ff465

File tree

3 files changed

+180
-78
lines changed

3 files changed

+180
-78
lines changed

‎library/std/src/fs.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,13 @@ pub struct File {
116116
inner: fs_imp::File,
117117
}
118118

119+
#[unstable(feature = "dirfd", issue = "120426")]
120+
#[cfg(target_family = "unix")]
121+
/// An object providing access to a directory on the filesystem.
122+
pub struct Dir {
123+
inner: fs_imp::Dir,
124+
}
125+
119126
/// Metadata information about a file.
120127
///
121128
/// This structure is returned from the [`metadata`] or
@@ -1353,6 +1360,25 @@ impl Seek for Arc<File> {
13531360
}
13541361
}
13551362

1363+
#[unstable(feature = "dirfd", issue = "120426")]
1364+
impl Dir {
1365+
/// Opens a file relative to this directory.
1366+
pub fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
1367+
self.inner.open(path).map(|f| File { inner: f })
1368+
}
1369+
/// Opens a file relative to this directory with the specified options.
1370+
pub fn open_with<P: AsRef<Path>>(&self, path: P, opts: &OpenOptions) -> io::Result<File> {
1371+
self.inner.open_with(path, &opts.0).map(|f| File { inner: f })
1372+
}
1373+
}
1374+
1375+
#[unstable(feature = "dirfd", issue = "120426")]
1376+
impl fmt::Debug for Dir {
1377+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1378+
self.inner.fmt(f)
1379+
}
1380+
}
1381+
13561382
impl OpenOptions {
13571383
/// Creates a blank new set of options ready for configuration.
13581384
///

‎library/std/src/sys/fs/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ pub fn with_native_path<T>(path: &Path, f: &dyn Fn(&Path) -> io::Result<T>) -> i
4545
f(path)
4646
}
4747

48+
#[cfg(target_family = "unix")]
49+
pub use imp::Dir;
4850
pub use imp::{
4951
DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions,
5052
ReadDir,

‎library/std/src/sys/fs/unix.rs

Lines changed: 152 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ use libc::{c_int, mode_t};
5353
#[cfg(target_os = "android")]
5454
use libc::{
5555
dirent as dirent64, fstat as fstat64, fstatat as fstatat64, ftruncate64, lseek64,
56-
lstat as lstat64, off64_t, open as open64, stat as stat64,
56+
lstat as lstat64, off64_t, open as open64, openat as openat64,stat as stat64,
5757
};
5858
#[cfg(not(any(
5959
all(target_os = "linux", not(target_env = "musl")),
@@ -63,14 +63,14 @@ use libc::{
6363
)))]
6464
use libc::{
6565
dirent as dirent64, fstat as fstat64, ftruncate as ftruncate64, lseek as lseek64,
66-
lstat as lstat64, off_t as off64_t, open as open64, stat as stat64,
66+
lstat as lstat64, off_t as off64_t, open as open64, openat as openat64,stat as stat64,
6767
};
6868
#[cfg(any(
6969
all(target_os = "linux", not(target_env = "musl")),
7070
target_os = "l4re",
7171
target_os = "hurd"
7272
))]
73-
use libc::{dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, stat64};
73+
use libc::{dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, openat64,stat64};
7474

7575
use crate::ffi::{CStr, OsStr, OsString};
7676
use crate::fmt::{self, Write as _};
@@ -262,7 +262,154 @@ impl ReadDir {
262262
}
263263
}
264264

265-
struct Dir(*mut libc::DIR);
265+
pub struct Dir(*mut libc::DIR);
266+
267+
// dirfd isn't supported everywhere
268+
#[cfg(not(any(
269+
miri,
270+
target_os = "redox",
271+
target_os = "nto",
272+
target_os = "vita",
273+
target_os = "hurd",
274+
target_os = "espidf",
275+
target_os = "horizon",
276+
target_os = "vxworks",
277+
target_os = "rtems",
278+
target_os = "nuttx",
279+
)))]
280+
impl Dir {
281+
pub fn open<P: AsRef<Path>>(&self, path: P) -> io::Result<File> {
282+
let mut opts = OpenOptions::new();
283+
opts.read(true);
284+
run_path_with_cstr(path.as_ref(), &|path| self.open_c(path, &opts))
285+
}
286+
287+
pub fn open_with<P: AsRef<Path>>(&self, path: P, opts: &OpenOptions) -> io::Result<File> {
288+
run_path_with_cstr(path.as_ref(), &|path| self.open_c(path, opts))
289+
}
290+
291+
pub fn open_c(&self, path: &CStr, opts: &OpenOptions) -> io::Result<File> {
292+
let flags = libc::O_CLOEXEC
293+
| opts.get_access_mode()?
294+
| opts.get_creation_mode()?
295+
| (opts.custom_flags as c_int & !libc::O_ACCMODE);
296+
let fd = cvt_r(|| unsafe {
297+
openat64(libc::dirfd(self.0), path.as_ptr(), flags, opts.mode as c_int)
298+
})?;
299+
Ok(File(unsafe { FileDesc::from_raw_fd(fd) }))
300+
}
301+
302+
// pub fn create_dir<P: AsRef<Path>>(&self, path: P) -> Result<()>
303+
// pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(&self, from: P, to_dir: &Self, to: Q) -> Result<()>
304+
// pub fn remove_file<P: AsRef<Path>>(&self, path: P) -> Result<()>
305+
// pub fn remove_dir<P: AsRef<Path>>(&self, path: P) -> Result<()>
306+
// pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(&self, original: P, link: Q)
307+
}
308+
309+
fn get_path_from_fd(fd: c_int) -> Option<PathBuf> {
310+
#[cfg(any(target_os = "linux", target_os = "illumos", target_os = "solaris"))]
311+
fn get_path(fd: c_int) -> Option<PathBuf> {
312+
let mut p = PathBuf::from("/proc/self/fd");
313+
p.push(&fd.to_string());
314+
run_path_with_cstr(&p, &readlink).ok()
315+
}
316+
317+
#[cfg(any(target_vendor = "apple", target_os = "netbsd"))]
318+
fn get_path(fd: c_int) -> Option<PathBuf> {
319+
// FIXME: The use of PATH_MAX is generally not encouraged, but it
320+
// is inevitable in this case because Apple targets and NetBSD define `fcntl`
321+
// with `F_GETPATH` in terms of `MAXPATHLEN`, and there are no
322+
// alternatives. If a better method is invented, it should be used
323+
// instead.
324+
let mut buf = vec![0; libc::PATH_MAX as usize];
325+
let n = unsafe { libc::fcntl(fd, libc::F_GETPATH, buf.as_ptr()) };
326+
if n == -1 {
327+
cfg_if::cfg_if! {
328+
if #[cfg(target_os = "netbsd")] {
329+
// fallback to procfs as last resort
330+
let mut p = PathBuf::from("/proc/self/fd");
331+
p.push(&fd.to_string());
332+
return run_path_with_cstr(&p, &readlink).ok()
333+
} else {
334+
return None;
335+
}
336+
}
337+
}
338+
let l = buf.iter().position(|&c| c == 0).unwrap();
339+
buf.truncate(l as usize);
340+
buf.shrink_to_fit();
341+
Some(PathBuf::from(OsString::from_vec(buf)))
342+
}
343+
344+
#[cfg(target_os = "freebsd")]
345+
fn get_path(fd: c_int) -> Option<PathBuf> {
346+
let info = Box::<libc::kinfo_file>::new_zeroed();
347+
let mut info = unsafe { info.assume_init() };
348+
info.kf_structsize = size_of::<libc::kinfo_file>() as libc::c_int;
349+
let n = unsafe { libc::fcntl(fd, libc::F_KINFO, &mut *info) };
350+
if n == -1 {
351+
return None;
352+
}
353+
let buf = unsafe { CStr::from_ptr(info.kf_path.as_mut_ptr()).to_bytes().to_vec() };
354+
Some(PathBuf::from(OsString::from_vec(buf)))
355+
}
356+
357+
#[cfg(target_os = "vxworks")]
358+
fn get_path(fd: c_int) -> Option<PathBuf> {
359+
let mut buf = vec![0; libc::PATH_MAX as usize];
360+
let n = unsafe { libc::ioctl(fd, libc::FIOGETNAME, buf.as_ptr()) };
361+
if n == -1 {
362+
return None;
363+
}
364+
let l = buf.iter().position(|&c| c == 0).unwrap();
365+
buf.truncate(l as usize);
366+
Some(PathBuf::from(OsString::from_vec(buf)))
367+
}
368+
369+
#[cfg(not(any(
370+
target_os = "linux",
371+
target_os = "vxworks",
372+
target_os = "freebsd",
373+
target_os = "netbsd",
374+
target_os = "illumos",
375+
target_os = "solaris",
376+
target_vendor = "apple",
377+
)))]
378+
fn get_path(_fd: c_int) -> Option<PathBuf> {
379+
// FIXME(#24570): implement this for other Unix platforms
380+
None
381+
}
382+
383+
get_path(fd)
384+
}
385+
386+
impl fmt::Debug for Dir {
387+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
388+
fn get_mode(fd: c_int) -> Option<(bool, bool)> {
389+
let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) };
390+
if mode == -1 {
391+
return None;
392+
}
393+
match mode & libc::O_ACCMODE {
394+
libc::O_RDONLY => Some((true, false)),
395+
libc::O_RDWR => Some((true, true)),
396+
libc::O_WRONLY => Some((false, true)),
397+
_ => None,
398+
}
399+
}
400+
401+
let fd = unsafe { dirfd(self.0) };
402+
let mut b = f.debug_struct("Dir");
403+
b.field("fd", &fd);
404+
if let Some(path) = get_path_from_fd(fd) {
405+
b.field("path", &path);
406+
}
407+
if let Some((read, write)) = get_mode(fd) {
408+
b.field("read", &read).field("write", &write);
409+
}
410+
b.finish()
411+
}
412+
}
266413

267414
unsafe impl Send for Dir {}
268415
unsafe impl Sync for Dir {}
@@ -1653,79 +1800,6 @@ impl FromRawFd for File {
16531800

16541801
impl fmt::Debug for File {
16551802
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1656-
#[cfg(any(target_os = "linux", target_os = "illumos", target_os = "solaris"))]
1657-
fn get_path(fd: c_int) -> Option<PathBuf> {
1658-
let mut p = PathBuf::from("/proc/self/fd");
1659-
p.push(&fd.to_string());
1660-
run_path_with_cstr(&p, &readlink).ok()
1661-
}
1662-
1663-
#[cfg(any(target_vendor = "apple", target_os = "netbsd"))]
1664-
fn get_path(fd: c_int) -> Option<PathBuf> {
1665-
// FIXME: The use of PATH_MAX is generally not encouraged, but it
1666-
// is inevitable in this case because Apple targets and NetBSD define `fcntl`
1667-
// with `F_GETPATH` in terms of `MAXPATHLEN`, and there are no
1668-
// alternatives. If a better method is invented, it should be used
1669-
// instead.
1670-
let mut buf = vec![0; libc::PATH_MAX as usize];
1671-
let n = unsafe { libc::fcntl(fd, libc::F_GETPATH, buf.as_ptr()) };
1672-
if n == -1 {
1673-
cfg_if::cfg_if! {
1674-
if #[cfg(target_os = "netbsd")] {
1675-
// fallback to procfs as last resort
1676-
let mut p = PathBuf::from("/proc/self/fd");
1677-
p.push(&fd.to_string());
1678-
return run_path_with_cstr(&p, &readlink).ok()
1679-
} else {
1680-
return None;
1681-
}
1682-
}
1683-
}
1684-
let l = buf.iter().position(|&c| c == 0).unwrap();
1685-
buf.truncate(l as usize);
1686-
buf.shrink_to_fit();
1687-
Some(PathBuf::from(OsString::from_vec(buf)))
1688-
}
1689-
1690-
#[cfg(target_os = "freebsd")]
1691-
fn get_path(fd: c_int) -> Option<PathBuf> {
1692-
let info = Box::<libc::kinfo_file>::new_zeroed();
1693-
let mut info = unsafe { info.assume_init() };
1694-
info.kf_structsize = size_of::<libc::kinfo_file>() as libc::c_int;
1695-
let n = unsafe { libc::fcntl(fd, libc::F_KINFO, &mut *info) };
1696-
if n == -1 {
1697-
return None;
1698-
}
1699-
let buf = unsafe { CStr::from_ptr(info.kf_path.as_mut_ptr()).to_bytes().to_vec() };
1700-
Some(PathBuf::from(OsString::from_vec(buf)))
1701-
}
1702-
1703-
#[cfg(target_os = "vxworks")]
1704-
fn get_path(fd: c_int) -> Option<PathBuf> {
1705-
let mut buf = vec![0; libc::PATH_MAX as usize];
1706-
let n = unsafe { libc::ioctl(fd, libc::FIOGETNAME, buf.as_ptr()) };
1707-
if n == -1 {
1708-
return None;
1709-
}
1710-
let l = buf.iter().position(|&c| c == 0).unwrap();
1711-
buf.truncate(l as usize);
1712-
Some(PathBuf::from(OsString::from_vec(buf)))
1713-
}
1714-
1715-
#[cfg(not(any(
1716-
target_os = "linux",
1717-
target_os = "vxworks",
1718-
target_os = "freebsd",
1719-
target_os = "netbsd",
1720-
target_os = "illumos",
1721-
target_os = "solaris",
1722-
target_vendor = "apple",
1723-
)))]
1724-
fn get_path(_fd: c_int) -> Option<PathBuf> {
1725-
// FIXME(#24570): implement this for other Unix platforms
1726-
None
1727-
}
1728-
17291803
fn get_mode(fd: c_int) -> Option<(bool, bool)> {
17301804
let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) };
17311805
if mode == -1 {
@@ -1742,7 +1816,7 @@ impl fmt::Debug for File {
17421816
let fd = self.as_raw_fd();
17431817
let mut b = f.debug_struct("File");
17441818
b.field("fd", &fd);
1745-
if let Some(path) = get_path(fd) {
1819+
if let Some(path) = get_path_from_fd(fd) {
17461820
b.field("path", &path);
17471821
}
17481822
if let Some((read, write)) = get_mode(fd) {

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /