Auto merge of #122812 - dtolnay:mode, r=workingjubilee
Show mode_t as octal in std::fs Debug impls Example: ```rust fn main() { println!("{:?}", std::fs::metadata("Cargo.toml").unwrap().permissions()); } ``` - Before: `Permissions(FilePermissions { mode: 33204 })` - ~~After: `Permissions(FilePermissions { mode: 0o100664 })`~~ - After: `Permissions(FilePermissions { mode: 0o100664 (-rw-rw-r--) })` ~~I thought about using the format from `ls -l` (`-rw-rw-r--`, `drwxrwxr-x`) but I am not sure how transferable the meaning of the higher bits between different unix systems, and anyway starting the value with a leading negative-sign seems objectionable.~~
This commit is contained in:
commit
b14d8b2ef2
@ -1,10 +1,13 @@
|
||||
// miri has some special hacks here that make things unused.
|
||||
#![cfg_attr(miri, allow(unused))]
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use crate::os::unix::prelude::*;
|
||||
|
||||
use crate::ffi::{CStr, OsStr, OsString};
|
||||
use crate::fmt;
|
||||
use crate::fmt::{self, Write as _};
|
||||
use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom};
|
||||
use crate::mem;
|
||||
use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd};
|
||||
@ -356,7 +359,7 @@ pub struct DirEntry {
|
||||
entry: dirent64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone)]
|
||||
pub struct OpenOptions {
|
||||
// generic
|
||||
read: bool,
|
||||
@ -370,7 +373,7 @@ pub struct OpenOptions {
|
||||
mode: mode_t,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct FilePermissions {
|
||||
mode: mode_t,
|
||||
}
|
||||
@ -389,7 +392,7 @@ pub struct FileTimes {
|
||||
created: Option<SystemTime>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, Debug)]
|
||||
#[derive(Copy, Clone, Eq)]
|
||||
pub struct FileType {
|
||||
mode: mode_t,
|
||||
}
|
||||
@ -406,11 +409,13 @@ fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DirBuilder {
|
||||
mode: mode_t,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct Mode(mode_t);
|
||||
|
||||
cfg_has_statx! {{
|
||||
impl FileAttr {
|
||||
fn from_stat64(stat: stat64) -> Self {
|
||||
@ -689,12 +694,26 @@ fn masked(&self) -> mode_t {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for FileType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let FileType { mode } = self;
|
||||
f.debug_struct("FileType").field("mode", &Mode(*mode)).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<u32> for FilePermissions {
|
||||
fn from_inner(mode: u32) -> FilePermissions {
|
||||
FilePermissions { mode: mode as mode_t }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for FilePermissions {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let FilePermissions { mode } = self;
|
||||
f.debug_struct("FilePermissions").field("mode", &Mode(*mode)).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ReadDir {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame.
|
||||
@ -1135,6 +1154,23 @@ fn get_creation_mode(&self) -> io::Result<c_int> {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for OpenOptions {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let OpenOptions { read, write, append, truncate, create, create_new, custom_flags, mode } =
|
||||
self;
|
||||
f.debug_struct("OpenOptions")
|
||||
.field("read", read)
|
||||
.field("write", write)
|
||||
.field("append", append)
|
||||
.field("truncate", truncate)
|
||||
.field("create", create)
|
||||
.field("create_new", create_new)
|
||||
.field("custom_flags", custom_flags)
|
||||
.field("mode", &Mode(*mode))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl File {
|
||||
pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
|
||||
run_path_with_cstr(path, &|path| File::open_c(path, opts))
|
||||
@ -1425,6 +1461,13 @@ pub fn set_mode(&mut self, mode: u32) {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for DirBuilder {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let DirBuilder { mode } = self;
|
||||
f.debug_struct("DirBuilder").field("mode", &Mode(*mode)).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<FileDesc> for File {
|
||||
#[inline]
|
||||
fn as_inner(&self) -> &FileDesc {
|
||||
@ -1597,6 +1640,73 @@ fn get_mode(_fd: c_int) -> Option<(bool, bool)> {
|
||||
}
|
||||
}
|
||||
|
||||
// Format in octal, followed by the mode format used in `ls -l`.
|
||||
//
|
||||
// References:
|
||||
// https://pubs.opengroup.org/onlinepubs/009696899/utilities/ls.html
|
||||
// https://www.gnu.org/software/libc/manual/html_node/Testing-File-Type.html
|
||||
// https://www.gnu.org/software/libc/manual/html_node/Permission-Bits.html
|
||||
//
|
||||
// Example:
|
||||
// 0o100664 (-rw-rw-r--)
|
||||
impl fmt::Debug for Mode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self(mode) = *self;
|
||||
write!(f, "0o{mode:06o}")?;
|
||||
|
||||
let entry_type = match mode & libc::S_IFMT {
|
||||
libc::S_IFDIR => 'd',
|
||||
libc::S_IFBLK => 'b',
|
||||
libc::S_IFCHR => 'c',
|
||||
libc::S_IFLNK => 'l',
|
||||
libc::S_IFIFO => 'p',
|
||||
libc::S_IFREG => '-',
|
||||
_ => return Ok(()),
|
||||
};
|
||||
|
||||
f.write_str(" (")?;
|
||||
f.write_char(entry_type)?;
|
||||
|
||||
// Owner permissions
|
||||
f.write_char(if mode & libc::S_IRUSR != 0 { 'r' } else { '-' })?;
|
||||
f.write_char(if mode & libc::S_IWUSR != 0 { 'w' } else { '-' })?;
|
||||
let owner_executable = mode & libc::S_IXUSR != 0;
|
||||
let setuid = mode as c_int & libc::S_ISUID as c_int != 0;
|
||||
f.write_char(match (owner_executable, setuid) {
|
||||
(true, true) => 's', // executable and setuid
|
||||
(false, true) => 'S', // setuid
|
||||
(true, false) => 'x', // executable
|
||||
(false, false) => '-',
|
||||
})?;
|
||||
|
||||
// Group permissions
|
||||
f.write_char(if mode & libc::S_IRGRP != 0 { 'r' } else { '-' })?;
|
||||
f.write_char(if mode & libc::S_IWGRP != 0 { 'w' } else { '-' })?;
|
||||
let group_executable = mode & libc::S_IXGRP != 0;
|
||||
let setgid = mode as c_int & libc::S_ISGID as c_int != 0;
|
||||
f.write_char(match (group_executable, setgid) {
|
||||
(true, true) => 's', // executable and setgid
|
||||
(false, true) => 'S', // setgid
|
||||
(true, false) => 'x', // executable
|
||||
(false, false) => '-',
|
||||
})?;
|
||||
|
||||
// Other permissions
|
||||
f.write_char(if mode & libc::S_IROTH != 0 { 'r' } else { '-' })?;
|
||||
f.write_char(if mode & libc::S_IWOTH != 0 { 'w' } else { '-' })?;
|
||||
let other_executable = mode & libc::S_IXOTH != 0;
|
||||
let sticky = mode as c_int & libc::S_ISVTX as c_int != 0;
|
||||
f.write_char(match (entry_type, other_executable, sticky) {
|
||||
('d', true, true) => 't', // searchable and restricted deletion
|
||||
('d', false, true) => 'T', // restricted deletion
|
||||
(_, true, _) => 'x', // executable
|
||||
(_, false, _) => '-',
|
||||
})?;
|
||||
|
||||
f.write_char(')')
|
||||
}
|
||||
}
|
||||
|
||||
pub fn readdir(path: &Path) -> io::Result<ReadDir> {
|
||||
let ptr = run_path_with_cstr(path, &|p| unsafe { Ok(libc::opendir(p.as_ptr())) })?;
|
||||
if ptr.is_null() {
|
||||
|
71
library/std/src/sys/pal/unix/fs/tests.rs
Normal file
71
library/std/src/sys/pal/unix/fs/tests.rs
Normal file
@ -0,0 +1,71 @@
|
||||
use crate::sys::pal::unix::fs::FilePermissions;
|
||||
|
||||
#[test]
|
||||
fn test_debug_permissions() {
|
||||
for (expected, mode) in [
|
||||
// typical directory
|
||||
("FilePermissions { mode: 0o040775 (drwxrwxr-x) }", 0o04_0775),
|
||||
// typical text file
|
||||
("FilePermissions { mode: 0o100664 (-rw-rw-r--) }", 0o10_0664),
|
||||
// setuid executable (/usr/bin/doas)
|
||||
("FilePermissions { mode: 0o104755 (-rwsr-xr-x) }", 0o10_4755),
|
||||
// char device (/dev/zero)
|
||||
("FilePermissions { mode: 0o020666 (crw-rw-rw-) }", 0o02_0666),
|
||||
// block device (/dev/vda)
|
||||
("FilePermissions { mode: 0o060660 (brw-rw----) }", 0o06_0660),
|
||||
// symbolic link
|
||||
("FilePermissions { mode: 0o120777 (lrwxrwxrwx) }", 0o12_0777),
|
||||
// fifo
|
||||
("FilePermissions { mode: 0o010664 (prw-rw-r--) }", 0o01_0664),
|
||||
// none
|
||||
("FilePermissions { mode: 0o100000 (----------) }", 0o10_0000),
|
||||
// unrecognized
|
||||
("FilePermissions { mode: 0o000001 }", 1),
|
||||
] {
|
||||
assert_eq!(format!("{:?}", FilePermissions { mode }), expected);
|
||||
}
|
||||
|
||||
for (expected, mode) in [
|
||||
// owner readable
|
||||
("FilePermissions { mode: 0o100400 (-r--------) }", libc::S_IRUSR),
|
||||
// owner writable
|
||||
("FilePermissions { mode: 0o100200 (--w-------) }", libc::S_IWUSR),
|
||||
// owner executable
|
||||
("FilePermissions { mode: 0o100100 (---x------) }", libc::S_IXUSR),
|
||||
// setuid
|
||||
("FilePermissions { mode: 0o104000 (---S------) }", libc::S_ISUID),
|
||||
// owner executable and setuid
|
||||
("FilePermissions { mode: 0o104100 (---s------) }", libc::S_IXUSR | libc::S_ISUID),
|
||||
// group readable
|
||||
("FilePermissions { mode: 0o100040 (----r-----) }", libc::S_IRGRP),
|
||||
// group writable
|
||||
("FilePermissions { mode: 0o100020 (-----w----) }", libc::S_IWGRP),
|
||||
// group executable
|
||||
("FilePermissions { mode: 0o100010 (------x---) }", libc::S_IXGRP),
|
||||
// setgid
|
||||
("FilePermissions { mode: 0o102000 (------S---) }", libc::S_ISGID),
|
||||
// group executable and setgid
|
||||
("FilePermissions { mode: 0o102010 (------s---) }", libc::S_IXGRP | libc::S_ISGID),
|
||||
// other readable
|
||||
("FilePermissions { mode: 0o100004 (-------r--) }", libc::S_IROTH),
|
||||
// other writeable
|
||||
("FilePermissions { mode: 0o100002 (--------w-) }", libc::S_IWOTH),
|
||||
// other executable
|
||||
("FilePermissions { mode: 0o100001 (---------x) }", libc::S_IXOTH),
|
||||
// sticky
|
||||
("FilePermissions { mode: 0o101000 (----------) }", libc::S_ISVTX),
|
||||
// other executable and sticky
|
||||
("FilePermissions { mode: 0o101001 (---------x) }", libc::S_IXOTH | libc::S_ISVTX),
|
||||
] {
|
||||
assert_eq!(format!("{:?}", FilePermissions { mode: libc::S_IFREG | mode }), expected);
|
||||
}
|
||||
|
||||
for (expected, mode) in [
|
||||
// restricted deletion ("sticky") flag is set, and search permission is not granted to others
|
||||
("FilePermissions { mode: 0o041000 (d--------T) }", libc::S_ISVTX),
|
||||
// sticky and searchable
|
||||
("FilePermissions { mode: 0o041001 (d--------t) }", libc::S_ISVTX | libc::S_IXOTH),
|
||||
] {
|
||||
assert_eq!(format!("{:?}", FilePermissions { mode: libc::S_IFDIR | mode }), expected);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user