use super::{
lowlevel::{FileAttrs, FileType as SftpFileType, Permissions as SftpPermissions},
UnixTimeStamp,
};
#[derive(Debug, Default, Copy, Clone)]
pub struct MetaDataBuilder(FileAttrs);
impl MetaDataBuilder {
pub const fn new() -> Self {
Self(FileAttrs::new())
}
pub fn reset(&mut self) -> &mut Self {
self.0 = FileAttrs::new();
self
}
pub fn id(&mut self, (uid, gid): (u32, u32)) -> &mut Self {
self.0.set_id(uid, gid);
self
}
pub fn permissions(&mut self, perm: Permissions) -> &mut Self {
self.0.set_permissions(perm.0);
self
}
pub fn len(&mut self, len: u64) -> &mut Self {
self.0.set_size(len);
self
}
pub fn create(&self) -> MetaData {
MetaData::new(self.0)
}
}
#[repr(transparent)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct MetaData(FileAttrs);
#[allow(clippy::len_without_is_empty)]
impl MetaData {
pub(super) fn new(attrs: FileAttrs) -> Self {
Self(attrs)
}
pub(super) fn into_inner(self) -> FileAttrs {
self.0
}
pub fn len(&self) -> Option<u64> {
self.0.get_size()
}
pub fn uid(&self) -> Option<u32> {
self.0.get_id().map(|(uid, _gid)| uid)
}
pub fn gid(&self) -> Option<u32> {
self.0.get_id().map(|(_uid, gid)| gid)
}
pub fn permissions(&self) -> Option<Permissions> {
self.0.get_permissions().map(Permissions)
}
pub fn file_type(&self) -> Option<FileType> {
self.0.get_filetype().map(FileType)
}
pub fn accessed(&self) -> Option<UnixTimeStamp> {
self.0
.get_time()
.map(|(atime, _mtime)| atime)
.map(UnixTimeStamp)
}
pub fn modified(&self) -> Option<UnixTimeStamp> {
self.0
.get_time()
.map(|(_atime, mtime)| mtime)
.map(UnixTimeStamp)
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct FileType(SftpFileType);
impl FileType {
pub fn is_dir(&self) -> bool {
self.0 == SftpFileType::Directory
}
pub fn is_file(&self) -> bool {
self.0 == SftpFileType::RegularFile
}
pub fn is_symlink(&self) -> bool {
self.0 == SftpFileType::Symlink
}
pub fn is_fifo(&self) -> bool {
self.0 == SftpFileType::FIFO
}
pub fn is_socket(&self) -> bool {
self.0 == SftpFileType::Socket
}
pub fn is_block_device(&self) -> bool {
self.0 == SftpFileType::BlockDevice
}
pub fn is_char_device(&self) -> bool {
self.0 == SftpFileType::CharacterDevice
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Permissions(SftpPermissions);
macro_rules! impl_getter_setter {
($getter_name:ident, $setter_name:ident, $variant:ident, $variant_name:expr) => {
#[doc = "Tests whether "]
#[doc = $variant_name]
#[doc = " bit is set."]
pub fn $getter_name(&self) -> bool {
self.0.intersects(SftpPermissions::$variant)
}
#[doc = "Modify the "]
#[doc = $variant_name]
#[doc = " bit."]
pub fn $setter_name(&mut self, value: bool) {
self.0.set(SftpPermissions::$variant, value);
}
};
}
impl Permissions {
pub const fn new() -> Self {
Self(SftpPermissions::empty())
}
impl_getter_setter!(suid, set_suid, SET_UID, "set-user-id");
impl_getter_setter!(sgid, set_sgid, SET_GID, "set-group-id");
impl_getter_setter!(svtx, set_vtx, SET_VTX, "set-sticky-bit");
impl_getter_setter!(
read_by_owner,
set_read_by_owner,
READ_BY_OWNER,
"read by owner"
);
impl_getter_setter!(
write_by_owner,
set_write_by_owner,
WRITE_BY_OWNER,
"write by owner"
);
impl_getter_setter!(
execute_by_owner,
set_execute_by_owner,
EXECUTE_BY_OWNER,
"execute by owner"
);
impl_getter_setter!(
read_by_group,
set_read_by_group,
READ_BY_GROUP,
"read by group"
);
impl_getter_setter!(
write_by_group,
set_write_by_group,
WRITE_BY_GROUP,
"write by group"
);
impl_getter_setter!(
execute_by_group,
set_execute_by_group,
EXECUTE_BY_GROUP,
"execute by group"
);
impl_getter_setter!(
read_by_other,
set_read_by_other,
READ_BY_OTHER,
"read by other"
);
impl_getter_setter!(
write_by_other,
set_write_by_other,
WRITE_BY_OTHER,
"write by other"
);
impl_getter_setter!(
execute_by_other,
set_execute_by_other,
EXECUTE_BY_OTHER,
"execute by other"
);
pub fn readonly(&self) -> bool {
!self.write_by_owner() && !self.write_by_group() && !self.write_by_other()
}
pub fn set_readonly(&mut self, readonly: bool) {
let writable = !readonly;
self.set_write_by_owner(writable);
self.set_write_by_group(writable);
self.set_write_by_other(writable);
}
}