Display file ownership and permissions.

This subsumes #414. Took feedback into account to display more
human-readble permissions. Also, display the owner and group ownership
inline with the permissions themselves.
This commit is contained in:
Austin Riba 2024-08-21 13:52:52 -07:00
parent b6bc5132bb
commit 4ba816b151
4 changed files with 128 additions and 2 deletions

22
Cargo.lock generated
View file

@ -1261,7 +1261,9 @@ dependencies = [
"test-log",
"tokio",
"trash",
"unix_permissions_ext",
"url",
"users",
"vergen",
"xdg",
"xdg-mime",
@ -1530,7 +1532,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.72",
"syn 2.0.75",
]
[[package]]
@ -6093,6 +6095,12 @@ version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
[[package]]
name = "unix_permissions_ext"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7497808a85e03f612f13e9c5061e4c81cdee86e6c00adfa1096690990ccd08e9"
[[package]]
name = "url"
version = "2.5.2"
@ -6111,6 +6119,16 @@ version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
[[package]]
name = "users"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24cc0f6d6f267b73e5a2cadf007ba8f9bc39c6a6f9666f8cf25ea809a153b032"
dependencies = [
"libc",
"log",
]
[[package]]
name = "usvg"
version = "0.37.0"
@ -7413,7 +7431,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.72",
"syn 2.0.75",
]
[[package]]

View file

@ -48,6 +48,8 @@ i18n-embed-fl = "0.7"
rust-embed = "8"
slotmap = "1.0.7"
zip = "2.1.6"
unix_permissions_ext = "0.1.2"
users = "0.11.0"
[dependencies.libcosmic]
git = "https://github.com/pop-os/libcosmic.git"

View file

@ -58,6 +58,15 @@ apply-to-all = Apply to all
keep-both = Keep both
skip = Skip
## Metadata Dialog
owner = Owner
group = Group
other = Other
read = Read
write = Write
execute = Execute
# Context Pages
## About

View file

@ -43,6 +43,7 @@ use std::{
fmt,
fs::{self, Metadata},
num::NonZeroU16,
os::unix::fs::MetadataExt,
path::PathBuf,
sync::{Arc, Mutex},
time::{Duration, Instant},
@ -60,6 +61,8 @@ use crate::{
mime_icon::{mime_for_path, mime_icon},
mouse_area,
};
use unix_permissions_ext::UNIXPermissionsExt;
use users::{get_group_by_gid, get_user_by_uid};
pub const DOUBLE_CLICK_DURATION: Duration = Duration::from_millis(500);
pub const HOVER_DURATION: Duration = Duration::from_millis(1600);
@ -199,6 +202,60 @@ fn format_size(size: u64) -> String {
format!("{} B", size)
}
}
enum PermissionOwner {
Owner,
Group,
Other,
}
fn format_permissions_owner(metadata: &Metadata, owner: PermissionOwner) -> String {
return match owner {
PermissionOwner::Owner => get_user_by_uid(metadata.uid())
.and_then(|user| user.name().to_str().map(ToOwned::to_owned))
.unwrap_or_default(),
PermissionOwner::Group => get_group_by_gid(metadata.gid())
.and_then(|group| group.name().to_str().map(ToOwned::to_owned))
.unwrap_or_default(),
PermissionOwner::Other => String::from(""),
};
}
fn format_permissions(metadata: &Metadata, owner: PermissionOwner) -> String {
let readable = match owner {
PermissionOwner::Owner => metadata.permissions().readable_by_owner(),
PermissionOwner::Group => metadata.permissions().readable_by_group(),
PermissionOwner::Other => metadata.permissions().readable_by_other(),
};
let writeable = match owner {
PermissionOwner::Owner => metadata.permissions().writable_by_owner(),
PermissionOwner::Group => metadata.permissions().writable_by_group(),
PermissionOwner::Other => metadata.permissions().writable_by_other(),
};
let executable = match owner {
PermissionOwner::Owner => metadata.permissions().executable_by_owner(),
PermissionOwner::Group => metadata.permissions().executable_by_group(),
PermissionOwner::Other => metadata.permissions().executable_by_other(),
};
format!(
"{} {} {}",
if readable {
fl!("read")
} else {
String::from("")
},
if writeable {
fl!("write")
} else {
String::from("")
},
if executable {
fl!("execute")
} else {
String::from("")
}
)
.trim_end()
.to_string()
}
#[cfg(not(target_os = "windows"))]
fn hidden_attribute(_metadata: &Metadata) -> bool {
@ -828,6 +885,46 @@ impl Item {
.format_localized(TIME_FORMAT, *LANGUAGE_CHRONO)
)));
}
#[cfg(not(target_os = "windows"))]
{
column = column.push(
widget::Row::new()
.push(widget::text(format!("{}:", fl!("owner"))))
.push(widget::text(format_permissions_owner(
metadata,
PermissionOwner::Owner,
)))
.push(widget::text(format!(
"({})",
format_permissions(metadata, PermissionOwner::Owner,)
)))
.spacing(10),
);
column = column.push(
widget::Row::new()
.push(widget::text(format!("{}:", fl!("group"))))
.push(widget::text(format_permissions_owner(
metadata,
PermissionOwner::Group,
)))
.push(widget::text(format!(
"({})",
format_permissions(metadata, PermissionOwner::Group,)
)))
.spacing(10),
);
column = column.push(
widget::Row::new()
.push(widget::text(format!("{}", fl!("other"))))
.push(widget::text(format!(
"({})",
format_permissions(metadata, PermissionOwner::Other,)
)))
.spacing(10),
);
}
}
ItemMetadata::Trash { .. } => {
//TODO: trash metadata