1pub use outof::OutOf;
3
4use std::os::unix::fs::MetadataExt;
5
6use crate::error::Error;
7
8pub const BLOCK_SIZE: u32 = 512;
9impl TryFrom<&std::fs::DirEntry> for crate::DirEntry {
10 type Error = Error;
11 fn try_from(e: &std::fs::DirEntry) -> Result<Self, Error> {
12 let metadata = e.metadata().map_err(|_| Error::NoFileDir)?;
13 let name = e.file_name();
14 let name = name.to_str().ok_or(Error::Encoding)?;
15 Ok(Self {
16 inode: metadata.ino(),
17 name: name.into(),
18 file_type: file_type(&metadata)?,
19 })
20 }
21}
22
23pub fn file_type(metadata: &std::fs::Metadata) -> Result<fuser::FileType, Error> {
27 let ft = metadata.file_type();
28 if ft.is_dir() {
29 Ok(fuser::FileType::Directory)
30 } else if ft.is_file() {
31 Ok(fuser::FileType::RegularFile)
32 } else if ft.is_symlink() {
33 Ok(fuser::FileType::Symlink)
34 } else {
35 Err(Error::Unimplemented)
36 }
37}
38
39pub fn file_attr(ino: u64, size: u64, time: std::time::SystemTime) -> fuser::FileAttr {
41 fuser::FileAttr {
42 ino,
43 size,
44 blocks: (size as f64 / BLOCK_SIZE as f64).ceil() as u64,
45 atime: time,
46 mtime: time,
47 ctime: time,
48 crtime: time,
49 kind: fuser::FileType::RegularFile,
50 perm: 0o644,
51 nlink: 1,
52 uid: 501,
53 gid: 20,
54 rdev: 0,
55 flags: 0,
56 blksize: BLOCK_SIZE,
57 }
58}
59pub fn dir_attr(ino: u64, children: u32, time: std::time::SystemTime) -> fuser::FileAttr {
60 fuser::FileAttr {
61 ino,
62 size: 0,
63 blocks: 0,
64 atime: time,
65 mtime: time,
66 ctime: time,
67 crtime: time,
68 kind: fuser::FileType::Directory,
69 perm: 0o644,
70 nlink: children + 2,
71 uid: 501,
72 gid: 20,
73 rdev: 0,
74 flags: 0,
75 blksize: BLOCK_SIZE,
76 }
77}
78pub fn unix_timestamp() -> u64 {
79 std::time::SystemTime::now()
80 .duration_since(std::time::SystemTime::UNIX_EPOCH)
81 .unwrap()
82 .as_secs()
83}
84
85mod outof {
86 use num_traits::cast::AsPrimitive;
87 use serde::{Deserialize, Serialize};
88
89 static PERCENT_DEFAULT_DISPLAY_PRECISION: usize = 0;
90 #[derive(Copy, Serialize, Deserialize, Clone)]
99 pub struct OutOf {
100 pub part: f64,
101 pub total: f64,
102 }
103 impl Default for OutOf {
104 fn default() -> Self {
105 Self {
106 part: 0.0,
107 total: 0.0,
108 }
109 }
110 }
111 impl AsPrimitive<f64> for OutOf {
112 fn as_(self) -> f64 {
113 self.part / self.total
114 }
115 }
116 impl OutOf {
117 pub fn new<A: AsPrimitive<f64>, B: AsPrimitive<f64>>(part: A, total: B) -> Self {
118 Self {
119 part: part.as_(),
120 total: total.as_(),
121 }
122 }
123 pub fn perc(&self) -> f64 {
124 self.part / self.total * 100.0
125 }
126 pub fn display_full(&self) -> String {
127 if self.total == 0.0 {
128 format!("{}/{}", self.part, self.total)
129 } else {
130 format!("{}/{} ({})", self.part, self.total, self)
131 }
132 }
133 }
134 impl std::fmt::Display for OutOf {
135 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
136 let prec = f.precision().unwrap_or(PERCENT_DEFAULT_DISPLAY_PRECISION);
137 let ratio = self.as_();
138 if ratio.is_finite() {
139 write!(f, "{:.*}%", prec, 100.0 * ratio)
140 } else {
141 Ok(())
142 }
143 }
144 }
145}