mirror of
https://github.com/Llewellynvdm/exa.git
synced 2024-11-22 20:15:11 +00:00
Merge branch 'sticky-bits'
This adds support for the setuid, setgid, and sticky bits like how ls does it: by replacing the user/group/execute bits with different flags depending on their presence. At least we do it with flair, and by flair, I mean purple. Fixes #142
This commit is contained in:
commit
110613bf95
25
Vagrantfile
vendored
25
Vagrantfile
vendored
@ -274,26 +274,25 @@ Vagrant.configure(2) do |config|
|
||||
|
||||
|
||||
# Awkward permission testcases.
|
||||
# Differences in the way ‘chmod’ handles setting ‘setuid’ and ‘setgid’
|
||||
# when you don’t already own the file mean that we need to use ‘sudo’
|
||||
# to change permissions to those.
|
||||
config.vm.provision :shell, privileged: false, inline: <<-EOF
|
||||
set -xe
|
||||
mkdir "#{test_dir}/permissions"
|
||||
|
||||
touch "#{test_dir}/permissions/all-permissions"
|
||||
chmod 777 "#{test_dir}/permissions/all-permissions"
|
||||
mkdir "#{test_dir}/permissions/forbidden-directory"
|
||||
chmod 000 "#{test_dir}/permissions/forbidden-directory"
|
||||
touch -t #{some_date} "#{test_dir}/permissions/forbidden-directory"
|
||||
sudo chown #{user}:#{user} "#{test_dir}/permissions/forbidden-directory"
|
||||
|
||||
touch "#{test_dir}/permissions/no-permissions"
|
||||
chmod 000 "#{test_dir}/permissions/no-permissions"
|
||||
|
||||
mkdir "#{test_dir}/permissions/forbidden-directory"
|
||||
chmod 000 "#{test_dir}/permissions/forbidden-directory"
|
||||
|
||||
for perms in 001 002 004 010 020 040 100 200 400; do
|
||||
touch "#{test_dir}/permissions/$perms"
|
||||
chmod $perms "#{test_dir}/permissions/$perms"
|
||||
for perms in 000 001 002 004 010 020 040 100 200 400 644 755 777 1000 1001 2000 2010 4000 4100 7666 7777; do
|
||||
touch "#{test_dir}/permissions/$perms"
|
||||
sudo chown #{user}:#{user} "#{test_dir}/permissions/$perms"
|
||||
sudo chmod $perms "#{test_dir}/permissions/$perms"
|
||||
sudo touch -t #{some_date} "#{test_dir}/permissions/$perms"
|
||||
done
|
||||
|
||||
touch -t #{some_date} "#{test_dir}/permissions/"*
|
||||
sudo chown #{user}:#{user} "#{test_dir}/permissions/"*
|
||||
EOF
|
||||
|
||||
|
||||
|
@ -67,6 +67,10 @@ pub struct Permissions {
|
||||
pub other_read: bool,
|
||||
pub other_write: bool,
|
||||
pub other_execute: bool,
|
||||
|
||||
pub sticky: bool,
|
||||
pub setgid: bool,
|
||||
pub setuid: bool,
|
||||
}
|
||||
|
||||
/// The three pieces of information that are displayed as a single column in
|
||||
|
@ -309,19 +309,25 @@ impl<'dir> File<'dir> {
|
||||
|
||||
/// This file’s permissions, with flags for each bit.
|
||||
pub fn permissions(&self) -> f::Permissions {
|
||||
let bits = self.metadata.permissions().mode();
|
||||
let bits = self.metadata.mode();
|
||||
let has_bit = |bit| { bits & bit == bit };
|
||||
|
||||
f::Permissions {
|
||||
user_read: has_bit(modes::USER_READ),
|
||||
user_write: has_bit(modes::USER_WRITE),
|
||||
user_execute: has_bit(modes::USER_EXECUTE),
|
||||
|
||||
group_read: has_bit(modes::GROUP_READ),
|
||||
group_write: has_bit(modes::GROUP_WRITE),
|
||||
group_execute: has_bit(modes::GROUP_EXECUTE),
|
||||
|
||||
other_read: has_bit(modes::OTHER_READ),
|
||||
other_write: has_bit(modes::OTHER_WRITE),
|
||||
other_execute: has_bit(modes::OTHER_EXECUTE),
|
||||
|
||||
sticky: has_bit(modes::STICKY),
|
||||
setgid: has_bit(modes::SETGID),
|
||||
setuid: has_bit(modes::SETUID),
|
||||
}
|
||||
}
|
||||
|
||||
@ -437,12 +443,18 @@ mod modes {
|
||||
pub const USER_READ: Mode = libc::S_IRUSR as Mode;
|
||||
pub const USER_WRITE: Mode = libc::S_IWUSR as Mode;
|
||||
pub const USER_EXECUTE: Mode = libc::S_IXUSR as Mode;
|
||||
|
||||
pub const GROUP_READ: Mode = libc::S_IRGRP as Mode;
|
||||
pub const GROUP_WRITE: Mode = libc::S_IWGRP as Mode;
|
||||
pub const GROUP_EXECUTE: Mode = libc::S_IXGRP as Mode;
|
||||
|
||||
pub const OTHER_READ: Mode = libc::S_IROTH as Mode;
|
||||
pub const OTHER_WRITE: Mode = libc::S_IWOTH as Mode;
|
||||
pub const OTHER_EXECUTE: Mode = libc::S_IXOTH as Mode;
|
||||
|
||||
pub const STICKY: Mode = libc::S_ISVTX as Mode;
|
||||
pub const SETGID: Mode = libc::S_ISGID as Mode;
|
||||
pub const SETUID: Mode = libc::S_ISUID as Mode;
|
||||
}
|
||||
|
||||
|
||||
|
@ -62,7 +62,10 @@ pub struct Permissions {
|
||||
pub other_write: Style,
|
||||
pub other_execute: Style,
|
||||
|
||||
pub attribute: Style,
|
||||
pub special_user_file: Style,
|
||||
pub special_other: Style,
|
||||
|
||||
pub attribute: Style,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||
@ -138,12 +141,18 @@ impl Colours {
|
||||
user_write: Red.bold(),
|
||||
user_execute_file: Green.bold().underline(),
|
||||
user_execute_other: Green.bold(),
|
||||
|
||||
group_read: Yellow.normal(),
|
||||
group_write: Red.normal(),
|
||||
group_execute: Green.normal(),
|
||||
|
||||
other_read: Yellow.normal(),
|
||||
other_write: Red.normal(),
|
||||
other_execute: Green.normal(),
|
||||
|
||||
special_user_file: Purple.normal(),
|
||||
special_other: Purple.normal(),
|
||||
|
||||
attribute: Style::default(),
|
||||
},
|
||||
|
||||
|
@ -6,11 +6,8 @@ use ansi_term::{ANSIString, Style};
|
||||
|
||||
impl f::PermissionsPlus {
|
||||
pub fn render(&self, colours: &Colours) -> TextCell {
|
||||
let x_colour = if self.file_type.is_regular_file() { colours.perms.user_execute_file }
|
||||
else { colours.perms.user_execute_other };
|
||||
|
||||
let mut chars = vec![ self.file_type.render(colours) ];
|
||||
chars.extend(self.permissions.render(colours, x_colour));
|
||||
chars.extend(self.permissions.render(colours, self.file_type.is_regular_file()));
|
||||
|
||||
if self.xattrs {
|
||||
chars.push(colours.perms.attribute.paint("@"));
|
||||
@ -27,7 +24,7 @@ impl f::PermissionsPlus {
|
||||
}
|
||||
|
||||
impl f::Permissions {
|
||||
pub fn render(&self, colours: &Colours, x_colour: Style) -> Vec<ANSIString<'static>> {
|
||||
pub fn render(&self, colours: &Colours, is_regular_file: bool) -> Vec<ANSIString<'static>> {
|
||||
let bit = |bit, chr: &'static str, style: Style| {
|
||||
if bit { style.paint(chr) } else { colours.punctuation.paint("-") }
|
||||
};
|
||||
@ -35,15 +32,44 @@ impl f::Permissions {
|
||||
vec![
|
||||
bit(self.user_read, "r", colours.perms.user_read),
|
||||
bit(self.user_write, "w", colours.perms.user_write),
|
||||
bit(self.user_execute, "x", x_colour),
|
||||
self.user_execute_bit(colours, is_regular_file),
|
||||
bit(self.group_read, "r", colours.perms.group_read),
|
||||
bit(self.group_write, "w", colours.perms.group_write),
|
||||
bit(self.group_execute, "x", colours.perms.group_execute),
|
||||
self.group_execute_bit(colours),
|
||||
bit(self.other_read, "r", colours.perms.other_read),
|
||||
bit(self.other_write, "w", colours.perms.other_write),
|
||||
bit(self.other_execute, "x", colours.perms.other_execute),
|
||||
self.other_execute_bit(colours)
|
||||
]
|
||||
}
|
||||
|
||||
fn user_execute_bit(&self, colours: &Colours, is_regular_file: bool) -> ANSIString<'static> {
|
||||
match (self.user_execute, self.setuid, is_regular_file) {
|
||||
(false, false, _) => colours.punctuation.paint("-"),
|
||||
(true, false, false) => colours.perms.user_execute_other.paint("x"),
|
||||
(true, false, true) => colours.perms.user_execute_file.paint("x"),
|
||||
(false, true, _) => colours.perms.special_other.paint("S"),
|
||||
(true, true, false) => colours.perms.special_other.paint("s"),
|
||||
(true, true, true) => colours.perms.special_user_file.paint("s"),
|
||||
}
|
||||
}
|
||||
|
||||
fn group_execute_bit(&self, colours: &Colours) -> ANSIString<'static> {
|
||||
match (self.group_execute, self.setgid) {
|
||||
(false, false) => colours.punctuation.paint("-"),
|
||||
(true, false) => colours.perms.group_execute.paint("x"),
|
||||
(false, true) => colours.perms.special_other.paint("S"),
|
||||
(true, true) => colours.perms.special_other.paint("s"),
|
||||
}
|
||||
}
|
||||
|
||||
fn other_execute_bit(&self, colours: &Colours) -> ANSIString<'static> {
|
||||
match (self.other_execute, self.sticky) {
|
||||
(false, false) => colours.punctuation.paint("-"),
|
||||
(true, false) => colours.perms.other_execute.paint("x"),
|
||||
(false, true) => colours.perms.special_other.paint("T"),
|
||||
(true, true) => colours.perms.special_other.paint("t"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl f::Type {
|
||||
@ -76,21 +102,21 @@ pub mod test {
|
||||
#[test]
|
||||
fn negate() {
|
||||
let mut details = Details::default();
|
||||
details.colours.punctuation = Fixed(44).normal();
|
||||
details.colours.punctuation = Fixed(11).normal();
|
||||
|
||||
let bits = f::Permissions {
|
||||
user_read: false, user_write: false, user_execute: false,
|
||||
group_read: false, group_write: false, group_execute: false,
|
||||
other_read: false, other_write: false, other_execute: false,
|
||||
user_read: false, user_write: false, user_execute: false, setuid: false,
|
||||
group_read: false, group_write: false, group_execute: false, setgid: false,
|
||||
other_read: false, other_write: false, other_execute: false, sticky: false,
|
||||
};
|
||||
|
||||
let expected = TextCellContents::from(vec![
|
||||
Fixed(44).paint("-"), Fixed(44).paint("-"), Fixed(44).paint("-"),
|
||||
Fixed(44).paint("-"), Fixed(44).paint("-"), Fixed(44).paint("-"),
|
||||
Fixed(44).paint("-"), Fixed(44).paint("-"), Fixed(44).paint("-"),
|
||||
Fixed(11).paint("-"), Fixed(11).paint("-"), Fixed(11).paint("-"),
|
||||
Fixed(11).paint("-"), Fixed(11).paint("-"), Fixed(11).paint("-"),
|
||||
Fixed(11).paint("-"), Fixed(11).paint("-"), Fixed(11).paint("-"),
|
||||
]);
|
||||
|
||||
assert_eq!(expected, bits.render(&details.colours, Fixed(66).normal()).into())
|
||||
assert_eq!(expected, bits.render(&details.colours, false).into())
|
||||
}
|
||||
|
||||
|
||||
@ -99,6 +125,7 @@ pub mod test {
|
||||
let mut details = Details::default();
|
||||
details.colours.perms.user_read = Fixed(101).normal();
|
||||
details.colours.perms.user_write = Fixed(102).normal();
|
||||
details.colours.perms.user_execute_file = Fixed(103).normal();
|
||||
|
||||
details.colours.perms.group_read = Fixed(104).normal();
|
||||
details.colours.perms.group_write = Fixed(105).normal();
|
||||
@ -109,9 +136,9 @@ pub mod test {
|
||||
details.colours.perms.other_execute = Fixed(109).normal();
|
||||
|
||||
let bits = f::Permissions {
|
||||
user_read: true, user_write: true, user_execute: true,
|
||||
group_read: true, group_write: true, group_execute: true,
|
||||
other_read: true, other_write: true, other_execute: true,
|
||||
user_read: true, user_write: true, user_execute: true, setuid: false,
|
||||
group_read: true, group_write: true, group_execute: true, setgid: false,
|
||||
other_read: true, other_write: true, other_execute: true, sticky: false,
|
||||
};
|
||||
|
||||
let expected = TextCellContents::from(vec![
|
||||
@ -120,6 +147,51 @@ pub mod test {
|
||||
Fixed(107).paint("r"), Fixed(108).paint("w"), Fixed(109).paint("x"),
|
||||
]);
|
||||
|
||||
assert_eq!(expected, bits.render(&details.colours, Fixed(103).normal()).into())
|
||||
assert_eq!(expected, bits.render(&details.colours, true).into())
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn specials() {
|
||||
let mut details = Details::default();
|
||||
details.colours.punctuation = Fixed(11).normal();
|
||||
details.colours.perms.special_user_file = Fixed(77).normal();
|
||||
details.colours.perms.special_other = Fixed(88).normal();
|
||||
|
||||
let bits = f::Permissions {
|
||||
user_read: false, user_write: false, user_execute: true, setuid: true,
|
||||
group_read: false, group_write: false, group_execute: true, setgid: true,
|
||||
other_read: false, other_write: false, other_execute: true, sticky: true,
|
||||
};
|
||||
|
||||
let expected = TextCellContents::from(vec![
|
||||
Fixed(11).paint("-"), Fixed(11).paint("-"), Fixed(77).paint("s"),
|
||||
Fixed(11).paint("-"), Fixed(11).paint("-"), Fixed(88).paint("s"),
|
||||
Fixed(11).paint("-"), Fixed(11).paint("-"), Fixed(88).paint("t"),
|
||||
]);
|
||||
|
||||
assert_eq!(expected, bits.render(&details.colours, true).into())
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn extra_specials() {
|
||||
let mut details = Details::default();
|
||||
details.colours.punctuation = Fixed(11).normal();
|
||||
details.colours.perms.special_other = Fixed(88).normal();
|
||||
|
||||
let bits = f::Permissions {
|
||||
user_read: false, user_write: false, user_execute: false, setuid: true,
|
||||
group_read: false, group_write: false, group_execute: false, setgid: true,
|
||||
other_read: false, other_write: false, other_execute: false, sticky: true,
|
||||
};
|
||||
|
||||
let expected = TextCellContents::from(vec![
|
||||
Fixed(11).paint("-"), Fixed(11).paint("-"), Fixed(88).paint("S"),
|
||||
Fixed(11).paint("-"), Fixed(11).paint("-"), Fixed(88).paint("S"),
|
||||
Fixed(11).paint("-"), Fixed(11).paint("-"), Fixed(88).paint("T"),
|
||||
]);
|
||||
|
||||
assert_eq!(expected, bits.render(&details.colours, true).into())
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
/testcases/permissions/forbidden-directory: Permission denied (os error 13)
|
||||
[4mPermissions[0m [4mSize[0m [4mUser[0m [4mGroup[0m [4mDate Modified[0m [4mName[0m
|
||||
.[38;5;244m---------[0m [1;32m0[0m cassowary cassowary [34m 1 Jan 12:34[0m 000
|
||||
.[38;5;244m--------[32mx[0m [1;32m0[0m cassowary cassowary [34m 1 Jan 12:34[0m 001
|
||||
.[38;5;244m-------[31mw[38;5;244m-[0m [1;32m0[0m cassowary cassowary [34m 1 Jan 12:34[0m 002
|
||||
.[38;5;244m------[33mr[38;5;244m--[0m [1;32m0[0m cassowary cassowary [34m 1 Jan 12:34[0m 004
|
||||
@ -9,6 +10,15 @@
|
||||
.[38;5;244m--[1;4;32mx[0m[38;5;244m------[0m [1;32m0[0m cassowary cassowary [34m 1 Jan 12:34[0m [1;32m100[0m
|
||||
.[38;5;244m-[1;31mw[0m[38;5;244m-------[0m [1;32m0[0m cassowary cassowary [34m 1 Jan 12:34[0m 200
|
||||
.[1;33mr[0m[38;5;244m--------[0m [1;32m0[0m cassowary cassowary [34m 1 Jan 12:34[0m 400
|
||||
.[1;33mr[31mw[4;32mx[0m[33mr[31mw[32mx[33mr[31mw[32mx[0m [1;32m0[0m cassowary cassowary [34m 1 Jan 12:34[0m [1;32mall-permissions[0m
|
||||
.[1;33mr[31mw[0m[38;5;244m-[33mr[38;5;244m--[33mr[38;5;244m--[0m [1;32m0[0m cassowary cassowary [34m 1 Jan 12:34[0m 644
|
||||
.[1;33mr[31mw[4;32mx[0m[33mr[38;5;244m-[32mx[33mr[38;5;244m-[32mx[0m [1;32m0[0m cassowary cassowary [34m 1 Jan 12:34[0m [1;32m755[0m
|
||||
.[1;33mr[31mw[4;32mx[0m[33mr[31mw[32mx[33mr[31mw[32mx[0m [1;32m0[0m cassowary cassowary [34m 1 Jan 12:34[0m [1;32m777[0m
|
||||
.[38;5;244m--------[35mT[0m [1;32m0[0m cassowary cassowary [34m 1 Jan 12:34[0m 1000
|
||||
.[38;5;244m--------[35mt[0m [1;32m0[0m cassowary cassowary [34m 1 Jan 12:34[0m 1001
|
||||
.[38;5;244m-----[35mS[38;5;244m---[0m [1;32m0[0m cassowary cassowary [34m 1 Jan 12:34[0m 2000
|
||||
.[38;5;244m-----[35ms[38;5;244m---[0m [1;32m0[0m cassowary cassowary [34m 1 Jan 12:34[0m 2010
|
||||
.[38;5;244m--[35mS[38;5;244m------[0m [1;32m0[0m cassowary cassowary [34m 1 Jan 12:34[0m 4000
|
||||
.[38;5;244m--[35ms[38;5;244m------[0m [1;32m0[0m cassowary cassowary [34m 1 Jan 12:34[0m [1;32m4100[0m
|
||||
.[1;33mr[31mw[0m[35mS[33mr[31mw[35mS[33mr[31mw[35mT[0m [1;32m0[0m cassowary cassowary [34m 1 Jan 12:34[0m 7666
|
||||
.[1;33mr[31mw[0m[35ms[33mr[31mw[35ms[33mr[31mw[35mt[0m [1;32m0[0m cassowary cassowary [34m 1 Jan 12:34[0m [1;32m7777[0m
|
||||
[1;34md[0m[38;5;244m---------[0m [38;5;244m-[0m cassowary cassowary [34m 1 Jan 12:34[0m [1;34mforbidden-directory[0m
|
||||
.[38;5;244m---------[0m [1;32m0[0m cassowary cassowary [34m 1 Jan 12:34[0m no-permissions
|
||||
|
@ -1,5 +1,6 @@
|
||||
/testcases/permissions/forbidden-directory: Permission denied (os error 13)
|
||||
[4mPermissions[0m [4mSize[0m [4mUser[0m [4mGroup[0m [4mDate Modified[0m [4mName[0m
|
||||
.[38;5;244m---------[0m [1;32m0[0m [1;33mcassowary[0m [1;33mcassowary[0m [34m 1 Jan 12:34[0m 000
|
||||
.[38;5;244m--------[32mx[0m [1;32m0[0m [1;33mcassowary[0m [1;33mcassowary[0m [34m 1 Jan 12:34[0m 001
|
||||
.[38;5;244m-------[31mw[38;5;244m-[0m [1;32m0[0m [1;33mcassowary[0m [1;33mcassowary[0m [34m 1 Jan 12:34[0m 002
|
||||
.[38;5;244m------[33mr[38;5;244m--[0m [1;32m0[0m [1;33mcassowary[0m [1;33mcassowary[0m [34m 1 Jan 12:34[0m 004
|
||||
@ -9,6 +10,15 @@
|
||||
.[38;5;244m--[1;4;32mx[0m[38;5;244m------[0m [1;32m0[0m [1;33mcassowary[0m [1;33mcassowary[0m [34m 1 Jan 12:34[0m [1;32m100[0m
|
||||
.[38;5;244m-[1;31mw[0m[38;5;244m-------[0m [1;32m0[0m [1;33mcassowary[0m [1;33mcassowary[0m [34m 1 Jan 12:34[0m 200
|
||||
.[1;33mr[0m[38;5;244m--------[0m [1;32m0[0m [1;33mcassowary[0m [1;33mcassowary[0m [34m 1 Jan 12:34[0m 400
|
||||
.[1;33mr[31mw[4;32mx[0m[33mr[31mw[32mx[33mr[31mw[32mx[0m [1;32m0[0m [1;33mcassowary[0m [1;33mcassowary[0m [34m 1 Jan 12:34[0m [1;32mall-permissions[0m
|
||||
.[1;33mr[31mw[0m[38;5;244m-[33mr[38;5;244m--[33mr[38;5;244m--[0m [1;32m0[0m [1;33mcassowary[0m [1;33mcassowary[0m [34m 1 Jan 12:34[0m 644
|
||||
.[1;33mr[31mw[4;32mx[0m[33mr[38;5;244m-[32mx[33mr[38;5;244m-[32mx[0m [1;32m0[0m [1;33mcassowary[0m [1;33mcassowary[0m [34m 1 Jan 12:34[0m [1;32m755[0m
|
||||
.[1;33mr[31mw[4;32mx[0m[33mr[31mw[32mx[33mr[31mw[32mx[0m [1;32m0[0m [1;33mcassowary[0m [1;33mcassowary[0m [34m 1 Jan 12:34[0m [1;32m777[0m
|
||||
.[38;5;244m--------[35mT[0m [1;32m0[0m [1;33mcassowary[0m [1;33mcassowary[0m [34m 1 Jan 12:34[0m 1000
|
||||
.[38;5;244m--------[35mt[0m [1;32m0[0m [1;33mcassowary[0m [1;33mcassowary[0m [34m 1 Jan 12:34[0m 1001
|
||||
.[38;5;244m-----[35mS[38;5;244m---[0m [1;32m0[0m [1;33mcassowary[0m [1;33mcassowary[0m [34m 1 Jan 12:34[0m 2000
|
||||
.[38;5;244m-----[35ms[38;5;244m---[0m [1;32m0[0m [1;33mcassowary[0m [1;33mcassowary[0m [34m 1 Jan 12:34[0m 2010
|
||||
.[38;5;244m--[35mS[38;5;244m------[0m [1;32m0[0m [1;33mcassowary[0m [1;33mcassowary[0m [34m 1 Jan 12:34[0m 4000
|
||||
.[38;5;244m--[35ms[38;5;244m------[0m [1;32m0[0m [1;33mcassowary[0m [1;33mcassowary[0m [34m 1 Jan 12:34[0m [1;32m4100[0m
|
||||
.[1;33mr[31mw[0m[35mS[33mr[31mw[35mS[33mr[31mw[35mT[0m [1;32m0[0m [1;33mcassowary[0m [1;33mcassowary[0m [34m 1 Jan 12:34[0m 7666
|
||||
.[1;33mr[31mw[0m[35ms[33mr[31mw[35ms[33mr[31mw[35mt[0m [1;32m0[0m [1;33mcassowary[0m [1;33mcassowary[0m [34m 1 Jan 12:34[0m [1;32m7777[0m
|
||||
[1;34md[0m[38;5;244m---------[0m [38;5;244m-[0m [1;33mcassowary[0m [1;33mcassowary[0m [34m 1 Jan 12:34[0m [1;34mforbidden-directory[0m
|
||||
.[38;5;244m---------[0m [1;32m0[0m [1;33mcassowary[0m [1;33mcassowary[0m [34m 1 Jan 12:34[0m no-permissions
|
||||
|
Loading…
Reference in New Issue
Block a user