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