1#![allow(clippy::unnecessary_cast)]
2pub mod bind_mount;
3pub mod mapping;
4pub mod open_options;
5pub mod whiteout;
6
7use tracing::error;
8
9use std::{fmt::Display, path::PathBuf};
10
11#[cfg(target_os = "macos")]
12use libc::stat as stat64;
13#[cfg(target_os = "linux")]
14use libc::stat64;
15use rfuse3::{FileType, Timestamp, raw::reply::FileAttr};
16use serde::{Deserialize, Serialize};
17
18#[derive(Debug, Deserialize, Serialize, Clone, Default)]
19pub struct GPath {
20 pub path: Vec<String>,
21}
22
23impl GPath {
24 pub fn new() -> GPath {
25 GPath { path: Vec::new() }
26 }
27 pub fn push(&mut self, path: String) {
28 self.path.push(path);
29 }
30 pub fn pop(&mut self) -> Option<String> {
31 self.path.pop()
32 }
33 pub fn name(&self) -> String {
34 self.path.last().unwrap().clone()
35 }
36 pub fn part(&self, i: usize, j: usize) -> String {
37 self.path[i..j].join("/")
38 }
39}
40
41impl From<String> for GPath {
42 fn from(mut s: String) -> GPath {
43 if s.starts_with('/') {
44 s.remove(0);
45 }
46 GPath {
47 path: s.split('/').map(String::from).collect(),
48 }
49 }
50}
51
52impl From<GPath> for PathBuf {
53 fn from(val: GPath) -> Self {
54 let path_str = val.path.join("/");
55 PathBuf::from(path_str)
56 }
57}
58impl Display for GPath {
59 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
60 write!(f, "{}", self.path.join("/"))
61 }
62}
63
64pub fn convert_stat64_to_file_attr(stat: stat64) -> FileAttr {
65 FileAttr {
66 ino: stat.st_ino,
67 size: stat.st_size as u64,
68 blocks: stat.st_blocks as u64,
69 atime: Timestamp::new(stat.st_atime, stat.st_atime_nsec.try_into().unwrap()),
70 mtime: Timestamp::new(stat.st_mtime, stat.st_mtime_nsec.try_into().unwrap()),
71 ctime: Timestamp::new(stat.st_ctime, stat.st_ctime_nsec.try_into().unwrap()),
72 #[cfg(target_os = "macos")]
73 crtime: Timestamp::new(0, 0), kind: filetype_from_mode(stat.st_mode as u32),
75 perm: (stat.st_mode & 0o7777) as u16,
76 nlink: stat.st_nlink as u32,
77 uid: stat.st_uid,
78 gid: stat.st_gid,
79 rdev: stat.st_rdev as u32,
80 #[cfg(target_os = "macos")]
81 flags: 0, blksize: stat.st_blksize as u32,
83 }
84}
85
86pub fn filetype_from_mode(st_mode: u32) -> FileType {
87 let st_mode = st_mode & (libc::S_IFMT as u32);
88 if st_mode == (libc::S_IFIFO as u32) {
89 return FileType::NamedPipe;
90 }
91 if st_mode == (libc::S_IFCHR as u32) {
92 return FileType::CharDevice;
93 }
94 if st_mode == (libc::S_IFBLK as u32) {
95 return FileType::BlockDevice;
96 }
97 if st_mode == (libc::S_IFDIR as u32) {
98 return FileType::Directory;
99 }
100 if st_mode == (libc::S_IFREG as u32) {
101 return FileType::RegularFile;
102 }
103 if st_mode == (libc::S_IFLNK as u32) {
104 return FileType::Symlink;
105 }
106 if st_mode == (libc::S_IFSOCK as u32) {
107 return FileType::Socket;
108 }
109 #[cfg(target_os = "macos")]
114 if st_mode == 0xE000 {
115 return FileType::RegularFile;
116 }
117 error!("wrong st mode : {st_mode}");
118 unreachable!();
119}
120#[cfg(test)]
121mod tests {
122 use super::GPath;
123
124 #[test]
125 fn test_from_string() {
126 let path = String::from("/release");
127 let gapth = GPath::from(path);
128 assert_eq!(gapth.to_string(), String::from("release"))
129 }
130}