hotl_platform/privatefs/
unix.rs1use super::{EffectiveAccess, PrivateFs, Writes};
4use std::fs::{DirBuilder, File, OpenOptions};
5use std::io;
6use std::os::unix::fs::{DirBuilderExt, MetadataExt, OpenOptionsExt, PermissionsExt};
7use std::path::Path;
8
9#[derive(Debug, Clone, Copy, Default)]
10pub struct UnixPrivateFs;
11
12impl UnixPrivateFs {
13 pub const fn new() -> Self {
14 Self
15 }
16}
17
18impl crate::sealed::Sealed for UnixPrivateFs {}
19
20impl PrivateFs for UnixPrivateFs {
21 fn create_dir(&self, path: &Path) -> io::Result<()> {
22 match DirBuilder::new().mode(0o700).recursive(false).create(path) {
23 Ok(()) => Ok(()),
24 Err(e) if e.kind() == io::ErrorKind::AlreadyExists => self.harden_existing(path),
28 Err(e) => Err(e),
29 }
30 }
31
32 fn create_file_new(&self, path: &Path, writes: Writes) -> io::Result<File> {
33 let mut opts = OpenOptions::new();
37 opts.create_new(true).mode(0o600);
38 match writes {
39 Writes::FromStart => opts.write(true),
40 Writes::Append => opts.append(true),
41 };
42 opts.open(path)
43 }
44
45 fn create_file_truncate(&self, path: &Path) -> io::Result<File> {
46 let file = OpenOptions::new()
47 .write(true)
48 .create(true)
49 .truncate(true)
50 .mode(0o600)
51 .open(path)?;
52 self.harden_existing(path)?;
55 Ok(file)
56 }
57
58 fn harden_existing(&self, path: &Path) -> io::Result<()> {
59 let meta = std::fs::metadata(path)?;
60 let mode = if meta.is_dir() { 0o700 } else { 0o600 };
61 std::fs::set_permissions(path, std::fs::Permissions::from_mode(mode))
62 }
63
64 fn effective_access(&self, path: &Path) -> io::Result<EffectiveAccess> {
65 let mode = std::fs::metadata(path)?.mode() & 0o777;
66 let group = mode & 0o070;
67 let other = mode & 0o007;
68 let mut other_readers = Vec::new();
69 if group != 0 {
70 other_readers.push(format!("group ({:03o})", group >> 3));
71 }
72 if other != 0 {
73 other_readers.push(format!("other ({other:03o})"));
74 }
75 Ok(EffectiveAccess {
76 owner_only: other_readers.is_empty(),
77 other_readers,
78 })
79 }
80}