Struct cap_primitives::fs::Metadata
source · pub struct Metadata { /* private fields */ }
Expand description
Metadata information about a file.
This corresponds to std::fs::Metadata
.
Implementations§
source§impl Metadata
impl Metadata
sourcepub fn from_file(file: &File) -> Result<Self>
pub fn from_file(file: &File) -> Result<Self>
Constructs a new instance of Self
from the given std::fs::File
.
Examples found in repository?
More examples
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
pub(crate) fn remove_open_dir_by_searching(dir: fs::File) -> io::Result<()> {
let metadata = Metadata::from_file(&dir)?;
let mut iter = read_dir_unchecked(&dir, Component::ParentDir.as_ref(), FollowSymlinks::No)?;
while let Some(child) = iter.next() {
let child = child?;
if child.is_same_file(&metadata)? {
return child.remove_dir();
}
}
// We didn't find the directory among its parent's children. Check for the
// root directory and handle it specially -- removal will probably fail, so
// we'll get the appropriate error code.
if is_root_dir(&dir, &iter)? {
fs::remove_dir(Component::RootDir.as_os_str())
} else {
Err(errors::no_such_file_or_directory())
}
}
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
pub(crate) fn file_path_by_searching(file: &fs::File) -> Option<PathBuf> {
// Use the `_noassert` functions because the asserts depend on `file_path`,
// which is what we're implementing here.
let mut base = MaybeOwnedFile::borrowed_noassert(file);
let mut components = Vec::new();
// Iterate with `..` until we reach the root directory.
'next_component: loop {
// Open `..`.
let mut iter =
read_dir_unchecked(&base, Component::ParentDir.as_ref(), FollowSymlinks::No).ok()?;
let metadata = Metadata::from_file(&*base).ok()?;
// Search the children until we find one with matching metadata, and
// then record its name.
while let Some(child) = iter.next() {
let child = child.ok()?;
if child.is_same_file(&metadata).ok()? {
// Found a match. Record the name and continue to the next component.
components.push(child.file_name());
base = MaybeOwnedFile::owned_noassert(
open_dir_unchecked(&base, Component::ParentDir.as_ref()).ok()?,
);
continue 'next_component;
}
}
// We didn't find the directory among its parent's children. If we're at
// the root directory, we're done.
if is_root_dir(&base, &iter).ok()? {
break;
}
// Otherwise, something went wrong and we can't determine the path.
return None;
}
let mut path = PathBuf::new();
path.push(Component::RootDir);
for component in components.iter().rev() {
path.push(component);
}
Some(path)
}
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526
pub(crate) fn stat(start: &fs::File, path: &Path, follow: FollowSymlinks) -> io::Result<Metadata> {
// POSIX returns `ENOENT` on an empty path. TODO: On Windows, we should
// be compatible with what Windows does instead.
if path.as_os_str().is_empty() {
return Err(errors::no_such_file_or_directory());
}
let mut options = OpenOptions::new();
options.follow(follow);
let mut symlink_count = 0;
let mut ctx = Context::new(MaybeOwnedFile::borrowed(start), path, &options, None);
assert!(!ctx.dir_precluded);
while let Some(c) = ctx.components.pop() {
match c {
CowComponent::PrefixOrRootDir => return Err(errors::escape_attempt()),
CowComponent::CurDir => ctx.cur_dir()?,
CowComponent::ParentDir => ctx.parent_dir()?,
CowComponent::Normal(one) => {
if ctx.components.is_empty() {
// If this is the last component, do a non-following
// `stat_unchecked` on it.
let stat = stat_unchecked(&ctx.base, one.as_ref(), FollowSymlinks::No)?;
// If we weren't asked to follow symlinks, or it wasn't a
// symlink, we're done.
if options.follow == FollowSymlinks::No || !stat.file_type().is_symlink() {
if stat.is_dir() {
if ctx.dir_precluded {
return Err(errors::is_directory());
}
} else if ctx.dir_required {
return Err(errors::is_not_directory());
}
return Ok(stat);
}
// On Windows, symlinks know whether they are a file or
// directory.
#[cfg(windows)]
if stat.file_attributes() & FILE_ATTRIBUTE_DIRECTORY != 0 {
ctx.dir_required = true;
} else {
ctx.dir_precluded = true;
}
// If it was a symlink and we're asked to follow symlinks,
// dereference it.
ctx.symlink(&one, &mut symlink_count)?
} else {
// Otherwise open the path component normally.
ctx.normal(&one, &options, &mut symlink_count)?
}
}
}
}
// If the path ended in `.` (explicit or implied) or `..`, we may have
// opened the directory with eg. `O_PATH` on Linux, or we may have skipped
// checking for search access to `.`, so re-check it.
if ctx.follow_with_dot {
if ctx.dir_precluded {
return Err(errors::is_directory());
}
ctx.check_dot_access()?;
}
// If the path ended in `.` or `..`, we already have it open, so just do
// `.metadata()` on it.
Metadata::from_file(&*ctx.base)
}
sourcepub fn from_just_metadata(std: Metadata) -> Self
pub fn from_just_metadata(std: Metadata) -> Self
Constructs a new instance of Self
from the given
std::fs::Metadata
.
As with the comments in std::fs::Metadata::volume_serial_number
and
nearby functions, some fields of the resulting metadata will be None
.
sourcepub const fn file_type(&self) -> FileType
pub const fn file_type(&self) -> FileType
Returns the file type for this metadata.
This corresponds to std::fs::Metadata::file_type
.
Examples found in repository?
8 9 10 11 12 13 14 15 16 17 18 19
pub(crate) fn remove_dir_all_impl(start: &fs::File, path: &Path) -> io::Result<()> {
// Code adapted from `remove_dir_all` in Rust's
// library/std/src/sys_common/fs.rs at revision
// 108e90ca78f052c0c1c49c42a22c85620be19712.
let filetype = stat(start, path, FollowSymlinks::No)?.file_type();
if filetype.is_symlink() {
remove_file(start, path)
} else {
remove_dir_all_recursive(read_dir_nofollow(start, path)?)?;
remove_dir(start, path)
}
}
More examples
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
pub(crate) fn open_unchecked(
start: &fs::File,
path: &Path,
options: &OpenOptions,
) -> Result<fs::File, OpenUncheckedError> {
let oflags = compute_oflags(options).map_err(OpenUncheckedError::Other)?;
#[allow(clippy::useless_conversion)]
#[cfg(not(target_os = "wasi"))]
let mode = Mode::from_bits_truncate(options.ext.mode as _);
#[cfg(target_os = "wasi")]
let mode = Mode::empty();
let err = match openat(start, path, oflags, mode) {
Ok(file) => {
return Ok(fs::File::from(file));
}
Err(err) => err,
};
match err {
// `ELOOP` is the POSIX standard and most widely used error code to
// indicate that a symlink was found when `O_NOFOLLOW` was set.
#[cfg(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd")))]
io::Errno::LOOP => Err(OpenUncheckedError::Symlink(err.into(), ())),
// FreeBSD and similar (but not Darwin) use `EMLINK`.
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
io::Errno::MLINK => Err(OpenUncheckedError::Symlink(err.into(), ())),
// NetBSD uses `EFTYPE`.
#[cfg(any(target_os = "netbsd"))]
io::Errno::FTYPE => Err(OpenUncheckedError::Symlink(err.into(), ())),
io::Errno::NOENT => Err(OpenUncheckedError::NotFound(err.into())),
io::Errno::NOTDIR => {
if options.dir_required
&& stat_unchecked(start, path, options.follow)
.map(|m| m.file_type().is_symlink())
.unwrap_or(false)
{
Err(OpenUncheckedError::Symlink(err.into(), ()))
} else {
Err(OpenUncheckedError::NotFound(err.into()))
}
}
_ => Err(OpenUncheckedError::Other(err.into())),
}
}
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526
pub(crate) fn stat(start: &fs::File, path: &Path, follow: FollowSymlinks) -> io::Result<Metadata> {
// POSIX returns `ENOENT` on an empty path. TODO: On Windows, we should
// be compatible with what Windows does instead.
if path.as_os_str().is_empty() {
return Err(errors::no_such_file_or_directory());
}
let mut options = OpenOptions::new();
options.follow(follow);
let mut symlink_count = 0;
let mut ctx = Context::new(MaybeOwnedFile::borrowed(start), path, &options, None);
assert!(!ctx.dir_precluded);
while let Some(c) = ctx.components.pop() {
match c {
CowComponent::PrefixOrRootDir => return Err(errors::escape_attempt()),
CowComponent::CurDir => ctx.cur_dir()?,
CowComponent::ParentDir => ctx.parent_dir()?,
CowComponent::Normal(one) => {
if ctx.components.is_empty() {
// If this is the last component, do a non-following
// `stat_unchecked` on it.
let stat = stat_unchecked(&ctx.base, one.as_ref(), FollowSymlinks::No)?;
// If we weren't asked to follow symlinks, or it wasn't a
// symlink, we're done.
if options.follow == FollowSymlinks::No || !stat.file_type().is_symlink() {
if stat.is_dir() {
if ctx.dir_precluded {
return Err(errors::is_directory());
}
} else if ctx.dir_required {
return Err(errors::is_not_directory());
}
return Ok(stat);
}
// On Windows, symlinks know whether they are a file or
// directory.
#[cfg(windows)]
if stat.file_attributes() & FILE_ATTRIBUTE_DIRECTORY != 0 {
ctx.dir_required = true;
} else {
ctx.dir_precluded = true;
}
// If it was a symlink and we're asked to follow symlinks,
// dereference it.
ctx.symlink(&one, &mut symlink_count)?
} else {
// Otherwise open the path component normally.
ctx.normal(&one, &options, &mut symlink_count)?
}
}
}
}
// If the path ended in `.` (explicit or implied) or `..`, we may have
// opened the directory with eg. `O_PATH` on Linux, or we may have skipped
// checking for search access to `.`, so re-check it.
if ctx.follow_with_dot {
if ctx.dir_precluded {
return Err(errors::is_directory());
}
ctx.check_dot_access()?;
}
// If the path ended in `.` or `..`, we already have it open, so just do
// `.metadata()` on it.
Metadata::from_file(&*ctx.base)
}
sourcepub fn is_dir(&self) -> bool
pub fn is_dir(&self) -> bool
Returns true
if this metadata is for a directory.
This corresponds to std::fs::Metadata::is_dir
.
Examples found in repository?
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526
pub(crate) fn stat(start: &fs::File, path: &Path, follow: FollowSymlinks) -> io::Result<Metadata> {
// POSIX returns `ENOENT` on an empty path. TODO: On Windows, we should
// be compatible with what Windows does instead.
if path.as_os_str().is_empty() {
return Err(errors::no_such_file_or_directory());
}
let mut options = OpenOptions::new();
options.follow(follow);
let mut symlink_count = 0;
let mut ctx = Context::new(MaybeOwnedFile::borrowed(start), path, &options, None);
assert!(!ctx.dir_precluded);
while let Some(c) = ctx.components.pop() {
match c {
CowComponent::PrefixOrRootDir => return Err(errors::escape_attempt()),
CowComponent::CurDir => ctx.cur_dir()?,
CowComponent::ParentDir => ctx.parent_dir()?,
CowComponent::Normal(one) => {
if ctx.components.is_empty() {
// If this is the last component, do a non-following
// `stat_unchecked` on it.
let stat = stat_unchecked(&ctx.base, one.as_ref(), FollowSymlinks::No)?;
// If we weren't asked to follow symlinks, or it wasn't a
// symlink, we're done.
if options.follow == FollowSymlinks::No || !stat.file_type().is_symlink() {
if stat.is_dir() {
if ctx.dir_precluded {
return Err(errors::is_directory());
}
} else if ctx.dir_required {
return Err(errors::is_not_directory());
}
return Ok(stat);
}
// On Windows, symlinks know whether they are a file or
// directory.
#[cfg(windows)]
if stat.file_attributes() & FILE_ATTRIBUTE_DIRECTORY != 0 {
ctx.dir_required = true;
} else {
ctx.dir_precluded = true;
}
// If it was a symlink and we're asked to follow symlinks,
// dereference it.
ctx.symlink(&one, &mut symlink_count)?
} else {
// Otherwise open the path component normally.
ctx.normal(&one, &options, &mut symlink_count)?
}
}
}
}
// If the path ended in `.` (explicit or implied) or `..`, we may have
// opened the directory with eg. `O_PATH` on Linux, or we may have skipped
// checking for search access to `.`, so re-check it.
if ctx.follow_with_dot {
if ctx.dir_precluded {
return Err(errors::is_directory());
}
ctx.check_dot_access()?;
}
// If the path ended in `.` or `..`, we already have it open, so just do
// `.metadata()` on it.
Metadata::from_file(&*ctx.base)
}
sourcepub fn is_file(&self) -> bool
pub fn is_file(&self) -> bool
Returns true
if this metadata is for a regular file.
This corresponds to std::fs::Metadata::is_file
.
sourcepub fn is_symlink(&self) -> bool
pub fn is_symlink(&self) -> bool
Returns true
if this metadata is for a symbolic link.
This corresponds to std::fs::Metadata::is_symlink
.
sourcepub const fn len(&self) -> u64
pub const fn len(&self) -> u64
Returns the size of the file, in bytes, this metadata is for.
This corresponds to std::fs::Metadata::len
.
sourcepub fn permissions(&self) -> Permissions
pub fn permissions(&self) -> Permissions
Returns the permissions of the file this metadata is for.
This corresponds to std::fs::Metadata::permissions
.
sourcepub fn modified(&self) -> Result<SystemTime>
pub fn modified(&self) -> Result<SystemTime>
Returns the last modification time listed in this metadata.
This corresponds to std::fs::Metadata::modified
.
sourcepub fn accessed(&self) -> Result<SystemTime>
pub fn accessed(&self) -> Result<SystemTime>
Returns the last access time of this metadata.
This corresponds to std::fs::Metadata::accessed
.
sourcepub fn created(&self) -> Result<SystemTime>
pub fn created(&self) -> Result<SystemTime>
Returns the creation time listed in this metadata.
This corresponds to std::fs::Metadata::created
.